当我写入超出另一个数组的边界时,为什么printf()的输出会发生变化?

时间:2016-09-15 23:12:13

标签: c arrays string char printf

#include <stdio.h>
#include <conio.h>
int main()
{
  char b[] = "samuel ricky";
  char c[2];

  c[0] =  'd';
  c[1] =  'a';
  c[2] =  'd';

  printf("%s\n", b);

  getch();
  return 0;   
}

如果我运行此代码,则输出为:

  

damuel ricky

如果代码被删除

c[2] =  'd';

输出是:

  

samuel ricky

如果代码被删除,则结果输出完全没有连接。 它是怎么发生的?

2 个答案:

答案 0 :(得分:3)

请使用-Wall标记启用所有警告,您将在控制台中找到答案:

C02QT2UBFVH6-lm:~ gsamaras$ gcc -Wall main.c 
main.c:10:5: warning: array index 2 is past the end of the array (which contains 2 elements) [-Warray-bounds]
    c[2] =  'd';
    ^ ~
main.c:6:5: note: array 'c' declared here
    char c[2];
    ^
1 warning generated.

正如警告所说,你写的内存是你不熟悉的,因为数组中的索引从0开始,但你似乎已经知道了。

因此char c[2];两个单元格c[0]c[1]。写入c[2]正在调用未定义的行为,这意味着您在机器中看到的内容现在,明天可能会有所不同,或者在任何其他时间都有所不同机。

总之,现在你机器上发生的事情就是你在写作&#39; d&#39;到c[2],它超出范围,恰好写在b[0]的存储单元中。这就是为什么看到&#34; damuel ricky&#34;例如,我看到&#34; samuel ricky&#34;。

如果我是你,我wouldn't use conio.h,你可能最终会像苏格拉底......;)

答案 1 :(得分:2)

声明0为具有索引12的两个元素的数组分配空间。您对该数组的索引damuel ricky的写入会调用undefined behavior

至于为什么你会看到结果+------+------+------+------+ <-- low memory | c[0] | c[1] | b[0] | b[1] | +------+------+------+------+ | b[2] | ... | +------+------+------+------+ <-- high memory - 许多实现在堆栈上的连续块中分配局部变量(忽略一些必要的填充)。此外,许多调用约定(如cdecl调用约定)将局部变量从高内存分配到低内存,就像这样(回想一下堆栈向低内存增长):

c

因此,访问b的索引2实际上与访问{{1}}的索引0相同。请注意,这是依赖于实现的,并且您可能不会使用其他编译器或计算机表现出相同的行为。