【问题标题】:Random segfaults in C++ [closed]C ++中的随机段错误[关闭]
【发布时间】:2009-08-22 21:49:39
【问题描述】:

我是 C++ 新手,不知道从哪里开始,所以我将代码上传到 pastebin,因为代码很多。

这段代码编译得很好,并且不会发出警告,即使使用 gcc 的 -Wall 选项。

它应该生成所有素数,直到作为命令行参数给出的数字。

对于较小的数字(例如 4,000 或 5,000),它可以正常工作。在更大的数字上,例如 4,000,000,它几乎总是因段错误而崩溃。在两者之间的数字上,它是否运行是命中注定的。

【问题讨论】:

  • 这真的不是问题。改写一下,也许有人可以帮助你。
  • 尝试附加到调试器或使用 cout 语句来查看是否可以找出段错误发生的位置。

标签: c++ segmentation-fault


【解决方案1】:
int primes[max];

prime = primes;
while(*prime) {
    *prime = 0;
    prime++;    
}

在前面的代码中,您可以轻松地在内存中随机运行,本质上您正在遍历 RAM,直到找到 0。如果您的数组中没有 0,那么它将运行到不属于进程和段错误会发生。

编辑:正如 Alcon 所指出的,您也在代码的其他地方执行此操作。

最好不要在堆栈上分配素数,因为您不太可能有那么多可用的堆栈内存。

要解决此问题,请尝试以下代码

int primes = new int[max];

size_t count = 0;
while( count < max ) 
{
    prime[count] = 0;
    count++;    
}

别忘了调用 delete[] primes;在代码的末尾(当您完成素数数组时)

【讨论】:

  • 此时素数的内容尚未初始化,因此(因为 int 是没有默认构造函数的基本类型等等)它将是未定义的;里面有没有零有点随机。
【解决方案2】:

您正在堆栈上分配数组。堆栈大小有限,可能会溢出。

尝试使用 new/delete 分配您的数组。

【讨论】:

  • 更好的是,使用向量,这样您就不会分配过多的内存。
  • 是的,这绝对是向量的正确情况,你分配的内存比你需要的多。
  • 溢出是因为没有检查长度,而不是特别是在堆栈上?
  • 这是因为数组大于操作系统为栈分配的内存。
【解决方案3】:

您应该动态分配素数数组primes,即:

int* primes = new int[max];

您的程序甚至不应该按原样编译。祝你作业顺利!

【讨论】:

  • 我相信动态大小的堆栈数组是 g++ 扩展。但是,是的,它不是符合标准的 C++。
【解决方案4】:

一方面,这是有问题的:

int sum_array(int num_array[]) {
    int current_total = 0;
    int *iptr = num_array;
    while(*iptr) {
        current_total += *iptr;
        iptr++;
    }
    return current_total;
}

这说的是从给定数组的开头开始。当 int 大小的内存块中的值不为零时,移动到下一个内存块。这里发生的事情是它会继续超过你的数组的末尾,最终弄乱它不应该的内存,这就是导致段错误的原因。看起来随机的原因是有时数组末尾的内存是空的,这会正常工作。但有时它不是,然后它访问不应该访问的内存并崩溃。

这可能不是唯一的问题,但这是我注意到的第一个问题。要修复它,请跟踪数组的大小,将其传递给函数,然后使用 for 循环迭代它而不是使用指针。像这样:

int sum_array(int num_array[], int arraySize) {
    int current_total = 0;
    for(int i = 0; i < arraySize; i++) {
        current_total += num_array[i];
    }
    return current_total;
}

我再看看有没有别的。

编辑:

再看一遍,你在另外两个地方做同样的事情。这里:

while(*prime) {
        cout << *prime << " ";
        prime++;
    }

这里:

while(*prime) {
    *prime = 0;
    prime++;    
}

在这两个地方,我都在甜甜圈上打赌,你的数组已经超出了你的数组,这就是导致段错误的原因。如果您是新手,我强烈建议您不要使用指针算法来遍历您的数组。坚持使用旧的 for 循环并跟踪 for 循环的结束。

其他人建议从堆而不是堆栈分配数组。这对于一个巨大的数组来说是个好主意,但是,至少根据我的经验,堆栈溢出通常不会导致段错误。当您分配的空间多于堆栈中的空间时,编译器通常会注意到。我仍然建议使用向量(对于你的家庭作业有很大的额外功劳,看看你是否可以弄清楚如何使用从堆中分配为指针数组的双指针来实现你自己的向量;)或者只使用标准: :向量。它是一个可扩展的数组,可以让您在找到它们时将素数添加到数组中,而不是分配大量您不一定需要的空间。

【讨论】:

    【解决方案5】:

    Goz 指出事情是如何早期开始出错的。

    初学者很容易犯错误,但即使是老手也会犯同样的错误。出于这个原因,老手们制作了出色的程序来自动发现问题:

    免费程序包括lint,它会在您运行代码之前检查代码,以及 - 更好的是 - valgrind,它会在您运行代码时检查代码!在 Windows 上,还有其他商业替代品,例如 Purify

    在开发期间通过 valgrind 和静态代码检查器运行程序,以及使用编译器启用的所有警告进行编译,即使对于经验丰富的老手来说也是开发卫生的一部分。

    【讨论】:

      【解决方案6】:

      其他人(例如 Goz)提供了正确的答案 - 未初始化变量的值不能依赖,因为它们因运行而异。正如其他人指出的那样,在堆栈上分配大型数组也是有风险的,因为堆栈空间通常比堆空间更稀缺。

      作为一个附带问题,以您使用 primes[max] 的方式分配可变大小的数组不是符合标准的 C++,而是一个 g++ 扩展,因此您的代码不太可能与其他编译器一起使用。您可以使用 newdelete 代替 - 但在这些情况下养成使用 vector&lt;int&gt; 的习惯会更好,因为它会为您完成清理工作。

      [编辑:感谢 Will 指出问题的真正根源在其他地方。]

      【讨论】:

      • 你是对的——Goz 的回答更可能是真正的原因(尽管在堆栈上分配大的数组仍然存在风险)。我会更新我的答案。
      【解决方案7】:
      int primes[max];
      

      在堆栈中分配巨大的数组是不好的,因为默认情况下堆栈的大小很小。最好在堆中分配 primes[]。

      【讨论】:

      • 崩溃可能发生在未初始化缓冲区的循环“while(*prime)”中;把它放在堆上不会改变这一点。
      • 你是对的,威尔。无论如何,在堆栈中分配巨大的内存块是一个额外的缺陷。
      猜你喜欢
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 2015-05-23
      • 2012-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多