【问题标题】:Why does the output from printf() change when I write beyond the bounds of another array? [closed]当我写入超出另一个数组的范围时,为什么 printf() 的输出会发生变化? [关闭]
【发布时间】:2017-01-24 02:28:14
【问题描述】:
#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;   
}

如果我运行这段代码,输出是:

达缪尔·瑞奇

如果代码被删除

c[2] =  'd';

输出是:

塞缪尔·瑞奇

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

【问题讨论】:

  • 你确定输出是daniel ricky 而不是damuel ricky
  • @purag 好吧。
  • c 是一个足以容纳两个元素的数组。你把三个元素放进去。这是未定义的行为。
  • 那是令人着迷的行为。好地方。

标签: c arrays string char printf


【解决方案1】:

请使用-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] 是在调用Undefined Behavior,这意味着您现在在您的机器上看到的打印内容可能会在明天或任何其他机器上的任何时间有所不同。

总之,你的机器现在发生的事情是你正在向c[2] 写入'd',这是越界的,它恰好被写入b[0] 的内存单元中。这就是为什么看到“damuel ricky”而我看到“samuel ricky”。​​


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

【讨论】:

  • 感谢回复,现在,如何激活-Wall?我用的是windows,我试着打开dev c++ - 工具 - 编译器选项 - 在“添加以下命令......”我写了“-Wall”并检查。但是警告仍然没有出现。
  • @SamuelRicky ah dev-c++,这是一个非常古老的工具,我不知道如何在那里启用它们。如果您正在上课,请询问您的助教,他可能会知道,如果这可能的话..
  • 那么,什么编译器可以使用 -wall ?
  • 我在 Windows 上使用过 EclipseNetbeans。两者都提供了许多警告。 -Wall 用于gcc
【解决方案2】:

声明char c[2] 为包含两个元素的数组分配空间,索引为01。您写入该数组的索引2 会调用undefined behavior

至于为什么您会看到damuel ricky 的结果——许多实现在堆栈上的连续块中分配局部变量(忽略一些必要的填充)。此外,许多调用约定(如 cdecl 调用约定)将局部变量从高内存分配到低内存,就像这样(回想一下,堆栈向低内存增长):

+------+------+------+------+   <-- low memory
| c[0] | c[1] | b[0] | b[1] |
+------+------+------+------+
| b[2] | ...                |
+------+------+------+------+  <-- high memory

因此访问c 的索引2 实际上与访问b 的索引0 相同。仍然请注意,这依赖于实现,您可能不会在使用其他编译器或机器时表现出相同的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-07-30
    • 2016-02-02
    • 1970-01-01
    相关资源
    最近更新 更多