format specifier for double in scanf - c

I wrote this program for getting a double input:
double n;
scanf("%lf",&n);
while(fgetc(stdin)!='\n')
return 0;
printf("%lf",n);
This program is supposed to take double as input. Provided that %lf is the format specifier for double in scanf, I used it. But for inputs of a digit followed by e. ex.(3e), the input is being read without errors. But during processing of the same variable, it is discarding the e and only considering 3 as is shown by the printf statement. What is the cause of such behaviour?

Following the rationale given in defect report #22 (http://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_022.html), functions like scanf (with %lf) and strtod should consume as much input as satisfies the expected format for the floating point constant. This means that they should consume the e character in "3e" even though the e character is not followed by the actual exponent value (the exponent value is required to be present by 6.4.4.2).
This applies in equal degree to %lf and %f. In my experiments they behave exactly the same on this input. (Of course, %f requires target variable of type float.)
However, even after consuming both 3 and e from the input stream, I would expect scanf (and strtod) to recognize "3e" as an invalid representation of a floating point number (since, again, 6.4.4.2 requires the exponent value to be present) and act accordingly. In my experiment scanf successfully read 3.0. This I cannot explain yet.

Related

Why is this code printing 0?

void main()
{
clrscr();
float f = 3.3;
/* In printf() I intentionaly put %d format specifier to see
what type of output I may get */
printf("value of variable a is: %d", f);
getch();
}
In effect, %d tells printf to look in a certain place for an integer argument. But you passed a float argument, which is put in a different place. The C standard does not specify what happens when you do this. In this case, it may be there was a zero in the place printf looked for an integer argument, so it printed “0”. In other circumstances, something different may happen.
Using an invalid format specifier to printf invokes undefined behavior. This is specified in section 7.21.6.1p9 of the C standard:
If a conversion specification is invalid, the behavior is
undefined.282) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
What this means is that you can't reliably predict what the output of the program will be. For example, the same code on my system prints -1554224520 as the value.
As to what's most likely happening, the %d format specifier is looking for an int as a parameter. Assuming that an int is passed on the stack and that an int is 4 bytes long, the printf function looks at the next 4 bytes on the stack for the value given. Many implementations don't pass floating point values on the stack but in registers instead, so it instead sees whatever garbage values happen to be there. Even if a float is passed on the stack, a float and an int have very different representations, so printing the bytes of a float as an int will most likely not give you the same value.
Let's look at a different example for a moment. Suppose I write
#include <string.h>
char buf[10];
float f = 3.3;
memset(buf, 'x', f);
The third argument to memset is supposed to be an integer (actually a value of type size_t) telling memset how many characters of buf to set to 'x'. But I passed a float value instead. What happens? Well, the compiler knows that the third argument is supposed to be an integer, so it automatically performs the appropriate conversion, and the code ends up setting the first three (three point zero) characters of buf to 'x'.
(Significantly, the way the compiler knew that the third argument of memset was supposed to be an integer was based on the prototype function declaration for memset which is part of the header <string.h>.)
Now, when you called
printf("value of variable f is: %d", f);
you might think the same thing happens. You passed a float, but %d expects an int, so an automatic conversion will happen, right?
Wrong. Let me say that again: Wrong.
The perhaps surprising fact is, printf is different. printf is special. The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be, because it depends on the details of the %-specifiers buried in the format string. So there are no automatic conversions to just the right type. It's your job to make sure that the types of the arguments you actually pass are exactly right for the format specifiers. If they don't match, the compiler does not automatically perform corresponding conversions. If they don't match, what happens is that you get crazy, wrong results.
(What does the prototype function declaration for printf look like? It literally looks like this: extern int printf(const char *, ...);. Those three dots ... indicate a variable-length argument list or "varargs", they tell the compiler it can't know how many more arguments there are, or what their types are supposed to be. So the compiler performs a few basic conversions -- such as upconverting types char and short int to int, and float to double -- and leaves it at that.)
I said "The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be", but these days, good compilers go the extra mile and try to figure it out anyway, if they can. They still won't perform automatic conversions (they're not really allowed to, by the rules of the language), but they can at least warn you. For example, I tried your code under two different compilers. Both said something along the lines of warning: format specifies type 'int' but the argument has type 'float'. If your compiler isn't giving you warnings like these, I encourage you to find out if those warnings can be enabled, or consider switching to a better compiler.
Try
printf("... %f",f);
That's how you print float numbers.
Maybe you only want to print x digits of f, eg.:
printf("... %.3f" f);
That will print your float number with 3 digits after the dot.
Please read through this list:
%c - Character
%d or %i - Signed decimal integer
%e - Scientific notation (mantissa/exponent) using e character
%E - Scientific notation (mantissa/exponent) using E character
%f - Decimal floating point
%g - Uses the shorter of %e or %f
%G - Uses the shorter of %E or %f
%o - Signed octal
%s - String of characters
%u - Unsigned decimal integer
%x - Unsigned hexadecimal integer
%X - Unsigned hexadecimal integer (capital letters)
%p - Pointer address
%n - Nothing printed
The code is printing a 0, because you are using the format tag %d, which represents Signed decimal integer (http://devdocs.io).
Could you please try
void main() {
clrscr();
float f=3.3;
/* In printf() I intentionaly put %d format specifier to see what type of output I may get */
printf("value of variable a is: %f",f);
getch();
}

sscanf("0X80.9", "%f", &value) sets value to a hex float not a float

I have some code that reads letter value pairs. It can be simplified as:
float value = 0.0;
sscanf("0X80.9", "%f", &value);
In Visual Studio 2013, value = 0
In Visual Studio 2015 and above, value = 128.5625 (i.e. 0x80 in hex = 128 in decimal)
Anyone know why this has changed? More importantly, anyone know how to make it work like it used to?
C99 added a new feature, hexadecimal floating-point constants. It also added new formats to the *scanf() functions. (A hexadecimal floating-point constant in source code must have an exponent part; for scanf, the exponent is optional.)
scanf reads as much of the input as it can that's consistent with the format. For pre-1999 C, this is the initial "0"; the following "X80.9"is left. For C99, "0X80.9" is valid, and is converted to the floating-point value 128.5625. (The format is the same as what's accepted by strtof().)
The C++ standard includes most of the C standard library by reference. It didn't update to the C99 version of the C library until c++2012.
Most likely Visual Studio 2015 supports C++12 or later, and Visual Studio 2013 doesn't.
Since the new behavior is now standard, I suggest adapting your code to deal with it rather than trying to force the old behavior. If there's a way to make VS2015 behave in the old way, it should be documented.
C99 adds hexadecimal floating point constants. The printf() formats are %a and %A; there are the corresponding scanf() formats too. But as with %f, %e, %g, the scanf() floating point formats all accept any floating point format (so %f can read output printed using %e, etc).
ISO/IEC 9899:2011 — §6.4.4.2 Floating constants
floating-constant:
decimal-floating-constant
hexadecimal-floating-constant
…
hexadecimal-floating-constant:
hexadecimal-prefix hexadecimal-fractional-constant
binary-exponent-part floating-suffixopt
hexadecimal-prefix hexadecimal-digit-sequence
binary-exponent-part floating-suffixopt
…
hexadecimal-fractional-constant:
hexadecimal-digit-sequenceopt .
hexadecimal-digit-sequence
hexadecimal-digit-sequence .
binary-exponent-part:
p signopt digit-sequence
P signopt digit-sequence
hexadecimal-digit-sequence:
hexadecimal-digit
hexadecimal-digit-sequence hexadecimal-digit
floating-suffix: one of
f l F L
(The hexadecimal prefix is 0x or 0X of course.)
The 0X80.9 notation doesn't exactly correspond to the notation required of hexadecimal floating point constants in C source code because there is no 'binary-exponent-part', but …
the scanf() family of functions can only push back 1 character, so they can't tell there's a problem until far too late, so it ends up treating it as if there was a P0 at the end. The scanf() functions read data items according to a conversion specification:
An input item is read from the stream, unless the specification includes an n specifier. 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.285)
The first character, if any, after the input item remains unread.
the strtod() family of functions accept:
— a 0x or 0X, then a nonempty sequence of hexadecimal digits optionally containing a
decimal-point character, then an optional binary exponent part as defined in 6.4.4.2;
and the scanf() family of functions accept:
a, e, f, g
Matches an optionally signed floating-point number, infinity, or NaN, whose
format is the same as expected for the subject sequence of the strtod
function. The corresponding argument shall be a pointer to floating.
In the 1999 C Standard it was added that the input for strtod (which is what %f in scanf refers to) can include a 0x or 0X prefix to indicate a hex float.
16 years later it seems Microsoft have finally gotten around to doing the work.
Your best option would be to move forward with the new behaviour, rather than trying to invoke compiler flags to get the old behaviour (which may not even be possible, I don't know).
To emulate the old behaviour in your project you could use code like:
double my_scan(char const *s)
{
double value = 0.0;
if ( ! memcmp(s, "0X", 2) )
sscanf(s, "%f", &value);
return value;
}
or whatever would suit your use case. Perhaps you might end up writing your own tokenizer.

Standard form in C

After a few hours of searching I have not been able to find an answer, but if this is a duplicate please point me in the correct direction.
Will a C program accept a standard form input into something like scanf("%f",&float); from the keyboard. Standard form is writing a number like 2400 as 2.4E3 if this helps you understand what I am asking.
I must stress this MUST be from the keyboard.
Yes.
scanf works identically, regardless of whether stdin is connected to a terminal, a file, or some other input stream.
The %a, %e, %f, %g scanf format codes all do the same thing: interpret the longest string which would be acceptable to strtod (§7.21.6.2/12). (And so do %A, %E, %F and %G -- paragraph 14 of the same clause.) The redundancy is because scanf formats accepts the same format codes as printf.
strtod accepts any of the following (§7.22.1.3/3):
a nonempty sequence of decimal digits optionally containing a decimal-point character, then an optional exponent part as defined in 6.4.4.2;
a 0x or 0X, then a nonempty sequence of hexadecimal digits optionally containing a decimal-point character, then an optional binary exponent part as defined in 6.4.4.2;
INF or INFINITY, ignoring case
NAN or NAN(n-char-sequenceopt), ignoring case in the NAN part,…
Yes, it is being accepted from my terminal and also the IDEone interpreter (added it in stdin which is the same as "from the keyboard").
And probably a typo, but you have missed the "" in
scanf("%f", &float)

Why cant I enter a number with decimal point in scanf? in C

I'm writing a simple C program to classfiy distances into certain ranges such as short long or medium
I understand that C will cancel out numbers after the decimal point to store as an int.
So that confuses me that why can't I type in a number such as 7.5 during scanf? as that will leads me to error.
Why can't it just read in as 7 into my scanf?
Is it because a keystroke of "." simply couldnt be accepted in declaring an int variable?
Why is it exactly?
I guess you mean 7.5 rather than 7+.+5.
This is just the way the scanf function works. When you specify %d, it means "Read digits of an integer". When you specify %f,it means "Read floating point value". The documentation for scanf gives the full detail about what is read and what stops.
If you want to read values with decimals and ignore the decimal, you have many options:
Read a double and convert to int afterwards
Read an int and check for a following . ; read another int if you find one
don't use scanf; read a string and do your own parsing
etc.
Personally I'd prefer not to use scanf, it has unavoidable UB when reading integral or floating point values.

Scanf syntax - %6d and %-6d and %0d

What are the differences between using scanf with the following format specifiers, when the input being scanned is 123456 versus when it's 123:
%6d
%-6d
%0d
What are the differences in the output?
I ended up just trying it with GCC 4.3.4, and got the following:
%6d: Works fine; only reads 6 characters (so if you try to read 123456789 it will only read 123456)
%-6d: Emits the warning:
warning: unknown conversion type character '-' in format
Doesn't read anything, and the int being written to is unmodified
%0d: Emits the warning:
warning: zero width in scanf format
Reads as though there were no width in the format specifier (%d)
I haven't checked the spec to see if those results are mandated or just how GCC handles it (EDIT: AndreyT found it)
The %-6d is an invalid format specifier. There are no format specifiers with - in them in scanf.
In %6d the 6 part is called maximum field width. It works with all format specifiers (not only with d) and specifies the maximum number of characters to read before any format-specific conversion is performed. For example, if input sequence is 1234567, then %3d will read and convert 123 and %6d will read and convert 123456.
The %0d is an invalid format specifier. Maximum field width in scanf must be a non-zero integer (see 7.19.6.2/3 in the language specification).
So, that leaves us with %6d as the only meaningful format specifier among the three you provided. Under these circumstances the question about differences in output (in results?) makes little sense.
EDIT: One can probably argue that in %-6d the -6 part is the maximum field width, which satisfies the standard requirement of being non-zero decimal integer. However, in C language terminology a decimal integer as a lexical element is a sequence of digits and digits only. It is not allowed to include a sign. I.e. neither -6 nor +6 are decimal integers. Every time you use -6 or +6 as integers in your program it is actually unary - and + operator lexeme followed by decimal integer lexeme. So, since the specification of scanf requires a non-zero decimal integer as maximum field width, it must be a sign-less integer.
Here's what I think will happen: %6d will get you the first 6 digits of the number, %-6d will probably not work as you expect, since - is more of an output alignment specifier. %0d would mean you want only 0 characters, which would probably not work as expected.
Both %-6d and %0d are invalid conversion specifications for scanf, so the behavior for those cases will be undefined. See the language standard, § 7.19.6.2, ¶ 3.
I'll assume, like Arkadiy, that you really meant printf-style formatting, since you refer to "output". I'll also assume that you're using C (as the tag suggests).
If you run:
printf("%6d %-6d %0d", num1, num2);
...you'll end up with compiler errors (or, worse still, runtime bugs), as you haven't supplied enough arguments for three formats.
I've a feeling that that's not what you were asking, though. Let's assume that you actually run:
// (I've added some extra stuff to show how the formatting works.)
printf("'%6d'/'%-6d'/'%0d'", num2, num2, num2);
...you'll get:
' 123'/'123 '/'123'
Normally, if the field width (6 in this case) is wide enough, numbers are right-aligned, space-padded. If you put a '-' before the field width, they will be right-aligned, space-padded.
The subtlety here is in the "%0d" format. You might think you're specifying a zero-width field...and you'd be wrong. The first thing after the '%' is an option flag, and '0' is a valid flag. It means, "If the field width is wider than the content, left-pad with zeroes." In this case, you haven't supplied a field width (the '0' is a flag, remember?), so the '0' flag has no effect: the field will be as wide as the content requires.
There's an even worse subtlety, though. If you specified "%-06d", you'd get right-padding with zeroes, right? Um, no. The '-' flag overrides the '0' flag, whichever order they're supplied. You'd get '123 '.

Resources