2

次のコード セグメントの出力は 9 です。関数 foo の引数 a は値渡しだと思います。私の仮定は正しいですか。もしそうなら、出力はどのように9になりますか?

 #include <stdio.h>

void foo(int[][3]);

int main(void)
{
   int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };

   foo(a);
   printf("%d\n", a[2][1]);

   return 0;
}

void foo(int b[][3])
{
   ++b;
   b[1][1] = 9;
}
4

4 に答える 4

2

[]関数パラメーターの型の構文は、単なる構文糖衣です。この場合、関数呼び出しコンテキストでの配列の他の使用と同様に、ポインターが渡されます。つまり、foo()関数の署名は次と同等です。

void foo(int (*b)[3])

つまり、3 つの整数の配列へのポインターを受け入れます。それを念頭に置いて、実装が何をするかを見てみましょう。最初に、メモリ内のの 3 つの整数の配列を++b指すようにポインターを進めます。つまり、 で進みます。あなたのプログラムの場合、それは行の「中間行」を指していることを意味します。b3 * sizeof(int)a{ 4, 5, 6 }

次に、[2][1]new の要素にアクセスしますb。つまり、行 2、この新しいオフセット論理配列の要素 1 です。これにより、プログラムは の末尾を過ぎたアドレスに書き込みますがa、これは未定義の動作です。この段階では、すべての賭けはオフです。プログラムの出力は何でもかまいません。

その行を次のように変更することで、定義された動作に戻すことができます。

b[1][2] = 157;

例えば。次に、印刷a[2][2]して、関数のコンテキストからの変更を確認しmain()ます。

于 2013-05-25T04:38:38.470 に答える