Повреждение кучи при освобождении памяти

У меня есть следующий класс

 struct CliHandler {
     CliHandler(int argc, char** argv);
     ~CliHandler();

     int doWork();

     int argc_; 
     char** argv_;  
     private:
     CliHandler(const CliHandler&){}
     CliHandler& operator=(const CliHandler&){} 
 };

//Конструктор

 CliHandler::CliHandler(int argc,
 char** argv) {
     //set command line parameters
     argc_ = argc; 

     argv_ = (char**) malloc(argc_ * sizeof(char*));

     for(int i=0; i<argc_; ++i)
     {
         std::cout<<sizeof(argv[i]); 
         argv_[i] = (char*) malloc(strlen(argv[i]) *
 sizeof(char));
         StrCpy(argv_[i], argv[i]);
     } }

// деструктор

 CliHandler::~CliHandler() {
     for(int i=0; i<argc_; ++i)
         free(argv_[i]); 
     free(argv_);  }

Во время отладки я получаю сообщение об ошибке «Обнаружено повреждение кучи. CRT обнаружила, что приложение записало в память после завершения буфера кучи». Мой идентификатор вопроса: «Где именно я делаю ошибку? Как мне это исправить». Я использую visual stdio 2008.

Изменить: я сделал что-то вроде этого, чтобы добавить 1

argv_ [i] = (char *) malloc (strlen (argv [i] + 1) * sizeof (char));

Что ужасно, поскольку он увеличивает указатель argv [i] на единицу. Мой коллега указал на эту тонкую проблему. Должен быть

argv_ [i] = (char *) malloc ((strlen (argv [i]) + 1) * sizeof (char));


person Eternal Learner    schedule 09.05.2011    source источник
comment
Одна вещь, которую я вижу, - это то, что вы не выделяете место для нулевого конца. Должно быть strlen(argv[i]) + 1.   -  person Marius Bancila    schedule 09.05.2011
comment
Почему, если вы используете C ++, вы используете malloc? И почему вы не используете std:; vector и std :: string?   -  person    schedule 09.05.2011
comment
Другая потенциальная проблема, которую я вижу, заключается в том, что вы не следуете Правилу трех. Если произойдет какое-либо копирование, у вас проблемы.   -  person Fred Larson    schedule 09.05.2011
comment
@unapersson - я интегрирую некоторую функцию с унаследованным кодом.   -  person Eternal Learner    schedule 10.05.2011
comment
Ну и что? Вещи, которые вы выделяете, являются частными, поэтому они не могут использоваться непосредственно в устаревшем коде, поэтому вы можете (и должны) реализовать их с помощью векторов и строк. В противном случае вы просто пишете БОЛЬШЕ устаревшего кода.   -  person    schedule 10.05.2011


Ответы (4)


Измените код на:

 argv_[i] = (char*) malloc(strlen(argv[i]) + 1) ; 
 strcpy(argv_[i], argv[i]); 

Это потому, что ваш StrCpy, вероятно, уничтожает вашу память. Вы также должны учитывать завершающий нулевой байт, при условии, что ваш StrCpy работает как стандартный strcpy (который должен быть полезным, лучше просто используйте стандартный strcpy (), если у вас нет веской причины не делать этого).

sizeof (char) по определению равен 1, поэтому его тоже можно опустить.

person nos    schedule 09.05.2011

Вам нужно выделить на один символ больше, чем strlen C-строки, если вы хотите ее скопировать. Это связано с тем, что strlen не считает нулевой символ завершения.

person Mikael Persson    schedule 09.05.2011

Пожалуйста, используйте strdup () - он выделяет правильный объем памяти и копирует символы за вас.

person Community    schedule 09.05.2011
comment
@Arkadiy Нестандартный, невозможно сказать, как освободить, std :: string - бесконечно лучший способ делать что-то, ..... - person ; 09.05.2011
comment
это часть стандарта Posix, и вы избавляетесь от нее с помощью free (). Согласны, что std :: string - правильный способ сделать это. - person ; 10.05.2011
comment
Здесь парень явно использует строки в стиле C. Если он этого хочет, strdup () в порядке. Он находится в стандартной библиотеке C. - person Joshua; 10.05.2011
comment
@Joshua: strdup() не является частью стандартной библиотеки C. Это часть POSIX.1-2001. - person Evan Teran; 10.05.2011
comment
@unapersson: strdup не нестандартно. Это просто не является частью стандарта C. Вместо этого он является частью стандарта POSIX, в котором конкретно говорится, что вам нужно free освободить его. - person Evan Teran; 10.05.2011
comment
@Evan Если этот вопрос был помечен как POSIX, это могло бы быть хорошим аргументом. К сожалению, это не так. - person ; 10.05.2011
comment
@unapersson: Я хочу сказать, что утверждение, что невозможно сказать, как освободить место, не соответствует действительности. Стандарт POSIX очень специфичен. Я согласен, что это не стандартный C, и поэтому он менее переносимый. Но на самом деле POSIX - довольно широко распространенный стандарт. Если вы нацелены на платформу POSIX, нет ничего плохого в ее использовании. - person Evan Teran; 10.05.2011

Если StrCpy чем-то похож на strcpy, он будет записывать на один байт больше, чем возвращает strlen (), обнуление завершает строку.

person Bo Persson    schedule 09.05.2011
comment
Подводя итог, ему нужно добавить место для лишнего байта на 2-м malloc() - person karlphillip; 09.05.2011