8-3 配列のポインタ

この記事は約4分で読めます。

6-3のプログラムを見てください。

#include <stdio.h>
void setHairetsu(int ary[5]);
int main(void){
	int i,mat[5]={0,1,2,3,4};
	for (i=0;i<5;i++){
		printf("mat[%d]=%d\n",i,mat[i]);
	}
	setHairetsu(mat);
	puts("関数setHairetsuを呼び出しました。");
	for (i=0;i<5;i++){
		printf("mat[%d]=%d\n",i,mat[i]);
	}
	return 0;
}
void setHairetsu(int ary[5]){
	int i;
	for (i=0;i<5;i++) ary[i]=0;
}

実行結果

mat[0]=0
mat[1]=1
mat[2]=2
mat[3]=3
mat[4]=4
関数setHairetsuを呼び出しました。
mat[0]=0
mat[1]=0
mat[2]=0
mat[3]=0
mat[4]=0

6-3では関数の引数が配列の場合は、値が渡されるのではなく配列そのものが渡されると説明しました。つまり、関数から引数の配列の値を書き換えると呼び出し元の配列の値も変わります。これも、ポインタが深くかかわっています。

C言語では、配列名を評価すると配列の先頭要素のポインタとなります。

まず、配列名がint型と仮定してプログラムをコンパイルするとエラーとなります。

#include <stdio.h>
void printInt(int n){
	printf("int:%d\n",n);
}
int main(void){
	int a[]={2,-5,1};
	printInt(a);
	return 0;
}

実行結果

コンパイルエラーにより実行できません
エラー表示(筆者の環境の場合)

エラー 7行目 パラメータ 'n' は int 型として定義されているので int * は渡せない(関数 main )
警告 9行目 'a' に代入した値は使われていない(関数 main )

C言語は型に関して厳密な言語なので、互換性のない型を引数にするとエラーとなります。つまり、配列名aはint型ではありません。

#include <stdio.h>
void printIntP(int*np){
	printf("intポインタ:%p\n",np);
}
int main(void){
	int a[]={2,-5,1};
	printIntP(a);
	return 0;
}

実行結果

intポインタ:0019FF30
(実行結果は環境により異なります)

aをint*と仮定してプログラムを書くとコンパイルできました。つまり、配列名そのものはポインタとなります。

ポインタの演算

ポインタには足し算と引き算が用意されています。加減算を行うと、ポインタが指すオブジェクトの大きさの分だけアドレスが変わります。例えば、intへのポインタ型変数pに対して、p+1はpよりsizeof intだけ大きいアドレスになります。

#include <stdio.h>

int main(void){
	int a[]={2,-5,1};
	printf("sizeof int=%d\n",sizeof(int));
	printf("&a[0]=%p,&a[1]=%p,&a[2]=%p\n",&a[0],&a[1],&a[2]);
	printf("a=%p\n",a);
	printf("a+1=%p\n",a+1);
	printf("a+2=%p\n",a+2);
	return 0;
}

実行結果

sizeof int=4
&a[0]=0019FF30,&a[1]=0019FF34,&a[2]=0019FF38
a=0019FF30
a+1=0019FF34
a+2=0019FF38
(実行結果は環境により異なります)

プログラムを見ると、aと&a[0]、a+1と&a[1]、a+2と&a[2]が等しいことがわかります。実は、C言語の[n]は配列の先頭要素に対してn個後のポインタが指す要素という意味です。

まとめ

関数を呼び出すときに配列名を引数にすると、配列の各要素の値ではなく、先頭要素のポインタが渡される。

ポインタに加減算を行うと、ポインタが指す変数のサイズ(バイト単位)だけ増減する。

コメント

タイトルとURLをコピーしました