Используете scanf и fgets в одной программе? - PullRequest
6 голосов
/ 05 апреля 2011

Мне нужно сделать что-то вроде следующего:

int main(void) {
char a,b,cstring;

printf("please enter something");
scanf("%c %c",&a,&b);
prinf("thanks, now some more");
fgets(cstring,35,stdin);

}

Проблема в том, что всякий раз, когда я вхожу в Vars из первого файла, он пропускается до конца программы.Как мне сделать несколько входов?

Ответы [ 4 ]

7 голосов
/ 05 апреля 2011

Первая проблема заключается в том, что scanf() читает два символа, но не перевод строки после этого.

Это означает, что ваш fgets() читает символ новой строки и завершает.

Вам повезло, что ваша программа не падает. Вы говорите fgets(), что он получает массив из 35 символов, но вместо передачи массива вы передаете символ (даже не адрес символа). Это также говорит о том, что вы не , включая #include <stdio.h> (вы не можете использовать scanf() надежно в соответствии со стандартом C без прототипа для scanf() в области действия), и вы не компилируете с достаточным количеством предупреждения включены или не уделяют достаточного внимания тому, что говорит ваш компилятор.

Вы должны получать предупреждения компилятора. Например, GCC 4.6.0 говорит:

/usr/bin/gcc -g -I/Users/jleffler/inc -std=c99 -Wall -Wextra -Wmissing-prototypes \
     -Wstrict-prototypes -Wold-style-definition xxx.c
xxx.c: In function ‘main’:
xxx.c:7: warning: implicit declaration of function ‘prinf’
xxx.c:8: warning: passing argument 1 of ‘fgets’ makes pointer from integer without a cast

И, черт возьми, я даже не заметил орфографической ошибки prinf() для printf(), пока не попытался связать, и компилятор потер мне нос, сказав: «Не знаю, что такое prinf()! ».

Если ваш компилятор по крайней мере не выдает второе предупреждение, найдите себе лучший компилятор.


Комментарий:

Как мне остановить чтение новой строки после нее?

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

#include <stdio.h>
int main(void)
{
    char a,b,cstring[35];

    printf("please enter something");
    scanf("%c %c%*c", &a, &b);
    printf("thanks, now some more");
    fgets(cstring, 35, stdin);
    printf("OK: I got %c and %c and <<%s>>\n", a, b, cstring);
    return 0;
}

%*c читает дополнительный символ (новую строку), не назначая его где-либо (это из-за *). Однако, если после второго непустого есть несколько символов, это не поможет. Вероятно, я бы написал цикл для чтения новой строки:

#include <stdio.h>
int main(void)
{
    char a,b,cstring[35];
    int c;

    printf("please enter something");
    scanf("%c %c", &a, &b);
    while ((c = getchar()) != EOF && c != '\n')
        ;
    printf("thanks, now some more");
    fgets(cstring, 35, stdin);
    printf("OK: I got %c and %c and <<%s>>\n", a, b, cstring);
    return 0;
}

Обратите внимание, что getchar() возвращает int, а не char. Это надежно отбрасывает все на первой строке ввода. Здесь также показано, как повторить прочитанное - важная часть отладки.

1 голос
/ 05 апреля 2011

Это неопределенное поведение.Ваша переменная cstring, несмотря на свое имя, представляет собой один символ , , и вы пытаетесь прочитать до 35 символов, в то время как ее текущее значение указывает на .Другими словами, текущий символ в cstring будет преобразован в указатель, и он попытается записать ваш ввод туда.Это будет область памяти (скорее всего) от 0 до 255. включительно.

Вот что вызывает ваше нарушение сегментации.Вместо этого начните с чего-то вроде этого:

#include <stdio.h>
int main(void) {
    char a,b,cstring[99];

    printf("please enter something");
    scanf("%c %c",&a,&b);
    printf("thanks, now some more");
    fgets(cstring,35,stdin);

    return 0;
}

Или, возможно, лучше:

#include <stdio.h>
int main(void) {
    char a,b,cstring[99];

    printf("please enter something");
    fgets(cstring,35,stdin);
    sscanf(cstring,"%c %c",&a,&b);
    printf("thanks, now some more");
    fgets(cstring,35,stdin);

    return 0;
}

Или, если вы хотите более надежное решение для пользовательского ввода, см. здесь .Это проверенный и проверенный метод с очень хорошей проверкой ошибок.

0 голосов
/ 06 декабря 2016

Вы можете просто использовать fflush (stdin) после использования scanf, который устраняет проблему

0 голосов
/ 16 июля 2016

Проблема в том, что когда поток достигает функции fgets (), этот API сначала просматривает ввод данных в stdin и находит там паразит '' n '.Что касается fgets (), в котором говорится, что этот API возвращается, когда он встречает EOF или '\ n', поскольку fgets () получил '\ n' от stdin, поэтому он выполнялся, не дожидаясь ввода пользователем чего-либо, поскольку API возвращали условия возврата.1001 *

Решение проблемы заключается в том, что вы используете getchar ();после scanf и игнорируйте лишние символы, оставленные функцией scanf ().Например:

scanf("%lf",&e);
getchar();
fgets(t,200,stdin);

или

. Другим решением может быть использование sscanf с fgets.например:

#include <stdio.h>
int main() {
int j;char t[200];
fgets(t,200,stdin);
sscanf(t,"%d",&j);
}
...