我有以下程序:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我可以想像X在存储器的布局,10盒含有int与一个float,p1将在第二个框(的开始点x[1]),并p2在第6框的开头(指向x[5]):
X 0 1 2 3 4 5 6 7 8 9
_______________________________
b |__|__|__|__|__|__|__|__|__|__|
a |__|__|__|__|__|__|__|__|__|__|
| |
| |
p1 p2
Run Code Online (Sandbox Code Playgroud)
我的图画是否正确?如果是这样,为什么i4 的结果呢?
理解减去两个地址有一些困难吗?
Jon*_*Jon 23
这是指针算法的工作原理.考虑:
p1 = (x*)100; // invalid memory address, just an example!
p2 = p1 + 1;
Run Code Online (Sandbox Code Playgroud)
在这一点上,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¹
Run Code Online (Sandbox Code Playgroud)
¹有些编译器可能会提供指针算法void*作为语言规范的扩展.在这种情况下,该语句确实可以编译,结果将取决于所述扩展的规范(例如,gcc将以值101结束).