为了理解区别,我们需要了解两个不同的上下文。
- 在 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 个 ints 的存储空间,并将其命名为 b。 a 也被分配了类似的存储空间。因此,实际上,上述分配意味着“我想让存储位置与之前的位置相同”。这没有意义。
如果你想复制a的内容到b,那么你可以这样做:
#include <string.h>
int b[4];
memcpy(b, a, sizeof b);
或者,如果您想要一个指向 a 的指针 b:
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。