C getchar vs scanf

Меня смущает кусок кода, найденный в функции, которую я изучаю:

char GetCommand( void )
{
    char command;

    do {
        printf( "Enter command (q=quit, n=new, l=list):  " );
        scanf( "%c", &command );
        Flush();
    }
    while ( (command != 'q') && (command != 'n')
           && (command != 'l') );

    printf( "\n----------\n" );
    return( command );
}

void Flush( void ) {
    while ( getchar() != '\n' )
        ;
}

То, что я не совсем понимаю, это использование функции Flush(). Я имею в виду, что книга, которую я читаю, объясняет это тем, что она не позволяет пользователю вводить более одного символа, а затем читать этот символ, когда им будет предложено ввести второй раз.

Я не понимаю, как Flush() предотвращает это. Он ничего не делает. Все это команда while. (Хотя это правда...... что?????) Не имеет смысла.

Ответ 1

getchar() имеет побочный эффект удаления следующего символа из входного буфера. Цикл в Flush считывает и отбрасывает символы до тех пор, пока - и не включит - новую строку \n, заканчивающую строку.

Поскольку scanf предлагается читать один и только один символ (%c), это приводит к игнорированию всего остального в этой строке ввода.

Вероятно, было бы более ясно, если scanf заменит

command = getchar();

но на самом деле это вообще плохой пример, так как он отлично не обрабатывает End Of File.

В общем scanf лучше всего забыть; fgets и sscanf работают намного лучше, так как каждый отвечает за получение ввода, а другой - за его синтаксический анализ. scanffscanf) пытаются выполнить слишком много заданий сразу.

Ответ 2

getchar считывает один символ из стандартного ввода. Если вы поместите его в цикл while, он будет продолжать читать один символ за раз, пока условие не станет ложным.

Функция Flush делает чтение, пока не встретит новую строку (\n). Это символ, созданный, когда пользователь нажимает клавишу ввода.

Итак, код, который вы указали, будет читать один символ (я не понимаю, почему он использует scanf для этого вместо простого getchar, который будет быстрее), а затем отбрасывает остальную часть ввода до тех пор, пока Ввод пользователей.

Если вы должны были прокормить эту программу foobar, она примет f и отбросит oobar в функции Flush. Без вызова Flush f может перейти к одному scanf, а второй scanf получит первый o.

Ответ 3

Следующий пример кода может помочь вам узнать логику использования Flush():

std::cerr << "Save this data (y for yes/Enter for no)? ";
int chr = getchar();
if(chr != '\n') while( getchar() != '\n' ); // Flush()
if(chr == 'y')
  std::cerr << "The current data was saved\n";

Ответ 4

Когда вы вводите свой символ и нажимаете Enter, символ новой строки генерируется нажатием клавиши Enter и остается в буфере. Это проблематично, потому что он будет ждать до следующего раза, когда вам потребуется ввод пользователя, и он будет использоваться для этого ввода. Flush используется для очистки символа новой строки от входного буфера, поэтому у вас нет этой проблемы.