在C中有一个标准的函数,将返回一个数组的长度?
在C中有一个标准的函数,将返回一个数组的长度?
其他答案中所描述的技术通常被封装在一个macros中,以使其更容易。 就像是:
#define COUNT_OF( arr) (sizeof(arr)/sizeof(0[arr]))
请注意,上面的macros使用一个将数组名称放在索引操作符(' []
')而不是0
的小技巧 – 这是为了防止macros在C ++代码中被错误地用于重载operator[]()
。 编译器会抱怨而不是给出一个不好的结果。
但是,还要注意,如果你碰巧传递了一个指针而不是一个数组,这个macros将默默地给出一个不好的结果 – 这是使用这种技术的主要问题之一。
我最近开始使用我从Google Chromium的代码库中偷取的更复杂的版本:
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
在这个版本中,如果指针错误地作为parameter passing,编译器会在某些情况下发出抱怨 – 特别是如果指针的大小不能被指针所指向的对象的大小整除。 在这种情况下,被零除会导致编译器错误。 实际上,至less有一个我用过的编译器给出了一个警告,而不是一个错误 – 我不确定这个expression式是如何产生的。
这个macros并没有错误地使用它,但是它和我在直线C中看到的一样接近。
如果您希望在C ++中使用更安全的解决scheme,请查看Compile time sizeof_array,而不使用描述微软在winnt.h
使用的相当复杂的基于模板的方法的winnt.h
。
不,那里没有。
对于常量大小的数组,你可以使用Andrew提到的常见技巧, sizeof(array) / sizeof(array[0])
– 但是这只适用于声明数组的范围。
sizeof(array)
给你整个数组的大小,而sizeof(array[0])
给你第一个元素的大小。
请参阅Michaels回答如何在macros中包装。
对于dynamic分配的数组,你可以跟踪整数types的大小,或者如果可能的话使它成为0终止(即分配多一个元素并将最后一个元素设置为0)。
sizeof array / sizeof array[0]
数组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()
可以访问长度和所有的元素,你不必担心数组/指针的二分法。
这具有允许长度改变的附加优点(即,正在使用的元素的数量, 而不是分配的单元的数量)。 但我倾向于不再使用这个,因为我认为两个参数的数组版本(大小和数据)更好。
简单的答案当然不是。 但是实际的答案是“我需要知道”,所以我们来讨论解决这个问题的方法。
已经有一百万次的提及,有一种方法是使用sizeof()
:
int i[] = {0, 1, 2}; ... size_t i_len = sizeof(i) / sizeof(i[0]);
这个工作,直到我们试图传递给i
一个函数,或者指向i
。 那么更通用的解决scheme呢?
可接受的通用解决scheme是将数组长度传递给数组。 我们在标准库中看到了很多:
void *memcpy(void *s1, void *s2, size_t n);
将n
个字节从s1
复制到s2
,允许我们使用n
来确保我们的缓冲区不会溢出。 这是一个很好的策略 – 开销很低,实际上它生成了一些高效的代码(与strcpy()
,它必须检查string的结尾,并且没有办法“知道”必须做多less次迭代,和困惑的strncpy()
,它们必须检查两者 – 两者都可能较慢,如果由于某种原因,恰好已经计算了string的长度,则可以通过使用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;
但是,我们的分配(和释放)变得更加复杂。 当然,这两种方法中的任何一个的好处是,你现在所用的数组将会随着它们而变长。 它的内存效率稍低,但是非常安全。 如果您select了这些path之一,一定要编写助手函数,以便您不必手动分配和取消分配(和使用)这些结构。
如果您有一个数组types的对象,则数组中元素的数量可以表示为sizeof a / sizeof *a
。 如果你允许你的数组对象衰减到指针types(或只有一个指针对象开头),那么在一般情况下,没有办法确定数组中的元素数量。