日記とか、工作記録とか

自分に書けることを何でも書いてゆきます。作った物、買ったもの、コンピュータ系の話題が多くなるかもしれません。

C言語のポインタの奇妙な表現

f:id:WindVoice:20210723094129j:plain
ツイッターに書かれていた記載を見て本当か? と思って実験したので記録してみました。

■ 問題

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の型によって変わるというのがどうにも理解できません。これはどう考えたらいいの……?