C言語には、メモリ上の位置を示すポインタという機能が用意されています。今回は、このポインタについて学びます。
メモリのアドレスの仕組み
メモリは、コンピュータのデータが記憶されているものということは、ご存じの方も多いと思います。このメモリ上の位置を示すのがアドレスになります。メモリ上の住所だと思っていただければわかりやすいかもしれません。
C言語のアドレスとは、メモリの場所を直接あらわすために使用されます。プログラミングでは、16進数を使って表していることが多いです。(例:0x10000000、0x10000002・・・)
実際に、メモリのアドレスを表示してみたいと思います。
変数の値が格納されているメモリのアドレスを知るためには、アドレス演算子( & )を使います。&を変数名の前に記述します。
アドレス演算子
&変数名
変数のアドレスを表示するサンプルプログラムを次に示します。
#include <stdio.h>
int main(void)
{
int number = 1;
printf("変数:%d\n", number);
printf("変数のアドレス:%p\n", &number);
return 0;
}
変換指定子の %p は、ポインタで出力するときに指定する変換指定子です。
サンプルプログラムを実行した結果は次のようになります。
実行結果
変数:1
変数のアドレス:000000000061FE1C
変数のnumberの前に&を付けることによって、変数のアドレスを表します。
ポインタの仕組み
変数の値を格納しているアドレスは知ることができました。今度は、このアドレスを格納する変数について学びます。
アドレスを格納する変数のことをポインタ変数と呼びます。
ポインタ変数を宣言するには次のようにします。
ポインタの宣言
型名 *変数名 ;
int *pointer;
この例では、pointer変数は、int型の変数のアドレスを格納できる変数として宣言しています。
変数の前に*が付いていますが、変数名には含みません。あくまで変数名は、pointerになります。
実際にこのポインタ変数にアドレスを格納するサンプルプログラムを次に示します。
#include <stdio.h>
int main(void)
{
int number = 5;
int *pointer;
pointer = &number;
printf("number:%d\n", number);
printf("numberアドレス:%p\n", &number);
printf("pointer:%p\n", pointer);
return 0;
}
8行目で、number変数の前に&を付けることによりアドレスが指定されて、それをpointerに格納しています。
これにより、pointerは、number変数と同じアドレスを示していることになります。
10行目のprintf関数では、従来通り変数の値を表示しています。
11行目では、number変数のアドレスを表示しています。
12行目では、number変数のアドレスを格納したpointer変数の値を表示しています。
実行結果は次にようになります。
実行結果
number:5
numberアドレス:000000000061FE14
pointer:000000000061FE14
このように、number変数のアドレスを代入しているので、pointerの値は、number変数のアドレスと同じとなります。
同じということは、pointer変数が示すアドレスに格納されている値は、number変数の値と同じことになっています。
ポインタ変数にアドレスが格納されていると、ポインタ変数を使用して、アドレスに格納されている値を知ることができます。
ポインタ変数のアドレスに格納されている値を知るには、*演算子(間接参照演算子)と呼ばれるものを使用します。
間接参照演算子
*ポインタ変数
*演算子を使うと、そのポインタ変数のアドレスに格納されている値を知ることができます。
実際に、ポインタ変数にアドレスに格納されている値を表示するサンプルプログラムを次に示します。
#include <stdio.h>
int main(void)
{
int number = 5;
int *pointer;
pointer = &number;
printf("number:%d\n", number);
printf("pointer:%d\n", *pointer);
return 0;
}
前のサンプルプログラムと同様に、8行目で、number変数のアドレスをpointerに格納しています。
11行目のprintf関数では、*pointerにてnumber変数のアドレスの値を表示しています。
実行結果は次にようになります。
実行結果
number:5
pointer:5
pointerのアドレスの値がnumber変数と同じとなっています。
ポインタ変数は、変数のアドレスを代入する以外にも、ポインタ変数同士の代入もできます。また、ポインタを使用して変数の値を変更することも可能です。
サンプルプログラムを次に示します。
#include <stdio.h>
int main(void)
{
int number = 5;
int *p1;
int *p2;
p1 = &number;
p2 = p1;
*p2 = 1;
printf("number:%d\n", number);
printf("pointer:%d\n", *p1);
printf("pointer:%d\n", *p2);
printf("number:%p\n", &number);
printf("pointer:%p\n", p1);
printf("pointer:%p\n", p2);
return 0;
}
10行目では、number変数のアドレスを格納しているポインタ変数p1をポインタ変数p2に代入しています。このようにポインタ同士の代入が可能です。
11行目では、ポインタ変数に格納しているアドレスの値を変更しています。このように、*を付けたポインタ変数へ値を代入することができます。これは、*を付けると、ポインタ変数に格納しているアドレスに割当たっている変数と同じ意味となるためです。サンプルプログラムでは、number変数と*p1と*p2は同じ変数を示しています。
ポインタの基本的な仕組みについては以上になります。
次に、関数の引数として使用するポインタについて学びます。