将堆栈字符串与堆字符串连接会产生奇怪的结果

时间:2011-07-29 10:35:30

标签: c++ windows string memory-management tchar

我确信以下有一个合理的解释,但我有点困惑。

问题在于创建_TCHAR[CONSTANT]_TCHAR*的函数,将它们连接起来并返回结果。

出于某种原因,whatTheHeck()_tmain()的调用会返回乱码。

_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()连接内存地址而不是内容并返回清除堆栈吗?

4 个答案:

答案 0 :(得分: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!
 }

正如你所看到的那样,你们都在使用无偿且鲁莽的new导致内存泄漏,并且你还在本地对象的生命周期内返回它的地址!

我强烈建议

  1. 阅读documentation for strcat并了解“来源”和“目的地”,
  2. 不使用strcat,而是使用更安全的版本,例如strncat
  3. 不使用strncat,而是使用std::string

答案 1 :(得分: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

答案 2 :(得分:0)

未初始化动态分配的内存what。它包含胡言乱语。 _tcscat期望字符串正确地以空值终止。

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

这会将what填充为'\0'个字符。

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

这正确地终止了空字符串。

GetCurrentDirectory不期望缓冲区以空值终止。它写了一些东西,并正确地null终止它。然后,您可以将其传递给连接函数。


作为旁注,您的函数似乎容易受到缓冲区溢出的影响。显然你允许GetCurrentDirectory填写你分配的所有内容,然后你想要附加它而不关心是否还有剩余的空间。

答案 3 :(得分:0)

_TCHAR* what = new _TCHAR[BUFSIZE];
what = _tcscat(Buffer, TEXT("\\"));

你是不是用what覆盖了Buffer,它是函数的局部变量。一旦堆栈被展开,Buffer就会超出范围,从而获得意外的值。这也是内存泄漏。

在堆分配方案中,您可能更愿意将指针声明为const以避免此类危险:

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

更好的方法是使用std::string并摆脱这些小问题。