任何人都可以帮助我,为什么我在尝试释放分配的内存时收到错误消息:检测到堆损坏。 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;
}
答案 0 :(得分:44)
char *s = new char [5];
strcpy(s, "hello");
导致未定义的行为(UB)。
你的写作超出了分配的memery的范围。您为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 *
。答案 1 :(得分:13)
new char [strlen(s)];
不计算结束\0
字符,因此您的缓冲区太短一个字符。
答案 2 :(得分:9)
strcpy
包含空终止符; strlen
没有。写:
char *s1 = new char [strlen(s) + 1];
答案 3 :(得分:6)
来自人strcpy(3):
strcpy()函数复制src指向的字符串, 包括终止空字节('\ 0'),指向的缓冲区 由dest。
因此,您需要为字符串保留6
字节5
,为1
字节保留NULL
char *s = new char [6];
strcpy(s, "hello");
答案 4 :(得分: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);
答案 5 :(得分:1)
您需要指定char *s1 = new char [strlen(s) + 1];
以便为终止字符串的'\0'
腾出空间。
答案 6 :(得分:0)
您的初始字符串s
只有五个字符长,因此无法终止。 "hello"
将strcpy
复制strlen
,包括空终止符,但您将超出缓冲区。 std::string
需要将其终止,所以如果null不在那里,你就会遇到问题。尝试更改此行:
char * s = new char [6];
更好的是,更喜欢new
到C风格的字符串函数 - 它们效率更高,更安全,更易于使用。另外,请尽量避免使用delete
和{{1}},除非您真的必须使用它们。你遇到的问题很常见,很容易避免。
答案 7 :(得分:0)
你已经通过
破坏了s2指针strcpy(s, "hello");
因为s的大小为5,而你错过了strcpy包含字符串终止符。