【问题标题】:c++ new/delete and char *c++ new/delete 和 char *
【发布时间】:2012-10-26 04:12:30
【问题描述】:

谁能帮助我,为什么我在尝试释放分配的内存时收到错误消息:检测到堆损坏。 CTR 检测到应用程序在堆缓冲区结束后写入内存。

char *ff (char *s){
    char *s1 = new char [strlen(s)];
    strcpy(s1, s);
    return s1;
}

int _tmain(int argc, _TCHAR* argv[])
{
    char *s = new char [5];

    strcpy(s, "hello");
    char *s2 = ff(s);

    delete []s;     // This works normal
    delete []s2;    // But I get an error on that line
    return 0;
}

【问题讨论】:

  • 显然,这只是一个练习,在真实环境中你会使用std::string,对吧?
  • @MatthieuM。绝对正确。我不允许使用 std::string;

标签: c++ char new-operator


【解决方案1】:
char *s = new char [5];
strcpy(s, "hello");

导致未定义行为(UB)
您正在写超出分配内存的范围。您为5 字符分配了足够的内存,但您的字符串包含6 字符,包括\0

一旦你的程序导致了这个 UB,所有的赌注都被取消了,任何行为都是可能的。

你需要:

char *s = new char [strlen("hello") + 1];

事实上,理想的解决方案是使用std::string 而不是char *。这些正是std::string 避免的错误。在您的示例中并没有真正需要使用char * 而不是std::string
std::string

  • 你不需要new 任何东西
  • 你不需要delete任何东西&
  • 您可以使用std::string 完成所有操作,就像使用char * 一样。

【讨论】:

  • 同意使用std::string 是最好的方法。在您的答案中途编写改进的new 分配的另一种方法是char *s = new char[sizeof("hello")],避免在运行时调用strlen()(尽管智能编译器可能会优化它)。不过,这显然只有在你有一个常量字符串时才有效,这可能不是常见的情况。
【解决方案2】:

new char [strlen(s)]; 不计算结束 \0 字符,因此您的缓冲区太短了一个字符。

【讨论】:

    【解决方案3】:

    strcpy 包含空终止符; strlen 没有。写:

    char *s1 = new char [strlen(s) + 1];
    

    【讨论】:

      【解决方案4】:

      来自strcpy(3)

      strcpy()函数复制src指向的字符串, 包括终止空字节 ('\0'),指向指向的缓冲区 按目的地。

      所以你需要为字符串保留6字节5,为NULL字节保留1

      char *s = new char [6];
      strcpy(s, "hello");
      

      【讨论】:

        【解决方案5】:

        到目前为止,所有答案都解决了第一个或第二个分配问题。总而言之,您必须进行两个更改:

        char *s1 = new char [strlen(s) + 1];
        ...
        char *s = new char [5 + 1];
        

        在这两种情况下,您都必须为字符串分配足够的空间加上一个字节用于终止的'\0'

        正如其他人已经指出的那样,在 c++ 中使用std::string 更容易、更安全。不用大惊小怪分配和释放内存或注意'\0'字节:

        std::string ff (const std::string &s){
            std::string s1(s);
            // do something else with s1
            return s1;
        }
        
        int main(int argc, char* argv[])
        {
            std::string s("hello");
            std::string s2 = ff(s);
            return 0;
        }
        

        如果只是复制字符串:

        std::string s("hello");
        std::string s2(s);
        

        【讨论】:

          【解决方案6】:

          您需要指定char *s1 = new char [strlen(s) + 1]; 为终止字符串的'\0' 腾出空间。

          【讨论】:

            【解决方案7】:

            你已经损坏了 s2 指针

            strcpy(s, "hello");
            

            因为 s 的大小为 5,而您错过了 strcpy 包含字符串终止符。

            【讨论】:

              【解决方案8】:

              您的初始字符串 s 只有五个字符长,因此不能以空值结尾。 "hello" 将被 strcpy 复制,包括空终止符,但您将超出缓冲区。 strlen 需要它以空值终止,因此如果空值不存在,您将遇到问题。尝试更改此行:

              char *s = 新字符 [6];

              更好的是,比起 C 风格的字符串函数,更喜欢 std::string - 它们同样高效,更安全,更易于使用。另外,尽量避免使用newdelete,除非你真的必须使用它们。您遇到的问题很常见,很容易避免。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2017-12-07
                • 2012-05-06
                • 2023-03-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-05-14
                相关资源
                最近更新 更多