Ошибка выделения памяти при простом назначении значений - PullRequest
0 голосов
/ 22 мая 2018

У меня есть следующий код для получения родительского каталога по заданному пути.Примечание: size_t является typedef для unsigned int .

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

Проблема заключается в том, что иногда добавляетстранный символ «@» в конце строки, которую он возвращает. enter image description here

Мне было интересно, знает ли кто-нибудь, что это было и почему это происходит.

1 Ответ

0 голосов
/ 23 мая 2018

Проблема в том, что вы выделяете только 1 TCHAR, а затем пишете после конца выделенного блока памяти.Ваш код имеет неопределенное поведение .

Вам нужно использовать new _TCHAR[...] вместо new _TCHAR().

Вы также не обрабатываете случай, когда обратные слэши не обнаружены.В этом случае lastBackslash равно 0, хотя 1-й символ не является обратной косой чертой.Вы не проверяете эту возможность.И поскольку ваш цикл использует <= вместо <, он будет копировать этот 1-й символ, когда это не должно быть.

Вместо этого попробуйте что-то более похожее на это:

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<_TCHAR> (если не std::string или std::wstring, или std::u16string или std::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);
}
...