【问题标题】:GCC - memcpy automatically copies null character?GCC - memcpy 自动复制空字符?
【发布时间】:2012-09-20 18:15:41
【问题描述】:

来自cplusplus.com 关于memcpy:“该函数不检查源中的任何终止空字符 - 它总是精确复制 num 个字节。”

所以下面的代码应该会给出运行时错误,不是吗?

char str1[20] = "";
char str2[20] = "Another Text---";

memcpy(str1, str2, strlen(str2));
printf("%s\n%s", str1, str2);

但我总是使用我的 gcc 编译器从这段代码中获得正确的输出。这是否意味着 memcpy 实际上是从 str2 末尾复制空字符,还是只是一个随机案例?

编辑:我得到与str1[20] = "A" 相同的行为,因为一些答案指出str1[20] = "" 正在使用所有NULL 字符初始化字符串。

【问题讨论】:

  • 在您的情况下,num bytes 是“Another Text---”的长度,因此将大量字符从缓冲区 str2 复制到缓冲区 str1 不会导致运行时错误。但是,如果 str1 未初始化为 null,则将 str1 用作以 null 结尾的字符串将导致崩溃(可能)。

标签: c gcc


【解决方案1】:

谜题中的关键成分是初始化器""。这等同于:

char str1[20] = { 0 };

这又等同于(至少在 GCC 中,并且总是在 C++ 中):

char str1[20] = { };

char str1[20] = { 0, 0, 0, ..., 0 };   // 20 times

所有这些初始化器都将数组初始化为包含 20 个零。

memcpy 调用确实复制空终止符(因为strlen 不计算在内),但目标数组首先被正确清零,所以一切都很好.

【讨论】:

  • 即使没有初始化器,它也不应该出现运行时错误,这只是意味着 str1 中字符串的末尾会有垃圾,所以当将缓冲区提供给某些东西时,它可能会爆炸需要一个以 null 结尾的字符串。
  • +1,但 {} 初始化器不适用于 C,不幸的是,它只存在于 C++ 中。
  • @Rafi: C99, 6.7.8.21 "如果大括号括起来的列表中的初始值设定项少于聚合的元素或成员的数量,或者 字符串中的字符少用于初始化一个已知大小的数组而不是数组中的元素,聚合的其余部分应隐式初始化,与具有静态存储持续时间的对象相同。" 具有静态存储的对象持续时间是零初始化的。
  • @JensGustedt:gcc 扩展支持空初始化列表(问题被标记为 gcc)。
  • @R.. 我完全同意,这是我已经在两种语言之间的无故差异列表中列出的内容之一:p99.gforge.inria.fr/defects-and-improvements
【解决方案2】:

您已经告诉它复制 strlen(str2) 字符数,这恰好是字符串的长度(空索引)。

它与使用 strcpy() 相同。它想说的是,如果您 需要 复制 NULL,您可以使用 memcpy,因为 strcpy() 将在它找到的第一个 null 处停止。

【讨论】:

    【解决方案3】:

    memcpy 正在将 strlen(str2) (但这并不意味着将空字节复制)字节从 str2 复制到 str1。由于 str1 中有足够的空间容纳这么多字节,因此它可以工作。 memcpy 复制内存完全如它所说。

    如果您尝试将超过 20 的任何内容从一个复制到另一个,您会收到错误消息。您也不应该在任一变量中存储超过 19 个字符。

    正如 kerrek 解释的那样,它还可以帮助您将 str1 初始化为空值,因为在这种特定情况下您不必担心空值终止。

    【讨论】:

    • 这个答案没有抓住重点,Kerrek 的解释更好,特别是目标缓冲区已经 0 初始化这一事实对于理解这里发生的事情至关重要。
    【解决方案4】:

    大于str2的字符串初始化str1,然后再试一次,你会发现它不会复制空值。你很幸运str1 是零填充的。我更改了代码以显示输出对 str1 内容的依赖关系:

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        char str1[20] = "xxxxxxxxxxxxxxxxxxx";
        char str2[20] = "Another Text---";
    
        memcpy(str1, str2, strlen(str2));
        printf("%s\n%s", str1, str2);
    
        return 0;
    }
    

    输出将是:

    Another Text---xxxx
    Another Text---
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-07
      • 2013-02-03
      • 1970-01-01
      • 2022-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多