21

谁能帮助我,为什么我在尝试释放分配的内存时收到错误消息:检测到堆损坏。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;
}
4

8 回答 8

50
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 *.
于 2012-11-06T08:29:50.293 回答
13

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

于 2012-11-06T08:29:32.563 回答
9

strcpy包括空终止符;strlen才不是。写:

char *s1 = new char [strlen(s) + 1];
于 2012-11-06T08:29:41.627 回答
6

从 man strcpy(3)

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

所以你需要为字符串和字节保留6字节51NULL

char *s = new char [6];
strcpy(s, "hello");
于 2012-11-06T08:30:20.443 回答
3

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

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);
于 2012-11-06T08:43:10.860 回答
1

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

于 2012-11-06T08:30:17.293 回答
1

您已经损坏了 s2 指针

strcpy(s, "hello");

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

于 2012-11-06T08:32:55.150 回答
0

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

字符 *s = 新字符 [6];

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

于 2012-11-06T08:29:50.800 回答