Nameless
Nameless

Reputation: 21

Why is scanf failing to read inputs correctly?

I cant figure out whats wrong. Am i using format specifiers in wrong way? Someone please help i am very new to coding.

#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;
}

Output

Upvotes: 1

Views: 622

Answers (2)

John Bode
John Bode

Reputation: 123458

Some things to remember about scanf:

  • Most conversion specifiers like %s, %d, and %f will skip over leading whitespace - %c and %[ will not. If you want to read the next single non-whitespace character, use " %c" - the leading blank tells scanf skip over any leading whitespace before reading the next non-whitespace character;

  • For what you are trying to do, you should not use \n in your format strings - it will cause scanf to block until you enter a non-whitespace character;

  • You do not need to use the & operator on array expressions like area; under most circumstances, array expressions are converted to pointer expressions1. Honestly, you should read area the same way you read name, using fgets (and you should always check the result of fgets), or you should specify the maximum field width in the specifier: scanf( "%9s", area ); (a 10-element array can hold up to a 9-character string, since one element has to be reserved for the string terminator);

  • You should get in the habit of checking the result of scanf - it will return the number of successful conversions and assignments. For example, scanf( "%d %d", &x, &y ) will return 2 if both x and y are read successfully. It will return EOF if end-of-file is signaled or there's a read error.

  • scanf will read up to the next character that doesn't match the conversion specifier - IOW, if you're using %d, then scanf will skip over any leading whitespace, then read up to the next character that isn't a decimal digit. That character is left in the input stream. This means if you're using %d and type in 123e456, scanf will read up to that 'e' character and assign 123 to the target. If you try to read again with %d, scanf will immediately stop reading on that e and return 0 without assigning anything to the target (this is called a matching failure). This will continue until you remove that 'e' from the input stream (such as with getchar or fgetc or scanf with the %c specifier, etc.

  • You need to make sure the types of the arguments match the format specifier. %s expects an argument of type char *, %d expects int *, %f expects float *. %x expects unsigned int *, %lf expects double *, etc.


  1. This is one of the "deeply unintuitive" aspects of C I was talking about in my comment.

Upvotes: 0

Govind Parmar
Govind Parmar

Reputation: 21532

You use fgets correctly when reading name. I'd recommend also using fgets for all your other inputs, and then parsing the intended values out of them. For example:

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

This is preferable to using scanf directly for non-string inputs since if input fails to match a format string, it will remain in stdin and screw up the other scanf calls.

If you would like to use scanf correctly:

  • Check its return value to see if it matches the number of format specifiers in the string. If not, some inputs were not successfully read. You may want to use a do/while loop for this.
  • Begin your format strings with a space, as in " %c", so that any whitespace remaining in stdin will be skipped over.
  • Don't end your format strings with a newline.

Upvotes: 1

Related Questions