Posted at

C言語の宣言、なぜそう書くのか?

More than 3 years have passed since last update.


動機

C言語での変数宣言に、一貫性を発見したので書きたいと思います

宣言の一貫した規則を示すために、いくつかの種類の変数宣言を見ていきたいと思います


変数宣言の一貫性

その発見とは「変数の宣言」は「その変数の特有のアクセス方法」に似せた構文になっているということです


配列


配列の宣言

int array[10];



配列特有のアクセス方法

printf("%d\n", array[2]);


まとめると、

宣言
アクセス方法

array[10]
array[2]

宣言とアクセス方法が似ていることが分かります。


ポインタ


ポインタの宣言

int *p;



ポインタ特有のアクセス方法

printf("%d\n", *p);


ポインタの特有の使い方は「*」を使ってポインタの指している値にアクセスすることだと思います。このアクセス方法がポインタの宣言に反映されていると考えられます

以前の私はint* pと書いてintポインタ型のpと解釈していましたが、これでは以下の結果の説明がつかないです。

/* qはただのint型でintのポインタ型ではない */

int* p, q;

まとめると、

宣言
アクセス方法

*p
*p


「配列」と「ポインタ」だけでは「「変数の宣言」は「その変数の特有のアクセス方法」に似せた構文」と言い切れないので、「配列へのポインタ」と「関数へのポインタ」見てみます


配列へのポインタ


要素数10個の配列へのポインタ

int (*arp)[10];


アドレスを入れるときは以下のように入れます。

int array_ten[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

arp = &array_ten;

以下の書き方でarray_ten[3]と同じ要素にアクセスします


特有のアクセス方法

printf("%d\n", (*arp)[3]); // 4


まとめると、

宣言
アクセス方法

(*arp)[10]
(*arp)[3]

宣言とアクセス方法、似ていませんか?


関数ポインタ


2つのintを引数にとり、戻り値がintの関数へのポインタ

int (*funp)(int, int);


アドレスを入れるときは以下のようにします

// a + bをしてintで返す

int add(int a, int b){
return a + b;
}
// addのアドレスを代入できる
funp = &add;


特有のアクセス方法

printf("%d\n", (*funp)(1, 2)); // 3


まとめると、

宣言
アクセス方法

(*funp)(int,int)
(*funp)(1,2)


まとめ

以上を踏まえるとC言語の変数の宣言とアクセス方法はとても良く似ています。私の憶測ではありますが、アクセス方法に似せた宣言というのが、C言語にある一貫した宣言の記法なのだと思います。

今までできた宣言に勢揃いしてもらうと、以下みたいになります

int *p, array[10], (*arp)[10], (*funp)(int, int);

上のC言語の宣言のp, array, arp, funpの解釈が前より変わって見えませんか?