分配给指针时从不兼容的指针类型警告初始化

时间:2017-06-13 14:02:43

标签: c arrays pointers

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");
}

但是当我使用这段代码时没有给出警告

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");
}

这两个片段之间的唯一区别是我指定* p =&amp; arr和* q = arr。

  • &amp;和&amp;制作?
  • 为什么代码会在两种情况下执行并提供完全相同的输出?

5 个答案:

答案 0 :(得分:12)

  • &arr提供了一个数组指针,一个特殊的指针类型int(*)[5],它指向整个数组。
  • arr,当用int *q = arr;这样的表达式写入时,“衰变”成指向第一个元素的指针。完全等同于int *q = &arr[0];

在第一种情况下,您尝试将int(*)[5]分配给int*。这些是不兼容的指针类型,因此是编译器诊断消息。

事实证明,数组指针和指向第一个元素的int指针很可能在内部具有相同的表示和相同的地址。这就是为什么第一个例子“有效”,即使它不正确C。

答案 1 :(得分:1)

这些是指向(开始)数组(没有警告)的方法,两者都有效:

int *q = arr;
/* OR */
int *q = &arr[0];

这个介于两者之间,会产生警告:

int *q = &arr;

答案 2 :(得分:1)

TL; DR 检查类型。

  • &arr的类型为int (*) [5]指向5 int s 数组的指针)。
  • arr的类型为int [5],但始终为

引用C11,章节§6.3.2.1,(强调我的

  

除非它是sizeof运算符,_Alignof运算符或者&运算符的操作数。   一元 int *q = arr; // int[5] decays to int *, == LHS 运算符,或者是用于初始化数组的字符串文字,一个表达式   type ''类型''的数组被转换为类型''指向类型''指针的表达式   到数组对象的初始元素并且不是左值。

因此,

 int *q = &arr[0];   // RHS == LHS

 int *q = &arr; // LHS (int *) != RHS (int (*) [5])

相同,而

{{1}}

是不匹配的类型表达式。

现在,它起作用,因为,如Lundin's answer中已经提到的,数组变量的地址可能与数组的第一个元素的地址相同,所以尽管类型不匹配, value 是一样的,所以这似乎有效。

答案 3 :(得分:0)

输出相同,因为$details = Subject::select('level', 'semester')->first(); 的地址实际上等同于指向arr[0]的指针。初始化为指向arr[]的任何指针的值都为arr[0]的地址;指针是什么。阅读指针,特别是它们与数组的关系。有无数的教程,其中一些可能会以两个案例为例。

答案 4 :(得分:0)

当在表达式中用作左值时,数组衰减到指向其第一个元素的指针。所以int *q = arr;使用数组q的第一个元素的地址初始化int pointer arr:一切正常,没有发出警告。

但是&arr是数组的地址。它只能正确地用于初始化(或分配)指向数组或相同大小的指针,或指向未确定大小的数组的指针。您可以使用它来初始化指向int的指针(这是一种不同且不兼容的类型),编译器会向您发出警告。因为根据标准使用从指向不同类型的指针初始化的指针是未定义行为。

但是在常见的实现中,指向任何类型的指针都具有相同的表示形式,即对象的第一个字节的地址。因此,即使标准不允许,指令int *p = arr;也会以p的相同值结束,因为它会给出正确的int *p = arr;。这就解释了为什么你的程序仍能给出预期值。

BTW,未定义的行为并不禁止预期的结果,只是一个不同的编译器可以给出不同的结果,崩溃,过早结束而没有错误,踢你的狗等等(即使没有编译器可以打我的狗到现在;-))