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
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.
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.
This is one of the "deeply unintuitive" aspects of C I was talking about in my comment.
Related
I'm trying to get user input for my string with spaces on my program but for some reason %[^\n] doesn't work.
The % part is marked red. I couldn't understand why. It just skips and doesn't ask for user input.
int prelim, midterm, semiFinal, final, totalScore, yearLevel, studentId;
float averageScore = 0;
char name[25], degree[25];
printf("Enter your student id: ");
scanf("%d", &studentId);
printf("Name: ");
scanf("%[^\n]s", &name);
printf("Degree: ");
scanf("%[^\n]s", °ree);
printf("Year: ");
scanf("%d", &yearLevel);
First of all, scanf("%[^\n]s", &name) must be scanf("%[^\n]", name) as
The s is not part of the %[ format specifier as people new to C often think.
The ampersand should be removed as the name of an array decays to a pointer to its first element which is already the type that %[ expects.
Now, to answer your question, %[^\n] will fail if the first character it sees is a \n. For the scanf for studentId, you type the number and press Enter. That scanf consumes the number but leaves the enter character (\n) in the input stream. Then, the scanf for name sees the newline character and since it's the first character that it sees, it fails without touching name. The next scanf fails for the same reason and the last scanf waits for a number.
But wait! Why doesn't the last scanf fail as well? The answer to that is certain format specifiers like %d skip leading whitespace characters. The %[ format specifier does not.
Now how do we fix this? One easy solution would be to tell scanf to skip whitespace characters before the %[ format specifier. You can do this by adding a space before it: scanf(" %[^\n]", name). When scanf sees the space, it will skip all whitespace characters from the input stream until the first non-whitespace character. This should solve your problem.
I'm required to do a seafood menu as an assignment in my college. I will provide the relevant code here:
int main ()
{
int a,d;
float c ;
char b,s,S,m,M,l,L;
printf ("\n\t\t\t\tSeafood Menu\n");
printf ("----------------------------------------------------------------------------------\n");
printf ("\t\t\t\t\t\t Dish Size\n");
printf ("Item Number\t Seafood Dish\t Small\t Medium Large\t\n");
printf ("----------------------------------------------------------------------------------\n");
printf ("\t 1\t Fried \t20.00 \t\t 40.00 \t\t 55.00\n");
//Continue with a bunch of menu here
printf (" Enter item number :");
scanf ("%d",&a);
printf (" Enter dish size (S/M/L) :");
scanf ("%s",&b);
if ((a==1)&&((b=='s')||(b=='S')))
{c=20.00;}
//continue with a bunch of condition to choose the price per dish stated in the menu
printf (" Enter dish quantity :");
scanf ("%d",&d);
printf (" Price per dish size :RM%.2f\n\n\n",c);
return 0;
}
When I tried to change the format identifier in this to %c, it just stopped accepting input for that particular scanf.
printf ("Enter dish size (S/M/L):");
scanf ("%s",b);
I would like to attach images but it seems that I am not allowed to do so 'll leave two links:
Normal, using %s: and abnormal, using %c
I'm curious about why it doesn't work when I use %c while %s works? As all I enter there is just character. Please enlighten me.
I'm curious about why it doesn't work when I use %c while %s works?
Well, guess what, it did not work, even if it appeared to.
As mentioned in the man page, for scanf(), the type of arguments are
%c expects a pointer to char
%s expects a pointer to the initial element of an char array.
Quoting C11, chapter §7.21.6.2, (emphasis mine)
c Matches a sequence of characters of exactly the number specified by the field
width (1 if no field width is present in the directive).
If no l length modifier is present, the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence. No null character is added.
s Matches a sequence of non-white-space characters.
If no l length modifier is present,the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence and a terminating null character, which will be added automatically.
In your case,
providing %s is wrong, as a single char is one element too short to scan and hold an array, that is null-terminated. This causes undefined behavior as memory overrun happens.
%c should have "worked" , if the input stream did not have the newline stored from previous ENTER key press. If you clean off the input stream of all pending inputs, you'll see it works. Use something like
scanf(" %c", &b); //the whitespace "eats up" all the previous whitespaces
You can see this previous answer of mine, for details on the same.
Is there some difference between
scanf("%s", c);
and
scanf(" %s", c);
Like can it affect my program in any way?
Thanks in advance.
The scanf %s conversion specifier skips leading whitespace characters and parses a word up to and not including subsequent whitespace.
Adding a space in front of the %s has no effect, it is fully redundant.
The same holds for %d and %f but not %c or %[.
Note also that the %s and %[ specifiers are risky since you do not provide scanf any limit for the number of characters to store into the destination. This might be OK for sscanf() as the conversion is implicitly limited by contents of the source string, but must be avoided for scanf and fscanf.
You can provide a numeric argument between the % and the s for the maximum number of chars to store before the null terminator:
char buffer[100];
if (scanf("%99s", buffer) == 1) {
/* a word was parsed correctly into buffer */
}
This question already has answers here:
What does space in scanf mean? [duplicate]
(6 answers)
Closed 7 years ago.
The following code gives the bizarre o/p as soon as I compile it.
main() {
char name[3];
float price[3];
int pages[3], i;
printf ( "\nEnter names, prices and no. of pages of 3 books\n" ) ;
for ( i = 0 ; i <= 2 ; i++ )
scanf ("%c %f %d", &name[i], &price[i], &pages[i] );
printf ( "\nAnd this is what you entered\n" ) ;
for ( i = 0 ; i <= 2 ; i++ )
printf ( "%c %f %d\n", name[i], price[i], pages[i] );
}
But if we give the space in the scanf statement before %c, it gives proper o/p.
Can anyone please explain me why is it so?
Update:-
If I am providing the input like this-
F
123.45
56
J
134
67
K
145
98
then my question is why not we are giving space before %f and space before %d? Why we need to give space before %c only?
Adding the space to the format string enables scanf to consume the newline character from the input that happens everytime you press return. Without the space, name[i] will receive the char '\n', and the real char is left to be misinterpreted by %f.
So, say your input is
a 1.0 2
b 3.0 4
c 5.0 6
The program sees it more like this:
a 1.0 2\nb 3.0 4\nc 5.0 6\n\377
That is, the line-breaks are actual characters in the file (and the \377 here indicates "end of file").
The first scanf will appear to work fine, consuming a char, a float, and an integer. But it leaves the input like this:
\nb 3.0 4\nc 5.0 6\n\377
So the second scanf will read the '\n' as its %c, unless you get rid of it first.
Adding the space to the format string instructs scanf to discard any whitespace characters (any of space ' ', tab '\t', or newline '\n').
A directive is one of the following:
A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)). This directive matches any amount of white space, including none, in the input.
...
from http://linux.die.net/man/3/scanf
This sort of problem arises whenever you use scanf with %c in a loop. Because, assuming free-form input, newlines can happen anywhere. So, it's common to try to avoid the whole issue by using a two-tiered approach. You read lines of input into a buffer (using fgets); chop-off the silly newline characters; then use sscanf instead of scanf to read from the buffer (string) instead of straight from the file.
Incorrect input using %c
Consider the following snippet of code:
int main( ){
int x;
char y;
scanf("%d", &x);
scanf("%c", &y);
printf("%d %c", x, y);
}
Behavior: When you run the above program, the first scanf is called
which will wait for you to enter a decimal number. Say you enter
12(That’s ASCII ‘1’ and ASCII ‘2’). Then you hit the "enter" key to
signal the end of the input. Next the program will execute the second
scanf, except you will notice that the program doesn't wait for you to
input a character and instead goes right ahead to output 12 followed
by a ‘\n’.
Explanation:Why does that happen? Let’s look at the behavior of the
program step-bystep.
Initially there is nothing in the buffer. When the first scanf() is called, it has nothing
to read, and so it waits. It keeps waiting until you type 1,2, then "enter". Now what's in
the buffer are the character 1, the character 2, and the character ‘\n’. Remember that ‘\n’
signifies the end of input, once all fields have been entered, but it is also stored in the
buffer as an ASCII character. At this point scanf will read the largest decimal input from
the buffer and convert that to an integer. In this example, it finds the string "12" and
converts it to the decimal value twelve and puts it in x. Then scanf returns control back to
the main function and returns the value 1, for being able to convert one entry
successfully. In our example, we do not catch the return value of the scanf in a variable.
For robust code, it is important to check the return value of scanf( ) to make sure that the
user inputted the correct data.
What is now left in the buffer is ‘\n’. Next, the second scanf is
called and it's expecting a character. Since the buffer already has
the ‘\n’ character in it, scanf sees that, takes it from the buffer,
and puts it in y. That's why when you execute the printf afterwards,
12 and “enter” are printed to the screen.
Solution: Moral of the story is, enter is a character like any other,
and is inputted to the buffer, and consumed from the buffer by %c just
like any other ASCII character. To fix this, try using this code
instead:
int main( ){
int x;
char y;
scanf("%d", &x);
scanf("\n%c", &y); /* note the \n !! */
printf("%d %c", x, y);
}
**
How does this fix the problem?
** So you again type ‘1’,’2’,’\n’. The first scanf reads "1" and "2", converts that to the decimal twelve and leaves the ‘\n’ in the buffer.
The next scanf now expects a ‘\n’ at the beginning of the next input.
It finds the ‘\n’ in the buffer, reads it, and discards it. Now the
buffer is empty and scanf is waiting on the user to input a character.
Say the user inputs ‘c’, followed by the enter key. ‘c’ is now
assigned to y, NOT "enter". Therefore printf will output "12 c" to the
screen. NOTE: there is again a ‘\n’ sitting in the queue now. So if
you need to do another scanf for a single character, you will have to
"consume" that '\n' before taking another character in from the user.
This is not an issue for any other format specifier, as they all ignore white spaces before
the input.
Here is the code
printf("\n");
printf("Enter a integer vaule:");
scanf("%d" , &num3);
printf("You entered: %015d", num3);
printf("Enter a float value:");
scanf("%f", &deci3);
printf("You entered: %15.2f", deci3);
printf("\n");
the output is
Enter a integer vaule:4.4
You entered: 000000000000004
Enter a float value:You entered: 0.40
The problem is this code is not stopping at
printf("Enter a float value:");
and this scanf
scanf("%f", &deci3);
seems to be getting its value from the previous scanf
The %d conversion stops wherever the integer stops, which is a decimal point. If you want to discard the input there, do so explicitly… getc in a loop, fgets, or such. This also allows you to validate the input. The program should probably complain about 4.4.
The scanf function works this way per the specification:
An input item shall be defined as the longest sequence of input bytes (up to any specified maximum field width, which may be measured in characters or bytes dependent on the conversion specifier) which is an initial subsequence of a matching sequence. [Emphasis added.]
In your example, the following C string represents the contents of stdin when the first scanf call requests input: "4.4\n".
For this initial call, your format string consists of a single specifier, %d, which represents an integer. That means that the function will read as many bytes as possible from stdin which satisfy the definition of an integer. In your example, that's just 4, leaving stdin to contain ".4\n" (if this is confusing for you, you might want to check out what an integer is).
The second call to scanf does not request any additional input from the user because stdin already contains ".4\n" as shown above. Using the format string %f attempts to read a floating-point number from the current value of stdin. The number it reads is .4 (per the specification, scanf disregards whitespace like \n in most cases).
To fully answer your question, the problem is not that you're misusing scanf, but rather that there's a mismatch between what you're inputting and how you're expecting scanf to behave.
If you want to guarantee that people can't mess up the input like that, I would recommend using strtol and strtod in conjunction with fgets instead.
This works, but it dont complains if you type 4.4 for the int
#include <stdio.h>
int main() {
char buffer[256];
int i;
float f;
printf("enter an integer : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%d", &i);
printf("you entered : %d\n", i);
printf("enter a float : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%f", &f);
printf("you entered : %f\n", f) ;
return 0;
}
use a fflush(stdin) function after the fist scanf(), this will flush the input buffer.