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

时间:2010-01-09 21:41:52

标签: c arrays initialization variable-assignment

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

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上使用是错误的?

7 个答案:

答案 0 :(得分:12)

为了理解差异,我们需要了解两个不同的上下文

  • value 上下文中,类型T的数组名称等同于指向类型T的指针,并且等于指向数组的第一个元素的指针
  • object 上下文中,类型为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&a[0])的第一个元素的指针。

的情况下
int a[]={1,2,3,4};
int b[4] = a;

名称b用于对象上下文,不会缩减为指针。 (顺便提一下,a此处在值上下文中是,并缩减为指针。)

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

如果您想将a的内容复制b,那么您可以这样做:

#include <string.h>
int b[4];
memcpy(b, a, sizeof b);

或者,如果您想要指向b的指针a

int *b = a;

此处,a位于值上下文中,并缩减为指向int的指针,因此我们可以将a指定给int *

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

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

这里,a有4个元素,初始化为1,2,3和4.你也可以这样做:

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

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

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

a[2]a[3]设为0。

答案 1 :(得分:7)

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

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

void f(int *arr);

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

答案 2 :(得分:6)

C不支持数组的赋值。在函数调用的情况下,数组衰减为指针。 C确实支持指针的分配。这里几乎每天都会问这个问题 - 你们读的C课本是不是解释了这个?

答案 3 :(得分:3)

尝试memcpy。

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

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

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:0)

请注意aint a[4]的类型为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
}

答案 6 :(得分:0)

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

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

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

void f(int arr[])

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

void f(int arr[4])

...形式参数表示数组大小。

void f(int *arr)

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