解除引用cout指针时的C ++ SegFault

我是C ++的新手,只是试图抓住它。 它通常看起来不是太糟糕,但我偶然发现了这种奇怪/病态的segfaulting行为:

int main () { int* b; *b = 27; int c = *b; cout << "c points to " << c << endl; //OK printf( "b points to %d\n", *b); //OK // cout << "b points to " << (*b) << endl; - Not OK: segfaults! return 0; } 

如此给出的这个程序产生了你所期望的:

 c points to 27 b points to 27 

另一方面,如果取消注释倒数第二行,则会得到一个在运行时崩溃(seg-fault)的程序。 为什么? 这是一个有效的指针。

int* b指向未知的内存地址,因为它未初始化。 如果你把它初始化为你的编译器存在的任何空值(C ++中的0或NULL,C ++ 0x中的nullptr),你肯定会更早地得到段错误。 问题在于您为指针分配了空间而不是它指向的数据。 如果您改为这样做:

 int c = 27; int* b = &c; cout << "c points to " << c << endl; printf ("b points to %d\n", *b); cout << "b points to " << (*b) << endl; 

事情会有效,因为int* b指的是程序可以访问的内存位置(因为内存实际上是程序的一部分)。

如果将指针保持未初始化状态或为其指定空值,则在指向您知道可以访问的内存地址之前,不能使用它。 例如,使用new运算符进行动态分配将为您保留数据的内存:

 int* b = new int(); *b = 27; int c = *b; //output delete b; 

更新3

我回答C ++标准究竟在哪里解释引用未初始化的指针是未定义的行为? 给出了一个更好的答案,为什么使用未初始化的指针是未定义的行为。 C ++草案标准的基本逻辑,第24.2迭代器要求 ,特别是第24.2.1一般5和第10段分别说( 强调我的 ):

[…] [示例:在声明未初始化的指针 x(与int * x;一样)之后, 必须始终假定 x 具有指针的奇异值 。 -end example] […]可解除引用的值总是非单数的。

更新2

这最初是一个C问题的答案,几乎完全相同,但我回答的原始问题与此问题合并。 我正在更新我的答案,包括特定于新问题和C ++草案标准的答案。

b没有被初始化,因此它的值是不确定的,但你在b上使用了间接行为 ,这是未定义的行为 。

一个可能的简单修复方法是将b分配给现有变量的地址,例如:

 int a ; int* b = &a; 

另一种选择是通过new使用动态分配。

为了完整起见,我们可以看到这是未定义的行为 ,请参阅草案C ++标准第5.3.1一元运算符1段( 强调我的 ):

一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针, 结果是一个左值,引用表达式指向的对象或函数。[。 ..]

然后,如果我们转到第3.10Lvalues和rvalues1段说( 强调我的 ):

左值(历史上所谓的左值,因为左值可以出现在赋值表达式的左侧)指定一个函数或一个对象。 […]

但是b没有指向有效的对象

原始答案

你没有为fb分配任何内存,但你在两者都使用了间接,这是未定义的行为 。

更新

值得注意的是,启动警告级别应该表明这是一个问题,例如使用gcc -Wall为此代码提供以下警告:

 warning: 'f' is used uninitialized in this function [-Wuninitialized] 

最简单的解决方法是将f指定为指向有效对象,如下所示:

 char a ; char *f = &a ; 

另一个选择是使用动态分配,如果你没有方便的参考, C FAQ不是一个糟糕的起点。

为了完整起见,如果我们看一下C99标准草案附件J.2 未定义的行为1段说:

在以下情况下,行为未定义:

并包括以下项目:

具有自动存储持续时间的对象的值在不确定时使用(6.2.4,6.7.8,6.8)。

fb的值都是自动变量,因为它们未初始化,所以它们是不确定的。

通过阅读引用的部分并不清楚哪个语句使其未定义,但第6.5.2.5复合文字17段是规范性文本的一部分,其中有一个示例,其中包含使用相同语言的以下文本并说:

[…]下一次p会有一个不确定的值,这将导致未定义的行为。

在C11标准草案中,该段为16

指针有效,因为它有一个值。 但记忆可能不是。 这是你的操作系统告诉你,你正在触摸不属于你的记忆。

我坦率地说它不会比这更早崩溃。


原因如下:

 int* b; // b is uninitialized. *b = 27; 

b指向哪里? 它可能在某个地方有效,或者在某个完全禁止的地方。 你通常可以赌后者。

这是一个更好的方式来做你想要的。

 int b1 = 27; int *b = &b1; 

现在b指向堆栈中存储b1 s值的位置。

这是因为f是一个指针,需要为它分配一些内存。

一般规则: 在使用之前初始化变量

char* f; 是一个变量。 *f是此变量的用法。 与任何变量一样, f必须在使用前初始化。