Подтвердить что ты не робот

Каков наилучший способ получить вход от пользователя в C?

Многие говорили, что scanf не следует использовать в "более серьезной программе", как и в случае с getline.

Я начал теряться: если каждая входная функция, которую я встречал, сказала, что я не должен использовать их, то что мне использовать? Есть ли более "стандартный" способ получить ввод, о котором я не знаю?

4b9b3361

Ответ 1

Как правило, fgets() считается хорошим вариантом. Он считывает целые строки в буфер, а оттуда вы можете делать то, что вам нужно. Если вам нужно поведение типа scanf(), вы можете передать строки, которые вы читаете, в sscanf().

Основным преимуществом этого является то, что если строка не может конвертироваться, ее легко восстановить, тогда как с scanf() вы останетесь с вводом на stdin, который вам нужно слить. Кроме того, вы не закроетесь в ловушке смешения линейно-ориентированного ввода с помощью scanf(), что вызывает головные боли, когда такие вещи, как \n, остаются на stdin, обычно ведущие новые кодеры, полагая, что входные вызовы были полностью проигнорированы.

Что-то вроде этого может быть по вашему вкусу:

char line[256];
int i;
if (fgets(line, sizeof(line), stdin)) {
    if (1 == sscanf(line, "%d", &i)) {
        /* i can be safely used */
    }
}

Вы должны заметить, что fgets() возвращает NULL в EOF или ошибке, поэтому я завернул его в if. Вызов sscanf() возвращает количество успешно преобразованных полей.

Имейте в виду, что fgets() может не читать целую строку, если строка больше, чем ваш буфер, что в "серьезной" программе, безусловно, вы должны рассмотреть.

Ответ 2

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

Это связано с тем, что fgets() позволяет указать размер буфера (в отличие от gets(), который по этой причине почти никогда не будет использоваться для чтения данных от людей):

char line[256];

if(fgets(line, sizeof line, stdin) != NULL)
{
  /* Now inspect and further parse the string in line. */
}

Помните, что он сохранит, например. символ перевода строки, что может быть неожиданным.

ОБНОВЛЕНИЕ: Как указано в комментарии, есть лучшая альтернатива, если вы будете получать ответственность за отслеживание памяти: getline(). Это, вероятно, лучшее универсальное решение для кода POSIX, поскольку оно не имеет никакого статического предела длины строк, которые нужно читать.

Ответ 3

Существует несколько проблем с использованием scanf:

  • чтение текста с помощью простого спецификатора преобразования %s имеет тот же риск, что и при использовании gets(); если пользователь вводит строку, длина которой превышает размер целевого буфера, вы получите переполнение буфера,

  • если вы используете %d или %f для чтения числового ввода, некоторые плохие шаблоны не могут быть пойманы и полностью отвергнуты - если вы читаете целое число с %d, а пользовательские типы "12r4", scanf преобразует и назначает 12, оставляя r4 во входном потоке, чтобы сгладить следующее чтение;

  • некоторые спецификаторы преобразования пропускают ведущие пробелы, другие - нет, и неспособность принять это во внимание может привести к проблемам, когда какой-либо ввод пропускается полностью;

В основном, при использовании scanf требуется много дополнительных усилий для чтения с пуленепробиванием.

Хорошей альтернативой является чтение всего ввода в виде текста с помощью fgets(), а затем токенизация и преобразование ввода с использованием sscanf или комбинаций strtok, strtol, strtod и т.д.

Ответ 4

Используйте fgets для получения данных и используйте sscanf (или другой метод) для их интерпретации.

См. эту страницу, чтобы узнать, почему лучше использовать fgets + sscanf, а не scanf

http://c-faq.com/stdio/scanfprobs.html