2011-07-29 88 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和是出于这样的小问题。