【问题标题】:Segmentation fault occurs way after index leaves array boundary in C++ [duplicate]在 C++ 中索引离开数组边界后发生分段错误 [重复]
【发布时间】:2017-05-18 23:54:14
【问题描述】:

我有这个代码:

#include <cstdio>

int foo[100];

int main()
{
for(int i=0;i<10000;i++)
    foo[i]=10000;
}

使用 GDB 进行调试会得到令人惊讶的结果:

[New Thread 23684.0x59b4]
[New Thread 23684.0x5c0c]
[New Thread 23684.0x541c]

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401564 in main () at C:\Users\DARREN\Documents\Visual Studio 
2017\Projects\Untitled1.cpp:9
warning: Source file is more recent than executable.
9       }
(gdb) print i
$1 = 4080
(gdb)

现在,我知道声明 foo[i]=10000 导致了错误,但我声明 foo 的大小仅为 100。为什么i的值会在错误发生之前这么大?

感谢任何解释。

【问题讨论】:

  • 越界访问元素是“未定义的行为”,这意味着任何事情都可能发生。 “直到错误发生很久之后才报告任何问题”是“任何事情”的一种可能结果。
  • 不幸的是,未定义的行为不一定会导致明显的问题。由于que[] 是数据段的一部分,因此似乎有很多有效的内存位置可以在遇到无效内存位置之前被读取。
  • C++ 遵循“只为你使用的东西付费”的理念。一个正确的程序没有缓冲区溢出,因此检查缓冲区溢出是他们不应该付出的代价。结果是零检查,程序将继续运行,直到可能由溢出导致的某些事情导致它停止。
  • 使用std::vector 代替普通数组,使用.at(size_t pos) 代替下标运算符。这样你会在越界时遇到异常。
  • 我不认为这是重复的,因为链接的答案没有回答问题,这就是为什么在偏移 4080 之前没有错误。只是说“那是未定义的行为”没有回答这个问题,不仅仅是“问:为什么天空是蓝色的?答:因为它不是黄色的”

标签: c++ arrays debugging segmentation-fault


【解决方案1】:

在您更新问题后,您发布了以下内容:

int foo[100];

int main()
{
for(int i=0;i<10000;i++)
    foo[i]=10000;
}

你问的是分段错误。

在这里,您有一个大小为100 的数组,并且您有一个范围为[0,9999] 的循环,并且在for 循环中,您使用for 循环增量变量i 对数组进行索引。当您为 i 的每次迭代逐步执行 for 循环时,您会得到:

foo[i] = 10000; 

i &lt;= 99一切正常时。

你认为i &gt;= 100 时会发生什么?

当您使用原始数组时,没有边界检查;这是您和用户必须负责的事情。如果您希望为您完成自动边界检查以防止这种超出范围的内存分段错误,您应该根据您的需要使用任何标准容器,例如std::vector&lt;T&gt;std::list&lt;T&gt;std::set&lt;T&gt; 等。如果您需要使用数组索引表示法,那么std::vector&lt;T&gt; 是要走的路。或来自任何其他库的任何其他vector,例如boost

编辑

要解决此问题,您必须将数组的大小从 100 增加到 10,000,或者您必须将循环的条件从 i&lt;10000 减少到 i&lt;100 以适应正确的数组索引。不要忘记C++ 数组的起始索引为0,因此您将拥有一个基本数组和循环:

int var[10]; // Uninitialized

for ( int i = 0; i < 10; ++i ) {
    var[i] = 0; // Initialize all array indexes to 0
}

注意,for循环中的条件是i &lt; 10,它小于声明时数组的实际大小,而不是i &lt;= 10小于或等于,因为这也会产生分段错误或超出边界错误。

【讨论】:

  • OP 似乎在问为什么错误发生在 i=4080 而不是 i=100,而不是为什么会发生错误。
  • @MilesBudnek 也许,但第一个应该在后者之前很明显,任何不确定超出范围错误的人都不应该访问大于索引数组大小的数组索引。但是,如果他关心i = 4080,那么他需要考虑假设它是一个32 位系统,那么int 类型应该是4 个字节。那么4 x 4080 = 16320 bytes 32 位系统上的正常页面或扇区大小是多少?
  • @MilesBudnek 因此,当您最终到达页面文件的末尾时;你开始经历缓存未命中和其他事情;它们也可能导致段错误。基本上,他正在践踏不属于该数组的内存,因为它不属于该数组,或者最初没有为它保留。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-13
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
相关资源
最近更新 更多