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

Adr*_*ian 8 c c++

我有以下程序:

#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结束).