增加内存地址如何影响指针
How does incrementing memory address affects pointer
我正在寻求有关递增地址如何影响指针的解释。
我了解了 C 指针的工作原理以及如何通过考虑指针类型来完成指针的递增。我还是不明白下面的案例
int main()
{
int a[] = {1,2,3,4,5};
int *p = (int*)(&a+1);
printf("%d\n%d\n", *(a+1), *(p-1));
return 0;
}
我期待这一行
int *p = (int*)(&a+1);
使 p
指向数组 a
之后的地址,因此我期望输出:
2
因为它只是 a[1]
但输出是 unknown_number - 因为我不知道哪个 int 落后 (&a+1)
实际结果是:
2
5
为什么p
好像直接指向a
之后的内存?
我困惑的根源是什么?
所以在这个例子中 &a
是类型 int(*)[5]
。当您将 1 添加到它时,它实际上会添加 sizeof(int[5])
- 因为这就是指针算法的工作原理,添加偏移量会将指向的类型的大小乘以偏移量。这就是你如何让 p
成为 a
的最后一个元素,之后你将它转换为 int*
所以现在你有一个指向整数的指针a
的最后一个元素。如此有效,从中减去 1 得到 a
.
的最后一个元素
您可以将数组 a
作为指向 int int *
的指针进行操作。但是 &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 %d\n", *(a+1), *(p-1));
return 0;
}
两个基本概念:
除非它是 sizeof
或一元 &
运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则 expression类型"N-element array of T
"将被转换("decay")为类型"pointer to T
"的表达式,表达式的值将是第一个地址数组的元素。
向类型 "pointer to T
" 的表达式加 1 会产生紧跟在当前对象之后的类型 T
的对象的地址。 IOW,如果 p
指向一个 4 字节的 int
,p+1
指向紧随其后的 int
。如果 p
指向 int
的 5 元素数组,则 p+1
指向紧随其后的下一个 int
的 5 元素数组。这就是数组索引的工作原理——下标操作 a[i]
被定义为 *(a + i)
。给定起始地址 a
(指针表达式或衰减为指针的数组表达式),找到第 i
个 对象 的地址解决并取消引用结果。
所以,如果你有声明
int a[] = {1, 2, 3, 4, 5};
则下列说法成立:
表达式 a
的类型为“int
的 5 元素数组”(int [5]
) - 如果该表达式不是 sizeof
或一元 &
运算符的操作数,它 "decays" 键入 "pointer to int
" (int *
) 并且它的值是数组的第一个元素 (&a[0]
).
表达式 *(a + 1)
与 a[1]
相同,计算结果为数组中的第二个对象 (2
)。
表达式 &a + 1
的类型为 int (*)[5]
并生成 a
之后 int
的 5 元素数组的起始地址。此表达式的类型转换为 int *
并分配给 p
。
表达式 p
的类型为 int *
- 从中减去 1 会得到 p
之前的 int
对象的地址,这发生了成为 a
.
的最后一个元素
图形化:
+–––+
a: | 1 |
+–––+
| 2 | <–– a + 1
+–––+
| 3 |
+–––+
| 4 |
+–––+
| 5 | <–– p - 1
+–––+
| ? | <–– p (&a + 1)
+–––+
我正在寻求有关递增地址如何影响指针的解释。
我了解了 C 指针的工作原理以及如何通过考虑指针类型来完成指针的递增。我还是不明白下面的案例
int main()
{
int a[] = {1,2,3,4,5};
int *p = (int*)(&a+1);
printf("%d\n%d\n", *(a+1), *(p-1));
return 0;
}
我期待这一行
int *p = (int*)(&a+1);
使 p
指向数组 a
之后的地址,因此我期望输出:
2
因为它只是 a[1]
但输出是 unknown_number - 因为我不知道哪个 int 落后 (&a+1)
实际结果是:
2
5
为什么p
好像直接指向a
之后的内存?
我困惑的根源是什么?
所以在这个例子中 &a
是类型 int(*)[5]
。当您将 1 添加到它时,它实际上会添加 sizeof(int[5])
- 因为这就是指针算法的工作原理,添加偏移量会将指向的类型的大小乘以偏移量。这就是你如何让 p
成为 a
的最后一个元素,之后你将它转换为 int*
所以现在你有一个指向整数的指针a
的最后一个元素。如此有效,从中减去 1 得到 a
.
您可以将数组 a
作为指向 int int *
的指针进行操作。但是 &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 %d\n", *(a+1), *(p-1));
return 0;
}
两个基本概念:
除非它是
sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则 expression类型"N-element array ofT
"将被转换("decay")为类型"pointer toT
"的表达式,表达式的值将是第一个地址数组的元素。向类型 "pointer to
T
" 的表达式加 1 会产生紧跟在当前对象之后的类型T
的对象的地址。 IOW,如果p
指向一个 4 字节的int
,p+1
指向紧随其后的int
。如果p
指向int
的 5 元素数组,则p+1
指向紧随其后的下一个int
的 5 元素数组。这就是数组索引的工作原理——下标操作a[i]
被定义为*(a + i)
。给定起始地址a
(指针表达式或衰减为指针的数组表达式),找到第i
个 对象 的地址解决并取消引用结果。
所以,如果你有声明
int a[] = {1, 2, 3, 4, 5};
则下列说法成立:
表达式
a
的类型为“int
的 5 元素数组”(int [5]
) - 如果该表达式不是sizeof
或一元&
运算符的操作数,它 "decays" 键入 "pointer toint
" (int *
) 并且它的值是数组的第一个元素 (&a[0]
).表达式
*(a + 1)
与a[1]
相同,计算结果为数组中的第二个对象 (2
)。表达式
&a + 1
的类型为int (*)[5]
并生成a
之后int
的 5 元素数组的起始地址。此表达式的类型转换为int *
并分配给p
。表达式
p
的类型为int *
- 从中减去 1 会得到p
之前的int
对象的地址,这发生了成为a
. 的最后一个元素
图形化:
+–––+
a: | 1 |
+–––+
| 2 | <–– a + 1
+–––+
| 3 |
+–––+
| 4 |
+–––+
| 5 | <–– p - 1
+–––+
| ? | <–– p (&a + 1)
+–––+