PR ソフトウェア

【ソフトウェア開発】C言語のポインタについて解説

前回記事の流れでC言語のポインタについてお話しします。

今回の記事の内容はこれからIT業界を目指す人向けの内容からは少し脱線した内容となります。
とはいえ、機会の兼ね合いで、今回、あえて書かせていただきますことご了承ください。

C言語のポインタを意識するのはプログラミングの仕事を初めてから2から3ヶ月後ぐらいの仕事内容がきっかけからくるのではとイメージしています。
このため、その2から3ヶ月後ぐらいの時期にこの記事を改めて読んでもらえるとうれしいです。

あわせてC言語自体これからという方が多いかと思いますので斜め読みだけで十分です。
本記事ではここでは敢えてC言語の文法など基礎部分については書きません。

それではまいりましょう。

C言語ポインタを学ぶための学習書

私がC言語を学ぶ上で役にたった本(今でも大切に保持している本)をご紹介いたします。

C言語は書籍による学習と実践(仕事)で身につけることがベストです。

  • 「はじめてのC(改訂第4版[ANSI C対応])」(技術評論社)
  • 「ビジュアルラーニング C++入門」(X-media)
  • 「C言語ポインタが理解できない理由」(技術評論社)
  • 「図解雑学 CPUの働きと高速化のしくみ」(ナツメ社)

その他、独習シリーズ(翔泳社)などありますが、まずは、上の4つをお勧めします。

ここからは本記事ではC言語のポインタのお話しします。
C言語でつまずく原因で一番多いのが、ポインタです。

C言語ポインタを理解するためのポイント

ポインタは住所

ポインタ型変数の中身=先頭1バイト目のアドレス番地

ポインタは1バイト、8ビットの数字です。
正確には32bitCPUの場合ですけどね。

メモリのアドレス番地とはメモリ上の住所(**県**市**町***番地のような)のことです。
しかしメモリのアドレス番地の値は"0x03fdab21"のような形で16進数で表現されます。
しかし、この数字自体は覚える必要がありません、というか意味がありません。
(例)char *a → 変数aにはメモリアドレスの住所が格納される。

ポインタの値は住所にある家

ポインタ型変数の左に*を付けた時の中身=メモリのアドレス番地に立っている建築物の名前

(例)char *a → 変数*aにはメモリアドレス番地に立っている建築物の名前が格納される。

ポインタをずらすということは場所をずらすこと

ポインタを1つずらすということ=メモリのアドレス番地を変数型のサイズバイト分ずらすということ

(例)char型ポインタの場合
char* aのaに"0x03fdab21"という住所が入っていた場合に、
aを1つ前にずらす(a++;)とchar型のサイズ1byte分、住所がずれ、住所は"0x03fdab22"となる。

(例)int型ポインタの場合
int* bのbに"0x03fdab21"という住所が入っていた場合に、
bを1つ前にずらす(b++;)とint型のサイズ4byte分、住所がずれ、住所は"0x03fdab25"となる。

構造体ポインタの例

上の考え方はその他のポインタ(構造体型変数ポインタや関数ポインタ(C言語の中でも高等技術に相当します))でも同じです(=ポインタのサイズは常に1バイトしかない)。

(例)構造体型変数ポインタの例

typedef struct *kouzoutaipointer{
  char b;
  int c;
  double d;
}

kouzoutaipointer* a = malloc(kouzoutaipointer構造体のバイトサイズ)の時、aには先頭1バイト目のメモリアドレス番地(char bの住所)が入っている。
構造体の値はa->b等で参照または変更できる。

ダブルポインタは住所の住所

ダブルポインタは、できれば使わないほうがいいです。
プログラミングコードの可読性が失われがちになる状況を見てきましたので、推奨しません。

char **a →いわゆるポインタのポインタ(アドレスのアドレス)というものです。
実際の利用例で理解したほうがわかりやすいでしょう。

(例)関数内で引数のアドレスを更新したい(例えば関数内でメモリ領域確保し、その先頭のアドレスを再設定したい)場合等

関数内で引数のアドレスを更新したい(例えば関数内でメモリ領域確保し、その先頭のアドレスを再設定したい)場合等

   void doublepointerfunc( char** a ){
        ...
         *a = &GLOBAL_HENSUU;(または*a = malloc(sizeof(4));)
        ...
      }

呼び出し側では

char **b = null;
*b = &a;

このタイミングで*bにはaのメモリアドレス番地が入っている。

doublepointerfunc(b);

このタイミングで*bにはGLOBAL_HENSUU(またはmalloc(sizeof(4))で確保したメモリの先頭)のメモリアドレス番地に置き換わっている。

最後に

これからC言語を学ぼうという方にとっては、ちんぷんかんぷんな内容だったかもしれません。

数か月後、改めてこの記事を思い出して頂ければ、少し救われます。。。

ただ、これからC言語を学ぼうという方にとっても、少しは参考になりそうな点があったかもしれないと思っています。

例えば"メモリ"、"16進数表記"等、これらはC言語の知識というよりもIT全般に共通する知識です。
このため、C言語の書籍学習(冒頭で紹介した本等を利用した学習)と並行してIT全般に共通する知識の学習も同時並行で進めていけるとベストだと思います。

-ソフトウェア