2012-11-06 71 views
17

任何人都可以幫助我,爲什麼我在嘗試釋放分配的內存時收到錯誤消息:檢測到堆損壞。 CTR檢測到應用程序在堆緩衝區結束後寫入內存。C++ new/delete和char *

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; 
} 
+9

顯然,這僅僅是一個鍛鍊和在真實設置你將使用'std :: string'來代替,對吧? –

+0

@MatthieuM。絕對正確。我不允許使用std :: string; – user1448906

回答

41
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

同意使用'std :: string'是最好的方法。在你的答案的中途編寫改進的'new'分配的另一種方式是'char * s = new char [sizeof(「hello」)]',避免在運行時調用'strlen()'(儘管是一個智能編譯器可能可以優化它)。這顯然只適用於你有一個常量字符串,但是,這可能不是常見的情況。 –

13

new char [strlen(s)];不計收\0性格,所以你的緩衝區是一個字符太短。

9

strcpy包括空終止符; strlen沒有。寫:

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

您的初始字符串s只有5個字符長,因此不能以NULL結尾。 "hello"將被複制strcpy包括空終止符,但你會超出緩衝區。 strlen需要它是空終止的,所以如果空不在那裏,你會遇到問題。嘗試改變這一行:

char * s = new char [6];

更妙的是,喜歡std::string到C風格的字符串函數 - 他們只是作爲高效,安全很多,更容易使用。另外,儘量避免使用newdelete,除非你真的必須使用它們。你遇到的問題非常普遍,很容易避免。

1

你需要指定char *s1 = new char [strlen(s) + 1];以騰出空間給其終止字符串的'\0'

6

從人strcpy(3)

的的strcpy()函數將字符串由src指出, 包括終止空字節( '\ 0'),到緩衝器dest指向到 。

所以你需要通過

strcpy(s, "hello"); 

由於S有大小5預留6字節5的字符串和1NULL字節

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

你已經損壞S2指針,而你錯過了strcpy包含字符串結束符。

3

迄今爲止所有的答案都解決了第一次或第二次分配。歸納起來,有改變,你必須:

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

在這兩種情況下,你必須爲字符串加上終止「\ 0」一個字節分配足夠的空間。

正如其他人已經指出的那樣,使用C++可以更容易和更安全地使用std::string

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; 
} 

,如果它只是複製字符串:與分配和釋放內存或關注「\ 0」字節無事

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