当我减去内存地址时,为什么结果比我预期的要小?
When I subtract memory addresses, why is the result smaller than I expected?
我有以下程序:
#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
将指向第二个盒子(x[1]
)的开始,p2
指向第六个盒子(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)
的1倍!相反,从指针中减去整数实际上减去了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结束)。
相关文章:
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 为什么在逗号分隔符上下文中将预增量的结果强制转换为void
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 为什么这个程序的结果是3 "born"?和 4 死
- 为什么在递归中使用循环会产生意想不到的结果?
- 为什么我的程序在 O0 和 O2 的优化级别返回不同的结果
- 为什么第二个代码给出了预期的结果,而第一个代码却没有?
- 为什么组合的上限和下限比较的计算结果总是为 true?
- 为什么这两段使用 constexpr、__PRETTY_FUNCTION__ 和 char * 的代码有不同的结果?
- C++向量与 C# 列表.为什么它们会产生不同的结果?
- 为什么'typeid(x) == typeid(y)'的计算结果为 true,其中 'x' 和 'y' 分别是 T 和 T& 类型的 id-表达式?
- 为什么函数 tellg() 没有返回好的结果?
- 双摆返回楠结果.为什么?
- 相机校准结果:为什么与输入相似
- 按回车键后,程序没有输出任何结果.为什么会这样
- 两个明显相似的函数给出了不同的结果.为什么
- 顺序和并行版本给出不同的结果 - 为什么
- 按位运算的意外结果 为什么 (1 | 1 & 2) 给出 1 而不是 2?