Integer taken with scanf() does not get its intended value in C - c

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.

Related

Wanting scanf to proceed without all parameters filled [duplicate]

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.

scanf("%[^\n]s",a) with set size of string

So I had a code where I use
scanf("%[^\n]s",a);
and has multiple scanf to take different inputs some being string input. So I understand that scanf("%[^\n]s",a) takes input until new line has been reached, however I was wondering suppose my string can only hold up to 10 characters, then after my string has been filled, but new line hasn't been reached how can i get rid of the extra input before going to new line. I was thinking of doing getchar() until new line has been reached however in order to even check if my 10 spots has been filled I need to use getchar, so doesn't that mess up my next scanf input? Anybody have any other way to do it? Still using scanf() and getchar?
scanf("%[^\n]s",a) is a common mistake; the %[ directive is distinct from the %s directive. What you're asking from scanf is:
A group of non-'\n' characters, followed by...
A literal s character.
Perhaps you intended to write scanf("%[^\n]",a)? Note the deleted s...
You can use the * modifier to suppress assignment for a directive, for example scanf("%10[^\n]", a); followed by scanf("%*[^\n]"); to read and discard up to the next newline and getchar(); to read and discard that newline:
scanf("%10[^\n]", a);
scanf("%*[^\n]"); // read and discard up to the next newline
getchar(); // read and discard that newline
As pointed out, the two format strings could be concatenated to reduce the number of calls to scanf. I wrote my answer this way for the sake of documentation, and I'll leave it as is. Besides, I figure that attempt at optimisation would be negligible; a profiler is likely to indicate much more significant bottlenecks for optimisation in realistic scenarios.
You can use this format to hold the first 10 characters and keep the next lines of input:
scanf("%10[^\n]%*[^\n]",a);
getchar();

Why scanf() reads two values when we put spaces after format specifier even we are passing one reference

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

Difference between different scanf formats [duplicate]

This question already has answers here:
whitespace in the format string (scanf)
(4 answers)
Closed 6 years ago.
I'm currently prepping myself for programming school by going through the textbook. There's this particular question which I don't understand and the textbook doesn't give the answer.
PS: I've learned some C++/C# online, but never go through proper-taught programming classes, so I'm struggling with some of the concepts.
Q: For each of the following pairs of scanf format strings, indicate
whether or not the two strings are equivalent. If they are not, show
how they can be distinguished.
A) "%d" versus " %d"
B) "%d-%d-%d" versus "%d -%d -%d"
C) "%f" versus "%f "
D) "%f,%f" versus "%f, %f"
First off, I don't even understand what the question is asking. What does the textbook mean by whether or not the 2 strings are 'equivalent'?
If they are, could someone explain the differences and possibly show me how they can be distinguished?
Let us try A first: "%d" versus " %d", they are equivalent format strings for scanf().
" " will do the following. It never fails.
1) Scan and discard (skip) optional white-space.
2) After reading a non-white-space or end-of-file, if not (EOF), the last character read is put back into stdin.
"%d" itself will attempt 3 things (It can fail)
1) Scan and discard (skip) optional white-space.
2) Scan and convert numeric text representing a decimal integer.
3) After reading a non-numeric text or end-of-file, if not (EOF), the last character read is put back into stdin.
" %d" does both the above. It is the same result of just doing the 2nd with "%d".
With *scanf() specifiers note:
Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier. C11 §7.21.6.2 8
B, C, D differences?
Mouse over for hint 1:
A " " before a scanf() specifier, except the 3 noted above, is an equivalent scanf() format as without it.
Mouse over for hint 2:
Only 1 of 3 equivalent.
Mouse over for hint 3:
Consider inputs:
"123 -456-789"
"123.456 x" What is the next character to be read?
B) "%d-%d-%d" versus "%d -%d -%d"
C) "%f" versus "%f "
D) "%f,%f" versus "%f, %f"
Answer:
Awww, Do you really want to be given the answer?
From Wikipedia
whitespace: Any whitespace characters trigger a scan for zero or more whitespace characters. The number and type of whitespace characters do not need to match in either direction.
scanf is about keep consuming the input and get the thing you care about. The normal char in format string means it consumes the exactly same char, and do nothing else. %d, %f could skip the leading whitespace. So, sum it up, we got:
A, it is the same, because %d skip the leading space
B, %d-%d-%d is pretty strict, it reads an integer after exactly - and then another integer and so on, so it reads 1-2-3 well, 1- 2- 3 well, too, but it fails on 1 - 2 - 3. While on the other hand, %d -%d -%d first skip spaces, read an integer, skip spaces, expect char-, then skip spaces again, and so on...
C, trailing spaces does not make a difference
D, it is the same, because %f skip leading spaces, too
So the answer would be B.

Scanf Y/N and Save for Future Use

I want to ask a specific question and get a Y/N answer read in by the user. I will need to use the character Y or N to change the outcome of the next question eventually, which is why I need the character to be saved so I can retrieve it later. I don't want to use a string or a for/while loop. Also, why do I need to include the * after "%c*"?
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int avgTemp, lowestTemp, temperature;
char choice ='Y';
char decision ='N';
printf("What is the average temperature?\n");
scanf("%d", &avgTemp);
printf("What is the lowest temperature in last 24 hours?\n");
scanf("%d", &lowestTemp);
printf("Has the temperature been over 99 degrees F for more than 30 minutes?
Please answer Y for yes and N for no.\n");
scanf("%c*", &choice);
printf("choice is %c", choice);
return 0;
}
Also, why do I need to include the * after "%c*"?
%c* means to scan for a character and then a * (which it will discard). Maybe you meant %*c which means do the scan but discard it. You don't need either of them.
scanf is a very problematic function and should be avoided. Your program illustrates the problem. scanf does not read a whole line. scanf will only scan stdin up to what you asked for and then stop. This means extra input and newlines can sometimes be left on the input stream for the next unsuspecting scanf. From the man page...
Each successive pointer argument must correspond properly with each
successive conversion specifier (but see the * conversion below). All
conversions are introduced by the % (percent sign) character. The format string may also contain other characters. White space (such as blanks, tabs, or newlines) in the format string match any
amount of white space, including none, in the input. Everything else matches only
itself. Scanning stops when an input character does not match such a format character. Scanning also stops when an input conversion cannot be made (see below).
This makes it very easy to accidentally leave characters on the input buffer. Each of your scanf("%d") will read in the number and stop. This leaves a newline on the input buffer. This is fine for %d because...
Before conversion begins, most conversions skip white space
...but not for %c.
Matches a sequence of width count characters (default 1); the next pointer must be a pointer to char, and there must be enough room for all the characters (no terminating NUL is added). The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format.
So you need scanf(" %c") to make it work at all.
scanf is to be avoided because it's very, very vulnerable to unexpected input. Try giving "foo" to the first question. All the scanf("%d") will silently fail. And scanf("%c") will read f.
Instead, read the whole line with getline (preferred as it handles memory allocation for you) or fgets and then use sscanf on the resulting string. This avoids all the above problems.

Resources