如何确定C语言中数组的大小?
也就是说,数组可以容纳多少元素?
如何确定C语言中数组的大小?
也就是说,数组可以容纳多少元素?
当前回答
每个人都在使用的宏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将以指针类型结束,并使整个宏无效(就像您试图在带有指针形参的函数中使用宏一样)。
在一天结束的时候,在这个特殊的例子中,错误并不重要(所以我只是在浪费大家的时间;Huzzah !),因为你没有数组类型的表达式。但是我认为关于预处理器评估的微妙之处是很重要的。
其他回答
执行概要:
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)但如果类型 如果你忘记改变,你会有一个讨厌的bug sizeof(int)也是。
因此首选除数是sizeof(a[0])或等效的sizeof(*a),即数组第一个元素的大小。
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
另一个优点是您现在可以轻松地参数化 宏中的数组名,get:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
最好的方法是保存这些信息,例如,在一个结构中:
typedef struct {
int *array;
int elements;
} list_s;
实现所有必要的功能,如创建、销毁、检查是否相等以及其他所有需要的功能。它更容易作为参数传递。
除了已经提供的答案,我想指出一个特殊的情况下使用
sizeof(a) / sizeof (a[0])
如果a是char、unsigned char或signed char的数组,则不需要使用sizeof两次,因为带有这些类型的一个操作数的sizeof表达式的结果总是1。
引用自C18,6.5.3.4/4:
当sizeof应用于具有char类型、unsigned char类型或signed char类型(或其限定版本)的操作数时,结果为1。
因此,如果a是char、unsigned char或signed char类型的数组,sizeof(a) / sizeof(a[0])将等效于NUMBER OF ARRAY ELEMENTS / 1。除1是多余的。
在这种情况下,你可以简单地缩写为do:
sizeof(a)
例如:
char a[10];
size_t length = sizeof(a);
如果你想要证明,这里有一个GodBolt的链接。
尽管如此,如果类型发生重大变化(尽管这种情况很少见),该部门仍会保持安全。
对于预定义数组:
int a[] = {1, 2, 3, 4, 5, 6};
计算数组中的元素数量:
element _count = sizeof(a) / sizeof(a[0]);
大小的“技巧”是我所知道的最好的方法,在括号的使用上有一个小而重要的变化(对我来说,这是一个主要的烦恼)。
正如维基百科的条目所表明的那样,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类型,您引入了一种搬起石头砸自己的脚的微妙方法。如果一个改变了,而另一个没有改变,代码就会崩溃。因此,总是这样做:
send(&foo, sizeof foo);
现在你被保护了。当然,你复制了变量的名称,但如果你改变了它,编译器很可能会检测到这种破坏。