以下是一个C代码:

#include <stdio.h>
int main(void) {
    int a[4][2] = { {1, 2}, {3, 4}, {5, 6}, {7, 8} };

    printf("   a + 2 = %p,    a[2] = %p\n", a + 2,  a[2]);
    printf("   *(a + 2) = %d,     *(a[2]) = %d\n", *(a + 2), *(a[2]));

    return 0;
}

结果是:

   a + 2 = 0x7ffc31494b00,    a[2] = 0x7ffc31494b00
   *(a + 2) = 826886912,     *(a[2]) = 5

a + 2a[2]指向相同的地址.为什么我在取消引用后会得到两个不同的值?

推荐答案

*(a+2)*(a[2])之间的差异是由于a+2a[2]的不同类型,以及C将数组自动转换为指针.a+2指向数组,*(a+2)是array.a[2]是一个数组,*(a[2])是一个int.

C有一条规则,即表达式中使用的数组自动转换为指向其第一个元素的指针,除非它是sizeof的操作数、一元&的操作数或用于初始化数组的字符串文字.

因此,a + 2的判断是:

  • a是由两个元素的四个数组组成的array.
  • 该数组会自动转换为指向其第一个元素的指针,因此结果为&a[0],这是指向包含两个元素的数组的指针.
  • 加上2将其调整为指向a中更多的两个元素.
  • 最终结果是&a[2],这是一个指向两个元素数组的指针.

a[2]的判断结果为:

  • a[2]被指定为等同于*(a+2).
  • a+2的计算结果如上所述,得到&a[2],这是一个指向两个元素数组的指针.
  • 应用*将生成a[2],这是一个由两个元素(a[2][0]a[2][1])组成的array.
  • 该数组自动转换为指向其第一个元素&a[2][0]的指针,这是指向int的指针.

printf(" a + 2 = %p, a[2] = %p\n", a + 2, a[2]);年中,印刷的两件事是:

  • a+2,从上面我们知道是&a[2].
  • a[2],从上面我们知道是&a[2][0].

这两个地址是存储器中相同点的地址--数组a[2]从其第一个元素a[2][0]开始的相同位置开始.因此,打印它们会打印出相同的价值也就不足为奇了.(从技术上讲,您应该通过将这些地址转换为void *来打印它们,因为%p转换被指定为期望void *参数.)

printf(" *(a + 2) = %d, *(a[2]) = %d\n", *(a + 2), *(a[2]));年中,印刷的两件事是:

  • *(a + 2).同样,a + 2&a[2],它是指向两个int的数组的指针.应用*将生成该array.该数组被自动转换为指向其第一元素的指针,&a[2][0].用%d打印是错误的,因为%d被指定为需要int个参数,但您给它传递了一个指针.打印的"826886912"是地址部分的十进制表示,31494b0016.(这并不总是结果.C标准没有定义打印带有%d的地址时的行为.)
  • *(a[2]).从上面看,a[2]等于&a[2][0].当应用*时,这将生成a[2][0],即int.该int的值被打印为十进制数字.

C++相关问答推荐

使用sd-设备列举设备导致seg错误

为什么下面的递归基本情况在C中不起作用?

如何在C中只使用一个带双方括号([i][j])访问语法的malloc来分配动态大小的2d数组?

使用NameSurname扫描到两个单独的字符串

GLIBC:如何告诉可执行文件链接到特定版本的GLIBC

在CLANG中调试预处理器宏

如何在C中打印包含扫描字符和整数的语句?

为什么指针运算会产生错误的结果?

如何使用_newindex数组我总是得到错误的参数

编译器如何处理具有更复杂值的枚举?

接受任何参数的函数指针是否与接受不同参数的函数兼容

在C中创建任意类型的只读指针参数

覆盖读取函数,但当文件描述符为3或4时,我有问题

C语言中的数字指针

判断系统命令返回值的正确方法

生成一个半RNG,结果用C表示(无随机/随机)

如果类型是新的,offsetof是否与typeof一起工作?

为什么INT_MIN是在c语言的头文件limits.h中定义的(-INT_MAX-1)而不是直接使用-2147483648

在 C 中传递参数时出现整数溢出

是否可以在多字 C 类型中的任何位置混合存储和类型限定符?