В C строки - это последовательность символов, оканчивающаяся нулевым байтом.У вас есть ряд отдельных ошибок, в основном связанных с неучтением этого факта, а также утечек памяти.
Когда вы впервые устанавливаете message
в main
:
char *message = "";
message = realloc(NULL, 0);
message
либо равен NULL, либо указывает на 0 байт памяти.Когда вы звоните, то звоните rean
в первый раз:
int mln = strlen( message );
Вы либо пытаетесь разыменовать нулевой указатель, чтобы прочитать после конца выделенной памяти.Вы хотите выделить как минимум 1 байт для запуска и установить этот байт в 0, чтобы у вас была пустая строка:
char *message = realloc(NULL, 1);
message[0] = '\0';
Затем, когда вы скопируете буфер в сообщение:
message = realloc(message, nln);
memmove(message + mln, buf, bln);
Вы не выделяете достаточно места для завершающего нулевого байта и не копируете его, поэтому у вас нет строки.Когда вы затем пытаетесь распечатать его, либо puts
, либо printf
читает после конца выделенной памяти.Вам нужно выделить 1 дополнительный байт и скопировать 1 дополнительный байт:
message = realloc(message, nln + 1); // allocate 1 extra byte for the null terminator
memmove(message + mln, buf, bln + 1); // copy 1 extra byte
При повторном копировании чего-либо после 20 символов возникают похожие проблемы:
int exl = nln -20; // leftover length
char *lo = realloc(NULL, exl); // leftover placeholder
memmove(lo, message+20, exl); // copy leftover
wbuff(message); // write clear buff
message = realloc(NULL, nln);
message = realloc(NULL, exl); // resize buffer
memmove(message, lo, exl); // restore leftover
- строки 2-3: Вы не выделяете место для завершающего нулевого байта для
lo
и не копируете его. - строка 5: утечка памяти, ранее сохраненная
message
в первом realloc
, путем передачи присваивания message
при использовании NULL
в качестве первого аргумента - строка 6-7: Вы теряете память, выделенную в строке 5, делая то же самое.Кроме того, вы снова не выделяете место для нулевого байта и не копируете его на следующую строку.
Как и раньше, выделяйте 1 дополнительный байт для каждого выделения и перемещайте 1 дополнительный байт на счетдля нулевого терминатора.Кроме того, освободите lo
в конце блока, удалите лишние realloc
для message
и передайте предыдущее значение от message
до realloc
, чтобы не допустить утечки памяти:
int exl = nln -20;
char *lo = realloc(NULL, exl + 1); // allocate 1 extra byte
memmove(lo, message+20, exl + 1); // copy 1 extra byte
wbuff(message);
// remove extra realloc
message = realloc(message, exl + 1); // pass in old message, allocate 1 extra
memmove(message, lo, exl + 1); // copy 1 extra byte
free(lo); // free leftover
Все эти проблемы чтения и записи после окончания выделенной памяти вызывают неопределенное поведение , которое объясняет, почему вы видите разные результаты в разных операционных системах.
Что касается кода, соответствующегоидет, используйте fgets
intead из gets
:
fgets(line, sizeof(line), stdin);
Эта функция будет включать новую строку в line
, если есть место для этого, поэтому обязательно удалите ее, если это так.
Также измените main
, чтобы он возвращал int
, и удалите #include <malloc.h>
, поскольку семейство функций malloc
определено как находящееся в stdlib.h
.
Если вы использовали strcpy
иstrcat
вместо memmove
вам не пришлось бы учитывать копирование нулевого завершающего байта, поскольку эти функции делают это за вас.Однако вам все равно придется учитывать это при распределении памяти.Также нет конфликта между strcpy
, malloc
и realloc
, так как все они являются частью стандарта и работают вместе должным образом.Использование их вместе - не проблема.Если они не работают должным образом, вы не используете их правильно.
После применения моих обновлений вы можете заменить это:
memmove(message + mln, buf, bln + 1);
на это:
strcat(message, buf);
И замените это:
memmove(lo, message+20, exl + 1); // copy leftover
...
memmove(message, lo, exl + 1); // restore leftover
На это:
strcpy(lo, message+20);
...
strcpy(message, lo);
И оно все равно будет работать должным образом и будет соответствовать.