C - Могу ли я использовать scanf, чтобы приостановить цикл, когда пользователь нажимает Enter? - PullRequest
1 голос
/ 16 июня 2019

В цикле мне нужно приостановить ожидание, пока пользователь попросит продолжить, нажав клавишу ввода.

Можно ли использовать функцию scanf() внутри цикла, чтобы сделать паузу и подождать, пока пользователь нажмет ввод, чтобы продолжить? Что мне нужно, это как в RPG, где вам нужно нажать A, чтобы увидеть остальную часть диалога.

Из того, что я тестировал, эта функция кажется плохим выбором для приостановки.

Если это так, есть ли другой способ вызвать такое поведение в C?

Ответы [ 3 ]

2 голосов
/ 17 июня 2019

У меня есть эта функция в моей библиотеке:

void    alx_wait4enter(void)
{
    int c;

    do {
        c = getchar();
    } while ((c != '\n') && (c != EOF));
}

Это сработало для меня.

Вы просто вызываете его, и он блокируется до ввода:

foo();
alx_wait4enter(); // Block here until enter
bar();
alx_wait4enter(); // Block again
foobar();

AFAIK, он правильно обрабатывает ввод мусора перед вводом и может использоваться в цикле или любом другом контексте, даже в программе ncurses.

2 голосов
/ 16 июня 2019

getchar () будет лучше.Если вы просто хотите ввести блокировку до тех пор, пока пользователь не нажмет, это будет вашим самым дешевым и минимальным решением.Вы можете проигнорировать результат.Этот обновленный ответ является альтернативой очень хорошему циклу do ... while, предлагаемому в другом месте.

#include <stdio.h>

....

while(thing_is_happening) {
  /* do some stuff */
  for(int c = 1; c != '\n' && c != EOF; c = getchar());
  /* do some more stuff */
}
0 голосов
/ 17 июня 2019

Можно ли использовать функцию scanf() внутри цикла, чтобы приостановить и подождать, пока пользователь нажмет ввод, чтобы продолжить?

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

В зависимости от того, что именно вы хотите, scanf() может быть неплохой альтернативой, ноЕсть некоторые ошибки, связанные с этим.В целом, scanf() сложно использовать правильно.

То, что мне нужно, это как в RPG, где вам нужно нажать A, чтобы увидеть остальную часть диалога.

Если вы читаете со стандартного ввода, вам необходимо понимать, что типовые терминалы строки буфера данных поступают в программу.Это означает, что они будут хранить набранные символы до тех пор, пока не будет нажата [enter] или пока не заполнится его буфер, и только в этот момент данные будут отправлены в программу.В результате сложно ожидать нажатия любой клавиши , но [enter].

С другой стороны, вы должны знать о возможности нажатия других клавиш до * 1024.*.Есть несколько вещей, которые вы можете выбрать в этой ситуации, но если вам больше нечего делать, то вам, вероятно, следует просто слить все данные из ввода, пока не достигнете новой строки.

Из того, что я тестировал, эта функция кажется плохим выбором для приостановки.

Вы не описали, какой тип тестирования вы выполняли, но scanf() сложно использовать правильно.Тем не менее, я думаю, что это хороший выбор для того, что вы пытаетесь сделать.Однако следует обратить внимание на то, что новая строка в строке формата не означает «соответствовать одной новой строке».Скорее, любой запуск одного или нескольких пробельных символов в строке формата означает «соответствовать нулю или нескольким пробельным символам», и функция не может знать, что он достиг конца пробельного запуска, пока не увидит next ,непробельный символ (или конец файла).

Вот как я бы использовал scanf для ожидания нажатия клавиши [enter], с исключением чего-либо до этого:

char c;
int n;

c = 0;
switch(scanf("%*[^\n]%c", &c)) {
    case 1:   // a newline was scanned, corresponding to an [enter] keypress
        assert(c == '\n');
        break;
    case 0:   // the next character was a newline, or an error or EOF occurred
        n = getchar();         // consume the newline
        if (n == '\n') break;  // else it was actually error or EOF
        assert(n == EOF);
        // fall through
    case EOF: // end-of-file was reached or an I/O error occurred
        break;
    default:  // should not happen
        break;
}

Формат scanf определяет именно то, что я описал.Дескриптор поля %*[^\n] говорит, что соответствует последовательности одной или нескольких не-новых строк, но нигде не назначает их.Это пожирает любые символы, предшествующие следующей новой строке.Если это успешно, то %c читает следующий символ, который должен быть символом новой строки.

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

Поскольку существует толькоодно поле в формате, для которого присвоение не подавляется, единственные возвращаемые значения: 0, 1 и EOF.

Но, посмотрев немного, я бывероятно, замените его следующим:

int c;

do {
    c = getchar();
while (c != '\n' && c != EOF);
// ... optionally handle the c == EOF case here ...
...