Почему Scanf не может правильно прочитать ввод? - PullRequest
0 голосов
/ 22 февраля 2019

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

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char name[20];int age;char grade;double gpa;char area[10];
    printf("User Input\n");
    printf("Enter your name: ");
    fgets(name,20,stdin);
    printf("Your name is %s\n",name);
    printf("Enter your age: ");
    scanf("%d\n",&age);
    printf("Your age is %d\n",age);
    printf("Enter you grade: ");
    scanf("%c\n",&grade);
    printf("Your grade is %c\n",grade);//Why is this giving an int output?
    printf("Enter your gpa: ");
    scanf("%f\n",&gpa);
    printf("Your gpa is %f\n",gpa);
    printf("Enter your area: ");
    scanf("%s\n",&area);
    printf("Your area is %s",area);//This shows grade input
    return 0;
}

Вывод

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Некоторые вещи, которые нужно помнить о scanf:

  • Большинство спецификаторов преобразования, таких как %s, %d и %f, пропускают пробелы в начале - %c и%[ не будет.Если вы хотите прочитать следующий единственный непробельный символ, используйте " %c" - начальный пробел говорит scanf пропустить любой начальный пробел перед прочтением следующего непробельного символа;

  • Для того, что вы пытаетесь сделать, вы не должны использовать \n в строках формата - это приведет к блокировке scanf до тех пор, пока вы не введете непробельный символ;

  • Вам не нужно использовать оператор & для выражений массива, таких как area;в большинстве случаев выражения массива преобразуются в выражения указателя 1 .Честно говоря, вы должны читать area так же, как вы читаете name, используя fgets (и вы всегда должны проверять результат fgets), или вы должны указать максимальную ширину поля в спецификаторе: scanf( "%9s", area );(10-элементный массив может содержать до 9-символьной строки, поскольку один элемент должен быть зарезервирован для ограничителя строки);

  • Вы должны привыкнуть проверять результат scanf - он вернет количество успешных преобразований и назначений.Например, scanf( "%d %d", &x, &y ) вернет 2, если оба x и y прочитаны успешно.Он вернет EOF, если будет сообщен конец файла или произошла ошибка чтения.

  • scanf будет читать до следующего символа, который не соответствует спецификатору преобразования - IOW, если вы используете %d, то scanf пропустит любойведущий пробел, затем читайте до следующего символа, который не является десятичной цифрой.Этот символ остается во входном потоке.Это означает, что если вы используете %d и вводите 123e456, scanf будет считывать до этого 'e' символа и назначать 123 цели.Если вы попытаетесь прочитать снова с помощью %d, scanf немедленно прекратит чтение на этом e и вернет 0, не назначая что-либо для цели (это называется ошибкой совпадения).Это будет продолжаться до тех пор, пока вы не удалите 'e' из входного потока (например, с getchar или fgetc или scanf со спецификатором %c и т. Д.

  • Необходимо убедиться, что типы аргументов соответствуют спецификатору формата. %s ожидает аргумент типа char *, %d ожидает int *, %f ожидает float *. %x ожидает unsigned int *%lf ожидает double * и т. Д.


Это один из «глубоко не интуитивных» аспектов КИговорил в моем комментарии.
0 голосов
/ 22 февраля 2019

Вы правильно используете fgets при чтении name.Я бы порекомендовал также использовать fgets для всех других ваших входных данных, а затем анализировать намеченные значения из них.Например:

char age_str[20];
fgets(age_str, 20, stdin);
age = strtol(age_str, NULL, 10);

Это предпочтительнее, чем использовать scanf напрямую для нестроковых входов, так как если ввод не соответствует строке формата, он останется в stdin и облажает другие scanf звонки.

Если вы хотите правильно использовать scanf:

  • Проверьте возвращаемое значение, чтобы увидеть, соответствует ли оно количеству спецификаторов формата в строке.Если нет, некоторые входные данные не были успешно прочитаны.Для этого вы можете использовать цикл do / while.
  • Начните строки форматирования с пробела, как в " %c", так что все оставшиеся в stdin пробелы будут пропущены.
  • Не заканчивайте строки формата новой строкой .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...