2012-07-23 22 views
10

配列の長さ、たとえばint array[] = {1, 2, 3, 4}を取得したいとします。私はそれを行うためにsizeofを使用しました。だから、なぜsizeof(param_array)がポインタのサイズですか?

int length(int array[]) 
{ 
    return sizeof(array)/sizeof(int); 
} 

int main() 
{ 
    int array[] = {1, 2, 3, 4}; 
    printf("%d\n", length(array)); // print 1 
    printf("%d\n", sizeof(array)/sizeof(int)); // print 4 
} 

、なぜarrayのポインタのサイズを返しますlength機能でsizeof(array)?しかし、機能mainで動作します。

length関数を変更して配列の長さを取得するにはどうすればよいですか?

+1

はい、私はこれはC++の質問ですけど、それは同様にCに関するとても有用な情報が含まれていますhttp://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in -c – chris

答えて

18

特別なCルールでは、関数のパラメータでは、ポインタ型に対してが調整されたとなっています。これは意味:あなたがsizeofあなたが実際にポインタのサイズを計算している配列を計算する際

int length(int array[]);

だから

int length(int *array);

に相当します。

(C99、6.7.5.3p7)タイプの配列「としてパラメータの宣言は、 『タイプ修飾子 (もしあれば)これらの中で指定されている『とタイプする修飾ポインタ』に調整されなければなりません』配列型導出の[と]。

+4

...これは、関数が配列のサイズを知る必要がある場合、関数を別のパラメータとして渡す必要がある場合に、あなたが望むように 'length()'を書き直すことができないことを意味します。 – caf

+0

@caf私はあなたに同意します。詳細は、特にr0、r1、r2、r3の32ビットレジスタを持つARMプロセッサの場合には、このようにするのが理にかなっています。したがって、スタックを使用する代わりに、ポインタをr0に渡すことができます。 –

2

Cは、変数を持つ配列のサイズに関する実行時メタデータを格納しません。あなたはどこかにそれを保管しなければなりません。

あなたの方法の文脈におけるタイプINT []の変数は、メモリのブロックにだけポインタです。そのため、サイズはシステム上の他のポインタのサイズと同じになります。 sizeofが、それは代わりに、配列が占めるバイト数を返します(あなたのメイン機能のように)コンパイル時に、配列へのアクセス権を持っている

+1

"int型の変数はメモリブロックへのポインタに過ぎません" - これは一般的には間違っています。 'int []' *型の変数はメモリブロックです。これはポインタではありません。 'int []'がポインタを表す唯一のコンテキストは、関数のパラメータ宣言であり、*特殊なケース*です。 – AnT

+0

メソッドlength()*のコンテキスト内のポインタ*であることを明確にしました。それを指摘してくれてありがとう。 –

3

メインプログラムでは、コンパイラは配列の長さを認識します。サブルーチンでは、それはしません。特に、サブルーチンでは、タイプint[]のパラメータは、タイプint *のパラメータと同じです。一方、メインプログラムではarrayint[4]です。 (arrayに別の値を代入しようとすると、mainにコンパイルされます。

0

可変長配列の長さは外側の可変配列と同じではないためです。 main関数にsizeof(array)/ sizeof(int)を保持する必要があります。

4

配列は、関数に渡すとポインタに崩壊します。 lengthは、配列の長さを得ることができるように

0

マクロにそれを回す、あなたのコードを変更するには:あなたが期待するようにコードのサンプルについて

#define length(x) (sizeof(x)/sizeof(*x)) 

を、これは動作します。

は、静的に割り当てられた配列に対してのみ機能し、元の配列を使用して呼び出された場合のみ有効です(配列へのポインタを使用すると機能しません)。これは、sizeof(x)を書くとき、xが配列へのポインタであるため、コンパイラは文字通り解釈します。 sizeofを評価する前に、xを指し示す配列にマッピングする方法はありません。

1

lengthに渡された配列の実際のサイズを認識させたい場合は、その情報を渡す必要があります。それはまた、内蔵された情報の配列への参照を受信するためにしかし、それは可能です:

int length(int n, int (* array)[n]) 
{ 
    return sizeof(*array)/sizeof(int); 
} 

int main() 
{ 
    int array[] = {1, 2, 3, 4}; 
    printf("%d\n", length(4, &array)); // print 1 
    printf("%d\n", sizeof(array)/sizeof(int)); // print 4 
} 

私はサイズがすでに提供されているためということは、実際に、しかし、あなたを行う良いかわかりません最初の場所。しかし、この場合には、sizeofオペレータがあなたが望むように動作することがわかります。

4

他の回答者が指摘したように、配列を取ると宣言された関数は、ポインタをとった場合と同じようにコンパイルされます。

私があなたの長さの方法を行うのが見られる最も一般的な方法は#defineですが、あなたがテンプレートを使ってトリックをプレイすると、あなたの機能を動作させることができます。長さ4のあなたの配列で

template <size_t _Size> inline int length(int(& array)[_Size]) 
{ 
    //return sizeof(array)/sizeof(int); 
    return _Size; 
}; 

int array[] = {1, 2, 3, 4}; 
printf("%d\n", length(array)); // print 4 

が、これは長さ4の配列を受け取り、および静的4.これはまた、あなたがいない何かを渡そうという利点を有する返すメソッドとしてコンパイルされます配列の場合、コンパイラはエラーを返しますが、#defineメソッドはエラーになりません。

int* foo = array; 
printf("%d\n", length(foo)); 
    // error C2784: 'int length(int (&)[_Size])' : could not deduce template 
    //  argument for 'int (&)[_Size]' from 'int *' 
    // test.cpp(56) : see declaration of 'length' 
+1

質問タグC、C++ではありません。 – jxh

+0

ああ、まあまあ。ああ、おそらく彼はとにかくそれを見つけるだろう。 –

関連する問題