Почему возврат указателя malloc в данном случае приводит к бесплатному «HEAP CORRUPTION»? - PullRequest
1 голос
/ 15 сентября 2011

примечание: пожалуйста, подавьте комментарии о "C ++? Использовать std :: string!" . Этот вопрос использует строки C, но больше касается управления памятью, чем строк в целом.

У меня есть эта функция

char* strclone( char* src )
{
    char* dst = (char*)malloc(strlen(src+1));
    strcpy(dst,src);
    return dst;
}

Функция должна работать для выделения нового указателя (в strclone), записи в него строки в src и возврата адреса новой строки.

Однако, когда строка free d, через некоторое время в программе:

str = strclone( some_str_variable );    
// ..code..
free( str ) ; //! ERROR!  

Ошибка гласит:

Ошибка отладки! Программа: C: \ ... ОБНАРУЖЕНА КОРРУПЦИЯ КАРТЫ: после блока Normal (# 39713) в 0x090CC448. CRT обнаружил, что приложение записало в память после завершения буфера кучи.

Ошибка возникает в строке, где я вызываю free( str ) в программе. Если я изменю назначение str на это:

str = (char*)malloc( strlen( some_string_variable ) +1);
strcpy( str, some_string_variable ) ;
//...
free( str ) ; //fine now

Тогда ошибок нет, программа работает отлично.

Почему функция strclone не работает должным образом?

Ответы [ 5 ]

15 голосов
/ 15 сентября 2011

Я считаю, что проблема в том, что вы написали

(char*)malloc(strlen(src+1));

Обратите внимание, что при вызове strlen вы написали

strlen(src + 1)

вместо

strlen(src) + 1

В этой первой строке указано «длина строки, начинающейся на один символ после src», то есть длина строки минус один (или общая сумма мусора, если строка пуста) Второй - тот, который вам нужен - длина строки плюс один для нулевого терминатора. Если вы используете первую версию, то в строке

strcpy(dst,src);

Вы закончите писать за концом буфера, что приведет к страшному неопределенному поведению. В вашем случае это проявлялось в ошибке повреждения кучи, когда вы пытались освободить блок, что имеет смысл, потому что вы действительно повредили кучу!

Попробуйте убрать +1 из скобок и посмотрите, все ли исправлено.

В качестве альтернативы, большинство компиляторов поставляются с нестандартной функцией под названием strdup, которая делает именно то, что пытается сделать указанная выше функция. Возможно, вы захотите использовать это вместо этого.

Надеюсь, это поможет!

3 голосов
/ 15 сентября 2011

strlen(src+1) не совпадает с strlen(src)+1. Таким образом, вы перезаписываете границы вашего массива двумя элементами, когда делаете это для strcpy.

Так что я думаю, что оправдано: C ++? Используйте std::string!

0 голосов
/ 15 сентября 2011

Ошибка возникает из-за того, что вы на самом деле пишете за выделенную память. измените свою строку malloc на это:

char* dst = (char*)malloc(strlen(src)+1);

Поскольку в исходной реализации вы продвигаете указатель на 1, а затем передаете его в strlen (), что даст вам длину строки-1. Так как вам также нужен NULL в конце, вы фактически не на 2.

0 голосов
/ 15 сентября 2011

Полагаю, вы должны были набрать

char* dst = (char*)malloc(strlen(src) + 1);

вместо

char* dst = (char*)malloc(strlen(src+1));
0 голосов
/ 15 сентября 2011

Попробуйте это:

malloc(strlen(src)+1);

...