Home > Mobile >  What does scanf("%f%c", ...) do against input `100e`?
What does scanf("%f%c", ...) do against input `100e`?

Time:10-04

Consider the following C code (online available io.c):

#include <stdio.h>
int main () {
  float f;
  char c;
  
  scanf ("%f%c", &f, &c);
  printf ("%f \t %c", f, c);

  return 0;
}

When the input is 100f, it outputs 100.000000 f. However, when the input is 100e, it outputs only 100.000000, without e followed. What is going on here? Isn't 100e an invalid floating-point number?

CodePudding user response:

This is (arguably) a glibc bug.

This behaviour clearly goes against the standard. However it is exhibited by other implementations. Some people consider it a bug in the standard instead.

Per the standard, An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence. So 100e is an input item because it is a prefix of a matching input sequence, say, 100e1, but any longer sequence of characters from the input isn't. Further, If the input item is not a matching sequence, the execution of the directive fails: this condition is a matching failure. 100e is not a matching sequence so the standard requires the directive to fail.

The standard cannot tell scanf to accept 100 and continue scanning from e, as some people would expect, because stdio has a limited push-back of just one character. So having read 100e, the implementation would have to read at least one more character, say a newline to be specific, and then push back both newline and e, which it cannot always do.

CodePudding user response:

I'd say this is pretty clearly a pretty unclear, gray area.

If you're an implementor of a C library (or a member of the X3J11 committee), you have to worry about this sort of thing — sometimes a lot. You have to worry about the edge cases, and sometimes the edge cases can be particularly edgy.

However, you did not tag your question with the "language lawyer" tag, so perhaps you're not worried about a scrupulously correct, official interpretation.

If you're not an implementor of a C library or a member of the X3J11 committee, I'd say: don't worry what the "right" answer here is! You don't have to worry, because you don't care, because you'd be crazy to write code which is sensitive to this question — precisely because it's such an obvious gray area. (Even if you do figure out what the right behavior here is, do you trust every implementor of every C library in the world to always implement that behavior?)

I'd say there are three things you can do in the category of "not worrying", and not writing code which is sensitive to this question.

  1. Don't use scanf at all (for anything). It's an odious, imprecise, imperfect function, that's not good for anything except — perhaps — getting numbers into the first few programs you ever write while you're first learning C. After that, scanf has no use in any serious program.

  2. Don't arrange your code and data such that it has to confront ambiguous input like "100e" in the first place. Where is it coming from, anyway? Is it input the user might type? Data being read in from a data file? Is it expected or unexpected, correct or incorrect input? If you're reading a data file, do you have control over the code that writes the data file? Can you guarantee that floating-point fields will always be delimited appropriately, will not occasionally have random alphabetic characters appended?

  3. If you do have to parse input that might contain a valid floating-point number, might have random alphabetic characters appended, and might therefore be ambiguous like this, I'd encourage you to use strtod instead, which is likely to be both better-defined and better-implemented.

CodePudding user response:

From the C Standard (6.4.4.2 Floating constants)

decimal-floating-constant:
    fractional-constant exponent-partopt floating-suffixopt
    digit-sequence exponent-part floating-suffixopt

and

exponent-part:
    e signopt digit-sequence
    E signopt digit-sequence

If you will change the call of printf the following way

printf ("%e \t %d\n", f, c);

you will get the output

1.000000e 02     10

that is the variable c has gotten the new line character '\n'.

It seems that the implementation of scanf is made such a way that the symbol e is interpreted as a part of a floating number though there is no digit after the symbol.

CodePudding user response:

Give a space between "%f %c" like that and also when you are going to enter input make sure to have a space between two inputs. I am assuming you just want to print a character.

  • Related