回答:
エグゼクティブサマリー:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
完全な答え:
配列のサイズをバイト単位で決定するには、sizeof
演算子を使用できます。
int a[17];
size_t n = sizeof(a);
私のコンピューターでは、intは4バイト長なので、nは68です。
配列の要素数を決定するには、配列の合計サイズを配列要素のサイズで除算します。次のように、タイプを使用してこれを行うことができます。
int a[17];
size_t n = sizeof(a) / sizeof(int);
正しい答え(68/4 = 17)を取得しますが、タイプがa
変更された場合、
変更するのを忘れると厄介なバグが発生します。sizeof(int)
。
したがって、推奨される除数は、配列の最初の要素のサイズsizeof(a[0])
または同等のものsizeof(*a)
です。
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
もう1つの利点は、マクロで配列名を簡単にパラメーター化して取得できることです。
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
ARRAYSIZE
makroが以下で定義されています。WinNT.h
(他のヘッダーによってます。したがって、WinAPIユーザーは自分のマクロを定義する必要はありません。
static int a[20];
。ただし、コメントは、配列とポインタの違いを理解していない読者に役立ちます。
sizeof
やり方は正しい方法であるIFFあなたがパラメータとして受け取っていない配列を扱っています。関数へのパラメーターとして送信された配列はポインターとして扱われるためsizeof
、配列ではなくポインターのサイズを返します。
したがって、関数内ではこのメソッドは機能しません。代わりに、常にsize_t size
配列の要素数を示す追加のパラメーターを渡します。
テスト:
#include <stdio.h>
#include <stdlib.h>
void printSizeOf(int intArray[]);
void printLength(int intArray[]);
int main(int argc, char* argv[])
{
int array[] = { 0, 1, 2, 3, 4, 5, 6 };
printf("sizeof of array: %d\n", (int) sizeof(array));
printSizeOf(array);
printf("Length of array: %d\n", (int)( sizeof(array) / sizeof(array[0]) ));
printLength(array);
}
void printSizeOf(int intArray[])
{
printf("sizeof of parameter: %d\n", (int) sizeof(intArray));
}
void printLength(int intArray[])
{
printf("Length of parameter: %d\n", (int)( sizeof(intArray) / sizeof(intArray[0]) ));
}
出力(64ビットLinux OSの場合):
sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
出力(32ビットWindows OSの場合):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
length of parameter:2
最初の配列要素へのポインタだけが渡されるのですか?
(sizeof array / sizeof *array)
。
sizeof
ポインタに減衰した配列値を処理する場合、これは役に立たないことに注意する必要があります。それが配列の先頭を指している場合でも、コンパイラにとっては、その配列の単一の要素へのポインタと同じです。ポインタは、それを初期化するために使用された配列について他に何も「記憶」しません。
int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
char
32ビットのCがあったことを覚えています。すべての標準では、0〜127の整数値を表すことができ、その範囲は少なくとも-127〜127(charは符号付き)または0〜255(charは符号なし)のいずれかです。
「トリック」のサイズは、私が知る最良の方法です。括弧の使用法は1つ小さいですが(私にとっては、これは大きな不満です)、重要な変更点があります。
ウィキペディアのエントリで明らかになっているように、C sizeof
は関数ではありません。それは演算子です。したがって、引数が型名でない限り、引数を括弧で囲む必要はありません。これにより、引数がキャスト式のようになり、括弧も使用されるため、覚えやすくなります。
だから:あなたが以下を持っている場合:
int myArray[10];
あなたはこのようなコードで要素の数を見つけることができます:
size_t n = sizeof myArray / sizeof *myArray;
それは、私にとって、括弧付きの代替案よりもはるかに読みやすいです。また、インデックスよりも簡潔であるため、部門の右側の部分にアスタリスクを使用することをお勧めします。
もちろん、これもすべてコンパイル時間なので、除算がプログラムのパフォーマンスに影響することを心配する必要はありません。したがって、このフォームは可能な限り使用してください。
タイプではなく、実際のオブジェクトがある場合は、実際のオブジェクトでsizeofを使用するのが常に最善です。エラーが発生したり、間違ったタイプを指定したりする必要がないためです。
たとえば、ネットワークを介して、一部のデータをバイトストリームとして出力する関数があるとします。関数を呼び出して、send()
送信するオブジェクトへのポインタとオブジェクトのバイト数を引数として受け取るようにします。したがって、プロトタイプは次のようになります。
void send(const void *object, size_t size);
そして、整数を送信する必要があるので、次のようにコーディングします。
int foo = 4711;
send(&foo, sizeof (int));
これでfoo
、2か所でタイプを指定することにより、足で自分自身を撮影する微妙な方法を導入しました。一方が変更されても他方が変更されない場合、コードは壊れます。したがって、常に次のようにします。
send(&foo, sizeof foo);
今、あなたは保護されています。確かに、変数の名前を複製しますが、変更すると、コンパイラが検出できる方法で壊れる可能性が高くなります。
sizeof(int)
より少ない指示が必要sizeof(foo)
ですか?
int x = 1+1;
対について考えてくださいint x = (1+1);
。ここで、括弧は純粋に完全に美的です。
sizeof
C ++およびC89では常に一定です。C99の可変長配列では、実行時に評価できます。
sizeof
演算子かもしれませんが、Linus Torvaldsによると関数として扱う必要があります。同意する。彼の有理をここで読んでください:lkml.org/lkml/2012/7/11/103
ptrdiff_t
ます。(通常、64ビットシステムでは、これはより大きいタイプになりますint
)。このコードでに変更int
しptrdiff_t
た場合でもarr
、アドレス空間の半分以上を占有する場合はバグが残っています。
/3G
オプション付きWindowsの@Aidiakapiでは、3G / 1Gユーザー/カーネル分割があり、アドレススペースサイズの最大75%までのアレイサイズを使用できます。
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
グローバル変数と考えてください。 定数ではないため、buf3[]
宣言は失敗し(&buf1)[1] - buf1
ます。
sizeof演算子を使用できますが、これはポインタの参照を取得するため関数では機能しません。配列の長さを見つけるには、次の操作を実行できます。
len = sizeof(arr)/sizeof(arr[0])
元々ここにあったコード: 配列の要素数を見つけるCプログラム
配列のデータ型がわかっている場合は、次のようなものを使用できます。
int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};
int noofele = sizeof(arr)/sizeof(int);
または、配列のデータ型がわからない場合は、次のようなものを使用できます。
noofele = sizeof(arr)/sizeof(arr[0]);
注:これは、配列が実行時に定義されておらず(mallocなど)、配列が関数に渡されない場合にのみ機能します。どちらの場合も、arr
(配列名)はポインターです。
int noofele = sizeof(arr)/sizeof(int);
コーディングよりも半分ほど優れていint noofele = 9;
ます。を使用sizeof(arr)
すると、配列のサイズが変化しても柔軟性が維持されます。ただしsizeof(int)
、arr[]
変更の種類に応じて更新が必要です。sizeof(arr)/sizeof(arr[0])
タイプがよく知られている場合でも使用することをお勧めします。使用した理由は不明int
のためnoofele
対size_t
、タイプがで返されますsizeof()
。
ARRAYELEMENTCOUNT(x)
誰もが利用しているマクロは正しく評価されません。これは現実的には敏感な問題です。「配列」型になる式を使用することはできないためです。
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
実際には次のように評価されます:
(sizeof (p + 1) / sizeof (p + 1[0]));
一方
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])
ARRAYELEMENTCOUNT(p + 1);
それは正しく評価されます:
(sizeof (p + 1) / sizeof (p + 1)[0]);
これは、配列のサイズと明示的には関係ありません。Cプリプロセッサがどのように機能するかを真に観察しないことから、多くのエラーに気づきました。マクロパラメーターは常にラップします。式が関係する可能性はありません。
これは正しいです; 私の例は悪いものでした。しかし、それは実際に起こるべきことです。前に述べたようp + 1
に、最終的にはポインター型になり、マクロ全体を無効にします(ポインターパラメーターを使用して関数でマクロを使用しようとした場合と同様です)。
結局のところ、この特定の例では、タイプが「配列」の式がないため、障害は本当に問題ではありません(つまり、私はみんなの時間を無駄にしているだけです。しかし、実際にはプリプロセッサの評価に関する微妙な点は重要だと思います。
(sizeof (x) / sizeof (*x))
か?
以下のために多次元配列には、少しはより複雑です。多くの場合、人々は明示的なマクロ定数、すなわち
#define g_rgDialogRows 2
#define g_rgDialogCols 7
static char const* g_rgDialog[g_rgDialogRows][g_rgDialogCols] =
{
{ " ", " ", " ", " 494", " 210", " Generic Sample Dialog", " " },
{ " 1", " 330", " 174", " 88", " ", " OK", " " },
};
ただし、これらの定数は、sizeofを使用してコンパイル時に評価することもできます。
#define rows_of_array(name) \
(sizeof(name ) / sizeof(name[0][0]) / columns_of_array(name))
#define columns_of_array(name) \
(sizeof(name[0]) / sizeof(name[0][0]))
static char* g_rgDialog[][7] = { /* ... */ };
assert( rows_of_array(g_rgDialog) == 2);
assert(columns_of_array(g_rgDialog) == 7);
このコードはCおよびC ++で機能することに注意してください。3次元以上の配列の場合
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
など、無限に。
sizeof(array) / sizeof(array[0])
Cでの配列のサイズ:
int a[10];
size_t size_of_array = sizeof(a); // Size of array a
int n = sizeof (a) / sizeof (a[0]); // Number of elements in array a
size_t size_of_element = sizeof(a[0]); // Size of each element in array a
// Size of each element = size of type
size_t size_of_element
はまだint
でint n = sizeof (a) / sizeof (a[0]);
はなくsize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
、int n
での使用でint n = sizeof (a) / sizeof (a[0]);
は不十分です(UBです)。を使用size_t n = sizeof (a) / sizeof (a[0]);
してもこの問題は発生しません。
私がsizeof
ここで示す最後の2つのケースである、要素の数またはバイトのいずれかで、配列の2つの異なるサイズのいずれかを取得するために(たとえ使用できるとしても)決して使用しないことをお勧めします。2つのサイズのそれぞれについて、以下に示すマクロを使用して、より安全にすることができます。その理由は、コードの意図をメンテナに明らかにし、一見したところ(このように書かれたものは明らかではありません)との違いsizeof(ptr)
をsizeof(arr)
明らかにし、コードを読むすべての人にとってバグが明らかになるようにするためです。
TL; DR:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
must_be_array(arr)
(以下で定義)-Wsizeof-pointer-div
バギーと同様に必要です(2020年4月現在):
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
このトピックに関して重要なバグがありました:https : //lkml.org/lkml/2015/9/3/428
Linusが提供するソリューションには同意しません。これは、関数のパラメーターに配列表記を使用しないことです。
私は、ポインタが配列として使用されているというドキュメントとしての配列表記が好きです。しかし、それはバグのあるコードを書くことができないように、誰にでもできるソリューションを適用する必要があることを意味します。
配列から、3つのサイズがわかります。
最初の方法は非常に単純で、配列とポインターのどちらを処理しても問題はありません。これは同じように行われるためです。
使用例:
void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
qsort(arr, nmemb, sizeof(arr[0]), cmp);
}
qsort()
3番目の引数としてこの値が必要です。
質問のトピックである他の2つのサイズについては、配列を処理していることを確認し、そうでない場合はコンパイルを中断します。ポインターを処理している場合、間違った値が取得されるためです。 。コンパイルが失敗すると、配列ではなくポインターを使用していたことを簡単に確認できます。変数のサイズまたはマクロを格納するマクロを使用してコードを記述するだけで、ポインタの後ろの配列。
これが最も一般的であり、多くの答えが典型的なマクロARRAY_SIZEを提供しています:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
ARRAY_SIZEの結果はタイプの符号付き変数で一般的に使用さptrdiff_t
れるため、このマクロの符号付きバリアントを定義することをお勧めします。
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
PTRDIFF_MAX
メンバーを超える配列は、この署名されたバージョンのマクロに対して無効な値を提供しますが、C17 :: 6.5.6.9を読み取ることから、そのような配列はすでに火で遊んでいます。のみARRAY_SIZE
とsize_t
これらの例で使用されるべきです。
GCC 8などのコンパイラの最近のバージョンでは、このマクロをポインタに適用すると警告が表示されるため、安全です(古いコンパイラで安全にする方法は他にもあります)。
これは、配列全体のバイト単位のサイズを各要素のサイズで割ることによって機能します。
使用例:
void foo(ptrdiff_t nmemb)
{
char buf[nmemb];
fgets(buf, ARRAY_SIZE(buf), stdin);
}
void bar(ptrdiff_t nmemb)
{
int arr[nmemb];
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(arr); i++)
arr[i] = i;
}
これらの関数が配列を使用せず、代わりにそれらをパラメーターとして取得した場合、以前のコードはコンパイルされないため、バグが発生する可能性はありません(最新のコンパイラバージョンが使用されているか、他のトリックが使用されている場合)。 、そしてマクロ呼び出しを値で置き換える必要があります:
void foo(ptrdiff_t nmemb, char buf[nmemb])
{
fgets(buf, nmemb, stdin);
}
void bar(ptrdiff_t nmemb, int arr[nmemb])
{
for (ptrdiff_t i = 0; i < nmemb; i++)
arr[i] = i;
}
ARRAY_SIZE
前のケースの解決策として一般的に使用されますが、このケースがあまり一般的でないためか、このケースが安全に作成されることはほとんどありません。
この値を取得する一般的な方法は、 sizeof(arr)
です。問題:前の問題と同じ。配列の代わりにポインタがある場合、プログラムはおかしくなります。
この問題の解決策には、以前と同じマクロを使用することが含まれていますが、これは安全であることがわかっています(ポインターに適用するとコンパイルが失敗します)。
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
どのように機能するかは非常に簡単です。除算を元に戻すARRAY_SIZE
ので、数学的取り消しの後、最終的には1つだけになりますsizeof(arr)
が、ARRAY_SIZE
構造のれます。
使用例:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
memset()
3番目の引数としてこの値が必要です。
以前と同様に、配列がパラメーター(ポインター)として受け取られた場合、それはコンパイルされず、マクロ呼び出しを値で置き換える必要があります。
void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
-Wsizeof-pointer-div
バグがある:今日、GCCの新しい警告は、マクロがシステムヘッダーではないヘッダーで定義されている場合にのみ機能することがわかりました。システムにインストールされているヘッダーでマクロを定義すると(通常は/usr/local/include/
または/usr/include/
)(#include <foo.h>
)、コンパイラーは警告を発行しません(GCC 9.3.0を試しました)。
したがって、私たちは#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
それを安全にする必要があります。C11 _Static_assert()
といくつかのGCC拡張が必要になります:式のステートメントと宣言、__builtin_types_compatible_p:
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
sizeof(arr) / sizeof((arr)[0]); \
} \
)
今ARRAY_SIZE()
は完全に安全であり、したがってそのすべての派生物は安全です。
__arraycount()
:Libbsdはでマクロ__arraycount()
を提供しますが<sys/cdefs.h>
、これには括弧のペアがないため安全ではありませんが、それらの括弧を自分で追加できるため、ヘッダーに除算を記述する必要さえありません(なぜ既存のコードを複製するのでしょうか? )。そのマクロはシステムヘッダーで定義されているため、使用する場合は上記のマクロを使用する必要があります。
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
__arraycount((arr)); \
} \
)
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
一部のシステムnitems()
は<sys/param.h>
代わりに提供し、一部のシステムは両方を提供します。あなたはあなたのシステムをチェックし、あなたが持っているものを使うべきです、そしておそらく移植性と両方をサポートするためにいくつかのプリプロセッサ条件を使います。
残念ながら、({})
gcc拡張子はファイルスコープでは使用できません。マクロをファイルスコープで使用できるようにするには、静的アサーションが内にある必要がありsizeof(struct {})
ます。次に、0
結果に影響を与えないように乗算します。へのキャストは(int)
、戻る関数をシミュレートするのに適している場合があります(int)0
(この場合は必要ありませんが、他のものに再利用できます)。
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
#define ARRAY_SIZE(arr) (__arraycount((arr)) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
sizeof(arr)
他では表示されていない、安全で一般的な構造()の解決策を示していますARRAY_BYTES(arr)
。
sizeof
、代わりにこの構造を使用することです。これらの構造を毎回書きたいと思うと、間違いを犯す可能性があります(貼り付けをコピーする場合は非常に一般的ですが、括弧が多いため毎回書く場合も非常に一般的です)...
sizeof
は明らかに安全ではありません(理由は答えにあります)、そしてマクロを使用せずに、毎回提供した構造を使用することは、さらに安全ではないので、行く唯一の方法マクロです。
「あなたは足で自分を撃つ微妙な方法を導入しました」
Cの「ネイティブ」配列はサイズを格納しません。したがって、配列の長さを別の変数/定数に保存し、配列を渡すときはいつでも渡すことをお勧めします。
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
あなたは常にネイティブ配列を避けるべきです(あなたが足を気にすることができない場合を除いて)。C ++を記述している場合は、STLの「ベクター」コンテナを使用します。「配列と比較して、それらはほとんど同じパフォーマンスを提供します」、そしてそれらははるかに便利です!
// vector is a template, the <int> means it is a vector of ints
vector<int> numbers;
// push_back() puts a new value at the end (or back) of the vector
for (int i = 0; i < 10; i++)
numbers.push_back(i);
// Determine the size of the array
cout << numbers.size();
enum
宣言を使用することであると読みました。
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
本当にこれを実行して配列を渡したい場合は、配列が必要な型へのポインタと配列のサイズを表す整数を格納する構造を実装することをお勧めします。次に、それを関数に渡すことができます。配列変数値(最初の要素へのポインター)をそのポインターに割り当てるだけです。次にArray.arr[i]
、i番目の要素を取得して使用できますArray.size
を取得し、して配列の要素数を取得できます。
私はあなたのためにいくつかのコードを含めました。あまり便利ではありませんが、より多くの機能で拡張できます。正直なところ、これらが必要な場合は、Cの使用を中止し、これらの機能が組み込まれた別の言語を使用する必要があります。
/* Absolutely no one should use this...
By the time you're done implementing it you'll wish you just passed around
an array and size to your functions */
/* This is a static implementation. You can get a dynamic implementation and
cut out the array in main by using the stdlib memory allocation methods,
but it will work much slower since it will store your array on the heap */
#include <stdio.h>
#include <string.h>
/*
#include "MyTypeArray.h"
*/
/* MyTypeArray.h
#ifndef MYTYPE_ARRAY
#define MYTYPE_ARRAY
*/
typedef struct MyType
{
int age;
char name[20];
} MyType;
typedef struct MyTypeArray
{
int size;
MyType *arr;
} MyTypeArray;
MyType new_MyType(int age, char *name);
MyTypeArray newMyTypeArray(int size, MyType *first);
/*
#endif
End MyTypeArray.h */
/* MyTypeArray.c */
MyType new_MyType(int age, char *name)
{
MyType d;
d.age = age;
strcpy(d.name, name);
return d;
}
MyTypeArray new_MyTypeArray(int size, MyType *first)
{
MyTypeArray d;
d.size = size;
d.arr = first;
return d;
}
/* End MyTypeArray.c */
void print_MyType_names(MyTypeArray d)
{
int i;
for (i = 0; i < d.size; i++)
{
printf("Name: %s, Age: %d\n", d.arr[i].name, d.arr[i].age);
}
}
int main()
{
/* First create an array on the stack to store our elements in.
Note we could create an empty array with a size instead and
set the elements later. */
MyType arr[] = {new_MyType(10, "Sam"), new_MyType(3, "Baxter")};
/* Now create a "MyTypeArray" which will use the array we just
created internally. Really it will just store the value of the pointer
"arr". Here we are manually setting the size. You can use the sizeof
trick here instead if you're sure it will work with your compiler. */
MyTypeArray array = new_MyTypeArray(2, arr);
/* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
print_MyType_names(array);
return 0;
}
strcpy(d.name, name);
オーバーフローの処理を行わないコードには賛成できません。
最良の方法は、たとえば、この情報を構造に保存することです。
typedef struct {
int *array;
int elements;
} list_s;
作成、破棄、等価性のチェックなど、必要なすべての機能を実装します。パラメータとして渡す方が簡単です。
int elements
対 何らかの理由size_t elements
?
&
演算子を使用できます。ここにソースコードがあります:
#include<stdio.h>
#include<stdlib.h>
int main(){
int a[10];
int *p;
printf("%p\n", (void *)a);
printf("%p\n", (void *)(&a+1));
printf("---- diff----\n");
printf("%zu\n", sizeof(a[0]));
printf("The size of array a is %zu\n", ((char *)(&a+1)-(char *)a)/(sizeof(a[0])));
return 0;
};
これがサンプル出力です
1549216672
1549216712
---- diff----
4
The size of array a is 10
ptrdiff_t
ます。 sizeof()
結果はsize_t
です。Cは、どちらがより広いか、より高いか、または同じランクであるかを定義しません。したがって、商のタイプは((char *)(&a+1)-(char *)a)/(sizeof(a[0]))
確実size_t
ではなく、したがってで印刷するz
とUBになる可能性があります。単に使うだけprintf("The size of array a is %zu\n", sizeof a/sizeof a[0]);
で十分です。
(char *)(&a+1)-(char *)a
は定数ではなく、固定サイズであっても実行時に計算される場合がありますa[10]
。 sizeof(a)/sizeof(a[0])
この場合、コンパイル時に常に行われます。
よりエレガントな解決策は
size_t size = sizeof(a) / sizeof(*a);
すでに提供されている回答に加えて、私は次の使用によって特別なケースを指摘したいと思います
sizeof(a) / sizeof (a[0])
a
がの配列の場合char
、unsigned char
またはこれらの型の1つのオペランドを持つ式の結果が常にになるため、2回signed char
使用する必要はありません。sizeof
sizeof
1
C18,6.5.3.4 / 4からの引用:
「とき
sizeof
タイプを有するオペランドに適用されるchar
、unsigned char
またはsigned char
、(またはその修飾バージョン)の結果です1
」。
したがって、if が、またはのタイプの配列である場合sizeof(a) / sizeof (a[0])
と同等になります。1による除算は冗長です。NUMBER OF ARRAY ELEMENTS / 1
a
char
unsigned char
signed char
この場合、単純に省略して実行できます。
sizeof(a)
例えば:
char a[10];
size_t length = sizeof(a);
証明が必要な場合は、ここにGodBoltへのリンクがあります。
それでも、タイプが大幅に変更された場合、部門は安全を維持します(これらのケースはまれです)。
注:これは、コメントでMMによって指摘されている未定義の動作を提供する可能性があります。
int a[10];
int size = (*(&a+1)-a) ;
*
オペレータは、過去エンドポインタに適用されなくてもよい
*(&a+1) - a;
とは異なり(&a)[1] - a;
、上記していないの両方 *(&a+1)
と(&a)[1]
エンド過去1としてカウント?
x[y]
次のように定義されます*(x + (y))