函数参数中的数组长度

时间:2022-03-09 17:26:58

This is well known code to compute array length in C:

这是众所周知的用C计算数组长度的代码:

sizeof(array)/sizeof(type)

But I can't seem to find out the length of the array passed as an argument to a function:

但我似乎无法找出作为参数传递给函数的数组的长度:

#include <stdio.h>

int length(const char* array[]) {
  return sizeof(array)/sizeof(char*);
}

int main() {
  const char* friends[] = { "John", "Jack", "Jim" };
  printf("%d %d", sizeof(friends)/sizeof(char*), length(friends)); // 3 1
}

I assume that array is copied by value to the function argument as constant pointer and reference to it should solve this, but this declaration is not valid:

我假设数组被值复制到函数参数中作为常量指针和引用应该可以解决这个问题,但是这个声明是无效的:

int length(const char**& array);

I find passing the array length as second argument to be redundant information, but why is the standard declaration of main like this:

我发现将数组长度作为第二个参数传递是多余的信息,但是为什么main的标准声明是这样的呢:

int main(int argc, char** argv);

Please explain if it is possible to find out the array length in function argument, and if so, why is there the redundancy in main.

请解释在函数参数中是否有可能找到数组长度,如果有,为什么在main中有冗余。


8 个解决方案

#1


56  

sizeof only works to find the length of the array if you apply it to the original array.

如果将sizeof应用到原始数组中,则只能找到数组的长度。

int a[5]; //real array. NOT a pointer
sizeof(a); // :)

However, by the time the array decays into a pointer, sizeof will give the size of the pointer and not of the array.

然而,当数组衰减成指针时,sizeof将给出指针的大小而不是数组的大小。

int a[5];
int * p = a;
sizeof(p); // :(

As you have already smartly pointed out main receives the length of the array as an argument (argc). Yes, this is out of necessity and is not redundant. (Well, it is kind of reduntant since argv is conveniently terminated by a null pointer but I digress)

正如您已经巧妙地指出的,main接收数组的长度作为参数(argc)。是的,这是出于需要,并不是多余的。(这是一种冗余,因为argv被一个空指针很方便地终止了,但是我离题了)

There is some reasoning as to why this would take place. How could we make things so that a C array also knows its length?

关于为什么会发生这种情况,有一些理由。我们如何让C数组知道它的长度?

A first idea would be not having arrays decaying into pointers when they are passed to a function and continuing to keep the array length in the type system. The bad thing about this is that you would need to have a separate function for every possible array length and doing so is not a good idea. (Pascal did this and some people think this is one of the reasons it "lost" to C)

第一个想法是,当数组传递给函数时,不要让它们衰减成指针,并在类型系统中继续保持数组长度。最糟糕的是,你需要为每一个可能的数组长度设置一个单独的函数,这样做不是一个好主意。(Pascal这么做过,有些人认为这是它输给C的原因之一)

A second idea is storing the array length next to the array, just like any modern programming language does:

第二个想法是将数组长度存储在数组旁边,就像任何现代编程语言所做的那样:

a -> [5];[0,0,0,0,0]

But then you are just creating an invisible struct behind the scenes and the C philosophy does not approve of this kind of overhead. That said, creating such a struct yourself is often a good idea for some sorts of problems:

但是,您只是在幕后创建一个不可见的结构体,而C哲学并不赞成这种开销。也就是说,创建这样的结构体常常是解决某些问题的好办法:

struct {
    size_t length;
    int * elements;
}

Another thing you can think about is how strings in C are null terminated instead of storing a length (as in Pascal). To store a length without worrying about limits need a whopping four bytes, an unimaginably expensive amount (at least back then). One could wonder if arrays could be also null terminated like that but then how would you allow the array to store a null?

您可以考虑的另一件事是C中的字符串如何终止而不是存储长度(如Pascal)。要存储长度而不担心限制,需要大量的4个字节,这是一个难以想象的开销(至少在那时)。你可能想知道数组是否也可以像那样被终止,但是你如何让数组存储一个空值呢?

#2


12  

The array decays to a pointer when passed.

数组在传递时衰减为指针。

Section 6.4 of the C FAQ covers this very well and provides the K&R references etc.

cfaq的第6.4节很好地介绍了这一点,并提供了K&R参考资料等。


That aside, imagine it were possible for the function to know the size of the memory allocated in a pointer. You could call the function two or more times, each time with different input arrays that were potentially different lengths; the length would therefore have to be passed in as a secret hidden variable somehow. And then consider if you passed in an offset into another array, or an array allocated on the heap (malloc and all being library functions - something the compiler links to, rather than sees and reasons about the body of).

除此之外,假设函数可以知道在指针中分配的内存的大小。你可以调用函数两次或更多次,每次都有不同的输入数组,它们的长度可能不同;因此,必须以某种方式将长度作为一个秘密隐藏变量传入。然后再考虑是否将偏移量传递到另一个数组或分配到堆上的数组(malloc和所有的都是库函数——编译器链接到这些函数,而不是查看和解释堆的主体)。

Its getting difficult to imagine how this might work without some behind-the-scenes slice objects and such right?

很难想象如果没有一些幕后切片对象,这是如何工作的,对吧?


Symbian did have a AllocSize() function that returned the size of an allocation with malloc(); this only worked for the literal pointer returned by the malloc, and you'd get gobbledygook or a crash if you asked it to know the size of an invalid pointer or a pointer offset from one.

Symbian确实有一个AllocSize()函数,它使用malloc()返回分配的大小;这只适用于malloc返回的文字指针,如果您要求它知道无效指针的大小或指针与一个指针的偏移量,您将得到gobbledygook或崩溃。

You don't want to believe its not possible, but it genuinely isn't. The only way to know the length of something passed into a function is to track the length yourself and pass it in yourself as a separate explicit parameter.

你不会想相信这是不可能的,但它确实不是。要知道传递给函数的内容的长度,唯一的方法是自己跟踪长度,并将其作为单独的显式参数传递给自己。

#3


2  

As stated by @Will, the decay happens during the parameter passing. One way to get around it is to pass the number of elements. To add onto this, you may find the _countof() macro useful - it does the equivalent of what you've done ;)

如@Will所述,衰减发生在参数传递期间。绕过它的一种方法是传递元素的数量。要添加这个,您可能会发现_countof()宏非常有用——它的功能与您所做的相同;)

#4


2  

First, a better usage to compute number of elements when the actual array declaration is in scope is:

首先,当实际数组声明在范围内时,更好地计算元素数量的用法是:

sizeof array / sizeof array[0]

This way you don't repeat the type name, which of course could change in the declaration and make you end up with an incorrect length computation. This is a typical case of don't repeat yourself.

这样,您就不会重复类型名,这当然会在声明中更改,从而导致不正确的长度计算。这是一个典型的不重复自己的例子。

Second, as a minor point, please note that sizeof is not a function, so the expression above doesn't need any parenthesis around the argument to sizeof.

其次,作为次要的一点,请注意sizeof不是一个函数,因此上面的表达式不需要在sizeof的参数周围加上任何括号。

Third, C doesn't have references so your usage of & in a declaration won't work.

第三,C没有引用,所以在声明中使用&将不起作用。

I agree that the proper C solution is to pass the length (using the size_t type) as a separate argument, and use sizeof at the place the call is being made if the argument is a "real" array.

我同意正确的C解决方案是将长度(使用size_t类型)作为单独的参数传递,如果参数是“真实”数组,则在调用的地方使用sizeof。

Note that often you work with memory returned by e.g. malloc(), and in those cases you never have a "true" array to compute the size off of, so designing the function to use an element count is more flexible.

注意,您经常使用malloc()返回的内存,在这些情况下,您永远不会有一个“true”数组来计算该数组的大小,所以设计函数来使用元素计数更灵活。

#5


2  

Regarding int main():

关于int main():

According to the Standard, argv points to a NULL-terminated array (of pointers to null-terminated strings). (5.1.2.2.1:1).

根据标准,argv指向一个空终止数组(指向空终止字符串的指针)。(5.1.2.2.1:1)。

That is, argv = (char **){ argv[0], ..., argv[argc - 1], 0 };.

即argv = (char **){argv[0],…, argv[argc - 1], 0};

Hence, size calculation is performed by a function which is a trivial modification of strlen().

因此,大小计算是由一个对strlen()进行简单修改的函数来完成的。

argc is only there to make argv length calculation O(1).

argc仅用于对argv长度进行计算(1)。

The count-until-NULL method will NOT work for generic array input. You will need to manually specify size as a second argument.

从计数到null的方法不适用于泛型数组输入。您将需要手动指定size作为第二个参数。

#6


1  

This is a old question, and the OP seems to mix C++ and C in his intends/examples. In C, when you pass a array to a function, it's decayed to pointer. So, there is no way to pass the array size except by using a second argument in your function that stores the array size:

这是一个老问题,OP似乎在他的意图/示例中混合了c++和C。在C中,当你将一个数组传递给一个函数时,它会衰变为指针。因此,除了在函数中使用第二个参数存储数组大小之外,没有办法传递数组大小:

void func(int A[]) 
// should be instead: void func(int * A, const size_t elemCountInA)

They are very few cases, where you don't need this, like when you're using multidimensional arrays:

它们是非常少的情况,你不需要这个,比如当你使用多维数组:

void func(int A[3][whatever here]) // That's almost as if read "int* A[3]"

Using the array notation in a function signature is still useful, for the developer, as it might be an help to tell how many elements your functions expects. For example:

对开发人员来说,在函数签名中使用数组表示法仍然很有用,因为它可以帮助告诉您的函数需要多少元素。例如:

void vec_add(float out[3], float in0[3], float in1[3])

is easier to understand than this one (although, nothing prevent accessing the 4th element in the function in both functions):

比这一个更容易理解(虽然没有什么可以阻止在两个函数中访问函数中的第4个元素):

void vec_add(float * out, float * in0, float * in1)

If you were to use C++, then you can actually capture the array size and get what you expect:

如果您要使用c++,那么您实际上可以捕获数组大小并得到您期望的结果:

template <size_t N>
void vec_add(float (&out)[N], float (&in0)[N], float (&in1)[N])
{
    for (size_t i = 0; i < N; i++) 
        out[i] = in0[i] + in1[i];
}

In that case, the compiler will ensure that you're not adding a 4D vector with a 2D vector (which is not possible in C without passing the dimension of each dimension as arguments of the function). There will be as many instance of the vec_add function as the number of dimensions used for your vectors.

在这种情况下,编译器将确保不添加一个2D向量的4D向量(在C中,如果不将每个维度的维度作为函数的参数传递,就不可能添加2D向量)。vec_add函数的实例数量与向量使用的维数相同。

#7


-1  

int arsize(int st1[]) {
    int i = 0;
    for (i; !(st1[i] & (1 << 30)); i++);
    return i;
}

This works for me :)

这对我很管用:

#8


-3  

Best example is here

最好的例子就是在这里

thanks #define SIZE 10

谢谢# define 10码

void size(int arr[SIZE])
{
    printf("size of array is:%d\n",sizeof(arr));
}

int main()
{
    int arr[SIZE];
    size(arr);
    return 0;
}

#1


56  

sizeof only works to find the length of the array if you apply it to the original array.

如果将sizeof应用到原始数组中,则只能找到数组的长度。

int a[5]; //real array. NOT a pointer
sizeof(a); // :)

However, by the time the array decays into a pointer, sizeof will give the size of the pointer and not of the array.

然而,当数组衰减成指针时,sizeof将给出指针的大小而不是数组的大小。

int a[5];
int * p = a;
sizeof(p); // :(

As you have already smartly pointed out main receives the length of the array as an argument (argc). Yes, this is out of necessity and is not redundant. (Well, it is kind of reduntant since argv is conveniently terminated by a null pointer but I digress)

正如您已经巧妙地指出的,main接收数组的长度作为参数(argc)。是的,这是出于需要,并不是多余的。(这是一种冗余,因为argv被一个空指针很方便地终止了,但是我离题了)

There is some reasoning as to why this would take place. How could we make things so that a C array also knows its length?

关于为什么会发生这种情况,有一些理由。我们如何让C数组知道它的长度?

A first idea would be not having arrays decaying into pointers when they are passed to a function and continuing to keep the array length in the type system. The bad thing about this is that you would need to have a separate function for every possible array length and doing so is not a good idea. (Pascal did this and some people think this is one of the reasons it "lost" to C)

第一个想法是,当数组传递给函数时,不要让它们衰减成指针,并在类型系统中继续保持数组长度。最糟糕的是,你需要为每一个可能的数组长度设置一个单独的函数,这样做不是一个好主意。(Pascal这么做过,有些人认为这是它输给C的原因之一)

A second idea is storing the array length next to the array, just like any modern programming language does:

第二个想法是将数组长度存储在数组旁边,就像任何现代编程语言所做的那样:

a -> [5];[0,0,0,0,0]

But then you are just creating an invisible struct behind the scenes and the C philosophy does not approve of this kind of overhead. That said, creating such a struct yourself is often a good idea for some sorts of problems:

但是,您只是在幕后创建一个不可见的结构体,而C哲学并不赞成这种开销。也就是说,创建这样的结构体常常是解决某些问题的好办法:

struct {
    size_t length;
    int * elements;
}

Another thing you can think about is how strings in C are null terminated instead of storing a length (as in Pascal). To store a length without worrying about limits need a whopping four bytes, an unimaginably expensive amount (at least back then). One could wonder if arrays could be also null terminated like that but then how would you allow the array to store a null?

您可以考虑的另一件事是C中的字符串如何终止而不是存储长度(如Pascal)。要存储长度而不担心限制,需要大量的4个字节,这是一个难以想象的开销(至少在那时)。你可能想知道数组是否也可以像那样被终止,但是你如何让数组存储一个空值呢?

#2


12  

The array decays to a pointer when passed.

数组在传递时衰减为指针。

Section 6.4 of the C FAQ covers this very well and provides the K&R references etc.

cfaq的第6.4节很好地介绍了这一点,并提供了K&R参考资料等。


That aside, imagine it were possible for the function to know the size of the memory allocated in a pointer. You could call the function two or more times, each time with different input arrays that were potentially different lengths; the length would therefore have to be passed in as a secret hidden variable somehow. And then consider if you passed in an offset into another array, or an array allocated on the heap (malloc and all being library functions - something the compiler links to, rather than sees and reasons about the body of).

除此之外,假设函数可以知道在指针中分配的内存的大小。你可以调用函数两次或更多次,每次都有不同的输入数组,它们的长度可能不同;因此,必须以某种方式将长度作为一个秘密隐藏变量传入。然后再考虑是否将偏移量传递到另一个数组或分配到堆上的数组(malloc和所有的都是库函数——编译器链接到这些函数,而不是查看和解释堆的主体)。

Its getting difficult to imagine how this might work without some behind-the-scenes slice objects and such right?

很难想象如果没有一些幕后切片对象,这是如何工作的,对吧?


Symbian did have a AllocSize() function that returned the size of an allocation with malloc(); this only worked for the literal pointer returned by the malloc, and you'd get gobbledygook or a crash if you asked it to know the size of an invalid pointer or a pointer offset from one.

Symbian确实有一个AllocSize()函数,它使用malloc()返回分配的大小;这只适用于malloc返回的文字指针,如果您要求它知道无效指针的大小或指针与一个指针的偏移量,您将得到gobbledygook或崩溃。

You don't want to believe its not possible, but it genuinely isn't. The only way to know the length of something passed into a function is to track the length yourself and pass it in yourself as a separate explicit parameter.

你不会想相信这是不可能的,但它确实不是。要知道传递给函数的内容的长度,唯一的方法是自己跟踪长度,并将其作为单独的显式参数传递给自己。

#3


2  

As stated by @Will, the decay happens during the parameter passing. One way to get around it is to pass the number of elements. To add onto this, you may find the _countof() macro useful - it does the equivalent of what you've done ;)

如@Will所述,衰减发生在参数传递期间。绕过它的一种方法是传递元素的数量。要添加这个,您可能会发现_countof()宏非常有用——它的功能与您所做的相同;)

#4


2  

First, a better usage to compute number of elements when the actual array declaration is in scope is:

首先,当实际数组声明在范围内时,更好地计算元素数量的用法是:

sizeof array / sizeof array[0]

This way you don't repeat the type name, which of course could change in the declaration and make you end up with an incorrect length computation. This is a typical case of don't repeat yourself.

这样,您就不会重复类型名,这当然会在声明中更改,从而导致不正确的长度计算。这是一个典型的不重复自己的例子。

Second, as a minor point, please note that sizeof is not a function, so the expression above doesn't need any parenthesis around the argument to sizeof.

其次,作为次要的一点,请注意sizeof不是一个函数,因此上面的表达式不需要在sizeof的参数周围加上任何括号。

Third, C doesn't have references so your usage of & in a declaration won't work.

第三,C没有引用,所以在声明中使用&将不起作用。

I agree that the proper C solution is to pass the length (using the size_t type) as a separate argument, and use sizeof at the place the call is being made if the argument is a "real" array.

我同意正确的C解决方案是将长度(使用size_t类型)作为单独的参数传递,如果参数是“真实”数组,则在调用的地方使用sizeof。

Note that often you work with memory returned by e.g. malloc(), and in those cases you never have a "true" array to compute the size off of, so designing the function to use an element count is more flexible.

注意,您经常使用malloc()返回的内存,在这些情况下,您永远不会有一个“true”数组来计算该数组的大小,所以设计函数来使用元素计数更灵活。

#5


2  

Regarding int main():

关于int main():

According to the Standard, argv points to a NULL-terminated array (of pointers to null-terminated strings). (5.1.2.2.1:1).

根据标准,argv指向一个空终止数组(指向空终止字符串的指针)。(5.1.2.2.1:1)。

That is, argv = (char **){ argv[0], ..., argv[argc - 1], 0 };.

即argv = (char **){argv[0],…, argv[argc - 1], 0};

Hence, size calculation is performed by a function which is a trivial modification of strlen().

因此,大小计算是由一个对strlen()进行简单修改的函数来完成的。

argc is only there to make argv length calculation O(1).

argc仅用于对argv长度进行计算(1)。

The count-until-NULL method will NOT work for generic array input. You will need to manually specify size as a second argument.

从计数到null的方法不适用于泛型数组输入。您将需要手动指定size作为第二个参数。

#6


1  

This is a old question, and the OP seems to mix C++ and C in his intends/examples. In C, when you pass a array to a function, it's decayed to pointer. So, there is no way to pass the array size except by using a second argument in your function that stores the array size:

这是一个老问题,OP似乎在他的意图/示例中混合了c++和C。在C中,当你将一个数组传递给一个函数时,它会衰变为指针。因此,除了在函数中使用第二个参数存储数组大小之外,没有办法传递数组大小:

void func(int A[]) 
// should be instead: void func(int * A, const size_t elemCountInA)

They are very few cases, where you don't need this, like when you're using multidimensional arrays:

它们是非常少的情况,你不需要这个,比如当你使用多维数组:

void func(int A[3][whatever here]) // That's almost as if read "int* A[3]"

Using the array notation in a function signature is still useful, for the developer, as it might be an help to tell how many elements your functions expects. For example:

对开发人员来说,在函数签名中使用数组表示法仍然很有用,因为它可以帮助告诉您的函数需要多少元素。例如:

void vec_add(float out[3], float in0[3], float in1[3])

is easier to understand than this one (although, nothing prevent accessing the 4th element in the function in both functions):

比这一个更容易理解(虽然没有什么可以阻止在两个函数中访问函数中的第4个元素):

void vec_add(float * out, float * in0, float * in1)

If you were to use C++, then you can actually capture the array size and get what you expect:

如果您要使用c++,那么您实际上可以捕获数组大小并得到您期望的结果:

template <size_t N>
void vec_add(float (&out)[N], float (&in0)[N], float (&in1)[N])
{
    for (size_t i = 0; i < N; i++) 
        out[i] = in0[i] + in1[i];
}

In that case, the compiler will ensure that you're not adding a 4D vector with a 2D vector (which is not possible in C without passing the dimension of each dimension as arguments of the function). There will be as many instance of the vec_add function as the number of dimensions used for your vectors.

在这种情况下,编译器将确保不添加一个2D向量的4D向量(在C中,如果不将每个维度的维度作为函数的参数传递,就不可能添加2D向量)。vec_add函数的实例数量与向量使用的维数相同。

#7


-1  

int arsize(int st1[]) {
    int i = 0;
    for (i; !(st1[i] & (1 << 30)); i++);
    return i;
}

This works for me :)

这对我很管用:

#8


-3  

Best example is here

最好的例子就是在这里

thanks #define SIZE 10

谢谢# define 10码

void size(int arr[SIZE])
{
    printf("size of array is:%d\n",sizeof(arr));
}

int main()
{
    int arr[SIZE];
    size(arr);
    return 0;
}