指向自己的指针

时间:2019-05-01 23:35:28

标签: c pointers

我正在探索typedef,偶然发现了这个程序

编辑:几乎所有答案都与它生成的警告有关。因此,我继续删除所有警告,但问题仍然相同。

#include<stdio.h>
typedef int int3[3];
int main(){
    int a[2][3] = {{1,2,3}, {4,5}};
    int3 *p = a;
    int *ip = (int *) a;
    printf("sizeof:\np: %lu\n(*p+0): %lu\n**p: %lu\nip: %lu\n*ip: %lu\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
    printf("---\n");
    printf("p: %p\tp+1: %p\n*p: %p\t*p+1: %p\n**p: %d\nip: %p\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
    return 0;
}

在一次运行中显示:

sizeof:
p: 8
(*p+0): 8
**p: 4
ip: 8
*ip: 4
---
p: 0x7ffe36df31b0   p+1: 0x7ffe36df31bc
*p: 0x7ffe36df31b0  *p+1: 0x7ffe36df31b4
**p: 1
ip: 0x7ffe36df31b0
*ip: 1

我的问题是: 如果p和* p相等
和** p = 1
那为什么不也* p = 1?

提供的指针大小= 8,整数大小= 4
   即使考虑到指针算术,* p也应至少为0xkk kk kk kk 00 00 00 01
   k为任何十六进制数字(考虑little-endian)
   因为取消引用与int相同的地址应该给1

编辑: 为了使事情更清楚,请考虑以下表格:

+-----------+----------------------+------------------+
|Variable   | Value                | Address          |
|           |                      |                  |
|           |                      |                  |
| p         | 0x7ffe36df31b0       |                  |
|           |                      |                  |
|*p         | 0x7ffe36df31b0       |  0x7ffe36df31b0  |
|           |                      |                  |
|**p        | 1                    |  0x7ffe36df31b0  |
+-----------+----------------------+------------------+

* p和** p如何具有相同的地址但值不同?

3 个答案:

答案 0 :(得分:2)

首先,请注意,此代码在混乱的约束冲突杂乱混搭中与array decay结合使用,产生了有用的可疑输出。但是,我将尝试回答您有关正在发生的事情的问题,并尝试使用平凡的解释而不求助于C标准的引用,因为其他人已经以这种方式回答了问题。

  

* p和** p如何具有相同的地址但值不同?

因为p是指向数组的指针。

给出

typedef int int3[3];
int3 *p;

这意味着*p是三维数组。请注意

int3 *p = a;
如其他地方所述,

是违反约束的。您可以 force 强制执行“强制转换”操作,但是从根本上来说还是错误的,并且代码只能“放弃”,因为数组的地址就是该数组的第一个元素的地址-您当前的实现并没有以足够大的方式区分指针类型,因为它们根本上是不兼容的。选择一个实现,其中普通int *是32位偏移值,而数组将同时具有32位段 32位偏移值作为其地址,如果代码没有完全失败,它很可能会产生废话。这就是C标准要求指针必须为“兼容类型”的原因-因为指针根本不需要兼容。

除了这个问题,您的实现上的初始化/赋值似乎可以被视为

int3 *p = ( int3 * ) a;

由于“有效”,这意味着p包含int值的三元素数组的地址。因此,用p解引用*pa[0]或二维int数组中的前三个元素a数组相同。

那么*p是什么?

在这种情况下,它与数组a[0]完全相同。这样的裸数组引用decays to an address *,并且该地址与指向数组元素的指针具有相同的 type 类型。并且该地址的值将是数组第一个元素的地址。

因此*pint的三元素数组,它本身可以被取消引用并求值到a[0]a[0][0]的第一个元素。因此,**pa[0][0]相同。

a[0][0]-或**p-是一个int,它的初始化值为1

*pa[0]和第一个元素的地址

*-很多人说数组“衰减指针”或“数组是指针”,但我喜欢“衰减地址”,因为可以将指针分配给一个地址,而仅将地址分配给-它不能分配给自己,就像不能将数组本身分配给它一样,但是可以将地址分配给其他内容,例如指针。请注意,当数组传递给函数时,数组的地址实际上是作为实际指针传递的。指针是函数的参数,可以将该函数参数分配给...

答案 1 :(得分:1)

发布的代码,当使用以下命令编译时:

gcc -c -Wall -Wextra -Wconversion -pedantic -std=gnu11 

导致以下编译器消息:

gcc    -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c"  (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int *ip = a;
               ^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                         ~^
                         %ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                     ~^
                                     %ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                              ~^
                                              %ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                      ~^
                                                      %ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                               ~^
                                                               %ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                ~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                         ~^                                                ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                 ~^
                                 %ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                           ~^                                     ~~~~
                                           %ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                                            ~^
                                                            %ls
Compilation finished successfully.

编译器通过说编译成功而结束。这并不意味着可以运行此代码并期望获得有效的结果/输出。

更正代码以使其干净编译后,请对包含修改/更正代码的问题发表EDIT。

gcc    -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c"  (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int *ip = a;
               ^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                         ~^
                         %ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                     ~^
                                     %ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                              ~^
                                              %ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                      ~^
                                                      %ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                               ~^
                                                               %ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                ~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                         ~^                                                ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                 ~^
                                 %ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                           ~^                                     ~~~~
                                           %ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                                            ~^
                                                            %ls
Compilation finished successfully.

答案 2 :(得分:0)

这里有约束冲突,因为您在以下初始化中使用了不兼容的指针类型:

int *ip = a;

根据Pointer declarators上的C11标准部分

  

要使两个指针类型兼容,则两者必须具有相同的限定条件,并且都应是指向兼容类型的指针。

Simple assignment/Constraints

  

左操作数具有原子,合格或不合格的指针类型,并且(考虑到左操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的合格或不合格版本的指针,并且由左侧具有右侧所指向类型的所有限定词;

在这种情况下,编译器需要发出诊断信息:

<source>:8:15: warning: initialization of 'int *' from incompatible pointer type 'int (*)[3]' [-Wincompatible-pointer-types]

     int *ip = a;

请参见Demo

编译程序时,好的做法是启用所有警告并将警告视为错误,以便(尽可能)避免这种行为。