我是用C编程的新手,我正在努力理解指针的概念.然而,一些印刷报表的结果相当令人困惑,我在网上找不到合适的答案.

因此,我在C中运行以下main函数:

int main() {
    int a[] = { 1, 2, 3, 4, 5 }; // a points to the address of a[0]
    int *p = a; // p points to the same address as a
    int **pp = &p; // points to p

    int *p2[] = { a, a+1, a+2, a+3, a+4 }; // points a
    int **pp2 = p2; // points to the same address as p2

    printf("  a: %p,         *a: %p\n", a, *a);
    printf("  p: %p,         *p: %p\n", p, *p); 
    printf(" pp: %p,        *pp: %p,        **pp: %p\n",        pp,  *pp,  **pp);
    printf(" p2: %p,        *p2: %p,        **p2: %p\n",        p2,  *p2,  **p2);
    printf("pp2: %p,       *pp2: %p,       **pp2: %p\n",       pp2, *pp2, **pp2);
    
    return 0;
}

对于gcc main.c -o main./main,我得到了以下输出:

  a: 0061FF04,         *a: 00000001
  p: 0061FF04,         *p: 00000001
 pp: 0061FEEC,        *pp: 0061FF04,        **pp: 00000001
 p2: 0061FEF0,        *p2: 0061FF04,        **p2: 00000001
pp2: 0061FEF0,       *pp2: 0061FF04,       **pp2: 00000001

这表明ap都指向a[0]ppp,这是预期行为.p2pp2指向与a相同的地址也是合理的,但我想不出一个原因,为什么输出ap以及输出p2pp2会得到相同的地址(分别为0061FF040061FEF0).如有任何帮助,我们不胜感激

推荐答案

首先,您对printf的所有调用都有未定义的行为,因为您对类型int的对象使用了无效的转换说明符p.要输出类型int的对象,需要使用转换说明符di.

在有极少数异常的表达式中使用的数组被隐式转换为指向其第一个元素的指针.

来自C标准(6.3.2.1 Lvalues, arrays, and function designators)

3,但当它是sizeof运算符的操作数或一元&时除外 运算符,或者是用于初始化数组的字符串文本,则 类型为"arrayof type"的表达式被转换为表达式 类型"类型的指针",该类型指向 数组对象,并且不是左值.如果数组对象具有register 存储类,则行为未定义.

例如,在这份声明中

int *p = a;

用作初始化表达式的数组a被隐式转换为指向其第一元素的指针.您可以按以下方式等效地重写该声明

int *p = &a[0];

取消引用与*ap[0]a[0]相同的*p中的指针p:您将获得数组a的第一个元素.

所以你应该写

printf("  a: %p,         *a: %d\n", ( void * )a, *a);
printf("  p: %p,         *p: %d\n", ( void * )p, *p);

在本声明中

int *p2[] = {a, a+1, a+2, a+3, a+4}; 

定义指向数组a的元素的指针array.

因此,例如,表达式中使用的数组指示符p2被转换为指向其第一个元素的指针.

因此,指针pp2声明为

int **pp2 = p2;

还接收数组p2的第一元素的地址.也就是说,在将数组指示符p2隐式转换为指向其第一个元素的指针之后,值pp2等于值p2.

另一方面,与pp2[0]p2[0]相同的表达式*pp2*p2产生数组p2的第一个元素.与pp2[0][0]p2[0][0](或( *pp2 )[0](*p2 )[0]*pp2[0]*p2[0])相同的表达式**pp2**p2产生数组a的第一个元素,因为数组p2的第一个元素包含数组a的第一个元素的地址.

所以你应该写

printf(" p2: %p,        *p2: %p,        **p2: %d\n",        ( void * )p2,  ( void * )*p2,  **p2);
printf("pp2: %p,       *pp2: %p,       **pp2: %d\n",       ( void * )pp2, ( void * )*pp2, **pp2);

虽然表达式pp2p2的值相等(它们都具有数组p2的第一个元素的地址的值),但是pppp2的值是不同的,因为指针pp指向指针p.然而,表达式*pp2*pp的值是相等的,因为两者都指向数组a的第一个元素.

C++相关问答推荐

如何用C(使用两个s补数算术的32位程序)计算

丑陋的三重间接:可扩展的缓冲区管理 struct

为什么net/if.h在ifaddrs.h之前?

致命:ThreadSaniizer:在Linux内核6.6+上运行时意外的内存映射

为什么将函数名括在括号中会禁用隐式声明?

在Linux上使用vscode和lldb调试用Makefile编译的c代码

如何读取文件并将内容保存在字符串中?(在C语言中,没有崩溃或核心转储错误)

在C中包装两个数组?

这个空指针类型的转换是有效代码还是恶意代码?

错误:字符串在C中获得意外输出

隐藏测试用例无法在c程序中计算位数.

Fscanf打印除退出C代码为1的程序外的所有内容

从整型转换为浮点型可能会改变其值.

OMP并行嵌套循环

未使用sem_open正确初始化信号量

共享内存未授予父进程权限

函数指针作为函数参数 - 应该使用 const 吗?

为什么 Linux 共享库 .so 在内存中可能比在磁盘上大?

从管道读取数据时丢失

clion.我无法理解 Clion 中发生的 scanf 错误