我刚发现一个问题,我不知道可能是什么。几周前我开始学习编程,并且正在学习指针。
我在2台不同的PC上编译了完全相同的代码。首先,该程序可以完美运行。在第二个步骤中,当到达特定的行时它将停止工作。
我使用2台PC。 我工作场所中的一个运行Windows XP SP3。在这一程序中,该程序运行良好。
我家中的一个运行Windows 7 SP1。它编译了代码,但是该程序无法正常工作。
我正在两个系统中使用DEV C ++和TDM GCC 5.1.0进行编写和编译。
#include<iostream>
using namespace std;
int main (void) {
int* pointer;
cout << "pointer == " << pointer << "\n";
cout << "*pointer == " << *pointer << "\n"; // this is the line where the program stops.
cout << "&pointer == " << &pointer << "\n";
return 0;}
第一台计算机上的输出如下:
pointer == 0x000001234
*pointer == some garbage value
&pointer == 0x000007865
在第二台计算机上,它停在第二行。
pointer == 0x1
我确实知道指针尚未分配给变量。因此,它不存储任何正确的地址。即使这样,它也至少应在其中显示垃圾值,或者应显示“ 0”以指示尚无指向的地址。我知道代码是正确的,因为它可以在第一台PC上正常工作。但是我不明白为什么它在其他计算机上失败了。
答案 0 :(得分:3)
我知道代码是正确的,因为它可以在第一台PC上正常工作
你不知道这样的事。
您有不确定的行为,并且一个完全有效的结果是程序始终有效。要么总是在星期六除外,要么一直工作到完成测试并将其运送给付费客户后,要么一直在一台机器上工作而在另一台机器上失败。
行为是未定义的,而不是“定义为某些特定的,一致的,可观察的故障模式”。
特别是,未定义行为的真正风险不仅是某些操作的结果具有未指定的值,而且还可能具有未定义和不可预测的副作用 >-在您的程序中似乎无关的区域,或者在整个系统中。
即使如此,它至少也应该在其中显示垃圾值
做到了。但是随后您要求它取消引用该垃圾值。
读取任何未指定值的变量本身就是未定义的行为,因此UB的第一部分正在读取指针的值。
跟随(取消引用)未指向有效对象的指针也是未定义的行为,因为您不知道您非法解释为地址的未指定值是否已针对该类型正确对齐或已映射到您的进程的地址空间。
如果您成功地从该地址加载了一些整数,则这是第三种未定义的行为,因为再次未指定其值。
因此,最坏情况下的立即陷阱(具有硬件陷阱值和限制性对齐)是:
但是,如果您的过程只是死而复生,则可以轻松进行调试和修复,而不会产生不良影响。从这个意义上讲,在调用UB时崩溃实际上是最好的结果。替代方案更糟糕,更难以预测且更难调试。
答案 1 :(得分:2)
我确实知道指针尚未分配给变量。因此,它不存储任何正确的地址。即使这样,它也至少应在其中显示垃圾值,或者应显示“ 0”以指示尚无指向的地址。
做到了!那就是0x000001234
。
很遗憾,您然后尝试取消引用这个无效的指针,并打印不存在的int
的值。你不能那样做。
如果您还没有这样做,我们将进入第三行,其中0x000007865
将正确表示指针的地址,该指针是一个名称为pointer
的对象,输入确实存在的int*
。
我知道代码是正确的,因为它可以在第一台PC上正常工作。
您必须习惯C ++的一件事是“它似乎可以在一台计算机上工作”远不能证明代码正确。阅读有关undefined behaviour的信息,然后哭泣缓慢。
但是我不明白为什么它在其他计算机上失败了。
因为代码不正确,并且这次您没有得到“幸运”。
我们可以分析出它似乎可以在一个系统上而不在另一个系统上运行的一些原因,并且有 的原因。但是已经很晚了,您才刚刚开始,并且由于这是未定义的行为,所以没关系。 :)