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

时间:2011-05-22 01:45:55

标签: c++ pointers segmentation-fault cout

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

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)的程序。为什么?这是一个有效的指针。

5 个答案:

答案 0 :(得分:10)

int* b指向未知的内存地址,因为它未初始化。如果你将它初始化为你的编译器存在的任何空指针值({C} 11之前的0,C ++ 11及更新版本中的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;

答案 1 :(得分:9)

更新3

我对Where exactly does C++ standard say dereferencing an uninitialized pointer is undefined behavior?的回答给出了一个更好的答案,为什么使用未初始化的指针是未定义的行为。 C++ draft standard部分24.2 迭代器要求的基本逻辑,特别是部分24.2.1 一般 5 10 分别说(强调我的):

  

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

更新2

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

b尚未初始化,因此它的值是 indeterminate ,但您在b上使用间接undefined behavior

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

int a ;
int* b = &a;

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

为了完整起见,我们可以通过转到草案C ++标准部分5.3.1 一元运算符 1 未定义的行为 >其中说(强调我的):

  

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

然后,如果我们转到3.10 Lvalues和rvalues 1 段(强调我的):

  

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

b未指向有效的对象

原始答案

您没有为fb分配任何内存,但您在undefined behavior上都使用了间接内存。

更新

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

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

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

char a ;
char *f = &a ;

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

为了完整起见,如果我们查看C99 draft standard附件J.2 未定义的行为 1 说:

  

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

并包含以下项目符号:

  

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

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

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

  

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

C11 draft standard中,段落 16

答案 2 :(得分:3)

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

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


原因如下:

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

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

这是一种更好的方式来做你想做的事。

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

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