为什么我没有用这个简单的代码得到段错误?

时间:2017-01-20 21:09:14

标签: c arrays pointers segmentation-fault undefined-behavior

当我访问数组外部的项目时,我必须显示错误(不创建我自己的函数)。所以我只是认为有必要从数组中访问值来触发段错误,但这段代码根本不会崩溃:

int main(){
    int tab[4];
    printf("%d", tab[7]);
}

为什么我这样做时不会出错?

3 个答案:

答案 0 :(得分:8)

当您调用undefined behavior时,任何事情都可能发生。您的程序可能会崩溃,可能会显示奇怪的结果,或者它似乎可能正常工作。

此外,进行看似无关的更改(例如添加未使用的局部变量或对printf进行简单调用)可能会改变未定义行为的显示方式。

当我运行这个程序时,它完成并打印63.如果我将引用的索引从7更改为7000,我会得到段错误。

简而言之,仅仅因为程序 崩溃并不意味着它

答案 1 :(得分:2)

因为当您执行规范不允许的操作时的行为是"undefined"。而且因为C中没有必要的边界检查。你得到了#34;幸运"。

int tab[4];表示为堆栈上的4个整数分配内存。 tab只是一个内存地址。它对于它所指向的内容或分配了多少空间一无所知。

printf("%d", tab[7]);表示打印出tab的第8个元素。所以编译器会......

  • tab设置为1000(例如),表示内存地址为1000。
  • tab代表int的列表,因此每个元素都是sizeof(int),可能是4或8个字节。让我们说8。
  • 因此tab[7]表示开始读取内存位置(7 * 8)+ 1000 = 1056以及另外8个字节。所以它读取1056到1063。

那就是它。程序本身没有边界检查。硬件或操作系统可能会进行边界检查以防止一个进程读取任意内存,查看protected memory,但C不需要任何内容​​。

所以tab[7]忠实地再现了1056到1063中的垃圾。

你可以写一个小程序来看这个。

int main(){
  int tab[4];
  printf("sizeof(int): %zu\n", sizeof(int));
  printf("tab: %d\n", tab);
  printf("&tab[7]: %d\n", &tab[7]);

  /* Note: tab must be cast to an integer else C will do pointer
     math on it. `7 + tab` gives the same result. */
  printf("(7 * sizeof(int)) + (int)tab: %d\n", (7 * sizeof(int)) + (int)tab);
  printf("7 + tab: %d\n", 7 + tab);
}

确切的结果会有所不同,但您会发现&tab[7]只是在tab上进行了一些数学计算,以确定要检查的内存地址。

$ ./test
sizeof(int): 4
tab: 1595446448
&tab[7]: 1595446476
(7 * sizeof(int)) + (int)tab: 1595446476
7 + tab: 1595446476

1595446476 - 1595446448是28. 7 * 4是28。

答案 2 :(得分:1)

C中的数组只是一个指向内存块的指针,其起点为tab[0]的任意位置。当然你已经设置了4的界限但是如果你超过了它,你只需要访问超过那块内存的随机值。 (也就是说它可能打印出奇怪的数字)。