我在一次面试中看到了这段代码。
int main()
{
int **p;
p = (int **) new int(7);
cout<<*p;
return 0;
}
我本来期望在*p处会有一些运行时错误。但是当我运行代码时,它成功执行并输出了“0x7”。请问有人能解释一下这是如何工作的吗?谢谢。
reinterpret_cast
)。第一个问题是,由于这是一个 reinterpret_cast
,在一般情况下,结果是未指定的;如果 int
的大小小于 int*
的大小(比如在64位架构中),结果就会变成未定义行为,因为你读取超过了 new
调用中分配的大小。static_cast
中,编译器将执行扩展大小的转换,但在reinterpret_cast
中,它将只添加代码来重新解释内存。也就是说,它将获取指向int
的指针,并读取下一个64位(8字节)作为int *
,这是未定义的行为。这是C样式转换最大的问题之一,它不像显式的C++转换那样清晰。 - David Rodríguez - dribeasint *x = new int(7);
int **p = (int**) new int(7);
*p is equal to (int*)7
这是一个值为7的指针。
p
的解引用会导致未定义的行为。 - David Rodríguez - dribeasnew int(7);
分配内存给一个值为7
的int
,并返回指向它的指针。
int **p = (int **) new int(7);
告诉编译器将该内存解释为一个 int**
。
cout << *p;
告诉编译器,在地址*p
处是一个int *
类型的值,并输出其值。该值为0x07
(它将int 7
视为地址)。多次解引用会导致崩溃(确切地说是未定义的行为)。
int main()
{
int **p; // declare pointer to pointer called p
p = (int **) new int(7); // new allocates integer initialized to value of 7 and returns a pointer. Cast the pointer to a point to pointer. p now represents a pointer to a pointer with contents of 0x7. If you called **p you would get the contents at address 0x7.
cout << *p; // dereference p, this yields a pointer, which is an int of value 0x7.
}
int main()
{
int **p = (int **) new int(7);
cout << *p;
}
所以,new int(7)
分配了 sizeof(int)
字节的内存并返回一个指向它的指针。假设内存恰好位于地址 X 处。然后将 X 强制转换为 (int**)
并存储在 p
中。
*p
解引用 int**
,这意味着它将地址为 X
的 int
值 7 解释为 int*
。
如果 sizeof(int*)
大于 sizeof(int)
,那么作为 int*
读取将超出使用 new
分配的缓冲区 - 不管数据类型和任何重新解释都是未定义的行为。
如果它们大小相同,则 CPU 将尝试将包含整数 7 的内存读取为 int*
- 这通常会产生值 int*(7)
,但查看标准 5.2.10.5:
int
7几乎肯定会产生一个值为7的int*
,从而解释了输出“7”的观察结果。int
大小,则它将读取int
值的一片,并将其解释为指针。 根据字节序,该片可能为0或7或甚至其他内容,但是作为一个int
,它必须能够转换为将显示的某些指针值。
new int(7)
返回int*
类型,所以你需要进行类型转换。但是进行类型转换并不能使代码变得正确,它只是掩盖了你犯错的事实。请移除类型转换并从此处开始工作。 - David Heffernan