【问题标题】:Memory allocation error when simply assigning values简单赋值时的内存分配错误
【发布时间】:2018-11-01 17:22:06
【问题描述】:

为了从给定路径获取父目录,我有以下代码。 注意:size_tunsigned inttypedef

/****************************************************
This function takes a full path to a file, and returns
the directory path by returning the string up to the last backslash.

Author: Aashish Bharadwaj
*****************************************************/
_TCHAR* GetDirectoryFromPath(const _TCHAR* path)
{
   size_t size = _tcslen(path);
   size_t lastBackslash = 0;
   for (size_t i = 0; i < size; i++)
   {
      if (path[i] == '\\')
      {
         lastBackslash = i;
      }
   }

   _TCHAR* dirPath = new _TCHAR();
   size_t i;
   for (i = 0; i <= lastBackslash; i++)
   {
      dirPath[i] = path[i];
   }
   dirPath[i + 1] = '\0';  //THIS IS VERY NECESSARY! Otherwise, a bunch of garbage is appended to the character array sometimes.

   return dirPath;
}

问题是有时它会在返回的字符串末尾附加一个奇怪的“@”符号。

我想知道是否有人知道这是什么以及为什么这样做。

【问题讨论】:

  • _TCHAR* dirPath = new _TCHAR(); 分配了多少个_TCHAR
  • " 它分配一个指向未指定大小的 _TCHAR 数组的指针。它会在您向其附加字符时自动调整大小。" - 这两种说法都是错误的。
  • 听起来你真的可以使用good C++ book。您对手动内存管理的工作方式有很多误解,并且程序无法按预期工作的事实证明您的数组分配不正确。
  • “它会自动调整大小”——不,它不会。 “这就是堆的工作方式” - 不,不是。如果您只是想否认所提供的知情建议的有效性,那么在这里提问真的没有意义。
  • @AashishBharadwaj 该代码具有未定义的行为并且正在破坏内存,因为它正在访问它尚未分配的非法内存。 new int() 分配 1 且仅 1 inthowdy[0]*(howdy+0) 在这种情况下有效,但 howdy[1]*(howdy+1) 超出范围且无效。

标签: c++ unicode mfc tchar


【解决方案1】:

问题是您分配仅 1 TCHAR,然后您正在写入超出已分配内存块的末尾。您的代码有未定义的行为

您需要使用new _TCHAR[...] 而不是new _TCHAR()

您也没有处理没有找到反斜杠的情况。在这种情况下,lastBackslash 为 0,即使第一个字符不是反斜杠。您没有检查这种可能性。而且由于您的循环使用的是&lt;= 而不是&lt;,因此它最终会在不应该复制第一个字符时复制。

试试类似的方法:

const size_t c_invalid_index = (size_t) -1;

_TCHAR* GetDirectoryFromPath(const _TCHAR* path)
{
    size_t lastBackslash = c_invalid_index;

    size_t size = _tcslen(path);
    for (size_t i = 0; i < size; ++i)
    {
        if (path[i] == _T('\\'))
        {
            lastBackslash = i;
        }
    }

    if (lastBackslash == c_invalid_index)
        return NULL;

    _TCHAR* dirPath = new _TCHAR[lastBackslash + 2];
    for (size_t i = 0; i <= lastBackslash; ++i)
    {
        dirPath[i] = path[i];
    }
    dirPath[lastBackslash + 1] = _T('\0');

    return dirPath;
}

或者:

_TCHAR* GetDirectoryFromPath(const _TCHAR* path)
{
    const _TCHAR *lastBackslash = NULL;

    size_t size = _tcslen(path);
    for (size_t i = 0; i < size; ++i)
    {
        if (path[i] == _T('\\'))
        {
            lastBackslash = &path[i];
        }
    }

    if (!lastBackslash)
        return NULL;

    size = (lastBackslash - path) + 1;

    _TCHAR* dirPath = new _TCHAR[size + 1];
    for (size_t i = 0; i < size; ++i)
    {
        dirPath[i] = path[i];
    }
    dirPath[size] = _T('\0');

    return dirPath;
}

话虽如此,你真的不应该像这样使用原始字符串指针。改用std::basic_string&lt;_TCHAR&gt; 会更安全、更干净(如果不是std::stringstd::wstring,或std::u16stringstd::u32string 在C++11 及更高版本中),例如:

#include <string>

typedef std::basic_string<_TCHAR> tstring;

...

tstring GetDirectoryFromPath(const tstring &path)
{
    tstring::size_type pos = path.find_last_of(_T('\\'));
    if (pos == tstring::npos)
        return tstring();
    return path.substr(0, pos+1);
}

【讨论】:

  • 非常感谢您的回答。不幸的是,使用 new _TCHAR[number] 也没有用。
  • 我发现问题实际上只是 dirPath[i + 1] = '\0' 应该是 dirPath[i] = '\0'。
  • 我认为我仍然应该使用新的 _TCHAR[...] 而不是 _TCHAR()。
  • 请注意,当 TCHAR 为 char 时,简单的循环是不够的。在具有多字节字符集的系统上,多字节字符可能包含一个反斜杠字符 (0x5C) 作为尾随字节。使用 find_last_of(),_tcsrchr() 等库函数比比较字节更安全。
猜你喜欢
  • 2011-02-17
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 2021-06-03
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
  • 2020-03-29
相关资源
最近更新 更多