在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(或只有一个指针对象开头),那么在一般情况下,没有办法确定数组中的元素数量。