配列がint
あり、その中の要素の数を見つける必要があります。何か関係があることは知っていますがsizeof
、正確に使用する方法がわかりません。
16 に答える
スコープ内に配列がある場合は、使用sizeof
してそのサイズをバイト単位で決定し、除算を使用して要素数を計算できます。
#define NUM_OF_ELEMS 10
int arr[NUM_OF_ELEMS];
size_t NumberOfElements = sizeof(arr)/sizeof(arr[0]);
関数の引数として配列を受け取ったり、配列をヒープに割り当てたりすると、sizeof
. サイズ情報を使用できるようにするには、何らかの方法でサイズ情報を保存/渡す必要があります。
void DoSomethingWithArray(int* arr, int NumOfElems)
{
for(int i = 0; i < NumOfElems; ++i) {
arr[i] = /*...*/
}
}
int a[20];
int length;
length = sizeof(a) / sizeof(int);
別の方法を使用して、コードをハードコーディングしないようにすることができますint
あなたが配列を持っているかどうか言ってくださいarray
あなたはただする必要があります:
int len = sizeof(array) / sizeof(array[0]);
個人的には sizeof(a) / sizeof(*a) の方がきれいに見えると思います。
また、マクロとして定義することも好みます。
#define NUM(a) (sizeof(a) / sizeof(*a))
次に、for ループで使用できます。
for (i = 0; i < NUM(a); i++)
超簡単。
を使用して、割り当てられたバイト数を配列のデータ型のバイト数で割りますsizeof()
。
たとえば、次の整数配列があるとします。myArray
int numArrElements = sizeof(myArray) / sizeof(int);
ここで、配列のデータ型が定数ではなく、変更される可能性がある場合は、方程式の除数が最初の値のサイズをデータ型のサイズとして使用するようにします。
例えば:
int numArrElements = sizeof(myArray) / sizeof(myArray[0]);
このように、コードは型にとらわれず、配列のデータ型に関係なく正しく機能します。
上記のように次のコードを使用して、2 次元配列の要素数を評価しました。
#include <stdio.h>
#include <string.h>
void main(void)
{
char strs[3][20] =
{
{"January"},
{"February"},
{""}
};
int arraysize = sizeof(strs)/sizeof(strs[0]);
for (int i = 0; i < arraysize; i++)
{
printf("Month %d is: %s\n", i, strs[i]);
}
}
それはうまく機能します。私の知る限り、C配列で異なるデータ型を混同することはできません。また、すべての配列要素を同じサイズにする必要があります(私が正しい場合)。したがって、この小さなトリックでそれを利用できます。
- 2次元配列全体から sizeof() 関数でバイト数をカウント (この場合は 3*20 = 60 バイト)
- 最初の配列要素 strs[0] (この場合は 20 バイト) から sizeof() 関数でバイト数をカウントします。
- 全体のサイズを1つの要素のサイズで割ると、要素の数が得られます
これは C の 2 次元配列に移植できるはずですが、他のプログラミング言語では、異なるサイズの配列内で異なるデータ型を使用できるため (JAVA のように)、機能しませんでした。
質問は簡単です: C++ 配列 (たとえばx
のようにint x[10]
) が与えられた場合、その中の要素の数をどのように取得しますか?
明らかな解決策は、次のマクロ(定義 1)です。
#define countof( array ) ( sizeof( array )/sizeof( array[0] ) )
配列を与えると正しい答えが得られるため、これが正しくないとは言えません。ただし、配列ではないものを指定すると、同じ式で偽物が表示されます。たとえば、
int * p;
次にcountof( p )
、int ポインターと int が同じサイズのマシン (たとえば、Win32 プラットフォーム) では常に 1 を返します。
また、このマクロは、メンバー関数 operator[] を持つクラスの任意のオブジェクトを誤って受け入れます。たとえば、次のように書くとします。
class IntArray {
private:
int * p;
size_t size;
public:
int & operator [] ( size_t i );
} x;
sizeof( x )
が指すバッファのサイズではなく、 x オブジェクトのサイズになりますx.p
。したがって、 では正解が得られませんcountof( x )
。
したがって、定義 1 は適切ではないと結論付けます。なぜなら、コンパイラは誤用を防げないからです。配列のみを渡すことができるようにすることはできません。
より良いオプションは何ですか?
countof へのパラメーターが常に配列であることをコンパイラーに保証させたい場合は、配列のみが許可されているコンテキストを見つける必要があります。同じコンテキストは、配列以外の式を拒否する必要があります。
一部の初心者はこれを試すかもしれません(定義 2) :
template <typename T, size_t N>
size_t countof( T array[N] )
{
return N;
}
彼らは、このテンプレート関数は N 要素の配列を受け入れ、N を返すと考えています。
残念ながら、これはコンパイルできません。これは、C++ が配列パラメーターをポインター パラメーターと同じように扱うためです。つまり、上記の定義は次と同等です。
template <typename T, size_t N>
size_t countof( T * array )
{
return N;
}
関数本体には N が何であるかを知る方法がないことが明らかになりました。
ただし、関数が配列参照を想定している場合、コンパイラは実際のパラメーターのサイズが宣言と一致することを確認します。これは、定義 2 をわずかな変更(定義 3)で機能させることができることを意味します。
template <typename T, size_t N>
size_t countof( T (&array)[N] )
{
return N;
}
この countof は非常にうまく機能し、ポインターを渡してだますことはできません。ただし、マクロではなく関数です。これは、コンパイル時の定数が予想される場所では使用できないことを意味します。特に、次のようなものは記述できません。
int x[10];
int y[ 2*countof(x) ]; // twice as big as x
それについて何かできることはありますか?
誰か (私はそれが誰なのかわからない - 未知の作者からのコードの一部でそれを見た) は賢いアイデアを思いついた: N を関数の本体から戻り値の型に移動する (例えば、関数を return にする) N 要素の配列) の場合、実際に関数を呼び出さずに N の値を取得できます。
正確には、C++ では配列を直接返すことができないため、関数が配列参照を返すようにする必要があります。
これの実装は次のとおりです。
template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&array)[N] ))[N];
#define countof( array ) (sizeof( _ArraySizeHelper( array ) ))
確かに、構文はひどく見えます。確かに、いくつかの説明が必要です。
まず、トップレベルのもの
char ( &_ArraySizeHelper( ... ))[N];
say は_ArraySizeHelper
、N 要素の char 配列への参照 (& に注意) を返す関数です。
次に、関数のパラメータは
T (&array)[N]
これは、N 要素の T 配列への参照です。
最後にcountof
、関数の結果のサイズとして定義されます_ArraySizeHelper
。を定義する必要さえないことに注意してください_ArraySizeHelper()
-- 宣言で十分です。
この新しい定義により、
int x[10];
int y[ 2*countof(x) ]; // twice as big as x
私たちが望むように、有効になります。
私は今幸せですか?まあ、この定義は私たちが訪れた他のものよりも間違いなく優れていると思いますが、それでも私が望むものではありません. 1 つには、関数内で定義された型では機能しません。これは、テンプレート関数_ArraySizeHelper
がグローバル スコープでアクセス可能な型を想定しているためです。
私はより良い解決策を持っていません。あなたが知っているなら、私に知らせてください。