一个未初始化的指针是如何在cin中创建SegFault的
How did an uninitialised pointer create a SegFault in cin?
我声明了一个指针,但没有初始化它。但正因为如此,我在cin语句中得到了一个与指针无关的segfault。这是代码:
char tempBuff[20];
char ** stat;
cout<<"All fine till here...";
cin>>tempBuff;
cout<<"Gotcha!";
这是输出,其中12是输入的数字:
All fine till here...12
Segmentation fault (core dumped)
如果指针stat
被初始化为NULL
,它工作得很好。如果我知道为什么会发生这种事,这将帮助我不再犯同样的错误。
谢谢!
更新:由于没有人能够用我给出的代码片段重现错误,以下是整个代码。我在GCC版本4.8.4上编译了代码以获得错误。
您被stdout
的缓冲误导了。如果添加显式刷新:
cout << "Gotcha!" << std::flush;
您将得到以下输出:
/选择在这里之前一切都很好。。。12明白了!分段故障
使用valgrind
运行会产生以下错误:
==5817==条件跳转或移动取决于未初始化的值===5817===在0x569E68B:____ strtol_l_internal(strtol_l.c:489)===5817===通过0x400BAF:addStudent()(选择.cpp:21)===5817===通过0x400C53:main(选择.cpp:30)===5817======5817===使用大小为8的未初始化值===5817===在0x569E68D:____ strtol_l_internal(strtol_l.c:490)===5817===通过0x400BAF:addStudent()(选择.cpp:21)===5817===通过0x400C53:main(选择.cpp:30)===5817======5817======5817===进程终止,信号11默认动作(SIGSEGV)===5817===地址0x400A29处映射区域的权限不正确===5817===在0x569E68D:____ strtol_l_internal(strtol_l.c:490)===5817===通过0x400BAF:addStudent()(选择.cpp:21)===5817===通过0x400C53:main(选择.cpp:30)
以下指令的哪一点:
newStud.mark = strtol(tempBuff, stat, 10);
事实上,您提供了指向strtol
的未初始化指针,然后NULL
对其进行测试(因此"条件跳转或移动取决于未初始化的值")。
然后,看到它不是(在您的情况下,它包含任意但非零的垃圾),继续将其结束指针存储在这个位置,从而触发segfault。
是否在代码的其他地方使用指针?根据我的经验,分段故障不一定发生在你期望的地方。它们甚至不总是发生在真正有错误的时候。例如,如果未初始化的指针恰好指向您允许的地址空间中的某个位置,则不会得到segfault。当您用完数组的末尾时,这种情况经常发生。
这里可能发生的情况是,当您声明stat时,您正在更改堆栈的外观,这也是tempBuff驻留在内存中的位置。在一种情况下,这可能会导致segfault,而在另一种情况中则不会导致错误,这很难说,因为你并不真正知道编译器在对你的代码做什么。如果你在linux平台上,我会尝试通过一个名为valgrind的程序来运行它,该程序会检查你的内存。
cout
被缓冲-缓冲区满时写入输出;当读取CCD_ 8时;或者当使用flush()
或通过写入std::endl
显式刷新cout
时。
在您的情况下,这会导致输出具有欺骗性,因为您的程序在cout<<"Gotcha!";
之后但在刷新缓冲区之前崩溃。
崩溃的原因是您从未初始化过stat
,并且像您的代码和strol
一样,取消对它的引用是未定义的。
然而,即使您将代码初始化为NULL
,您的代码也是未定义的,因为取消引用空指针也是未定义(我不知道为什么您的代码在这种情况下不会崩溃,但这就是未定义行为的本质。编译器可能已经删除了测试,因为它知道这是一个无效的取消引用,因此不可能在有效的程序中发生。)。
如果您对strtol
中的"结束指针"感兴趣,您应该向它传递一个指向变量的指针:
char * stat = NULL;
cout<<"All fine till here...";
cin>>tempBuff;
cout<<"Gotcha!";
student newStud;
newStud.mark = strtol(tempBuff, &stat, 10);
if(stat)
newStud.status == tempBuff[0];
else
newStud.status == 'P';
我不确定您对最终测试的意图是什么,因为strtol
总是在"end"参数中返回一个有效的指针
(如果转换成功,它是转换值末尾的一个,否则是第一个参数的值。)
这样做的寓意是:在跟踪调试时,始终编写一个endl
(或者使用cerr
而不是cout
)。
- C++中带有List类的迭代器Segfault
- C++中的cin.ignore()函数不适用于整个流
- 在while循环中输入带有std::cin的字符串后,控制台会输出大量胡言乱语
- Problems with std::cin.fail()
- 使用Vulkan hpp vk::enumerateInstanceVersion()会导致segfault
- 由cin中的字符串中未捕获空白引起的分割错误
- 在C++中使用Cin,我如何在1行中输入
- 将 cin 限制为只有一个
- cin >> int 给定一个字符串将 int 赋值为 0
- istream std::cin如何修改自定义istream缓冲区
- C++ 将 CIN 值存储到任何类型的数组中
- 为什么无论你输入什么,这"while(cin.get(str,3))"只运行一次?
- cin 的十进制输入验证?
- Turbo C++ cin() 不能与 gets() 一起使用
- 使用 cin 时接受小数点后的 2 位数字
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 在 std::getline 和 std::cin 期间卡在循环中
- 我无法在Visual Studio代码中使用CIN输入答案,它说输入您的年龄,但它说只读文本编辑器如何解决这个问题?
- 为什么我的两个 cin 语句没有在程序结束时运行?
- 一个未初始化的指针是如何在cin中创建SegFault的