This question already has answers here:
How to make that scanf is optionally ignoring one of its conversion specifiers?
(4 answers)
Closed 2 years ago.
I want to have a scanf function that allows the user to input up to four integers separated by spaces but still run if only 2 integers are put in.
scanf("%d %d %d %d", &command, &num_one, &num_two, &num_three);
scanf does exactly that. It returns the number of successful conversions it performed. If it cannot perform a conversion (or cannot match a literal character), it stops reading precisely at that point.
You should always check its return value, even if the examples you are copying don't do that.
What scanf doesn't guarantee is that the values converted are separated by spaces. They might be separated by newlines. If you want a newline character to stop the scan, you need to read the line using something like fgets (or, better if possible, the Posix getline function), and then call sscanf on the line which was read.
You could also force scanf to stop at the end of the line by using %*[ \t] instead of to separate the %ds, which will only match space and tab characters. (The * causes scanf to not try to save the matched string, and also to not count the conversion in its return count.) But that will run you into the other problem with scanf: if there is garbage in the line, you normally want to continue reading with the next line. The getline/sscanf solution will do that for you. If you use scanf, you'll need to manually flush the rest of the input line, which requires calling fgets or getline anyway.
And while I'm at it, note that there is no difference between scanf("%d %d %d %d", ...) and scanf("%d%d%d%d", ...), because %d, like all scanf conversions other than %c, %[ and %%, skips leading whitespace.
Related
Here is my C code:
#include "stdio.h"
int main()
{
int minx, x;
printf("Enter two ints: ");
scanf( "%d-%d", &minx, &x);
printf("You wrote: minx is %d x is %d", minx, x);
}
When the input is 5-3 or 5- 3 the output is You wrote: minx is 5 x is 3 which makes sense. However, when the input is 5 -3 or 5 - 3 or 6 -4 the output is You wrote: minx is 5 x is 8. I expected - to skip white spaces, so I expected minx to be 5 and x to be 3,6 and 4 for the other input. This also happens when - in %d-%d changed to ?, *, + even with the same inputs. I know it is probably because of that space after the first int. Here it says only three format specifiers do not skip white space — Whitespace before %c specification in the format specifier of scanf function in C. Did I get this wrong? Why - does not skip leading space here? What is the actual problem here and what is the cause of it? Why is it 8? What other operators or chars can lead to similar problems?
Let's look at your scanf format specifier "%d-%d" in detail:
%d skip whitespace if necessary, then read an integer
- match a literal '-' character
%d skip whitespace if necessary, then read an integer
So the inputs 5-3 and 5- 3 both work just fine. But when the input is 5 -3 (or anything else with a space before the -) the parse fails, because scanf does not immediately see the - it expects.
If that's not what you expected, or not what you want, or if that doesn't make sense, or if that's not how you'd like scanf to work, I'm afraid that's too bad: scanf works the way it works.
How can you fix this? That depends in part on why you included the - character in your format string in the first place.
You can use %d%d or %d %d, which will simply read two integers (separated by at least one whitespace character). If there's a - character preceding the second integer, that integer will be read as negative.
You can use %d -%d, which will skip (arbitrary) whitespace before it tries to match the - character.
You can use two separate scanf calls.
If you do continue to use scanf, you really need to check its return value so that your program can detect the case that the expected inputs were not matched.
Finally, you can use something other than scanf.
My recommendation to you depends on the ultimate purpose of this program.
If it's just for learning, then minimize the amount of time you spend fussing with the way your program does input at all. For example, if you need to read an integer, use one %d. As long as you can get the numbers you need into your program (so that you can test the rest of your program), you're fine. If there are things you can type that cause scanf to get confused, just don't worry about it, just don't type those things. Don't try to do anything fancy — that's not what scanf is for.
If this is a "real" program, that does have to accept arbitrary user input, or input with a specific syntax (like with that - in the right place), and if you need to deal gracefully with incorrect input, printing appropriate errors, and not reading the wrong values or getting confused — then run, do not walk, away from scanf, and never use it again. It is effectively impossible to write a program that performs high-quality input using scanf. Not even a C expert can do it. It's simply not worth it. You will spend five times as long, and get an inferior result, than if you simply abandoned scanf and read your input a line at a time using fgets or the like, then parsed the input line (perhaps even using sscanf — but again, check its return value).
Addendum: It's true, all format specifiers — with three exceptions (%c, %[…] scan sets, and %n) — skip whitespace before beginning their work. But format specifiers are things that begin with %. Literal characters in the format string must match exactly, and there's no implicit whitespace skipping for them. If you want to skip whitespace at spots in the input other than before the % format specifiers that do it, you can include a literal whitespace character (usually a single space) in your format string.
You need to check the return value of scanf. You should be doing this, in general, for every library function you call that has a return value.
In your case, scanf would return 2 (meaning two output parameters were set) for valid input. If you get any other return value, the input does not match the format you specified, and you should ignore the contents of your output parameters minx and x.
How exactly would you deal with having a variable amount of scanf inputs?
I'm scanning commands, some of them are 1. word commands but some require numeric argument. Does scanf allow the following?
scanf(" %s %d", command, argument);
Would that ignore the "argument" if only one value was inputed?
The other option i though of was
scanf(" %s", command)
if (strcmp(command, "somethin") {
scanf("%d", argument); }
But that would create a newline right? the terminal has to recieve the input in form of "> command argument"
SO, my question is, how to solve the problem of having variable number of inputs.
No, it won't "create a newline". scanf is completely unaware of any newlines. scanf treats the input stream as a linear sequence of data separated by whitespace. Newline is just whitespace, no different from any other whitespace. The only scanf format specifiers that can "see" newlines are %c and %[]. Your %s and %d are completely newline-agnostic.
Which means that your second example is doing it right (within the natural limitations of scanf). It won't "create a newline". It will read a single line, if you supply the input in a single line (like somethin 42).
You might actually run into the "opposite" problem: if the user forgets to input the required argument in a single line, the next scanf will wait for it on the next line. And on the next line. And on the next line... until he user finally supplies it. I'm not sure this behavior is desirable for you. If not, then a better idea would be to use dedicated line-based input through fgets and then parse the line manually.
P.S. There's no reason to prepend %s and %d with spaces.
This question already has answers here:
What is the effect of trailing white space in a scanf() format string?
(4 answers)
Closed 6 years ago.
I just had a test in my C class today and I have reason to believe that answer might be incorrect.
scanf("%d\n", &x); // Evaluate the expression for the string "54321\n"
The idea is pretty simplistic. Find an integer and place the scanned number at the memory location corresponding with integer variable x. However, I don't believe that this call to scanf would ever terminate.
As far as I am concerned, all calls to scanf to standard I/O terminate with the press of the enter key, so there is no need to include the newline in the specifier string. In fact, this redundancy will only cause the program to stall in search of something that will never match the string.
Is there anyone who can clarify the technicalities of the scanf function to put this problem to rest?
I don't believe that this call to scanf would ever terminate.
6 character input like "54321\n" is insufficient to cause this scanf("%d\n", &x); to return. The program stalls. Something else must yet occur.
'\n' directs scanf() to consume white-spaces and to do so until
a non-white-space is detected.
stdin is closed
An input error occurs on stdin (rare).
As stdin is usually line buffered, scanf() receives data in chunks.
The first chunk 123Enter is not enough to cause scanf("%d\n", &x); to return. One of the 3 above needs to happen.
Any following input with some non-white-space fulfills #1, be it:
456Enter or
xyzEnter or
EnterEnter$Enter or ...
Then scanf() will return with a 1 indicate a value, 123, was stored in x. The 4, x or $ above was the non-white-space detected that caused completion. That character will be the next character read by subsequent input on stdin.
scanf("%d\n", &x); is almost certainly the wrong code to use as it obliges another line of user input and does not check its return value.
all calls to scanf to standard I/O terminate with the press of the enter key, so there is no need to include the newline in the specifier string.
That's correct. The \n in the format string will ignore any number of whitespaces, including the "ENTER" key; so, you'll have to input a non-whitespace char to terminate the scanf() call. So, yes, the \n is problematic.
scanf()'s man page says:
· 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.
By the way, scanf() itself is considered problematic: Why does everyone say not to use scanf? What should I use instead?
#include<stdio.h>
main()
{
int a;
printf("Enter a value \n");
scanf("%d ",&a);
printf("a=%d \n",a);
}
In scanf() function I put space after the format specifier. When i run this program scanf() reads two values from the user and only the first value is assigned to 'a'.
Why does scanf() read two values when we use spaces after format specifier even though we are passing one reference in above program?
Why does scanf() read one value when we use space before format specifier even though we are passing one reference?
How will the scanf() function work?
First of all you would want to change your int a; to a pointer, 2) when you specify a variable to be as int it only expect integer number 0-9 and space is a char character, 3) i think number would answer this too
Same question has been asked on Quora
A space in a scanf format string matches an arbitrary amount of
whitespace in the input.
To match all of that arbitrary amount of input space, it has to see
something to terminate the whitespace--i.e., something other than
whitespace (and a new-line is whitespace, so it isn't sufficient).
That's why you need to enter second time(which should not be a whitespace to terminate the scanf()).
White space includes space, tabs, or newlines.
Hope my answer here helps!
Error While taking the input
Always avoid using whitespaces or tabspaces in the scanf unless you intend to! which is required in some scenarios.
Why this behaviour of scanf?
scanf uses whitespaces, newlines, tabs as delimiters. It stops taking input as soon as it read these 3 from the keyboard.
Since you are providing whitespace in the scanf, after entering the integer it will now wait either for a newline, whitespace to be entered through the keyboard to match that whitespace of yours and after that it will finish taking it's input from the keyboard.
This question already has answers here:
What does space in scanf mean? [duplicate]
(6 answers)
Closed 7 years ago.
what is the purpose of putting a space in scanf like this
scanf(" %c",&ch)
in place of
scanf("%c",&ch)?
Also what is input buffer in fflush(stdin)?
Because the space before %c ignores all whitespace. *scanf family of functions ignore all whitespace before any % by default except for %c, %[ and %n. This is mentioned in C11 at:
7.21.6.2.8
Input white-space characters (as specified by the isspace function) are skipped, unless
the specification includes a [, c, or n specifier.
To be complete, here's the part that says all whitespace will be ignored:
7.21.6.2.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. The directive never fails.
Regarding your second question, fflush(stdin) causes undefined behavior and must not be used (emphasis mine):
7.21.5.2.2
If stream points to an output stream or an update stream in which the most recent
operation was not input, the fflush function causes any unwritten data for that stream
to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
what is the purpose of putting a space in scanf like this scanf(" %c",&ch) in place of scanf("%c",&ch)?
So that scanf would ignore all spaces before the first non-space character is encountered in the stream.
Also what is input buffer in fflush(stdin)?
What you input into the console will exist in the stdin stream.
Don't flush that stream however, it's undefined behavior.
If you want to discard characters entered after scanf is called, you can read and discard them.
The space in the scanf in this case tells scanf to ignore any leading whitespace characters in front of the character you read. Still even if there is no whitespace in front of the character the code will work and read the character successfully.
I am not sure what you are asking in your last question, but stdin is the standard input stream for you program.
scanf(" %c",&ch);
As per the man page,
White space (such as blanks,
tabs, or newlines) in the format string match any amount of white space,
including none, in the input.
Stdin is standard input.The user enters the data for the program, this is first stored in a buffer and then when the program requests data transfers by use of the read operation the data is made available to the program. (using scanf etc).
I had the same problem a while ago in which if I would try to read a variable using scanf ("%c", &ans); it would not read anything. Thus I figured out that the \n character from the last input was being read.
Thus, doing scanf (" %c", &ans); solved my problem.
Although, I could not understand your second question clearly.
Just to give a space from the last object, if not, for example a string, everything will be together with no spaces between them.