C言語のポインタの奇妙な表現
某ツイッターに書かれていた記載を見て本当か? と思って実験したので記録してみました。
■ 問題
int a[10];
のような配列を定義したとき、下は全部同じ。
a[1]
*(a+1)
*(1+a)
1[a] ←え?
■ 実験
私としては、C言語ってとても数学的な文法の組み立てなので、言われてみればそうなるなぁと思ったのですが、しかし、数値リテラル(ここでは1)は暗黙のint型なので、a[]がint型の配列ではない場合はほんとに a[1] と 1[a] は同じになるのだろうか、と思ったのです。
ここのところを実験してみました。
環境はWindows 10のWSL2環境のUbuntuです。aptでgccがインストールしてあります。
とりあえず練習です。ポインタが指し示すアドレスを表示するときはprintfに%pで指定します。
windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ cat 001pointer.c #include<stdio.h> int main(){ int a; printf("%p\n", &a); } windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ ./001pointer 0x7ffe6e1564c4 windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$
簡単ですね。ということで次はint型の配列です。
windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ cat 002pointer.c #include <stdio.h> int main(int argc, char* argv){ int a[100]; printf("sizeof a[0]=%d\n", (int)sizeof(a[0])); printf("sizeof 1[a]=%d\n", (int)sizeof(1[a])); printf(" &a[1]=0x%p\n", &(a[1])); printf(" (a+1)=0x%p\n", (a+1)); printf(" (1+a)=0x%p\n", (1+a)); printf("&(1[a])=0x%p\n", &(1[a])); } windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ ./002pointer sizeof a[0]=4 sizeof 1[a]=4 &a[1]=0x0x7ffecaea5624 (a+1)=0x0x7ffecaea5624 (1+a)=0x0x7ffecaea5624 &(1[a])=0x0x7ffecaea5624 windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$
実行するとサラッと結果がでますけど、1[a]のアドレスはやっぱり違和感ありまくりです。
で、私が疑問に思っていたintではない場合どうなるの?ということですが……
windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ cat 003pointer.c #include <stdio.h> int main(int argc, char* argv){ long long a[100]; printf("sizeof a[0]=%d\n", (int)sizeof(a[0])); printf("sizeof 1[a]=%d\n", (int)sizeof(1[a])); printf(" &a[1]=0x%p\n", &(a[1])); printf(" (a+1)=0x%p\n", (a+1)); printf(" (1+a)=0x%p\n", (1+a)); printf("&(1[a])=0x%p\n", &(1[a])); } windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$ ./003pointer sizeof a[0]=8 sizeof 1[a]=8 &a[1]=0x0x7ffd1b2cee18 (a+1)=0x0x7ffd1b2cee18 (1+a)=0x0x7ffd1b2cee18 &(1[a])=0x0x7ffd1b2cee18 windvoice@DESKTOP-ULDQNNI:/mnt/d/C/pointer$
う~ん、long long型のように8byteのメモリをとる変数でも結果は同じなんですね。これは私の予想に反する結果でした。sizeof(1[a])の結果がaの型によって変わるというのがどうにも理解できません。これはどう考えたらいいの……?