Это правильное использование realloc ()? - PullRequest
0 голосов
/ 31 декабря 2018

Я хочу, чтобы пользователь мог вводить то, что он хочет сделать.Будут и другие варианты, но сейчас я работаю над «вставить».Другими двумя вариантами будут «поиск» и «удаление».

int main() {

    char *input = malloc(sizeof(char) * 6);
    printf("%s", "WELCOME TO USER'S SKIP LIST!\n\nWhat do you wish to do? ");
    scanf("%6s", input);
    if (strcmp(input, "insert") == 0) {
        printf("%s", "What is the item? ");
        input = realloc(input, (size_t)scanf("%s", input));
    }
}

Я изначально выделил достаточно памяти для input, чтобы иметь 6 символов.Это потому, что в двух других вариантах также будет только 6 символов.После того, как они введут insert, им нужно будет ввести элемент, который будет иметь любое количество символов, поэтому я хочу перераспределить память для input в зависимости от того, что они вводят для элемента.Поэтому, если они введут Nintendo Switch, будет перераспределение для 15 символов.Является ли моя реализация realloc() правильным способом сделать это?

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

Полагаю, вы в первую очередь спрашиваете об этом:

    input = realloc(input, (size_t)scanf("%s", input));

Нет, это не правильно использование из realloc().В этой строке есть как минимум четыре различных проблемы, в том числе:

  • scanf() возвращает количество входных элементов, успешно отсканированных и записанных, или EOF в случае возникновения ошибки.«Входные элементы» соответствуют директивам поля, таким как ваш %s, так что конкретный вызов scanf() никогда не вернет значение больше 1. Однако он может вернуть либо 0, либо EOF (обычно -1).

  • Даже если scanf() вернул количество прочитанных символов,

    • Любое перераспределение было бы слишком поздно.Данные сохраняются в предоставленном пространстве на scanf(), и если пространство недостаточно велико, его границы будут заполнены до любой возможности для перераспределения.

    • Пространство не зарезервированодля ограничителя строки.

    • realloc() может завершиться ошибкой, в этом случае возвращается NULL.Даже если вы проверите это, изучив input после realloc(), у вас больше не будет указателя на исходное пространство, поэтому он будет просачиваться.

0 голосов
/ 31 декабря 2018

Внимательно прочитайте документацию scanf, malloc, realloc, поэтому прочитайте их несколько раз.Вы также можете сослаться на стандарт C11 n1570 , в котором они упоминаются (в §7.22.3 ).

Является ли это правильной реализацией realloc ()?

Вы не внедряете realloc.Вот его шутка-реализация (см. Также это шутка-реализация malloc):

void *realloc(void*ptr, size_t siz) {
  errno = ENOMEM;
  return NULL;
}

Конечно, вы бы на самом деле использовали серьезный реализация realloc (не шутка выше), и она обеспечивается вашей стандартной библиотекой C реализация (например, выше операционная система примитивы или системные вызовы как mmap (2) в Linux).

Итак, нет, у вас нет реализации из realloc (и вы бы использовали realloc уже реализовано в вашей стандартной библиотеке C).И (по крайней мере в Linux) вы можете изучить реализацию realloc, потому что она обычно реализуется внутри некоторого свободного программного обеспечения (например, musl-libc или GNU glibc ). Здесь (в своем файле src/malloc/malloc.c строка 369) является musl-libc реализацией realloc.

вы ошибочно используете realloc

Затем вы используете scanf как scanf("%s", input).Но scanf возвращает EOF при ошибке и количество успешно введенных значений при успехе.Обычно EOF равно -1.Таким образом, в вашем случае, scanf("%s", input) может вернуть -1 (при ошибке), 0 (если входное значение не было обработано) или 1 (если что-то поместило в input).

The size_t - это некоторый беззнаковый целочисленный тип.В моей системе Linux / x86-64 это 64-разрядное число без знака, такое же как unsigned long.Таким образом, (size_t)(-1) становится огромным числом, то есть 2 64 - 1. Тогда realloc обязательно потерпит неудачу (потому что моя система не имеет такого большого количества памяти), если учесть это (size_t)(-1) поэтому realloc(input, (size_t)-1) должно дать NULL.

Если realloc задано (size_t)0, это задокументировано в Linux (см. realloc (3) ), чтобы сделать то, что free делает: освободить заданную память.Но стандарт C не требует такого поведения.

Если задано realloc (size_t)1, если будет (или, по крайней мере, разрешено) уменьшить зона памяти (только дляудерживайте один байт, что недостаточно для ваших нужд).

Итак, ваша программа полностью неверна

Кстати, вам нужно обработать ошибку realloc, поэтомукодирование input = realloc(input, newsize); очень наивно.

Кроме того, ваш scanf("%6s", input); неверен (потенциальный переполнение буфера , для ввода ровно шести байтов), так как вам нужно место для завершения NUL символ.

Итак, выбросьте вашу программу в мусорное ведро. Отдохните (или немного повеселитесь).Прочитайте документацию стандартных функций (и вики-страницу C динамического выделения памяти ).Подумай немного.И полностью переписать вашу программу.

Затем скомпилировать вашу программу со всеми предупреждениями и отладочной информацией: gcc -Wall -Wextra -g с GCC .Улучшите свой код, чтобы не получать предупреждений.Убедитесь, что ваша программа обрабатывает случаи сбоев (scanf, malloc, realloc и т. Д.).Прочитайте Как отлаживать небольшие программы .Используйте отладчик gdb и valgrind .Будьте напуганы из неопределенное поведение .

Для вашей программы (той, которую вы переписываете с нуля), вас может заинтересовать использование fgets (или даже в Linux getline (3) или readline (3) ...) для ввода.Иногда может потребоваться очистить входной буфер с помощью memset перед выполнением фактического ввода.

Имейте в виду, что stdio буферизуется, а stdout обычно является строковымбуферизация.Поэтому возьмите в привычку заканчивать строку формата printf с помощью \n или используйте fflush соответствующим образом.

PS.valgrind доступен в Linux (но не в Windows), и это одна из многих причин, по которой Linux становится очень удобной для разработчиков и студентов системой.Поэтому я рекомендую использовать дистрибутив Linux для изучения программирования на C.

...