当我使用这段代码时,GCC给我一个'来自不兼容指针类型的初始化'警告(虽然代码工作正常并且做了它应该做的事情,它打印了数组的所有元素).
#include <stdio.h>
int main(void)
{
int arr[5] = {3, 0, 3, 4, 1};
int *p = &arr;
printf("%p\n%p\n\n", p);
for (int a = 0; a < 5; a++)
printf("%d ", *(p++));
printf("\n");
}
Run Code Online (Sandbox Code Playgroud)
但是当我使用这段代码时没有给出警告
int main(void)
{
int arr[5] = {3, 0, 3, 4, 1};
int *q = arr;
printf("%p\n%p\n\n", q);
for (int a = 0; a < 5; a++)
printf("%d ", *(q++));
printf("\n");
}
Run Code Online (Sandbox Code Playgroud)
这两个片段之间的唯一区别是我指定*p =&arr和*q = arr.
Lun*_*din 15
&arr
给出一个数组指针,一个特殊的指针类型int(*)[5]
,它指向整个数组.arr
当用表达式写入时int *q = arr;
,"衰减"成指向第一个元素的指针.完全等同于int *q = &arr[0];
在第一种情况下,您尝试将a分配int(*)[5]
给a int*
.这些是不兼容的指针类型,因此是编译器诊断消息.
事实证明,数组指针和指向第一个元素的int指针很可能在内部具有相同的表示和相同的地址.这就是为什么第一个例子"工作"即使它不正确C.
TL;DR检查类型。
\n\n&arr
是类型int (*) [5]
(指向 5数组的指针int
)。arr
是类型int [5]
,但并非总是如此。引用C11
,章节 \xc2\xa76.3.2.1,(重点是我的)
\n\n\n除非它是运算
\nsizeof
符、_Alignof
运算符或一元运算&
符的操作数,或者是用于初始化数组的字符串文字, \n 类型为\xe2\x80\x98\xe2\x80\x98array 的表达式类型为 \xe2\x80\x99\xe2\x80\x99 的表达式转换为类型为\xe2\x80\x98\xe2\x80\x98 的表达式,指向类型为\xe2\x80\x99\xe2\x80\x99 的指针,该指针指向\ n 为数组对象的初始元素,并且不是左值。
因此,
\n\n int *q = arr; // int[5] decays to int *, == LHS\n
Run Code Online (Sandbox Code Playgroud)\n\n和
\n\n int *q = &arr[0]; // RHS == LHS\n
Run Code Online (Sandbox Code Playgroud)\n\n是相同的,然而,
\n\n int *q = &arr; // LHS (int *) != RHS (int (*) [5])\n
Run Code Online (Sandbox Code Playgroud)\n\n是一个不匹配的类型表达式。
\n\n现在,它可以工作,因为,正如Lundin\'s 答案中已经提到的,数组变量的地址可能与数组第一个元素的地址相同,因此尽管类型不匹配,但值是相同的,所以这似乎有效。
\n