Вывод инструкции printf() не отображается должным образом при добавлении функции gets()

Я попытался использовать библиотечную функцию gets() в C и обнаружил, что вывод инструкции printf() задерживается и отображается после того, как gets() получает ввод со стандартного ввода (т.е. с клавиатуры). Пожалуйста, проверьте приведенный ниже код C и его вывод.

 #include<stdio.h>
 #include<stdlib.h>
 int main()
 {
    int n, i, j;
    char ch, *str;

    printf("Enter size of input:\n");
    scanf("%d\n", &n);

    str = (char *) malloc(sizeof(char) * n);
    printf("Enter input string: \n");
    gets(str);

    printf("Given input string is : %s\n", str);
    return 0;
 }

Выход:

Введите размер ввода: 9

R Радж Кумар ‹-- Это имя дается из ввода, так как программа ожидает ввода для функции gets(), даже если printf("Введите входную строку\n") присутствует перед gets() и оператор printf() не отображается на консоль. Он печатается после получения входных данных gets() с консоли.

Введите входную строку:

Данная входная строка: R Raj ​​Kumar


person RajKumar Rampelli    schedule 11.11.2016    source источник
comment
Ввод намного больше, чем вы говорите, поэтому следует UB. gets устарел по какой-то причине.   -  person Deduplicator    schedule 11.11.2016
comment
Функция gets устарела, как можно скорее переключитесь на fgets.   -  person Weather Vane    schedule 11.11.2016
comment
Спасибо за быстрые ответы. Я хочу прочитать строку с консоли, которая может содержать пробелы, а длина строки неизвестна во время компиляции. Поэтому я использовал функцию gets() (которая также учитывает пробелы) и динамическое выделение памяти для переменной 'str'. Пожалуйста, дайте мне знать, можно ли использовать какую-либо другую библиотечную функцию для чтения строкового значения, которое удовлетворяет моему требованию здесь.   -  person RajKumar Rampelli    schedule 11.11.2016
comment
'\n' в scanf("%d\n", &n); задержках. scanf("%d\n", &n) не возвращается до тех пор, пока после числа не будет введено непробельное пространство. @JonathanLeffler Не согласен с тем, что опубликованный обман является хорошим объяснением этого, что является первой из многих проблем с этим кодом.   -  person chux - Reinstate Monica    schedule 11.11.2016
comment
Если вы хотите прочитать строку любой длины, сначала malloc немного памяти, а затем используйте fgets для получения ввода. Теперь fgets сохраняет введенное вами newline в конце строки, поэтому, если входная строка не содержит такого newline, вы знаете, что будут получены дополнительные данные. Таким образом, вы realloc увеличиваете объем памяти и повторяете до тех пор, пока вход не будет содержать указанное newline (или fgets не сработает). Но вы не должны смешивать scanf("%d",...) с fgets — вместо этого используйте fgets, а затем sscanf.   -  person Weather Vane    schedule 11.11.2016
comment
@chux: я согласен с вашим несогласием ... это неправильный дубликат, но это дубликат. Я пропустил завершающий пробел в строке формата.   -  person Jonathan Leffler    schedule 11.11.2016
comment
Ниже приведен вывод, когда я использую функцию fgets(): Введите размер ввода: 13 R Радж Кумар Введите входную строку: Дана входная строка: R Радж Кумар Я могу прочитать строку требуемого размера, но проблема та же. Я удалил неиспользуемые переменные i, j и ch в своем коде. printf (введите строку ввода: \n) не отображается в нужном месте. Мне нужно напечатать этот оператор непосредственно перед тем, как вводить данные с консоли.   -  person RajKumar Rampelli    schedule 11.11.2016
comment
Проблема заключается в конце \n в формате scanf() "%d\n", как сказал Чукс. Убери это. Затем добавьте цикл 'gobble': int ch; while ((ch = getchar()) != EOF && ch != '\n') ; (пустое тело цикла). Это читает завершающую новую строку.   -  person Jonathan Leffler    schedule 11.11.2016
comment
@JonathanLeffler: решение сработало отлично. Но правильное ли это решение этой проблемы? Нужно ли мне добавлять один и тот же код цикла while, где бы scanf() и fgets() (или любая функция чтения строк/символов) не использовались вместе?   -  person RajKumar Rampelli    schedule 11.11.2016
comment
Не преобразовывать результат malloc в C   -  person phuclv    schedule 11.11.2016
comment
Это один из правильных и стандартных способов решения проблемы scanf(), оставляющей символы новой строки (и завершающие пробелы или нецифры после цифр) в строке ввода. В качестве альтернативы, и очень часто, лучше читать только строки (все вводные с помощью fgets()), а затем анализировать строки с помощью sscanf(). Это имеет преимущества, не в последнюю очередь в том, что если первая попытка синтаксического анализа не сработает, вы можете попробовать еще раз с другим форматом и сообщить всю строку данных в сообщениях об ошибках.   -  person Jonathan Leffler    schedule 11.11.2016
comment
Ваш ввод, по моим подсчетам, имеет длину не менее 12 символов, вы передаете 9 в качестве размера. Вы выделяете недостаточно памяти... вам нужно достаточно места для хранения R[space]Raj[space]Kumar\0 -> 12 chars   -  person Elias Van Ootegem    schedule 11.11.2016
comment
Привет, Элиас Ван Отегем, мой вопрос заключается в том, почему консоль ожидает ввода от пользователя, не отображая оператор printf(), как объяснено в описании. Смотрите, есть printf(Enter input string:); непосредственно перед вызовом gets(), но эта печать не отображается, и консоль ожидает ввода пользователем строки. Как только я ввел строку, отображаются оба оператора printf().   -  person RajKumar Rampelli    schedule 20.01.2017


Ответы (2)


Когда вы используете gets(...), вам нужно иметь достаточно большой буфер для хранения ввода. Ваш ввод содержит 9 печатных символов, но фактический ввод также содержит 2 пробелов и завершающий null символ, поэтому размер вашего ввода на самом деле 12.

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

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

person Edwin Buck    schedule 11.11.2016

Я внес изменения в свою программу на основе комментариев/предложений здесь. Ниже приведена программа, которая дает правильный и желаемый результат.

Программа:

#include<stdio.h>
 #include<stdlib.h>
 int main()
 {
    int n;
    char ch, *str;

    printf("Enter size of input:\n");
    scanf("%d", &n);

    while ((ch = getchar()) != EOF && ch != '\n');

    str = (char *) malloc(sizeof(char) * n);
    printf("Enter input string: ");
    fgets(str, n, stdin);

    printf("Given input string is : %s\n", str);
    return 0;
 }

Выход:

Введите размер ввода: 9

Введите строку ввода: R Радж Кумар

Данная входная строка: R Raj ​​Ku

person RajKumar Rampelli    schedule 20.01.2017