int
配列があり、その中の要素の数を見つける必要があります。 sizeof
と関係があることは知っていますが、正確に使用する方法がわかりません。
スコープ内に配列がある場合は、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++)
文字配列でない限り、配列内の要素の数を見つけることはできません。以下の例を検討してください。
int main()
{
int arr[100]={1,2,3,4,5};
int size = sizeof(arr)/sizeof(arr[0]);
printf("%d", &size);
return 1;
}
上記の値は、要素の数が5であっても値100を与えます。文字配列の場合は、配列の最後にあるヌル文字列を直線的に検索し、進むにつれてカウンターを増やすことができます。
#include<stdio.h>
int main()
{
int arr[]={10,20,30,40,50,60};
int *p;
int count=0;
for(p=arr;p<&arr+1;p++)
count++;
printf("The no of elements in array=%d",count);
return 0;
}
OUTPUT = 6
説明
p
は1次元配列へのポインターであり、ループ内でfor(p=arr,p<&arr+1;p++)
私はp
がベースアドレスを指すようにしました。ベースアドレスが1000であるとします。 p
をインクリメントすると、1002などを指します。ここで&arr
の概念になります。これは基本的に配列全体を表し、配列全体に1を追加すると(つまり&arr+1
)、アドレス1012、つまり次の1-D配列のアドレス(この場合、intのサイズは2)であるため、条件は1000 <1012になります。
だから、基本的に条件は
for(p=1000;p<1012;p++)
そして、条件をチェックして値を数えましょう
p=1000
およびp<1012
条件はtrue
です。ループに入り、count
の値を1に増やします。p=1002
およびp<1012
条件はtrue
です。ループに入り、count
の値を2に増やします。p=1010
およびp<1012
条件はtrue
です。ループに入り、count
の値を6に増やします。p=1012
およびp<1012
条件がfalse:printf
ステートメントのcount=6
の値を出力します。上記のように次のコードを使用して、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配列に異なるデータ型を混在させることはできず、すべての配列要素のサイズが同じである必要があります(私が正しい場合)。したがって、この小さなトリックでそれを利用できます。
これは、Cの2D配列に移植可能である必要がありますが、他のプログラミング言語では、Javaのように異なるサイズの配列内で異なるデータ型を使用できるため動作しません。
sizeof
は、引数のサイズをバイト単位で返します。これはあなたが望むものではありませんが、助けになります。
配列があるとしましょう:
int array[4];
sizeof
を配列(sizeof(array)
)に適用すると、そのサイズをバイト単位で返します。この場合は4 * int
のサイズなので、合計で16バイト(実装によって異なります)。
sizeof
を配列の要素(sizeof(array[0])
)に適用すると、そのサイズをバイト単位で返します。この場合はint
のサイズなので、合計で多分4バイト(実装によって異なります)。
最初のものを2番目のもので割ると、(4 * int
のサイズ)/(int
のサイズ)= 4;それこそまさにあなたが望んでいたことです。
だからこれはする必要があります:
sizeof(array) / sizeof(array[0])
これで、おそらくこのロジックをカプセル化するマクロが必要になり、それがどのように行われるべきかを再度考える必要がなくなるでしょう。
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
他の複雑なマクロと同様に、すべてのマクロを囲む括弧が必要です。また、演算子の優先順位に関連する予期しないバグを避けるために、すべての変数も囲む必要があります。
これで、次のような任意の配列で使用できます。
int array[6];
ptrdiff_t nmemb;
nmemb = ARRAY_SIZE(array);
/* nmemb == 6 */
配列として宣言された関数の引数は実際には配列ではなく、配列の最初の要素へのポインタであるため、これは機能しません。
void foo(int false_array[6])
{
ptrdiff_t nmemb;
nmemb = ARRAY_SIZE(false_array);
/* nmemb == sizeof(int *) / sizeof(int) */
/* (maybe ==2) */
}
ただし、配列だけでなく配列へのポインターを渡すと、関数で使用できます。
void bar(int (*arrptr)[7])
{
ptrdiff_t nmemb;
nmemb = ARRAY_SIZE(*arrptr);
/* nmemb == 7 */
}
超簡単。
sizeof()
を使用して、割り当てられたバイト数を配列のデータ型のバイト数で割るだけです。
例えば。 myArray
という整数配列が与えられた
int numArrElements = sizeof(myArray) / sizeof(int);
ここで、配列のデータ型が一定ではなく、変更される可能性がある場合、方程式の除数に最初の値のサイズをデータ型のサイズとして使用するようにします
例えば。
int numArrElements = sizeof(myArray) / sizeof(myArray[0]);
質問は簡単です:C++配列(たとえば、int x[10]
のようにx
)が与えられた場合、その中の要素数をどのように取得しますか?
明らかな解決策は、次のマクロ(定義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.p
が指すバッファのサイズではなく、xオブジェクトのサイズになります。したがって、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を関数の本体から戻り値の型に移動する(例えば、関数を返すN要素の配列)、関数を実際に呼び出すことなくNの値を取得できます。
正確には、C++では配列を直接返すことができないため、関数に配列参照を返させる必要があります。
これの実装は次のとおりです。
template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&array)[N] ))[N];
#define countof( array ) (sizeof( _ArraySizeHelper( array ) ))
確かに、構文はひどく見えます。実際、何らかの説明が必要です。
まず、トップレベルのもの
char ( &_ArraySizeHelper( ... ))[N];
_ArraySizeHelper
は、N要素のchar配列への参照(&に注意)を返す関数です。
次に、関数パラメーターは
T (&array)[N]
これは、N要素のT配列への参照です。
最後に、countof
は、関数_ArraySizeHelper
の結果のサイズとして定義されます。 _ArraySizeHelper()
を定義する必要さえないことに注意してください-宣言で十分です。
この新しい定義により、
int x[10];
int y[ 2*countof(x) ]; // twice as big as x
希望どおりに有効になります。
私は今幸せですか?まあ、この定義は私たちが訪れた他のものよりも間違いなく優れていると思いますが、それでも私が望むものではありません。一つには、関数内で定義された型では機能しません。これは、テンプレート関数_ArraySizeHelper
がグローバルスコープでアクセス可能な型を予期しているためです。
より良い解決策はありません。知っていたら教えてください。
私はほとんどそのようなループ内で配列の長さを実行する簡単な方法を見つけました
int array[] = {10, 20, 30, 40};
int i;
for (i = 0; i < array[i]; i++) {
printf("%d\n", array[i]);
}
配列内の要素の数がわからない場合、および実行時にユーザーが入力を行うタイミング。次に、コードを次のように記述できます。
Cコード:
while(scanf("%d",&array[count])==1) {
count++;
}
C++コード:
while(cin>>a[count]) {
count++;
}
これで、カウントには入力された配列要素の数がカウントされます。