C中是否有一个标准函数可以返回数组的长度?
答案 0 :(得分:64)
通常,其他答案中描述的技术被封装在一个宏中,以使眼睛更容易。类似的东西:
#define COUNT_OF( arr) (sizeof(arr)/sizeof(0[arr]))
请注意,上面的宏使用了一个小技巧,即将数组名称放在索引运算符('[]
')而不是0
中 - 如果宏被错误地用于包含重载operator[]()
的项的C ++代码。编译器会抱怨而不是给出错误的结果。
但是,请注意,如果您碰巧传递指针而不是数组,宏将默默地给出错误的结果 - 这是使用此技术的主要问题之一。
我最近开始使用我从Google Chromium的代码库中窃取的更复杂的版本:
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
在这个版本中如果错误地将指针作为参数传递,编译器会在某些情况下抱怨 - 特别是如果指针的大小不能被指针所指向的对象的大小整除。在这种情况下,除零将导致编译器出错。实际上至少有一个我用过的编译器给出了一个警告而不是一个错误 - 我不确定它为那个除以零的表达式生成了什么。
那个宏没有关闭错误地使用它的大门,但是它在我用直接C看到的时候非常接近。
如果您希望在使用C ++时获得更安全的解决方案,请查看Compile time sizeof_array without using a macro,其中介绍了Microsoft在winnt.h
中使用的基于模板的相当复杂的方法。
答案 1 :(得分:14)
不,没有。
对于常量大小的数组,您可以使用Andrew提到的常见技巧sizeof(array) / sizeof(array[0])
- 但这仅适用于声明数组的范围。
sizeof(array)
为您提供整个数组的大小,而sizeof(array[0])
为您提供第一个元素的大小。
请参阅Michaels answer,了解如何将其包装在宏中。
对于动态分配的数组,您可以跟踪整数类型的大小,或者如果可能的话使其以0结尾(即分配1个元素并将最后一个元素设置为0)。
答案 2 :(得分:5)
sizeof array / sizeof array[0]
答案 3 :(得分:3)
数组x
中的元素数量可以通过以下方式获得:
sizeof(x)/sizeof(x[0])
你需要知道,当传递给函数时,数组会降级为不携带大小信息的指针。实际上,大小信息从不可用于运行时,因为它是在编译时计算的,但是您可以在数组可见的情况下(即,它尚未降级的情况下)可用)。
当我将数组传递给我需要视为数组的函数时,我总是确保传递两个参数:
因此,虽然可以将数组视为声明它的数组,但它在其他地方被视为大小和指针。
我倾向于使用以下代码:
#define countof(x) (sizeof(x)/sizeof(x[0]))
: : :
int numbers[10];
a = fn (countof(numbers),numbers);
然后fn()
将获得大小信息。
我过去使用的另一个技巧(我认为有点麻烦,但我会在这里给它完整性)是有一个联合数组并使第一个元素成为长度,如:
typedef union {
int len;
float number;
} tNumber;
tNumber number[10];
: : :
number[0].len = 5;
a = fn (number);
然后fn()
可以访问长度和所有元素,您不必担心数组/指针二分法。
这具有允许长度变化的附加优点(即,使用中的元素的数量,不分配的单元的数量)。但我倾向于不再使用它,因为我认为两个参数的数组版本(大小和数据)更好。
答案 4 :(得分:2)
简单的答案当然是否定的。但实际的答案是“无论如何我都需要知道”,所以让我们讨论一下解决这个问题的方法。
如前所述,已经有一百万次提到它的一种方法是使用sizeof()
:
int i[] = {0, 1, 2};
...
size_t i_len = sizeof(i) / sizeof(i[0]);
这是有效的,直到我们尝试将i
传递给函数,或者指向i
。那么更一般的解决方案呢?
公认的通用解决方案是将数组长度与数组一起传递给函数。我们在标准库中看到了很多:
void *memcpy(void *s1, void *s2, size_t n);
将n
字节从s1
复制到s2
,允许我们使用n
来确保缓冲区永不溢出。这是一个很好的策略 - 它具有较低的开销,并且它实际上生成了一些有效的代码(与strcpy()
相比,它必须检查字符串的结尾并且无法“知道”它必须有多少次迭代make,和困惑的混淆strncpy()
,它必须检查两者 - 可以更慢,如果你碰巧已经计算过,可以使用memcpy()
加速由于某种原因,字符串的长度。)
另一种方法是将代码封装在struct
中。常见的黑客是:
typedef struct _arr {
size_t len;
int arr[0];
} arr;
如果我们想要一个长度为5的数组,我们这样做:
arr *a = malloc(sizeof(*a) + sizeof(int) * 5);
a->len = 5;
但是,这是一个只有适度定义的黑客(C99允许你使用int arr[]
)并且相当劳力密集。 “更好定义”的方法是:
typedef struct _arr {
size_t len;
int *arr;
} arr;
然后我们的分配(和解除分配)变得更加复杂。当然,这些方法中的任何一个的好处是,现在制作的数组将随身携带。它的内存效率略低,但它非常安全。如果您选择其中一个路径,请务必编写辅助函数,这样您就不必手动分配和释放(并使用)这些结构。
答案 5 :(得分:0)
如果您有一个数组类型的对象a
,则数组中的元素数可以表示为sizeof a / sizeof *a
。如果你允许你的数组对象衰减到指针类型(或只有一个指针对象开始),那么一般情况下无法确定数组中元素的数量。
答案 6 :(得分:0)
我创建了一个宏,该宏返回数组的大小,但是如果在指针上使用它会产生编译器错误。但是请注意,它依赖于gcc扩展。因此,它不是便携式解决方案。
#define COUNT(a) (__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(a), typeof(&(a)[0])), \
(void)0, \
(sizeof(a)/sizeof((a)[0]))))
int main(void)
{
int arr[5];
int *p;
int x = COUNT(arr);
// int y = COUNT(p);
}
如果您删除评论,则会产生:error: void value not ignored as it ought to be