Есть ли способ контролировать, когда (или где) функции get () или fgets () начинают принимать Input? - PullRequest
0 голосов
/ 29 июня 2018

Во-первых, я хотел бы отметить, что я новичок в программировании.

Я пытаюсь написать программу, которая принимает несколько входов, последняя из которых является строкой, когда я использую функции gets () или fgets (), которые они читают из ввода после завершения предыдущего ввода. Так, например:

printf("Enter decimal:\n");
scanf("%d",&x);
printf("Enter string:\n");
gets(str[100]);
printf("%d\n%s",x,str);

Пример ввода / вывода:

Enter decimal:
3\n            //If I change line after inputting the decimal the program continues as if it already read the string
Enter string:
3  

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

Enter decimal:
3 Hello World\n            
Enter string:
3  
Hello World

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

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 01 июля 2018

В вашем коде несколько проблем:

  • gets() устарел и рискован, поскольку размер целевого массива не передается функции, поэтому он не может предотвратить переполнение буфера, если пользовательский ввод слишком длинный. Он был окончательно удален из последней версии стандарта C. Вместо этого используйте fgets().
  • смешивание scanf() и fgets() подвержено ошибкам, так как scanf() оставляет часть пользовательского ввода в ожидании, например, новую строку, набранную пользователем после номера, и этот ожидающий ввод будет прочитан fgets(), что в этом конкретном случае немедленно вернется, потому что ожидающий перевод строки - это именно то, что fgets() ожидает завершения ввода.

Я рекомендую использовать fgets() для чтения ввода построчно и использовать sscanf для преобразования ввода в ожидаемые типы. У него есть дополнительное преимущество, позволяющее легко восстанавливать ошибки.

Вот модифицированная версия:

#include <stdio.h>
#include <string.h>

int main() {
    char buf[100];
    int x;

    for (;;) {
        printf("Enter decimal: ");
        if (!fgets(buf, sizeof buf, stdin))
            return 1;
        if (sscanf(buf, "%d", &x) == 1)
            break;
        printf("Invalid input: not a number\n");
    }
    for (;;) {
        printf("Enter string:\n");
        if (!fgets(buf, sizeof buf, stdin))
            return 1;
        buf[strcspn(buf, "\n")] = '\0';  // strip the trailing newline if any
        if (buf[0] != '\0')
            break;
        printf("Invalid input: empty string\n");
    }
    printf("%d\n%s\n", x, buf);
    return 0;
}
0 голосов
/ 29 июня 2018

Узнайте больше о C стандарте IO . Обратите внимание, что gets устарел и опасен, но теперь удален из стандарта C. Никогда не используйте его (и, пожалуйста, забудьте, что он существовал). Возможно, вы имеете в виду fgets(str, sizeof(str), stdin) вместо вызова пропавшего gets, предполагая, что str это некоторый массив из char с, например. объявлен как char str[100];.

Вы можете прочитать всю строку с помощью fgets (или даже getline (3) , см. this ), а затем проанализировать этот буфер, возможно, используя sscanf (или strtol , или strtok , или используя ваши собственные lexing & синтаксический анализ методов).

Обратите внимание, что sscanf (например, fscanf и scanf) возвращает количество отсканированных элементов (и принимает %n), но не заботятся о конце строк. Вы должны использовать это.

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

При чтении из подлинного файла вы также можете изменить положение внутри него, используя fseek ftell ). Это не будет работать на консоли (так как терминал обычно не searchable ).

Возможно, вы могли бы использовать некоторые терминальные связанные библиотеки (такие как ncurses или readline ). Они не входят в стандарт C11 n1570 и могут быть недоступны в вашей операционной системе (но у вас есть ОС Linux и некоторые другие).

Помните, что ваш стандартный ввод не всегда является терминалом. Подумайте о перенаправлениях и конвейерах .

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

Если вы работаете в Linux или в другой операционной системе POSIX, учтите, что stdin связан с файловым дескриптором 0 (с именем STDIN_FILENO). Так что, если вы хотите подождать, пока какой-либо ввод будет доступен, рассмотрите возможность использования poll (2) для этого файлового дескриптора.

PS. Ваш вопрос действительно неясен. Я могу только догадываться, что вы хотите сделать .... Подумайте об улучшении после прочтения дополнительной документации ...

...