哪一个是数组变量的正确类型? (用于在 C 中使用指针)

which one is the correct type of an array variable? (for using with pointers in C)

如果我想将一个指向 int 的指针初始化为一个数组,我需要使用这种表示法:

int data[] = {34,35,36};
int *ptr = &data[0];

因为变量data的类型是int[],这就是下一个声明给出警告的原因:

int *ptr = &data;

在上面的例子中,我将一个“数组类型”分配给一个 int 指针,这是一个错误,但没关系。 那么,为什么可以使用下一段代码在数组中进行迭代:

for(int i=0;i<3;i++)
    *(data+i);

上面这行应该做的是在每次迭代中添加完整数组的大小,正确的代码应该如下所示:

for(int i=0;i<3;i++)
    *(&data[0] + i);

但是如果我们测试它们,它们是相等的并且在数组中迭代是正确的。

那么,变量数据的类型(单独,没有[])应该认为是int[]还是int? 我怎么知道什么时候一个变量会有一种或另一种类型来做正确的指针运算。

来自 C 标准(6.5.2.1 数组下标)

2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

和(6.3.2.1 左值、数组和函数指示符)

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

因此在这个表达式中

*(data+i)

数组data被隐式转换为指向其第一个元素的指针。表达式等同于 data[i]i[data].

所以表达式

 *(&data[0] + i);

可以改写成

 *(&*( data + 0 ) + i);

相同
 *( data + 0 + i);

反过来又是

 *( data + i);

同样在指针的声明中

int *ptr = &data[0];

你可以写

int *ptr = data;

好的。阅读您的评论后,我发现了“数组衰减”的概念。 数组名自然衰减为指向数组类型的指针;例如,如果我声明 int data[5],大多数时候 data 的类型将是 int*,但是这个 decay 也有一些例外.这里有更多信息:exceptions to array decaying

我的困惑由此而来:有时当我使用数组时,它会衰减,而其他时候则不会。

在大多数情况下,只要在表达式中使用数组名称,它就会退化为指向其第一个元素的指针。因此 int *ptr = &data[0]; 100% 等同于 int *ptr = data;.

至于访问数组的单个项,或通过指向第一个元素的指针指向的数组的单个项,arr[i] 100% 等同于 *(arr + i),后者只是不必要的困难阅读。参见

但是,上述数组衰减规则的一个例外是数组名称用作 & 运算符的操作数。在那种情况下,它不会衰减——相反,我们得到一个指向“整个数组”的指针。在你的例子中 int *ptr = &data; 是一个无效的指针转换,因为 &dataint(*)[3] 类型,一个指向数组的指针。

但是请注意,在表达式 &data[i] 中,运算符优先级表示 []&data 操作数“绑定得更紧”。所以它相当于&(data[i])。前面提到的数组衰减例外不适用,因为 & 从未应用于数组名称,而是应用于数组中的项目。当我们到达 & 时,数组衰减为指向第一个元素的指针已经发生了,因为它发生在遇到 [] 的地方。