Why can't I use "%[^\n]" scanset? - c

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", &degree);
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.

Related

Using scanf() function two times: works in one case but not in other case [duplicate]

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 3 years ago.
I'm the learning the very basics of C programming right now, and I'm practicing the scanf() function. This very, very simple program takes in a number and a letter and uses the printf() function to display the number and letter.
If I ask the user to enter the number first, the program works, i.e., asks for a number, asks for a letter, and prints the input. If I ask for the letter first, the program asks for a letter but then doesn't ask for a number.
I've tried multiple ways and reordered it, but it doesn't seem to work.
This works:
#include<stdio.h>
void main(){
int number;
char letter;
printf("Enter letter...");
scanf("%c", &letter);
printf("Enter number....");
scanf("%d", &number);
printf("Number entered: %d and letter entered: %c.\n", number, letter);
}
But, this combination doesn't work:
#include<stdio.h>
void main(){
int number;
char letter;
printf("Enter number....");
scanf("%d", &number);
printf("Enter letter...");
scanf("%c", &letter);
printf("Number entered: %d and letter entered: %c.\n", number, letter);
}
The output I get for the first program is:
Enter letter...a
Enter number....9
Number entered: 9 and letter entered: a.
Which is correct
But the second case doesn't work, and I don't get why it wouldn't work -- skips the "enter letter" part
the output is
Enter number....9
Enter letter...Number entered: 9 and letter entered:
.
Context: I entered "a" for letter and "9" for number in the above example.
It turns out there's a surprising difference between %d and %c. Besides the fact that %d scans potentially multiple digits while %c scans exactly one character, the surprising difference is that %d skips any leading whitespace, while %c does not.
And then there's another easily-overlooked issue when you're using scanf to read user inputs, which is, what happens to all those newlines -- the \n characters -- that get inserted when the user hits the ENTER key to input something?
So here's what happened. Your first program had
printf("Enter letter...");
scanf("%c", &letter);
printf("Enter number....");
scanf("%d", &number);
The user typed a letter, and ENTER, and a number, and ENTER. The first scanf call read the letter and nothing else. The \n stayed in the input stream. And then the second scanf call, with %d, skipped the \n (because \n is whitespace) and read the number, just like you wanted.
But in your second program you had the inputs in the other order, like this:
printf("Enter number....");
scanf("%d", &number);
printf("Enter letter...");
scanf("%c", &letter);
Now, the user types a number and hits ENTER, and the first scanf call reads the number and leaves the \n on the input stream. But then in the second scanf call, %c does not skip whitespace, so the "letter" it reads is the \n character.
The solution in this case is to explicitly force the whitespace-skipping that %c doesn't do by default. Another little-known fact about scanf is that a space in a format string doesn't mean "match one space character exactly", it means "match an arbitrary number of whitespace characters". So if you change your second program to:
printf("Enter number....");
scanf("%d", &number);
printf("Enter letter...");
scanf(" %c", &letter);
Now, the space character in " %c" in the second scanf call will skip over the \n that was left over after the user typed the number, and the second scanf call should read the letter it's supposed to.
Finally, a bit of editorializing. If you think this is a bizarre situation, if you think the exception to the way %c works is kind of strange, if you think it shouldn't have been this hard to read a number followed by a letter, if you think my explanation of what's going on has been far longer and more complicated than it ought to have been -- you're right. scanf is one of the uglier functions in the C Standard Library. I don't know any C programmers who use it for anything -- I don't believe I've ever used it. Realistically, its only use is for beginning C programmers to get data into their first programs, until they learn other, better ways of performing that task, ways that don't involve scanf.
So my advice to you is not to spend too much time trying to get scanf to work, or learning about all of its other foibles. (It has lots.) As soon as you're comfortable, start learning about the other, better ways of doing input, and leave scanf comfortably behind forever.
Try this
#include <stdio.h>
int main(void) {
int number;
char letter;
printf("Enter letter...");
scanf("%s", &letter);
printf("Enter number....");
scanf("%d", &number);
printf("Number entered: %d and letter entered: %c.\n", number, letter);
return 0;
}
If you change the %c to %s then you get the correct output.
Add a space before %c. So, change this:
scanf("%c", &letter);
to this:
scanf(" %c", &letter);
As I have written in caution when using scanf, this will make scanf eat the whitespaces and special characters (otherwise it will consider them as inputs).
Here, it will consume the newline character, on other words, the Enter you press, after typing your input!
To be exact, in your example, think of what the user (in this case you) do:
You type 9
You press Enter
You type 'a'
You press Enter
Now, when you input something, from your keyboard in this case, this will go into the Standard Input buffer, where it will patiently await to be read.
Here, scanf("%d", &number); will come and read a number. It finds 9 in the first cell of the STDIN buffer, it reads it, thus deleting it from the buffer.
Now, scanf("%c", &letter); comes, and it reads a character. It finds the newline character, that's the first Enter you pressed, and the function is now happy - it was told to read a character, and that's exactly what it did. Now that newline character gets deleted from the buffer (now what's left in there is 'a' and a newline character - these two are not going to be read, since there is no other function call. left for that).
So what changes if I write scanf(" %c", &letter); instead?
The first scanf will still read the number 9, and the buffer will now have a newline character, the 'a' character, and another newline character.
Now scanf(" %c", &letter);` is called, and it goes to search for a character to read in the STDIN buffer, only that now it will first consume any special characters found.
So there it goes to the buffer, it firstly encounters the newline character, it consumes it.
Then, it will encounter 'a', which is not a special character, and therefore it will read normally, and stored to the passed variable in scanf.
The last newline character will remain in the STDIN buffer, untouched and unseen, until the program terminates and the buffer gets deallocated.
Tip: You probably meant to write int main(void), instead of void main(). Read more in What should main() return in C and C++?
Specifying scanf the following way
scanf("%c", &letter);
does not skip white spaces and can read for example a new line character stored in the input buffer when the user pressed Enter entering previous data.
Use instead
scanf(" %c", &letter);
^^^
to skip white spaces.
From the C Standard (7.21.6.2 The fscanf function)
8 Input white-space characters (as specified by the isspace function)
are skipped, unless the specification includes a [, c, or n specifier.
and
5 A directive composed of white-space character(s) is executed by
reading input up to the first non-white-space character (which remains
unread), or until no more characters can be read.
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main(void)
From the C Standard (5.1.2.2.1 Program startup)
1 The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }

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
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.

Space in scanf after format specifier vs space before format specifier ("%c " vs " %c")

I wanted to know the meaning of space after the format specifier in scanf. There are many posts related to space in scanf and most of them talk of the space before %c. In the below code, I have to enter second character for first scanf to return. Just entering enter key will not break the scanf. Because of this second character, second scanf for reading the string is also getting affected.
Can I say that space after %c is for ignoring all white spaces entered after the character and wait until next character? But why "enter" key is not considered as a character itself?
char str[50];
char c;
printf("Enter the Character:");
scanf("%c ",&c);
printf("Char read is: %c",c);
printf("Enter the string:");
scanf("%s",str);
printf("%s", str);
If you use trailing space after "%c" then scanf will need to find the next non-white-space to be able to return. If there is none then scanf will block for ever.

Program exits without a space before format string and char conversion in scanf()

Why is it that when I use a space before the format specifier in scanf() the program works fine. Code below:
printf("What's your username: ");
scanf(" %s", username);
printf("Do you want to make a deposit or a withdrawal? [d/w]\n");
scanf(" %c", &choice);
When I don't have a space like this code below, it exits:
printf("What's your username: ");
scanf("%s", username);
printf("Do you want to make a deposit or a withdrawal? [d/w]\n");
scanf("%c", &choice);
Is there a good explanation to this?
Yes there is a good explanation, and the explanation is that the newline you entered for the first input is still in the buffer when you try to read the character for the second input. Reading a single character using the "%c" scanf format will read the first character in the input buffer, no matter what it is.
By adding the leading space you tell scanf to read and discard all leading white-space.
Most formats do this automatically, for example the "%s" format, so you don't need the leading space in the format string there. Read e.g. this scanf (and family) reference for more information, and for which formats you need to explicitly skip leading space.
This happens because scanf skips over white space when it reads data such as the integers or char. White space characters are those characters that affect the spacing and format of characters on the screen, without printing anything visible. The white space characters you can type as a user are the blank space (spacebar), the tab character (Tab key), and the newline (Enter Key). reference link here.

How to take character input if we have multiple white spaces?

Hello Everyone,
I am solving a question http://www.spoj.com/problems/ARITH2/. In this question I have to take first integer input then a character input, but there is no limitations of white spaces. how do I take only character input then integer input?
Use any whitespace character before %c. This character will discard all whitespace characters ,if any, until the first non-whitespace character. For example:
scanf(" %c", &character);
Note that you do not need this before %d as %d already discards leading whitespace characters.
As for the link to the challenge provided in the question, you can use
scanf("%d", &no_of_test_cases);
to get the number of test cases and
scanf("%d %c", &number, &character);
to get each number and character. Use the above scanf in a loop until character becomes '='. You'll get each line for each test case by doing this.

Resources