基于这个问题Calculate Length of Array in C by Using Function我真的需要解释。
假设我们有一个像这样的数组:
int arr[] = {1,2,3};
此处arr
的长度为3
,因此传入函数会衰减为指针,我们会失去对其长度的跟踪。
如果我们使用'\0'
Null终止此数组,会发生什么:
int arr[] = {1,2,3,'\0'};
并将其传递给这样的函数:
void foo(int *arr){
int length = 0;
while(arr[length] != '\0'){
length++;
}
printf("Length = %d\n",length);
}
这可以吗?
我写了以下代码:
#include<stdio.h>
void foo(int *arr);
int main(void){
int arr1[] = {10,'\0'};
int arr2[] = {12,44,'\0'};
int arr3[] = {87,1,71,'\0'};
int arr4[] = {120,15,31,82,'\0'};
int arr5[] = {28,49,16,33,11,'\0'};
int arr6[] = {19,184,90,52,38,77,'\0'};
int arr7[] = {2,17,23,41,61,78,104,'\0'};
int arr8[] = {16,92,11,35,52,118,79,44,'\0'};
int arr9[] = {20,44,33,75,49,36,9,2,11,'\0'};
int arr10[] = {92,145,24,61,99,145,172,255,300,10,'\0'};
foo(arr1);
foo(arr2);
foo(arr3);
foo(arr4);
foo(arr5);
foo(arr6);
foo(arr7);
foo(arr8);
foo(arr9);
foo(arr10);
return 0;
}
void foo(int *arr){
int length = 0;
while(arr[length] != '\0'){
length++;
}
printf("Length = %d\n",length);
}
我得到了以下输出:
Length = 1
Length = 2
Length = 3
Length = 4
Length = 5
Length = 6
Length = 7
Length = 8
Length = 9
Length = 10
打印所有10个阵列的长度。 现在我在这里感到很困惑,因为就我所关注的问题而言,正如我在一些书中读到的那样,没有办法让它发挥作用。
为什么foo
打印所有数组的长度?
使用像int arr[] = {1,2,3,'\0'};
这样的东西是违法的吗?
我知道如果数组内部有0
,int arr[] = {1,2,0,3,4};
的长度为2
,但这不是我的问题。
答案 0 :(得分:4)
使用int arr [] = {1,2,3,'\ 0'}之类的东西是违法的; ?
没有。这完全合法。 '\0'
是int
,与0
相同。使用任何数字作为标记来识别数组的结尾也没有什么不同。例如,如果数组仅包含正数,则可以使用-1
。所以你的方法是有效的。
你通常不会在实践中看到这样的原因,当你可以简单地将它作为一个额外的参数传递时,不必迭代数组,从维护的角度来看这很容易理解。
int arr[1024];
size_t len = sizeof arr/sizeof a[0];
func(arr, len);
void func(int *a, size_t length) {
}
将此与您的方法进行比较。
此外,大小是在编译时计算的,而在您的方法中,您已遍历数组。选择右标记可能会变得困难(o或-1或其他),如果它也需要是数组的元素。
答案 1 :(得分:4)
这就是C字符串标记其结尾和长度的方式。因为它们只是char数组,所以你自然也可以将它应用于其他类型的数组。
请记住,通过指针计算此类数组的长度具有线性时间复杂度。
答案 2 :(得分:2)
旁注:'\0'
在这里真的为0,就像您的商店int
一样。
你正在使用哨兵。几十年来,C风格的字符串一直在使用这种方法来标记字符串的完成位置。它具有相同的好处,但也有同样的缺点。
只要您维护不变量,即只在数组的最后位置发生哨兵,您将能够获得数组的长度。在O(N)时间内,您必须遍历序列。
请注意,您可以通过先前使用sentinel终止它来缩小序列:
1 2 3 4 0 //
1 2 3 0 * // * as in: anything
但是一旦你这样做,就不能再知道数组的大小了。即使你可以在技术上附加一个额外的元素,一个不知道上下文的函数也不能安全地做到这一点。实质上,您知道序列的大小,但您不再知道数组的大小。
答案 3 :(得分:1)
如果你需要一个方法来让你携带阵列的数组长度,那么尝试使用这些方法之一。
所以(理想情况下)array[0]
,第一个元素是长度。
问题是,只有当您的数组具有合适的类型并且长度适合该类型时才能使用。您原则上可以使用union
来定义一个足够大的元素来容纳不同类型的数据,包括长度,但这可能是浪费。
这就像:
struct arrayinfo_s {
int length ;
char *data ;
};
char name[1000] ;
struct arrayinfo a ;
a.length = sizeof(name) ;
a.data = name ;
myfunc( &arrayinfo ) ;
这种可能性有很多种。
正如有人提到的那样,通常会跟踪数组长度并将其作为单独的参数传递给函数。
myfunc( array, length ) ;
如果array
是固定大小,例如声明为int nums[100] ;
然后,如果变量声明的函数与使用sizeof()或全局的函数相同,则可以使用sizeof(nums)
。
对于允许函数返回未知长度的数组,还有一个变体。通常你会做一些事情,比如将一个点返回到数组,但是传递一个参数,该参数是指向某个整数类型的指针,以存储新数组的长度。
char *newstuff( int *newlength )
{
char *p = NULL ;
p = malloc( 102 ) ;
if( p == NULL )
{
*length = 102 ;
return p ;
}
else
{
*length = 0 ;
return NULL ;
}
}