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

mag*_*sen 8 c++ pointers cout segmentation-fault

我是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;
}
Run Code Online (Sandbox Code Playgroud)

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

c points to 27
b points to 27
Run Code Online (Sandbox Code Playgroud)

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

小智 11

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

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;
Run Code Online (Sandbox Code Playgroud)

事情会起作用,因为它int* b指的是程序可以访问的内存位置(因为内存实际上是程序的一部分).

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

int* b = new int();
*b = 27;
int c = *b;

//output

delete b;
Run Code Online (Sandbox Code Playgroud)


Sha*_*our 9

更新3

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

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

更新2

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

b没有初始化,因此它的值是不确定的,但你使用间接b未定义的行为.

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

int a ;
int* b = &a;
Run Code Online (Sandbox Code Playgroud)

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

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

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

如果我们再去3.10 Lvalues和rvalues1段说(强调我的):

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

b不指向有效的对象.

原始答案

你没有分配任何内存f,也没有b,但你用在这两者是间接未定义的行为.

更新

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

warning: 'f' is used uninitialized in this function [-Wuninitialized]
Run Code Online (Sandbox Code Playgroud)

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

char a ;
char *f = &a ;
Run Code Online (Sandbox Code Playgroud)

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

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

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

并包括以下项目:

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

fb均自动变量,是不确定的,因为他们不被初始化.

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

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

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