我写了一个像这样的array_length函数:
int array_length(int a[]){
return sizeof(a)/sizeof(int);
}
然而当我做的时候它会返回2
unsigned int len = array_length(arr);
printf ("%i" , len);
我在哪里
int arr[] = {3,4,5,6,1,7,2};
int * parr = arr;
但是当我做的时候
int k = sizeof(arr)/sizeof(int);
printf("%i", k);
在main函数中,它返回7.
编写array_length函数的正确方法是什么?如何使用它?
答案 0 :(得分:16)
计算数组长度(以C为单位)充其量只是个问题。
以上代码的问题在于:
int array_length(int a[]){
return sizeof(a)/sizeof(int);
}
您只是将指针作为“a”传递,因此sizeof(a)
为sizeof(int*)
。如果您使用的是64位系统,那么函数内部的sizeof(a)/sizeof(int)
总是会得到2,因为指针将是64位。
您可以(可能)将此作为宏而不是函数执行,但这有它自己的问题...(它完全内联这一点,因此您获得与int k =...
块相同的行为。 )
答案 1 :(得分:12)
您的功能无效。 C数组和C指针是不同的类型,但如果你看它有趣,数组将退化成指针。
在这种情况下,您将数组作为参数传递,并且它在调用中变为指针,因此您正在测量sizeof(int *)/sizeof(int)
。
使这项工作的唯一方法是使用宏:
#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x))
只有在该范围内将x
声明为数组而不是指针时才会有效。
答案 2 :(得分:8)
使用宏...
#define SIZEOF_ARRAY( arr ) sizeof( arr ) / sizeof( arr[0] )
它还可以为任何数组数据类型工作:)
答案 3 :(得分:5)
通常,无法测量数组大小C.在主函数中,编译器会为您在大括号之间编写的元素进行计数,因此您实际上是在声明int arr[7]
。这有你期望的尺寸。
但是,在您的函数中,int a[]
等同于int *a
- 指向整数的指针。 你知道它是一个数组,所以有更多整数跟随,但你的array_length
函数可以传递任何整数指针,所以它不能知道。
这是尽可能使用std::vector
而不是原始数组的众多原因之一。
答案 4 :(得分:5)
您的问题的简单答案是:无法编写array_length
函数。您可能能够使用宏定义,但这取决于您将使用宏的上下文。
你在C中混淆了数组和指针的常见错误。在C中,数组的名称,在大多数情况下,相当于指向其第一个元素的指针。您的array_length
函数在这样的上下文中接收数组a
。换句话说,不可能在C中将数组作为数组传递。您的函数就好像它是这样定义的:
int array_length(int *a){
return sizeof(a)/sizeof (int);
}
,基本上将int *
的大小除以int
的大小。另外,通过上面的描述,在函数中知道C中数组的大小是不可能的。
现在,如何在功能之外正确确定其大小?答案是sizeof
运算符是数组名称不减少为指向其第一个元素的指针的情况之一。我在this answer中更精细地解释了这些差异。另请注意,尽管有外观,但sizeof
是一个操作符,而不是一个函数(正如我们刚刚学到的那样,不能是一个函数,因为它将无法计算数组的大小。)
最后,要确定任何类型a
的数组T
的大小,我更喜欢:
size_t sz = sizeof a / sizeof a[0];
以上是与类型无关的:a
可以是上述任何类型。实际上,您甚至可以更改a
的类型,而无需更改上述内容。
答案 5 :(得分:3)
尝试_countof它在WinNT.h中定义为
// Return the number of elements in a statically sized array.
// DWORD Buffer[100];
// RTL_NUMBER_OF(Buffer) == 100
// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc.
//
#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0]))
答案 6 :(得分:3)
问题是函数参数实际上不是数组,即使C允许你做一个看起来像一个的声明。该参数最终成为一个简单的指针。我说elsewhere:
这归结为C / C ++中的普通数组参数是虚构的事实 - 它们确实是指针。应尽可能避免数组参数 - 它们实际上只是混淆了问题。
这就是为什么这种类型的构造返回数组中元素的数量最终成为C中的一个宏。为了我认为宏的一个好的(如果复杂的)实现,请参阅此前的SO答案:
为便于参考,这是宏:
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
该宏的复杂性使得它比大多数使用起来更安全(请注意,我并不声称自己是宏中使用的技术的创始人)。
答案 7 :(得分:2)
计算数组中元素数量的一般过程是sizeof arr / sizeof arr[0]
(或sizeof arr / sizeof *arr
)。说完了......
编写一个函数来计算作为参数传递的数组的长度注定要失败,因为函数接收的是指针,而不是数组。当您使用数组表达式作为参数调用函数时,数组表达式将其类型隐式地从“数组T”转换为“指向T的指针”,并且其值将设置为指向数组中的第一个元素。您的函数没有看到数组对象;它看到了一个指针。
在函数参数声明的上下文中,int a[]
与int *a
完全相同,但对于函数参数声明,仅为真(没有什么能比我更开心看到从C的所有未来版本中消除的第一个形式,但这不会发生)。
答案 8 :(得分:2)
int arr [whatever]函数参数列表中定义了一个指针,而不是一个数组。因此,有关长度的信息将永远丢失。
为什么!?
要了解原因,您必须了解C的全部内容。 C永远不会隐含地复制复杂的块。因此,当你说“传递给我一个数组”时,它实际上意味着“我想传递一个地址,通常是这个数组的名称”。
这不是一个缺点。如果您想要更多,则必须手动传递。奖励是你确切地知道机器的水平是什么,给你性能和其他好处。这就是为各种目的提供一种通用编程语言的方法。
答案 9 :(得分:2)
没有办法确定传递给像这样的函数的数组的大小
void foo(int a[]);
在编译时或运行时没有足够的信息来解决它
sizeof技巧仅适用于指定数组大小的源位置
答案 10 :(得分:1)
数组引用将解决这个问题,虽然我从来没有建议使用过这样的东西(因为它只会在你总是通过ref传递,或者在定义了数组的范围内使用它时才会起作用):
#include <iostream>
template <typename Arrtype>
unsigned mysize (Arrtype (&arr)) {
return sizeof(arr) / sizeof(arr[0]);
}
int main () {
unsigned arr[13];
std::cout << mysize(arr) << std::endl; // prints 13
}
此处还提到:http://cplusplus.co.il/2009/09/06/more-on-arrays/
编辑:正如评论中所建议的那样,另一种可能的解决方案是:
template <typename T, unsigned N>
unsigned mysize(T (&)[N]) {
return N;
}
答案 11 :(得分:1)
用作函数参数的“int a []”语法等同于“int * a”。
此语法:
int arr [] = {3,4,5,6,1,7,2};
仅在编译时工作。
所以你可以写: int arr [] = {3,4,5,6,1,7,2}; printf(“size =%d \ n”,sizeof(arr));
这只能在编译时使用。
解决这个问题的一种方法是使数组动态化并创建自己的数组类型。
e.g。
typedef struct array{
int length;
int *arr;
} array;
使用malloc设置它的大小。您可以使用elipses填充它。
populate_array(array, ...);
e.g。然后调用populate_array(arr,1,2,3,4,5,6); 见stdarg。
但是,因为你的C编译器很可能也是一个C ++编译器。考虑使用std :: vector代替。然后,为你完成了艰苦的工作。
答案 12 :(得分:1)
我发现这是我们的C编译器制作的陷阱! (那么它是CPL的标准吗?C99还是其他什么?) 我在x86平台上的visual studio 2010中编写了以下代码。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[3] = { 0xa, 0xb, 0xc }; // Declare an array which include 3 items.
int len = sizeof(a) / sizeof(a[0]); // And the variable len refer to the code like @Neil Chowdhury o_O
int * pa0 = a; // Then i declared a pointer point to the first element to the source array a.
int len2 = sizeof(a) / sizeof(pa0[0]); // Len2 refer to the same action like previous statement.
int len3 = sizeof(a) / sizeof(pa0); // Len3 refer to a's size(one int's size)divide may be a int pointer's size.
int len4 = sizeof(pa0); // Len4 is the size of int pointer pa0.
int len5 = sizeof(a); // And len5 is the size of pa0, the same theory as previous stmt represented.
int len6 = sizeof(a[0]); // Len6 equal to sizeof(int)
int len7 = sizeof(pa0[0]); // Len7 equal to sizeof(int) too.
return 0;
}
然后我构建了它们,并显示了反汇编代码。结果如下:
int a[3] = { 0xa, 0xb, 0xc };
00D13108 mov dword ptr [ebp-14h],0Ah
00D1310F mov dword ptr [ebp-10h],0Bh
00D13116 mov dword ptr [ebp-0Ch],0Ch
int len = sizeof(a) / sizeof(a[0]);
00D1311D mov dword ptr [ebp-20h],3 // caution!
int * pa0 = a;
00D13124 lea eax,[ebp-14h]
00D13127 mov dword ptr [ebp-2Ch],eax
int len2 = sizeof(a) / sizeof(pa0[0]);
00D1312A mov dword ptr [ebp-38h],3 // caution!
int len3 = sizeof(a) / sizeof(pa0);
00D13131 mov dword ptr [ebp-44h],3 // caution!
int len4 = sizeof(pa0);
00D13138 mov dword ptr [ebp-50h],4
int len5 = sizeof(a);
00D1313F mov dword ptr [ebp-5Ch],0Ch
int len6 = sizeof(a[0]);
00D13146 mov dword ptr [ebp-68h],4
int len7 = sizeof(pa0[0]);
00D1314D mov dword ptr [ebp-74h],4
return 0;
00D13154 xor eax,eax
那么,什么?看看这些“谨慎”的标记线! 我们的c编译器是如何处理我们的C代码的? 当指针到来时,特别是当我们写一个像这样的句子时 something = sizeof(数组的一个元素)/ sizeof(该数组的第一个元素) 编译器将我们的语法解析为数组的编号! 它尚未完成。
我也测试了一个“动态阵列”。由malloc等分配的数组。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int * a = NULL;
int len = 0;
a = (int *) calloc(7, sizeof(int));
len = sizeof(a) / sizeof(a[0]);
return 0;
}
构建..反汇编......
int * a = NULL;
013830FE mov dword ptr [a],0
int len = 0;
01383105 mov dword ptr [len],0
a = (int *) calloc(7, sizeof(int));
0138310C mov esi,esp
0138310E push 4
01383110 push 7
01383112 call dword ptr [__imp__calloc (13882CCh)]
01383118 add esp,8
0138311B cmp esi,esp
0138311D call @ILT+300(__RTC_CheckEsp) (1381131h)
01383122 mov dword ptr [a],eax
len = sizeof(a) / sizeof(a[0]);
01383125 mov dword ptr [len],1 // Hey!
return 0;
0138312C xor eax,eax
}
你知道吗?编译器此时错过了我们的语法。
所以结论是:
当你写一个特别喜欢的句子时:
something = sizeof(数组的一个元素)/ sizeof(该数组的第一个元素)
编译器将理解并解析我们的代码,并将数组容量签名。仅当源数组是固定数组,或者数组之前已声明大小时。 (此时,大小是常量,可以存储在编译器的变量表中。)
它基本上像@rmn说的那样。
这就是我发现的。可能毫无价值。
答案 13 :(得分:0)
这非常有效:
int A[5] = {10, 20, 30, 40, 3};
int length = sizeof(A) / sizeof(A[0]); // prints 5