C++ 分段故障常见原因的最终列表
注意:我们有很多segfault问题,基本上是相同的 答案,所以我试着把它们压缩成一个标准问题,比如 我们有时间 虽然我们有一个问题,它涵盖了什么,但没有列出很多原因。最上面的答案是“有很多原因”,只列出了一个,而其他大多数答案没有列出任何原因 总而言之,我认为我们需要一个组织良好的社区wiki,它列出了所有导致错误的常见原因(还有一些)。正如答案的免责声明中提到的,其目的是帮助调试 我知道分段错误是什么,但如果不知道它们通常是什么样子,就很难在代码中发现它们。虽然有很多人无法详尽地列出,C++ 分段故障常见原因的最终列表,c++,c,segmentation-fault,C++,C,Segmentation Fault,注意:我们有很多segfault问题,基本上是相同的 答案,所以我试着把它们压缩成一个标准问题,比如 我们有时间 虽然我们有一个问题,它涵盖了什么,但没有列出很多原因。最上面的答案是“有很多原因”,只列出了一个,而其他大多数答案没有列出任何原因 总而言之,我认为我们需要一个组织良好的社区wiki,它列出了所有导致错误的常见原因(还有一些)。正如答案的免责声明中提到的,其目的是帮助调试 我知道分段错误是什么,但如果不知道它们通常是什么样子,就很难在代码中发现它们。虽然有很多人无法详尽地列出, C+
什么是断层? 简言之,当代码试图访问其无权访问的内存时,会导致分段错误。每个程序都有一块内存(RAM)可供使用,出于安全原因,它只允许访问该块中的内存 有关分段错误的更全面的技术解释,请参阅。 以下是导致分段错误的最常见原因。同样,这些应用于诊断现有segfault。要学习如何避免它们,请学习您的语言未定义的行为 此列表也不能代替您自己的调试工作。(请参阅答案底部的那一部分。)这些是您可以查找的内容,但调试工具是解决问题的唯一可靠方法
访问空指针或未初始化指针 如果您的指针为空(
ptr=0
)或完全未初始化(尚未设置为任何值),则尝试使用该指针进行访问或修改将具有未定义的行为
int* ptr = 0;
*ptr += 5;
由于失败的分配(例如使用malloc
或new
)将返回空指针,因此在使用指针之前,应始终检查指针是否为空
还要注意的是,即使读取未初始化指针(以及通常的变量)的值(不取消引用),也是未定义的行为
int* ptr = 0;
*ptr += 5;
有时,对未定义指针的这种访问可能非常微妙,例如在试图将此类指针解释为C print语句中的字符串时
char* ptr;
sprintf(id, "%s", ptr);
另见:
访问悬空指针 如果您使用
malloc
或new
分配内存,然后稍后通过指针free
或delete
该内存,则该指针现在被视为悬挂指针。取消对它的引用(以及简单地读取它的值-假定您没有为它指定一些新值,例如NULL)是未定义的行为,并且可能导致分段错误
Something* ptr = new Something(123, 456);
delete ptr;
std::cout << ptr->foo << std::endl;
堆栈溢出的另一个原因是一次有太多(非动态分配的)变量
int stupidArray[600851475143];
有一种情况是,为了防止函数中出现无限递归,在条件语句中省略了return
语句。这个故事的寓意是,始终确保错误检查有效强>
另见:
野指针 创建指向内存中某个随机位置的指针就像用代码玩俄罗斯轮盘赌——您很容易会错过并创建指向您没有访问权限的位置的指针
int n = 123;
int* ptr = (&n + 0xDEADBEEF); //This is just stupid, people.
一般来说,不要创建指向文字内存位置的指针。即使他们工作过一次,下一次也可能不工作。您无法预测在任何给定执行时程序内存的位置
另见:
试图读取超过数组结尾的内容 数组是一个连续的内存区域,其中每个连续元素位于内存中的下一个地址。然而,大多数数组对它们有多大或最后一个元素是什么没有天生的感觉。因此,很容易吹过数组的末尾而永远不知道它,特别是在使用指针算法的情况下 如果读取超过数组的末尾,则可能会进入未初始化的内存或属于其他内容的内存。这在技术上是未定义的行为。segfault只是众多潜在的未定义行为之一。[坦率地说,如果你在这里遇到了一个SEGFULT,你就很幸运了。其他的更难诊断。]
// like most UB, this code is a total crapshoot.
int arr[3] {5, 151, 478};
int i = 0;
while(arr[i] != 16)
{
std::cout << arr[i] << std::endl;
i++;
}
甚至是一个不走运的打字错误,它编译得很好(如图所示),只分配了1个元素,并用dim
而不是dim
元素初始化
int* my_array = new int(dim);
此外,应该注意的是,甚至不允许创建(更不用说取消引用)指向数组外部的指针(只有当指针指向数组中的元素,或者指向数组末尾的元素时,才可以创建这样的指针)。否则,你就是
int* my_array = new int(dim);
char str[3] = {'f', 'o', 'o'};
int i = 0;
while(str[i] != '\0')
{
std::cout << str[i] << std::endl;
i++;
}
char* foo = "Hello, world!"
foo[7] = 'W';