Проблема с выделением строки в 'new' - PullRequest
0 голосов
/ 20 августа 2010

Если есть сомнения, обратитесь к Stackoverflow ...

У меня проблема с выделением строк. Моя цель - сохранить длину переданной строки в кавычках. Я проверяю m_p на ноль, потому что думаю, что в режиме отладки MS любит устанавливать адрес 0xcccccccc вместо 0x00000000

Я прошел 1 в длину. Но когда я выделяю его с помощью new, я получаю около 15 символов в m_p. Как это может быть, если m_size = lenth + 1 равно 2? Я ожидаю, что он выделит только две ячейки. Как я могу ограничить его длиной + 1?

 String::String(const char *str, int length) {
 m_size = length + 1;  // make room for null-terminated string

 if (m_p != NULL)
  m_p = NULL;

 try
 { 
  m_p = new char[m_size]; 
 }
 catch (bad_alloc e)
 {
  throw e;
 }

 strncpy(m_p, str, m_size); 
}

Ответы [ 8 ]

4 голосов
/ 20 августа 2010

Позвольте мне здесь указать на недостатки:

  • Вы не улавливаете проблемы выделения с обработкой исключений, вы проверяете возвращаемое значение для NULL.
  • Зачем использовать strncpy, еслиВы знаете размер источника и назначения?memcpy - самый быстрый вариант здесь.
  • Начальные значения ваших переменных не определены и будут варьироваться в зависимости от платформы и конфигурации.Не беспокойтесь о том, каким был m_p раньше, просто присвойте значение.
  • m_p - ужасное имя.Это не говорит, что это такое!m_pString хотя бы?
  • Поймать исключение и выбросить его?Зачем?
  • Ты не заканчиваешь строку.Это главная проблема.Ваша исходная строка завершена?Похоже, что в итоге вы получите неопределенную строку.
  • Как уже отмечалось, существуют готовые к использованию классы STL, которые делают все для вас и используются уже десятилетия.
3 голосов
/ 20 августа 2010

Вы уверены, что фактическая длина str соответствует length?

http://www.cplusplus.com/reference/clibrary/cstring/strncpy/

Нет нулевого символа неявно добавляется в конец пункта назначения, так пункт назначения будет только заканчивается на ноль, если длина C строка в источнике меньше чем num.

1 голос
/ 20 августа 2010

Можете ли вы использовать std::string и наблюдать, как все ваши ошибки, связанные со строками, просто исчезают?

1 голос
/ 20 августа 2010

Где вы видите 15 символов? Диспетчер памяти может решить выделить более 2 байтов (из-за оптимизации). Или может быть другое выделение памяти после 2 байтов, которое по некоторому совпадению также принадлежит вашей программе. Даже если вы видите 15 символов в отладчике Visual C ++, это не значит, что вы можете безопасно обращаться к ним в своем коде, поскольку вам гарантировано только то, что у вас выделено 2 байта.

Я также вижу некоторые другие проблемы в вашем коде:

if (m_p != NULL) m_p = NULL;

Это приведет к утечке памяти, если m_p уже был выделен. Вы должны установить m_p в NULL в вашем конструкторе и затем заменить вышеуказанную строку на:

if (m_p != NULL)  {
  delete[] m_p;
  m_p = NULL;
}

Если вы используете эту часть кода только в конструкторе, простой m_p = NULL; сделает свое дело.

Также блок try .. catch не имеет особого смысла, так как вы сразу же перезапускаете исключение. Либо сразу обработайте его в блоке catch, либо просто полностью удалите try catch.

0 голосов
/ 20 августа 2010

Другие ответы верны в отношении strncpy .Это, вероятно, источник проблемы, о которой вы спрашиваете.

Но я обеспокоен этим утверждением:

Я проверяю m_p на ноль, потому что я думаю, что в режиме отладки MSлюбит устанавливать адрес 0xcccccccc вместо 0x00000000.

Он только устанавливает неинициализированные указатели на 0xcccccccc.Это делает это, чтобы помочь поймать места, где ваш код предполагает, что неинициализированный указатель установлен в 0x00000000.В C ++ вы всегда должны помнить, что примитивные типы (указатели, char, short, int, float и т. Д.) Не имеют гарантированного значения, если их оставить неинициализированными.

Так что если вы оставляете этот указатель неинициализированным в режиме выпуска, иногда это можетбыть 0x00000000 и иногда это могут быть значения мусора, которые не равны нулю.И это очень вероятно вызовет проблемы в том, что вы пытаетесь сделать.

if (m_p != NULL) m_p = NULL; не является решением.Решение состоит в том, чтобы установить m_p в NULL в конструкторе вашего класса.Таким образом, вы гарантируете, что он имеет правильное значение, когда вы ожидаете.

0 голосов
/ 20 августа 2010

Я думаю, что вы наблюдаете отладчик, отображающий то, что находится в ячейке памяти, на которую указывает m_p.Отладчик отображает символы массива char до тех пор, пока не увидит нулевой символ, который вы не добавили в строку C, поэтому около 15 символов, добавленных , которые вы упомянули.Прочитайте другие ответы на свои вопросы, они помогут смягчить этот эффект в целом.

0 голосов
/ 20 августа 2010

Если вы хотите сохранить n символов переданной строки в кавычках, вам необходимо учитывать, что strncpy не добавляет нулевой символ, если длина исходной строки больше или равна аргументу length.Поэтому вы должны позаботиться об этом:

strncpy(m_p, str, length); // or strncpy(m_p, str, m_size-1);
m_p[length] = '\0'; // or m_p[m_size-1] = '\0'
0 голосов
/ 20 августа 2010

Как вы решаете, что в m_p "15 символов символов"?

'm_p' (я предполагаю) - это просто char *. Когда вы выделяете память с новым, это дает вам указатель на это. Эта память, выделенная вам, может быть длиной всего 2 байта, но сразу после нее еще больше памяти - которая сейчас или скоро будет назначена кому-то другому.

Теперь, если вы посмотрите на *m_p в отладчике (или распечатаете его), предполагается, что это строка с нулевым завершением, поэтому она будет продолжать печатать символ до тех пор, пока не достигнет 0-байт. Независимо от того, являются ли все эти символы частью назначенного вам блока, не имеет значения.

...