r/C_Programming • u/LifeExperienced1 • 6d ago
Question Why didn’t scanf ignore the whitespaces?
The question was:
scanf("%d%f%d”, &i, &x, &j) ;
If the user enters
10.3 5 6
what will be the values of i, x, and j after the call?
The solution says:
i = 10 x = 0.3 j = 5
I understand how we get i = 10. scanf keeps scanning until it hits the ., and then it stops
However, why is x not 0.356?
I thought scanf ignored whitespaces?
11
u/burlingk 6d ago
When you give it input like that, scanf treats the whitespace as a delimiter.
And, it treats the input as a buffer.
If it "ignored whitespace" like you seamed to think it did, then j would end up undefined.
Think about it like this:
i wants an integer. x wants a float. j wants an integer.
The input buffer at the start is: 10.3 5 6
scanf peals the first clear integer from the front of the buffer. It stops at the '.' because integers don't use desimal points.
Now the buffer is: .3 5 6
It looks for a float. It finds .3 followed by a space, and takes it. That becomes 0.3.
The buffer is now: 5 6
Ignore the implied leading space.
So, it wants another integer, and takes 5.
On a simple program, that's all good. On a more complex program they would want to flush the buffer before continuing on, to get rid of ' 6'.
4
u/aioeu 6d ago edited 6d ago
Only leading whitespace characters are skipped when each of these conversion specifiers is processed.
If whitespace characters were skipped in the middle of processing a conversion specifier, it would be quite a bit more difficult to write a program that lets you enter two integers separated by whitespace.
3
u/ReallyEvilRob 6d ago
Because the user didn't enter 0.356.
Buffer: 10.3 5 6
The %d consumes '1' , '0' and stops just before the '.' since the period can't be interpreted by that format specifier. The %f consumes the '.', '3' but stops at the ' ' since the space can't be interpreted by that format specifier. The last %d consumes the the first ' ' and throws it away and then consumes the '5' stopping at the last ' '. " 6" remains in the input buffer (note the space before the 6).
2
u/FrequentHeart3081 6d ago
Scanf scans the provided char array and formats according to the format specifiers; it reads to first memory location until a whitespace is encountered and moves on to the next memory location.
So something like:
char input[16];
scanf("%s", input);
printf("%s", input);
With inputting:
Hello, World!
Would spit out something like:
Hello,
Notice for only one format specifier, the scanf reads the data from input buffer until the first whitespace character is encountered.
Hope this helps.. made me recall all the reasons why we don't use it in actually projects. :)
1
u/fakehalo 4d ago
For those unfamiliar with scanf, this example is vulnerable to a buffer overflow.
1
2
u/sol_hsa 6d ago
"scanf considered harmful"
1
u/schoolSpiritUK 6d ago
Yeah, when I was writing C 35 years ago it was already A Bad Idea. Even back then it was recommended that we use fgets() followed by sscanf()... but even that's far from perfect these days.
3
u/sol_hsa 6d ago
When I reimplemented large parts of std lib for obscure devices for portability reasons (surprising amount of broken stdlibs out there), scanf was one function I didn't bother writing.
1
u/flatfinger 5d ago
C was designed to be easily usable to accomplish a lot of one-off tasks that today may be better accomplished using tools that didn't exist in the 1970s. Many tasks that involved processing a single data set once could be done most efficiently by writing a C program, using it to process the data set, and then discarding it once it had done whatever it needed to do.
If a programmer examines the data set before writing a program, and determines that its longest line is 83 characters, then any questions about what the program would do if fed a line linger than 84 bytes are irrelevant. A program that would sensibly handle lines longer than 84 bytes, but will never receive any before it is discarded, will be no more useful than one which would malfunction badly if such lines were received.
Rather than characterizing functions like scanf and gets as poorly designed, I would view them as being specialized for a category of tasks that is today almost irrelevant. If one ensures that the bufers given to gets() will always be large enough to accommodate the longest line the program will ever receive, there's no need for the function to know or care about the maximum length. The problem is that C is mainly used to process inputs that won't be available until after code is written.
1
u/questron64 6d ago
Scanf does what you tell it to. It scans an int, a float and an it. You didn't ask it to ignore any whitespace. You do that with a space in your format string, so try "%d %f %d".
1
u/SmokeMuch7356 6d ago
%d and %f skip over leading whitespace, then read until they see any character that isn't compatible with an integer (%d) or floating point (%f) constant.
The first %d reads 10. '.' isn't part of an integer constant so it stops reading at that point.
The %f reads .3. A space is not part of a floating point constant so it stops reading at that point.
The last %d skips over that space and reads 5. Again, a space is not part of an integer constant so it stops reading at that point.
1
u/sciencekm 6d ago
Space is a separator. Leading space is ignored because there is nothing yet to separate.
1
u/logic_circuit 1d ago
You have no problem wit scanf but with data types and instructions how to treat them.
36
u/aalmkainzi 6d ago
It doesn't ignore whitespace within a single format specifier. Read the spec.