2011-07-29 85 views
9

我相信以下內容有一個合理的解釋,但我仍然有點困惑。用堆字符串連接堆棧字符串給出奇怪的結果

問題是一個函數創建一個_TCHAR[CONSTANT],一個_TCHAR*,連接它們並返回結果。

由於某種原因,從_tmain()調用whatTheHeck()返回亂碼。

_TCHAR* whatTheHeck(_TCHAR* name) { 
    _TCHAR Buffer[BUFSIZE]; 
    DWORD dwRet; 
    dwRet = GetCurrentDirectory(BUFSIZE, Buffer); 
    _TCHAR* what = new _TCHAR[BUFSIZE]; 
    what = _tcscat(Buffer, TEXT("\\")); 
    what = _tcscat(what, name); 
    return what; 
} 

int _tmain(int argc, _TCHAR* argv[]) { 

    _TCHAR* failure = whatTheHeck(TEXT("gibberish);")); // not again .. 
    _tprintf(TEXT("|--> %s\n"), failure); 

    _TCHAR* success = createFileName(TEXT("readme.txt")); // much better 
    _tprintf(TEXT("|--> %s\n"), success); 

    return 0; 
} 

相比之下,當與堆事情一起工作如預期。

_TCHAR* createFileName(_TCHAR* name) { 
    _TCHAR* Buffer = new _TCHAR[BUFSIZE]; 
    DWORD dwRet; 
    dwRet = GetCurrentDirectory(BUFSIZE, Buffer); 
    Buffer = _tcscat(Buffer, TEXT("\\")); 
    Buffer = _tcscat(Buffer, name); 
    return Buffer; 
} 

爲什麼不同?

難道是因爲_tcscat()連接內存地址而不是它們的內容並返回清除堆棧?

回答

14

代碼有很多問題。讓我們把它拆開,我們應:

_TCHAR* whatTheHeck(_TCHAR* name) // We're inside a local scope 
{ 
    _TCHAR Buffer[BUFSIZE];   // "Buffer" has automatic storage 

    _TCHAR* what = new _TCHAR[BUFSIZE]; // "what" points to newly allocated dyn. memory 

    what = _tcscat(Buffer, TEXT("\\")); // Oh no, we overwrite "what" - leak! 
             // Now what == Buffer. 

    what = _tcscat(what, name); // Equivalent to "_tcscat(Buffer, name)" 

    return Buffer;    // WTPF? We're returning a local automatic! 
} 

正如你所看到的,你都造成內存泄漏與gratuitious和魯莽new,你也回本地對象的地址,過去它的一生!

我強烈recommmend

  1. 閱讀documentation for strcat和了解 「源」 和 「目的地」,
  2. 沒有使用strcat,而是一個更安全的版本,例如strncat
  3. 沒有使用strncat,而是std::string
0

動態分配的內存what指向未初始化。它含有亂碼。 _tcscat期望字符串正確地以null結尾。

_TCHAR* what = new _TCHAR[BUFSIZE](); 

這充滿what'\0'字符。

_TCHAR* what = new _TCHAR[BUFSIZE]; 
what[0] = '\0'; 

這正確地終止了空字符串。

GetCurrentDirectory不希望緩衝區以空終止。它寫了一些東西,並正確地終止它。然後你可以將它傳遞給串聯函數。


作爲一個方面說明,你的函數似乎容易受到緩衝區溢出的影響。顯然,您允許GetCurrentDirectory填寫您分配的所有內容,然後您不需要關心是否還有剩餘空間就可以追加。

+0

分配內存'what'指向泄漏,而不是亂碼的原因。 –

+0

我假設'_tcscat'像'strcat'一樣工作,在這種情況下,結果的賦值應該可以,儘管冗餘(目標指針不會被修改)。 – visitor

+0

它像'strcat'一樣工作。 –

4

這是因爲_tcscat符連接到目的地參數,這是第一個,然後返回。因此,它返回一個指向數組Buffer並且會儲存在what在這條線:

what = _tcscat(Buffer, TEXT("\\")); 

則返回此指針,你不確定的行爲,一旦你嘗試使用它,因爲當地Buffer沒有更長的存在。

此外,上面還行導致分配給what內存被泄露:

_TCHAR* what = new _TCHAR[BUFSIZE]; 
what = _tcscat(Buffer, TEXT("\\")); // this loses the memory allocated 
            // in the previous line 
0
_TCHAR* what = new _TCHAR[BUFSIZE]; 
what = _tcscat(Buffer, TEXT("\\")); 

你不覆蓋whatBuffer這是一個局部變量的函數。一旦堆棧解除,Buffer超出範圍,因此你會得到意想不到的價值。這也是內存泄漏。

在堆中分配方案,你可能更願意申報指針const避免這樣的危險:

_TCHAR* const what = new _TCHAR[BUFSIZE]; 
     ^^^^^ (avoids overwriting) 

更好的方法是使用std::string和是出於這樣的小問題。