c - 递增内存地址如何影响指针



我正在寻找有关递增地址如何影响指针的解释。

我了解了 C 指针的工作原理以及如何通过考虑指针类型来增加指针。 我仍然不明白以下情况

int main()
{
int a[] = {1,2,3,4,5};
int *p = (int*)(&a+1);
printf("%dn%dn", *(a+1), *(p-1));
return 0;
}

我期待这条线

int *p = (int*)(&a+1);

使p指向数组a后面的地址,因此我期望输出:

2 

因为它只是a[1]

但是输出是unknown_number的 -因为我不知道哪个 int 比(&a+1)晚 4 个字节

实际结果是:

2
5

为什么p似乎直接指向a之后的记忆?

我困惑的根源是什么?

所以在这个例子中,&a的类型是int(*)[5]。当你向它添加 1 时,它实际上增加了sizeof(int[5])- 因为这就是指针算术的工作方式,添加偏移量会增加所指向的类型的大小乘以偏移量。这就是你如何让p成为a的最后一个元素,之后你把它投射到int*所以现在你有一个指针指向一个整数,指向一个地址上的整数,一个超过a的最后一个元素。如此有效地,从中减去 1 会给你最后一个元素a.

两个基本概念:

  • 除非它是sizeof或一&元运算符的操作数,或者是用于初始化声明中字符数组的字符串文本,否则类型为"T的 N 元素数组"的表达式将被转换("衰减")为"指向T的指针"类型的表达式,并且表达式的值将是数组第一个元素的地址。

  • 将 1 添加到类型为"指向T的指针"的表达式中,将生成紧跟在当前对象之后的T类型的对象的地址。 IOW,如果p指向一个4字节的intp+1指向紧跟在它后面的int。 如果p指向一个 5 元素的int数组,则p+1指向紧随其后的下一个 5 元素int数组。 这就是数组索引的工作方式 -a[i]的下标操作定义为*(a + i)。 给定一个起始地址a(指针表达式或衰减到指针的数组表达式),找到该地址后面的第i对象的地址,并取消引用结果。

所以,如果你有声明

int a[] = {1, 2, 3, 4, 5};

那么以下情况是正确的:

  • 表达式a的类型为"5 元素数组int"(int [5]) - 如果表达式不是sizeof或一元&运算符的操作数,它"衰减"为类型"指向int的指针"(int *),其值是数组第一个元素的地址(&a[0])。

  • 表达式*(a + 1)a[1]相同,并且计算数组中的第二个对象 (2)。

  • 表达式&a + 1的类型为int (*)[5],并在a之后生成 5 元素数组的起始地址int。 此表达式的类型将转换为int *并分配给p

  • 表达式p的类型为int *- 从中减去 1 得到紧靠pint对象的地址,这恰好是a的最后一个元素。

图形:

+–––+
a: | 1 |
+–––+
| 2 | <–– a + 1
+–––+
| 3 |
+–––+
| 4 |
+–––+
| 5 | <–– p - 1
+–––+
| ? | <–– p (&a + 1)
+–––+

您可以将数组a操作为指向 intint *的指针。但是对于&a来说,它不一样,它是一个指向 5 个整数数组的指针:&a + 1会将 5 个整数的大小添加到指针中。

只需在将 1 添加到 a 之前删除&,它就会按预期工作:

#include <stdio.h>
int main()
{
int a[] = {1,2,3,4,5};
int *p = (int*)(a+1); // & removed
printf("%d %dn", *(a+1), *(p-1));
return 0;
}

最新更新