为了理解差异,我们需要了解两个不同的上下文。
- 在值上下文中,类型数组的名称
T
等价于指向 type 的指针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
需要一个指向 an 的指针int
,所以函数定义和使用匹配。传递给f()
的是指向a
( &a[0]
) 的第一个元素的指针。
如果是
int a[]={1,2,3,4};
int b[4] = a;
该名称b
在对象上下文中使用,并且不会简化为指针。(顺便说一下,a
这里是在一个值上下文中,并简化为一个指针。)
现在,int b[4];
分配 4 s 的存储值int
并为其命名b
。 a
也被分配了类似的存储空间。因此,实际上,上述分配意味着“我想让存储位置与之前的位置相同”。这没有意义。
如果你想复制a
into的内容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。