【问题标题】:Allocate room for null terminating character when copying strings in C?在C中复制字符串时为空终止字符分配空间?
【发布时间】:2010-12-07 13:41:23
【问题描述】:

const char* src = "你好";

调用 strlen(src); 返回大小 5...

现在说我这样做:

char* dest = new char[strlen(src)];
strcpy(dest, src);

这似乎不应该起作用,但是当我输出所有内容时,它看起来都是正确的。看来我最后没有为空终止符分配空间......这是对的吗?谢谢

【问题讨论】:

    标签: c++ c-strings


    【解决方案1】:

    您没有为终结者分配空间是正确的,但是不这样做并不一定会导致您的程序失败。您可能正在覆盖堆上的以下信息,或者您的堆管理器会将分配大小四舍五入为 16 字节的倍数或其他内容,因此您不一定会看到此错误的任何明显影响。

    如果您在Valgrind 或其他堆调试器下运行您的程序,您或许能够更快地检测到这个问题。

    【讨论】:

    • 哈哈谢谢,我一定是走运了……我做的时候好像不太对。
    • 我会说你越来越不走运了。理想情况下,这总是会导致错误,但不幸的是,在现实世界中,有些错误不会立即出现。
    【解决方案2】:

    是的,您应该至少分配 strlen(src)+1 个字符。

    【讨论】:

      【解决方案3】:

      这似乎不应该起作用,但是当我输出所有内容时,它看起来都正确。

      欢迎来到未定义行为的世界。当你这样做时,任何事情都可能发生。你的程序会崩溃,你的电脑会崩溃,你的电脑会爆炸,demons can fly out of your nose

      最糟糕的是,你的程序可以运行得很好,看起来它运行正常,直到有一天它开始吐出垃圾,因为它在某处覆盖敏感数据,因为在某处,有人为其分配了一个太少的字符数组,现在你已经损坏了堆,并且在一百万英里外的某个点出现了段错误,或者更糟糕的是,你的程序很高兴地伴随着损坏的堆而运行,并且你的函数在损坏的信用卡号上运行,你得到了巨大的麻烦。

      即使看起来有效,但实际上并没有。那是未定义的行为。避免它,因为你永远无法确定它会做什么,即使你尝试它时它的作用是好的,但在另一个平台上可能就不行了。

      【讨论】:

        【解决方案4】:

        我读过的最好的描述(在stackoverflow上)是这样的:

        如果限速为 50,而您以 60 的速度开车。您可能会走运而没有得到罚单,但有一天可能不是今天,也可能不是明天,但总有一天那个警察会等您。到那一天你会付出,你会付出惨痛的代价。

        如果有人能找到原文,我宁愿指出他们比我的解释更有说服力。

        【讨论】:

        • 至少在这种情况下,您知道为什么要付出高昂的代价。在 C 的情况下,您可能会看到“随机”崩溃或逻辑变化,而且根本原因并不总是很容易找到。
        【解决方案5】:

        strcpy 将复制空终止字符以及所有其他字符。

        因此,您将hello + 1 的长度(即 6)复制到大小为 5 的缓冲区中。

        但是,这里存在缓冲区溢出,并且覆盖不属于您自己的内存将产生未定义的结果。

        【讨论】:

          【解决方案6】:

          或者,您也可以使用 dest = strdup(src) 为字符串分配足够的内存 + 1 用于空终止符(+1 用于 Juliano 的回答)。

          【讨论】:

          • 我再次做出“注意strdup() 是非标准函数,可能不适用于任何给定平台”的评论。
          【解决方案7】:

          这就是为什么您应该始终、始终、始终在任何看起来可以工作的 C 程序上运行 valgrind

          【讨论】:

            【解决方案8】:

            是的,每个人都谈到了重点;你不能保证失败。事实上,空终止符通常为 0,而 0 是位于任何特定内存地址中的非常常见的值。所以它恰好起作用。您可以通过获取一组内存,向其中写入一堆垃圾然后在其中写入该字符串并尝试使用它来测试这一点。

            无论如何,我在这里看到的主要问题是你在谈论 C 但你有这行代码:

            char* dest = new char[strlen(src)];
            

            这不会在任何标准 C 编译器中编译。 C 中没有 new 关键字。那是 C++。在 C 中,您将使用其中一种内存分配函数,通常是malloc。我知道这看起来很琐碎,但实际上并非如此。

            【讨论】:

            • 不,他的问题也被明确标记为 C++。只是他的问题标题提到了 C(还有 strlen()strcpy() 是 C 函数的事实)。分配并不重要 - 重要的部分是不正确的分配长度和未定义的行为。
            • @Chris Lutz,我不确定你的意思......问题的标题是“在 C 中复制字符串时为空终止字符分配空间?”今晚我看到了几个关于在 C 中使用“new”的问题,所以我只是想指出这一点,以避免任何阅读这个可能对 C 编程语言不熟悉的 SO 线程的人感到困惑。
            • 我认为很多人会交替谈论 C 和 C++,因为这两种语言之间有很多重叠之处。我知道当我真正指的是 C++ 时,我一直因为提到 C 而感到内疚。这两个额外的音节只需要 so long 才能说出来。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-11-05
            • 2012-01-02
            • 2021-06-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-04-07
            相关资源
            最近更新 更多