当我减去内存地址时,为什么结果比我预期的要小?

我有以下程序:

#include  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的布局,10个包含intfloat框, p1将指向第二个框的开头( x[1] ), p2指向第6个框的开头( x[5] ):

  X 0 1 2 3 4 5 6 7 8 9 _______________________________ b |__|__|__|__|__|__|__|__|__|__| a |__|__|__|__|__|__|__|__|__|__| | | | | p1 p2 

我的图纸是否正确? 如果是这样,为什么i 4的结果呢?
理解减去两个地址有一些困难吗?

这就是指针算法的工作原理。 考虑:

 p1 = (x*)100; // invalid memory address, just an example! p2 = p1 + 1; 

此时, p2将不具有值101 ,而是100 + sizeof(x) (这可以说是8,因此108)。 它的增量不是1,而是增加了sizeof(x)一个倍数! 相反,从指针中减去一个整数实际上会减去sizeof(the pointed to type)倍数sizeof(the pointed to type)

所以现在如果你做int diff = p2 - p1 ,你当然会期望得到1回,而不是8 ! 否则,减去刚刚添加的数字将不会产生原始值。 因此,从另一个指针中减去一个指针不会产生存储器地址的差异,而是产生两个指针之间的元素数量。

此外,标准规定指针减法是没有意义的,除非两个指针指向同一个数组中的元素 (更准确地说,它是未定义的行为,你也可以使用指向“一个超过最后一个元素”的指针,即使没有这样的对象)。

最后,如果编译器不知道指向类型的大小(即指针是否为void* )怎么办? 在这种情况下,根本不允许指针运算。 例如:

 void* p = 100; void* x = p + 1; // does not compile¹ 

¹有些编译器可能会在void*上提供指针算法,作为语言规范的扩展 。 在这种情况下,该语句确实可以编译,结果将取决于所述扩展的规范(例如,gcc最终将得到值101)。