数组指针编译时警告:警告:从不兼容的指针类型初始化

时间:2018-01-23 18:28:03

标签: c arrays pointers

使用涉及数组点的简单示例会生成以下警告。代码编译和执行也导致问题。

这是int数组。         int numbers [3] = {101,202,303};

这两个调用会生成警告。

    int *p2 = &numbers;
    int **p3 = &numbers;

以下是生成的警告。

 > cc -o myApp test.c
 test.c: In function 'main':
 test.c:9:12: warning: initialization from incompatible pointer type [enabled by default]
 int *p2 = &numbers;
        ^
 test.c:10:13: warning: initialization from incompatible pointer type [enabled by default]
 int **p3 = &numbers;
         ^

使用的代码如下:

#include <stdio.h>

int main ()
{
    int numbers[3] = { 101, 202, 303};
    int size = sizeof(numbers) / sizeof (numbers[0]);

    int *p = numbers;
    int *p2 = &numbers;
    int **p3 = &numbers;
    int *p4 = &numbers[0];

    int *end = p + size;

    printf("p           = 0x%d\n", p);
    printf("p2          = 0x%d\n", p2);
    printf("p3          = 0x%d\n", p3);
    printf("numbers     = 0x%d\n", numbers);
    printf("&numbers    = 0x%d\n", &numbers);
    printf("numbers[0]  = 0x%d\n", numbers[0]);
    printf("&numbers[0] = 0x%d\n", &numbers[0]);

    for (; p != end; p++)
    {
            printf ("0x%d\n", p);
    }
}

执行时,这是输出。

> ./runTest
p           = 0x-207214704
p2          = 0x-207214704
p3          = 0x-207214704
numbers     = 0x-207214704
&numbers    = 0x-207214704
numbers[0]  = 0x101
&numbers[0] = 0x-207214704
0x-207214704
0x-207214700
0x-207214696

p2和p3以及p都指向同一地址。 我真的以为使用p3作为双指针会解决警告,但它似乎没有。 为什么p2和p3会生成警告以及它想说什么?

3 个答案:

答案 0 :(得分:3)

我明白这一点会让你感到困惑。你第一次看到

 int *p = numbers;

好吧,不要认为numbers是类型指针。它只是一个数组对象(int[3]),它被转换为指向它的第一个元素的指针 - 即int*。这称为阵列衰减。

现在您认为int **p3 = &numbers; - &numbers的类型为int**

这就是诀窍 - 在某些情况下不会发生数组衰减 - 当数组用作&运算符的操作数时 - 那么就是这样的一个案例 - 因此它不会衰减。它将是一个数组对象,其指针在这种情况下被认为是int(*)[3]

使用这个逻辑int *p2=&numbers也将是编译器会抱怨的东西。正确的是这里所说的int (*pp)[3] = &numbers。请注意,打印指针(不是函数指针)使用%p格式说明符,并将参数强制转换为void*

编译器试图警告您指针类型不匹配。 (对于指针,它指向的类型是重要的,因为指针算术由指示算术)。

来自§6.3.2.1p3

  

除非它是sizeof运算符,_Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,具有“数组类型”类型的表达式将转换为类型为“指向类型的指针”的表达式,该表达式指向数组对象的初始元素,而不是左值。

答案 1 :(得分:2)

First, always use %p to print pointer values:

printf( "%p\n", (void *) p );
printf( "%p\n", (void *) p1 );

Given the declaration

int numbers[3];

then the following are true:

Expression        Type        "Decays" to         Value
----------        ----        -----------         -----
   numbers        int [3]     int *               Address of first element of array
  &numbers        int (*)[3]  n/a                 Address of array (which is the same as above)
  *numbers        int         n/a                 Value of numbers[0]

Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. Thus, under most circumstances (such as when it's the RHS of an assignment, or a parameter to a function), the expression numbers will have type int *.

So how do you properly initialize p2 and p3? That depends on what you want to happen when you write p2 + 1 or p2[1] and p3 + 1 or p3[1]. If you want p2 + 1 to point to the second element in numbers, or if you want p2[1] to be equal to numbers[1], then you'd write

int *p2 = numbers;

If you want p2 + 1 to point to the next 3-element array of int following the end of the numbers array, then you'd write

int (*p2)[3] = &numbers;

Then you'd initialize p3 as

int **p3 = &p2;

or

int (**p3)[3] = &p2;

based on how p2 was declared.

A picture might help. Assume the following declarations:

int numbers[3] = { 0, 1, 2 };
int *p0 = numbers;
int (*p1)[3] = &numbers;

then things look something like this:

         +---+                    
numbers: | 0 | numbers[0] <------ p0, p1
         +---+                    
         | 1 | numbers[1] <------ p0 + 1
         +---+
         | 2 | numbers[2]
         +---+
          ...             <------ p1 + 1

Remember that with pointer arithmetic, p + 1 points to the next object of the pointed-to type; if p points to an object that's 4 bytes wide, then p + 1 points to the object starting 4 bytes after p. If p points to an object that's 32 bytes wide (such as a small array), then p + 1 points to the object starting 32 bytes after p.

答案 2 :(得分:1)

应该是

int numbers[3] = { 101, 202, 303};

int (*p2)[3] = &numbers; // Here p2 is a pointer to an array of 3 members

应该像

那样访问成员
(*p2)[0],(*p2)[1] and (*p2)[2]

等效
*(*(p2)+0),*(*(p2)+1) and *(*(p2)+2)

还有

p2[0][0],p2[0][1] and p2[0][2] // Since array notation can be used to dereference pointers.