【问题标题】:Overwritting null character in C array覆盖C数组中的空字符
【发布时间】:2015-06-27 15:24:30
【问题描述】:

考虑案例:

char s1[] = "abc";
s1[3] = 'x';
printf("%s", s1);

据我所知,printf 会打印字符,直到找到空字符然后停止。

当我用'x' 覆盖空字符时,为什么printf 正确打印s1 数组?它如何找到空字符?

【问题讨论】:

  • 小心区分 array(其中每个元素可以保存任何值)和 C 字符串(根据定义,它在第一个 0 代码处结束)。您的代码将恰好形成有效 C 字符串的数组转换为无效 C 字符串。

标签: c arrays


【解决方案1】:

您的printf 调用调用undefined behaviour,因为s1 没有零(又名空字节)终止符。 s1 是一个由 4 个字符组成的数组,重写空字节不是问题。 之后

s1[3] = 'x';

s1 将变为:

[a][b][c][x]

但您不能将其打印为字符串。根据定义,C 中的字符串是一个以空字节结尾的字节序列。这次它只是碰巧起作用了,但你永远不应该依赖它。

【讨论】:

    【解决方案2】:

    只是表示这个数组之后内存中不小心多了一个空字符。:)

    你可以试试下面的例子

    char s0[] = "xxx";
    char s1[] = "abc";
    char s2[] = "yyy";
    s1[3] = 'x';
    printf("%s",s1);
    

    看看结果。

    【讨论】:

    • 我编译了你的代码,我更困惑了。我得到了:“abcxxxx”,我认为 'y' 将是最后一个字符。
    • @Higgs 未指定编译器放置局部变量的顺序。
    • @Higgs 考虑到通常当一个新的局部变量被添加到堆栈时,堆栈地址会减少。所以 s0 在堆栈中有更高的地址。
    • 哈。是的,你是对的,我忘记了堆栈地址,我现在记得了。谢谢。
    【解决方案3】:

    printf 函数将打印所有字符,直到遇到空字符。

    在您的情况下,您已经开始访问超出分配的内存并且访问超出分配的内存是未定义的行为

    在这种情况下,它碰巧是 nul。

    【讨论】:

      【解决方案4】:

      如果它打印“abcx”。这意味着 s1[4] 中已经有一个空值。堆栈上的值取决于先前的操作。所以它可能在那个位置总是一个零,但更有可能发生的是,当你调试代码时有一个零并且没有任何问题,但是在发布时,一个零没有放在那个位置,你最终会有一个难以调试的错误。

      语言定义未定义并不意味着实现中未定义。例如,在调试模式下编译时,MS Visual Studio 会将内存设置为可预测的值以帮助调试。 When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?

      【讨论】:

      • 这是正确的,但事实是代码调用了未定义的行为,所以this 是一个更具体的答案,因为当未定义的行为发生时,可能的事情之一是它可以正常工作,我不知道'不按预期说,因为你不能期望给定的行为。
      • 语言定义未定义,但可以在实现中定义,也可以在实现中可预测,或者在重复使用相同数据运行时在特定编译程序中。
      猜你喜欢
      • 1970-01-01
      • 2015-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-29
      • 1970-01-01
      • 1970-01-01
      • 2017-01-24
      相关资源
      最近更新 更多