Как поставить команду новой строки, не нажимая Enter в C? - PullRequest
0 голосов
/ 22 мая 2018

Я нахожусь в Linux, использую C99, и моя проблема заключается в следующем: я запрограммировал мульти-опцию, основанную на целых числах.Для каждой итерации после первой, ввод большего числа, чем необходимо для массива, будет запускать другие опции меню, когда они остаются в буфере.Я хотел избежать функции fflush(stdin), так как я читал, что это вызывает неопределенное поведение, поэтому я попытался с while ((select = getchar()) != '\n'), но на первой итерации мне нужно нажать Enter, чтобы меню появилось в первую очередь.Могу ли я отправить новую строку в буфер, чтобы избежать проблемы?Кроме того, я объявил select как int

Вот часть кода, которая вызывает проблему:

for(;;) {
    while ((select = getchar()) != '\n') { }
    printf("\n\nWhat operation?\n1. Define array\n2. Delete element\n3. Add element\n4. Order array\n5. Randomize array\n6. Print array\n0. Exit\n");
    scanf("%d", &select);
    switch(select) {...}

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Используйте fgets для чтения строки.Разобрать строку с помощью sscanf.Разбор целого числа и завершающего непробельного символа позволит обнаружить любой ввод, следующий за целым числом.
ПРАВИТЬ, чтобы улучшить из-за комментария @ chux

#include <stdio.h>

int main ( void) {
    char buffer[100] = "";
    char extra = '\0';
    int scanned = 0;
    int choice = 0;

    do {
        printf("\n\nWhat operation?\n1. Define array\n2. Delete element\n3. Add element\n4. Order array\n5. Randomize array\n6. Print array\n0. Exit\n");
        if ( fgets ( buffer, sizeof buffer, stdin)) {
            if ( 1 == ( scanned = sscanf ( buffer, "%d %c", &choice, &extra))) {// the space will consume whitespace and %c a non-whitespace character
                printf ( "choice %d\n", choice);
                if ( 0 > choice || choice > 6) {
                    scanned = 0;
                }
            }
            if ( 1 != scanned) {
                printf ( "\t\tenter a number 0 to 6\n");
            }
        }
        else {
            fprintf ( stderr, "problem fgets\n");
            return 0;
        }
    } while ( 1 != scanned);

    return 0;
}
0 голосов
/ 22 мая 2018

В чистом стандарте C то, что вы хотите, вероятно, невозможно (и, конечно, плохо определено) и неясно.Стандарт C11 n1570 не знает о терминалах или клавиатуре (то есть о клавише enter ), но только о стандартных потоках .См. Также этот ответ на вопрос, близкий к вашему.

На практике, если вы работаете в какой-либо системе POSIX (которая, я полагаю, вы используете), терминал имеет строку Дисциплина управляется ядром.Однако стандартный ввод может не быть терминалом (с перенаправлениями или конвейерами ), и вы можете проверить, является ли он одним из них, используя isatty (3) как isatty(STDIN_FILENO) ...

Я рекомендую использовать некоторые библиотеки, такие как readline или ncurses , если это так.

Кстати, ваше использование select имя сбивает с толку (так как select (2) был старым системным вызовом, сегодня заменен poll (2) ).

Если вы ограничены чистымC стандартными функциями, внимательно прочитайте документацию scanf и используйте счетчик возвращаемых значений.Вы, конечно, не можете (переносимо) поместить символ новой строки (или любой другой символ) в некоторый поток ввода, такой как stdin.Но внимательно прочитайте о ungetc .

Я рекомендую скомпилировать все предупреждения и информацию об отладке (т. Е. gcc -Wall -Wextra -g с GCC ) и научиться использоватьgdb отладчик , чтобы понять поведение вашей программы.

...