我有以下程序:
#include <iostream>
struct X
{
int a;
float b;
} x[10], *p1, *p2;
int main(int argc, char *argv[])
{
p1 = &x[1];
p2 = &x[5];
int i = p2 - p1;
std::cout << i << std::endl;
}
我可以在内存中显示X
的布局,包含int
和float
的10个框,p1
将指向第二个框的开头({ {1}})和x[1]
指向第6个框的开头(p2
):
x[5]
我的图画是否正确?如果是这样,为什么 X 0 1 2 3 4 5 6 7 8 9
_______________________________
b |__|__|__|__|__|__|__|__|__|__|
a |__|__|__|__|__|__|__|__|__|__|
| |
| |
p1 p2
4的结果呢?
理解减去两个地址有一些困难吗?
答案 0 :(得分:23)
这就是pointer arithmetic的工作原理。考虑:
p1 = (x*)100; // invalid memory address, just an example!
p2 = p1 + 1;
此时,p2
的值不会为101
,而是100 + sizeof(x)
(假设为8,因此为108)。它增加了一个,但增加了sizeof(x)
的一倍!相反,从指针中减去一个整数实际上会减去 sizeof(the pointed to type)
的倍数。
现在,如果你int diff = p2 - p1
,你肯定希望得到1
,而不是8
!否则,减去刚刚添加的数字将不会产生原始值。因此,从另一个指针中减去一个指针不会产生内存地址的差异,而是两个指针之间的元素数量。
此外,标准要求指针减法没有意义,除非两个指针指向同一个数组中的元素(更准确地说,它是未定义的行为,你也可以使用指向“一个”过去最后一个元素“即使那里没有这样的对象。”
最后,如果编译器不知道指向类型的大小(即指针是void*
)怎么办?在这种情况下,根本不允许指针算术。例如:
void* p = 100;
void* x = p + 1; // does not compile¹
¹有些编译器可能会在void*
上为语言规范extension提供指针算法。在这种情况下,这个语句确实可以编译,结果将取决于所述扩展的规范(例如gcc最终会得到值101)。