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

时间:2011-12-02 13:37:06

标签: 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;
}

我可以在内存中显示X的布局,包含intfloat的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的结果呢? 理解减去两个地址有一些困难吗?

1 个答案:

答案 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)。