アドレスとポインタ
コンピュータのメモリは多くのセルに分割されており、それぞれのセルには固有の番号が与えられています。この番号をアドレスといいます。変数を宣言すると、メモリ内の特定のアドレスに位置するセルにスペースが確保されます。
C言語においては、アドレスを直接利用してデータを操作することが可能です。そのためには、変数のアドレスを格納する特別なタイプの変数、すなわちポインタが必要になります。
ポインタとは、アドレスを保持する変数のことです。
この章では、アドレスとポインタに焦点を当てます。
ポインタの基本的な使い方
1.ポインタ変数の宣言
ポインタ変数は変数名の前に*(アスタリスク)を付けて宣言します。
ポインタ変数であることを宣言するため、*(アスタリスク)が必要です。
int *p;

`int *p`と宣言することで、int型のポインタ変数pがメモリ上に確保されます。仮にアドレスを0x35とします。
2.アドレスの取得
変数のアドレスを取得するには、変数の前に&(アンパサンド)を付けます。
int a = 10;
p = &a;

int型の変数aに10を代入すると、メモリ上にaが確保されます。例えば、そのアドレスが0x39だとしましょう。

`p = &a` と記述すると、変数aのアドレスがポインタ変数pに代入されます。この場合、アドレス0x39がpに代入されることになります。
3.値の参照
ポインタが指し示すアドレスの値を取得するにはポインタ変数の前に*(アスタリスク)を付けます。
int value = *p;

int型の変数valueは、`int value = *p;`という記述によってメモリ上に確保され、ポインタ変数pが指すアドレスのメモリから値を取得してvalueにコピーします。例えば、ポインタ変数pがアドレス0x39を指している場合、そのアドレスにある値10がvalueに代入されます。
4.ポインタ変数を使って値を代入
ポインタ変数を使って、ポインタ変数が指し示す領域に値を代入することもできます。
*p = 100;

`*p = 100;` と記述することで、ポインタ変数pが指し示している領域に100を代入します。
結果、aに100が代入されます。
実際のプログラムコードを書いて確かめてみましょう。
#include <stdio.h>
int main(void){
int *p;
int a = 10;
int value;
p = &a;
printf("aのアドレス=%p\n",&a);
printf("pの中身=%p\n",p);
printf("pの指し示す場所の値=%d\n",*p);
value = *p;
printf("value=%d\n",value);
*p = 100;
printf("*p=%d\n",*p);
printf("a=%d\n",a);
return 0;
}
aのアドレス=0000008fd9fffce0
pの中身=0000008fd9fffce0
pの指し示す場所の値=10
value=10
*p=100
a=100
関数の引数について
関数の説明で、関数には引数を渡すことができると説明していました。
関数の引数には値を渡す「値渡し」とポインタを渡す「ポインタ渡し」が存在します。
1.値渡しについて
変数の値のみを渡す方法で、呼び出し元の変数の値には影響を与えません。
int sum(int a, int b);
int main(void){
int x = 10;
int y= 20;
int z = sum(10,20);
printf("%d + %d = %d\n",x,y,z);
return 0;
}
int sum(int a, int b){
int c = a + b;
a++;
b++;
printf("a=%d,b=%d,c=%d\n",a,b,c);
return c;
}
このサンプルプログラムでは、関数main()側で変数x,yを定義します。
x,yの値を実引数として関数sum()を呼び出します。
関数sum()では、仮引数a,bがメモリ上に用意され、実引数x,yの値を代入しています。
したがって、関数sum()で引数a、bの値を変更しても、呼び出し元のx、yの値は変わりません。

実行結果
a=11,b=21,c=30
10 + 20 = 30
2.ポインタ渡しについて
ポインタ変数を関数の引数にする方法です。
呼び出し側は、変数のアドレスを渡し、受け取り側はポインタ変数で受け取ります。
呼び出し側の変数の値にも影響を与えます。
void swap(int *a, int *b){
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int main(void){
int x = 10;
int y = 20;
printf("関数呼び出し前の値:x=%d,y=%d\n",x,y);
swap(&x,&y);
printf("関数呼び出し後の値:x=%d,y=%d\n",x,y);
return 0;
}
関数main()は変数x,yのアドレスを実引数として関数swap()を呼び出します。
関数swap()は、ポインタ変数を受け取り、ポインタ変数が指し示す領域の値を入れ替える処理を行っています。
そのため、関数swap()の実行後は、変数x,yの値が変わっています。

実行結果
関数呼び出し前の値:x=10,y=20
関数呼び出し後の値:x=20,y=10
swapについて
2つの変数の値を交換する際には、2つの変数だけでは交換ができないため、一方の変数の値を一時的に保持するための別の変数を用意し、その変数を使って値の交換を行います。
変数xと変数yの値を交換する場合、以下のようなステップで実施します。
①変数xの値を変数tmpへ退避します
↓
②変数yの値を変数xへ代入します。
↓
③①で退避した値を変数yへ代入

コメント