このコードは、ネット上のどこかで見つけました。プログラムの出力は文字列です。
#include<stdio.h>
int main()
{
char a[2][3][3] = {'s','t','r','i','n','g'};
printf("%s\n", *a);
printf("%s\n", a);
printf("%s\n", **a);
getchar();
return 0;
}
このコードは、ネット上のどこかで見つけました。プログラムの出力は文字列です。
#include<stdio.h>
int main()
{
char a[2][3][3] = {'s','t','r','i','n','g'};
printf("%s\n", *a);
printf("%s\n", a);
printf("%s\n", **a);
getchar();
return 0;
}
これは 3 次元配列 (配列の配列の配列) であるため*a
、 、a
、および**a
すべて同じアドレスを参照します。最初の 2 つの型は正しくありませんが、すべての場合でprintf()
フラット文字列として解釈されます。char *
コンパイラで警告を表示すると、フォーマット文字列と型が一致しないことがいくつか表示されるはずです。
*a
のようであり、のようa[0]
で**a
あることを覚えておいてくださいa[0][0]
。これにより、同じアドレスを参照している理由を簡単に確認できる場合があります。
char (*)[3]
aと achar (*)[3][3]
を として扱っていますchar *
。char *
それらは同じアドレスを指しており、(この場合) 同じメモリ内表現を持っているため、そのアドレスを指しているのと同じように読み取られます。
これは未定義の動作です。しないでください。
char a[2][3][3]
がメモリにどのように配置されているかを見てみましょう。私のマシンでは、次のようになります。
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffe230: 0x00 0x00
すべての配列が実際には線形であるため、これは当然のことです。これらの次元が意味することは、 のような配列インデックスで役立ちますa[i][j][k]
。しかし、メモリの観点から見ると、ベースアドレスからオフセットを計算するのは難しい方法です。
これを 3 次元配列として定義したので、C が初期化後にこの配列をどのように扱うかを知りたい場合があります。
{{{0x73, 0x74, 0x72}, {0x69, 0x6e, 0x67}, {0x0, 0x0, 0x0}}, {{0x0, 0x0, 0x0}, {0x0, 0x0, 0x0}, {0x0, 0x0, 0x0}}}
ここにあるものを見てみましょう...
Printf は文字列を出力するために呼び出され、アドレスとともに渡されます。したがって、printf が行うことは、そのアドレスを取得し、null が表示されるまで試行することです。
print
同じものへのすべての呼び出し:
(gdb) x/10xb **a
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00
(gdb) x/10xb *a
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00
(gdb) x/10xb a
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00
最後に、このようにコーディングすることをお勧めします。あなたが十分に賢いなら、ポインターだけですべてを行います。しかし、エラーが発生しやすくなります。したがって、下層のレイヤーはポインターと配列をほぼ同じように扱いますが、最初から使用しているものに固執します。手で物を操作できる場合は、ポインタのように扱います。インデックスによるより厳密な操作が必要な場合は、ものを配列のように扱います。