数组类型 – 指定/用作函数参数的规则

当我需要将一个数组传递给一个函数时,似乎所有以下函数声明都可以工作

void f(int arr[]) void f(int arr[4]) // is this one correct? 

为了这:

 int a[]={1,2,3,4}; f(a); 

但是当我将一个数组分配给另一个数组时,它就失败了

 int a[]={1,2,3,4}; int b[4] = a; // error: array must be initialized with a brace-enclosed initializer 

那么为什么作为函数的参数传递的数组是可以的,但是在简单赋值的rhs上使用是错误的?

为了理解差异,我们需要了解两种不同的背景

  • 上下文中,类型T的数组的名称等同于指向类型T的指针,并且等于指向数组的第一个元素的指针。
  • 对象上下文中,类型T的数组的名称不会缩减为指针。

什么是对象上下文?

a = b;a在对象上下文中。 当您获取变量的地址时,它将在对象上下文中使用。 最后,当您对变量使用sizeof运算符时,它将在对象上下文中使用。 在所有其他情况下,变量用于值上下文。

现在我们掌握了这些知识,当我们这样做时:

 void f(int arr[4]); 

完全等同于

 void f(int *arr); 

如您所知,我们可以省略函数声明中的大小(上面的4)。 这意味着您无法知道传递给f()的“数组”的大小。 以后,当你这样做时:

 int a[]={1,2,3,4}; f(a); 

在函数调用中,名称a在值上下文中,因此它缩减为指向int的指针。 这很好,因为f需要一个指向int的指针,所以函数定义和使用匹配。 传递给f()是指向( &a[0] )的第一个元素的指针。

如果是

 int a[]={1,2,3,4}; int b[4] = a; 

名称b用于对象上下文,而不是缩减为指针。 (顺便说一下,这里一个值上下文,并缩减为指针。)

现在, int b[4]; 分配4 int的存储空间并给它起名称ba也被分配了类似的存储空间。 因此,实际上,上述分配意味着“我想使存储位置与先前位置相同”。 这没有意义。

如果要将a的内容复制b ,则可以执行以下操作:

 #include  int b[4]; memcpy(b, a, sizeof b); 

或者,如果你想要一个指向b的指针b

 int *b = a; 

这里, a是值上下文,并缩减为指向int的指针,因此我们可以将a指定给一个int *

最后, 在初始化数组时 ,您可以为其指定显式值:

 int a[] = {1, 2, 3, 4}; 

这里有一个有4个元素,初始化为1,2,3和4.您还可以这样做:

 int a[4] = {1, 2, 3, 4}; 

如果列表中的元素数少于数组中元素的数量,则其余值将取0:

 int a[4] = {1, 2}; 

a[2]a[3]为0。

 void f(int arr[]); void f(int arr[4]); 

语法有误导性。 它们都是这样的:

 void f(int *arr); 

即,您正在将指针传递给数组的开头。 你没有复制数组。

C不支持数组的赋值。 在函数调用的情况下,数组衰减为指针。 C确实支持指针的分配。 这里几乎每天都会问这个问题 – 你们在阅读哪些C教科书并不能解释这个问题?

试试memcpy。

 int a[]={1,2,3,4}; int b[4]; memcpy(b, a, sizeof(b)); 

感谢你指出这一点,史蒂夫,自从我使用C以来已经有一段时间了。

为了获得您的直觉,您必须了解机器级别的情况。

初始化语义(= {1,2,3,4})意味着“以这种方式将它放在你的二进制映像上”,这样就可以编译了。

数组赋值会有所不同:编译器必须将其转换为循环,实际上迭代元素。 C编译器(或C ++,就此而言)永远不会做这样的事情。 理所当然地希望你自己做。 为什么? 因为你能。 所以,它应该是一个用C(memcpy)编写的子程序。 这完全是关于你的武器的简单性和贴近性,这是C和C ++的全部内容。

注意int a[4]a的类型是int [4]

但是TypeOf&a )== int (*)[4] != int [4]

还要注意a的类型是int * ,它与以上所有不同!

这是您可以尝试的示例程序:

 int main() { // All of these are different, incompatible types! printf("%d\n", sizeof (int[4])); // 16 // These two may be the same size, but are *not* interchangeable! printf("%d\n", sizeof (int (*)[4])); // 4 printf("%d\n", sizeof (int *)); // 4 } 

我想澄清一下。 答案中有一些误导性的提示……以下所有函数都可以采用整数数组:

 void f(int arr[]) void f(int arr[4]) void f(int *arr) 

正式的论点并不相同。 因此编译器可以以不同方式处理它们 在内部内存管理的意义上,所有参数都会引发指针。

 void f(int arr[]) 

… f()采用任意大小的数组。

 void f(int arr[4]) 

…forms参数表示数组大小。

 void f(int *arr) 

…您还可以传递整数指针。 f()对尺寸一无所知。