4

このガイドを使用して、配列は参照によって渡されると言われました。これは、構造体が次のような場合に当てはまります。

struct Person{
 char* name;
 int id;
}

しかし、構造体が次のようになっている場合はそうではありません。

struct Person{
 char name[20];
 int id;
}

seconds 構造体を使用する場合、name配列は値によってコピーされます。

struct Person p1 = {"John", 1234};
struct Person p2 = p1;
p2.name[0] = 'L';

// p1.name[0] is still 'K'

なぜこうなった?

4

3 に答える 3

3

配列は参照渡しだと言われました。

それは完全に真実ではありません。配列はまったく渡されません。どの関数も配列を引数として取ることはできません。関数を宣言したとき

void foo(int bar[]);

取る引数のタイプfooは実際にはint *であり、それを呼び出すと

int arr[23];
/* fill arr with meaningful values */
foo(arr);

の最初の要素へのポインターが値arrで渡されます。すべての関数引数は、例外なく、C では値によって渡されます。

したがって、struct Person値によって渡される関数に a を渡すと、のメンバーstructがコピーされます。メンバーの 1 つが配列の場合、それもコピーされます。これは、struct.

于 2013-01-28T17:07:41.517 に答える
2

これは両方に当てはまります。唯一の違いは、最初の構造体では、文字列へのポインターと id フィールドのみを格納することです。2 番目の構造体では、文字列全体と id フィールドを構造体に格納します。したがって、最初の構造体は約です。サイズは 8 バイト (32 ビット ポインターを想定) で、2 番目の構造体は約 1 です。24 バイトのサイズ。

どちらの場合も、関数を呼び出して値で渡すと、構造体全体がコピーされます。これは、name フィールドの代わりに id フィールドを変更することで確認できます。

参照によって (ポインターとして) 構造体と配列を関数に渡す理由は、このコピーがスタックにコピーされないようにするためです。

編集:クリアするには:最初の構造体の p2.name[0] にアクセスすることにより、メモリ内の別の場所(コピーされていない)(コピーされた)構造体の外側の場所にアクセスします。2 番目の構造体の p2.name[0] にアクセスすると、(コピーされた) 構造体に割り当てられたメモリ領域内の場所にアクセスします。

コードを確認すると、ここで注目に値する別の重要な部分が見つかりました。最初の構造体を文字列リテラル (ハードコードされた文字列) で初期化しているため、 p2.name[0] に書き込むと、未定義の動作が発生します (ツールチェーンとオペレーティング システムによっては、プログラムこれが原因でクラッシュする可能性があります!)

于 2013-01-28T16:50:01.003 に答える
1

最初のケースでは、構造体は文字のバッファへのポインタを保持し、2番目のケースでは、構造体は実際に20文字を含みます(読み取り:保持するスペースがあります)。

したがって、最初のケースでは、値を渡すときに、値ではなくポインタをコピーしています。

于 2013-01-28T16:49:19.520 に答える