web-dev-qa-db-ja.com

値によって関数に配列を渡す

以下は本の抜粋ですCプログラミングJust FAQs。配列は参照渡しできないため、これは間違っていませんか?

VIII.6:値によって配列を関数に渡すにはどうすればよいですか?

回答:末尾に角括弧(_[_および_]_)を付けた配列名を呼び出し先関数で宣言することにより、値によって関数に配列を渡すことができます。関数を呼び出すとき、呼び出された関数に配列のアドレス(つまり、配列の名前)を渡すだけです。たとえば、次のプログラムは、配列_x[]_を値によってbyval_func()という名前の関数に渡します。

_int[]_パラメーターは、byval_func()関数が1つの引数(整数の配列)を取ることをコンパイラーに伝えます。 byval_func()関数が呼び出されると、配列のアドレスをbyval_func()に渡します。

_byval_func(x);
_

配列は値で渡されるため、配列の正確なコピーが作成され、スタックに配置されます。呼び出された関数は、この配列のコピーを受け取り、印刷できます。 byval_func()に渡される配列は元の配列のコピーであるため、byval_func()関数内の配列を変更しても元の配列には影響しません。

36
Zuzu

配列は値で渡されるため、配列の正確なコピーが作成され、スタックに配置されます。

これは正しくありません:配列自体はコピーされません、そのアドレスへのポインタのコピーのみが呼び出し先に渡されます(スタックに配置されます) 。 (パラメーターをint[]として宣言するかint*として宣言するかにかかわらず、それは decays into pointer 。)これにより、呼び出された関数内から配列の内容を変更できます。したがって、これ

Byval_func()に渡される配列は元の配列のコピーであるため、byval_func()関数内で配列を変更しても元の配列には影響しません。

は明らかに間違っています(以下のコメントについて@Jonathan Lefflerに感謝します)。ただし、関数内でポインターを再割り当てしても、関数外の元の配列へのポインターは変更されません。

60
Péter Török

その本を燃やす。実際のC FAQ初心者プログラマーによって書かれたものではない場合は、これを使用してください: http://c-faq.com/aryptr/index.html

構文的には、厳密に言えばcannotはCの値で配列を渡します。

void func (int* x); /* this is a pointer */

void func (int x[]); /* this is a pointer */

void func (int x[10]); /* this is a pointer */

ただし、、レコードにはCの値で配列を渡すことができるCの汚いトリックがあります。これを自宅で試さないでください!このトリックにもかかわらず、値で配列を渡す理由はまだないためです。

typedef struct
{
  int my_array[10];
} Array_by_val;

void func (Array_by_val x);
52
Lundin

CおよびC++では、値としてメモリの完全なブロックをパラメーターとして関数に渡すことはできませんが、そのアドレスを渡すことは許可されています。実際には、これはほぼ同じ効果があり、はるかに高速で効率的な操作です。

安全のために、配列サイズを渡すか、ポインタの前にconst修飾子を配置して、呼び出し先がそれを変更しないようにすることができます。

1
Rongkai Xu