什么会导致C ++中的分段错误?

时间:2011-08-03 08:22:54

标签: c++ segmentation-fault

我注意到C ++中的分段错误的常见原因列表没有问题,所以我想我会添加它。

当然它是社区Wiki,因为没有一个正确答案。

我认为这对于学习C ++的新程序员可能有用,如果你不同意,可以随意关闭它。

9 个答案:

答案 0 :(得分:37)

仅当您的操作系统具有MMU(Memory Management Unit)时,才会因访问内存不良而导致分段错误。否则,你不会得到它,只会有奇怪的行为。

虚拟内存(您可以访问的整个内存= 2^(sizeof(pointer_type)*8)(即:2^num_bits_in_pointer_type))以命名页面或段为单位映射到物理内存(分页取代分段但仍然使用它们) 。

每个页面都有一些保护权限,如果您尝试从没有读取权限的页面读取,您将获得段错误。如果您尝试写入只读位置,您将获得SIGSEGV。

如果你有一个单位指针并使用它,它可能会发生它将指向另一个好的位置,所以你不会得到段错误。如果在绑定之后有一个小数组读取可能会破坏其他内存区域,如果它没有超过页面边界。

此外,由于页面很多,并非所有页面都被映射。如果您触摸非映射页面,则会出现段错误。实际上,对非映射页面的任何访问都必须考虑写入时的复制,交换页面,延迟加载,内存映射文件和其他内容。请参阅this article on page fault handling,特别是那里的第二张图,也在下面发布(但请阅读文章以获得更多解释)

page fault handling

您主要对用户空间和导致SIGSEGV的所有路径中发生的事情感兴趣。但内核空间也很有趣。

答案 1 :(得分:5)

取消引用NULL指针。

#include <cstddef> //For NULL.
int* p1 = NULL; //p1 points to no memory address
*p1 = 3; //Segfault.

答案 2 :(得分:4)

访问数组越界(可能):

int ia[10];
ia[10] = 4; // Someone forgot that arrays are 0-indexed! Possible Segfault.

答案 3 :(得分:4)

“段落错误”C ++的许多方法不一定保证发生,事实上,这里发布的大多数示例就是这种情况。如果你能在没有发生段错误的情况下执行这些操作,那只是好运(或运气不好,取决于你如何看待它!)。

这实际上是C ++中将其与其他语言分开的事情之一;未定义的行为。而在Java或C#中,您可能会遇到'InvalidOperationException'或类似情况,这可以保证在执行这些操作时发生;在C ++中,标准只是说“未定义的行为”,这基本上是抽奖的运气,而你永远不希望这种情况发生。

答案 4 :(得分:3)

我的最爱:

#include <iostream>
struct A {
    virtual void f() {
        std::cout << "A::f();\n";
    }
    int i;
};

struct B : A {
    virtual void f() {
        std::cout << "B::f();\n";
    }
    int j;
};

void seti(A* arr, size_t size) {
    for (size_t i = 0; i < size; ++i)
        arr[i].i = 0;
}

int main() {
    B b[10];
    seti(b, 10);
    b[3].f();
}

与大多数可能导致段错误的事情一样,这也可能失败。例如,在ideone上,b[3].f()失败,但b[2].f()有效。

答案 5 :(得分:1)

显而易见的答案是“未定义的行为”,但这是乞求 一个没有经验的程序员和一些类型的程序员的问题 未定义的行为不太可能导致分段错误 (或其他类型的崩溃)比其他人。最常见的原因 分段错误通常与指针相关:解除引用 未初始化的指针,空指针或以前释放的指针; 超越终点(或在开头前,但更少 频繁的)对象(数组或其他);使用非法的结果 当对象没有时,指针强制转换(static_cast到派生类型 实际上有这种类型,或大多数reinterpret_cast);等

然而,在这里要记住的最重要的一点是 通常,这些不能保证导致分段错误,并且 通常,它们引起的分段错误只会发生 一段时间后,在一个完全不相关的操作中。因此,写作 超出本地数组的末尾通常会“工作”, 但会修改堆栈上数组后面发生的事情:一些 其他局部变量(修改堆栈上对象的vptr 尝试调用虚拟时可能会导致分段错误 对象上的函数),调用函数的帧指针 (之后可能会导致该功能出现分段错误 你已经退货了)或者寄回地址(这可能会引起各种各样的问题) 奇怪的行为 - 分段错误或非法指令 陷阱可能是最好的事情)。写作超越了结束 释放内存,或通过已释放的指针,可以破坏自由 太空竞技场,导致分段错误(有时很多, 以后分配或免费;它还可以完全修改其他一些 不相关的对象,破坏其中的vptr或其他指针 对象,或只是一些随机数据 - 再次,分段错误 可能是最好的结果(很可能继续下去 损坏的数据)。

答案 6 :(得分:0)

忘记初始化指针,留下随机内存地址。注意:这可能不会总是段错误,但可能会。

int* p1; //No initialization.
*p1 = 3; //Possible segfault.

答案 7 :(得分:0)

取消引用已释放的内存可能会导致段错误。

SomeClass* someObject = new SomeClass();
delete someObject;
someObject->someMethod();  //Could cause a segfault.

答案 8 :(得分:0)

尝试修改字符串文字:

char* mystr = "test";
mystr[2] = 'w';

CAN 导致分段错误。