没有出界错误

时间:2012-02-04 00:07:53

标签: c indexoutofboundsexception

我在C中有这个代码,它接受了char s

的一堆
#include<stdio.h> 
# define NEWLINE '\n'
int main()
{

char c;
char str[6];
int i = 0;
while( ((c = getchar()) != NEWLINE))
{
        str[i] = c;
        ++i;
        printf("%d\n", i);
}

return 0;
}

输入是:testtesttest

输出: 1 2 3 4 五 6 7 8 117 118 119 120

我的问题是:

  1. 为什么我没有超出界限(分段错误)异常,尽管我明显超出了阵列的容量?

  2. 为什么输出中的数字突然跳到很大的数字?

  3. 我在C ++中尝试了这个并且得到了相同的行为。有谁可以解释一下这是什么原因?

8 个答案:

答案 0 :(得分:22)

  1. C不检查数组边界。仅当您尝试取消引用程序无权访问的内存指针时,才会发生分段错误。简单地越过数组的末尾不太可能导致这种行为。未定义的行为只是 - 未定义。它可能出现工作正常,但你不应该依赖它的安全。
  2. 您的程序通过访问数组末尾的内存导致未定义的行为。在这种情况下,您的str[i] = c次写入之一看起来会覆盖i中的值。
  3. 在这种情况下,C ++与C具有相同的规则。

答案 1 :(得分:6)

访问数组索引时,C和C ++不进行绑定检查。只有当您尝试读取或写入未分配的页面(或尝试在不允许的页面上执行某些操作,例如尝试写入只读页面)时,才会发生分段错误,但由于页面通常是非常大(几千字节的倍数;在Mac OS上,4 KB的倍数),它通常会给你留下很多空间。

如果你的阵列在堆栈上(和你的一样),它可能更糟糕,因为堆栈通常非常大(高达几兆字节)。这也是安全问题的原因:写入堆栈上的数组边界可能会覆盖函数的返回地址并导致任意代码执行(着名的“缓冲区溢出”安全漏洞)。

您阅读时获得的值正是在这个特定的地方发生的事情。它们完全未定义

如果你使用C ++(并且很幸运能够使用C ++ 11),那么标准定义了std::array<T, N>类型,它是一个知道其边界的数组。如果您尝试阅读它的末尾,则at方法将抛出。

答案 2 :(得分:2)

因为C / C ++没有检查边界。

数组是指向内存中某个位置的内部指针。当你致电arr[index]时它会做什么:

type value = *(arr + index);

结果是大数字(不一定),因为它们是垃圾值。就像一个未初始化的变量。

答案 3 :(得分:2)

C不检查数组边界。

实际上,分段错误并不是特别是超出数组边界而产生的运行时错误。相反,它是由操作系统提供的内存保护的结果。当您的进程尝试访问不属于它的内存,或者它尝试访问不存在的内存地址时,会发生此错误。

答案 4 :(得分:0)

编写外部数组边界(实际上甚至只是执行指针算术/数组下标,即使您不使用结果来读取或写入任何内容)也会导致未定义的行为。未定义的行为不是报告的或可报告的错误;它可以衡量你的程序可以做任何事情。这是非常危险的,你完全有责任避免它。 C不是Java / Python /等。

答案 5 :(得分:0)

内存分配比看起来更复杂。在这种情况下,变量“str”位于堆栈上,与其他变量相邻,因此未跟随未分配的内存。内存通常也是字对齐的(一个“字”是4到8个字节。)你可能正在搞乱另一个变量的值,或者使用一些“填充”(添加空白以保持字对齐)或其他完全不同的东西

像R ..说,这是未定义的行为。越界条件可能导致段错误......或者它们可能导致静默内存损坏。如果您正在修改已分配的内存,则操作系统不会捕获该内存。这就是为什么越界错误在C中是如此阴险的原因。

答案 6 :(得分:0)

你必须像这样编译:

gcc -fsanitize=address -ggdb -o test test.c

There is more information here.

答案 7 :(得分:0)

与Java不同,C和C ++没有数组边界检查。 例如,如果您有一个像这样的数组: int myArray[2] = {1, 2} 然后再打印std::cout << myArray[5];,编译器将不会给出任何错误,而是会打印垃圾值。