web-dev-qa-db-ja.com

C-Arrayが関数に渡されたときに間違ったsizeof()値を持つのはなぜですか?

完全な例:

#include <stdio.h>

void test(int arr[]) {
    int arrSize = (int)(sizeof(arr) / sizeof(arr[0]));
    printf("%d\n", arrSize); // 2 (wrong?!)
}

int main (int argc, const char * argv[]) {
    int point[3] = {50, 30, 12};

    int arrSize = (int)(sizeof(point) / sizeof(point[0]));
    printf("%d\n", arrSize); // 3 (correct :-) )

    test(point);

    return 0;
}

関数に渡す前に、sizeofは正しい値を教えてくれます。関数内のまったく同じ配列でまったく同じことを行うと、奇妙な結果が得られます。欠落している要素が1つあります。どうして?

34

配列をCの関数に渡すと、配列は最初の要素へのポインターに減衰します。パラメータでsizeofを使用すると、配列自体ではなく、ポインタのサイズを取得します。

配列のサイズを知る関数が必要な場合は、それを個別のパラメーターとして渡す必要があります。

_void test(int arr[], size_t elems) {
   /* ... */
}

int main(int argc, const char * argv[]) {
   int point[3] = {50, 30, 12};
   /* ... */
   test(point, sizeof(point)/sizeof(point[0]));
   /* ... */
}
_

また、同様の理由(sizeofをポインターとして使用)で、sizeof(point)/sizeof(point[0])トリックは動的に割り当てられた配列では機能せず、スタックに割り当てられた配列のみで機能することにも注意してください。

46
Nick Meyer

配列は関数の引数として渡されたときにポインタへの decayed であるため、sizeofは4と8を返しますそれぞれ32ビットおよび64ビットプラットフォーム用。

14

また、sizeofコンパイル時で評価されることを理解することが重要です。そのため、渡された内容に応じてtest()で異なる出力を期待することは意味がありません。sizeofの計算は、関数のコンパイル時に行われました。

6
tomlogic

なぜなら、渡されると、配列へのポインタだけが実際に渡されるからです。

あなたの質問は CプログラミングFAQ でも答えられます。質問6.21。

3

C、C++、Objective-Cでは、関数は実際には配列パラメーターを持つことができないためです。それらはのように見える配列パラメーターのみを持つことができますが、そうではありません。あなたの例では、

void test(int arr[])

コンパイラーは「intの配列のように見えるパラメーターがあります」と認識し、そのパラメーターを「intへのポインター」に置き換えます。つまり、あなたが書いた関数は完全に100パーセントで、

void test (int* arr)

したがって、関数sizeof(arr)内では、「intへのポインター」のサイズが得られます。

2
gnasher729

Sizeof()はCの配列のサイズを教えてくれないので、まったく違うことをします。

C++参照のサイズ

0
PeterK