Variable of type DOUBLE converts number strangely.

J

John

I'm new to C and I know this is probably one of those "most commonly
mis-interpreted as a problem", newcomer type of question, but for this code:


double x;
printf("Enter number:");
scanf("%f", &x);
printf("The number is %f", x);


If I enter 2 as the number, the following is returned:
-1.997517

This doesn't happen for 'float', only for 'double'.

Is there something I'm not getting here? Is there something I'm
supposed to be doing?

I'm teaching myself with GCC v3.3.6, and while I recall reading
somewhere that floating point numbers do slightly different things, I
didn't think they'd be THAT different!
 
M

Martin Ambuhl

John said:
I'm new to C and I know this is probably one of those "most commonly
mis-interpreted as a problem", newcomer type of question, but for this
code:


double x;
printf("Enter number:");
scanf("%f", &x);
printf("The number is %f", x);


If I enter 2 as the number, the following is returned:
-1.997517

This doesn't happen for 'float', only for 'double'.

Is there something I'm not getting here? Is there something I'm
supposed to be doing?

I'm teaching myself with GCC v3.3.6, and while I recall reading
somewhere that floating point numbers do slightly different things, I
didn't think they'd be THAT different!

The difference is not where you think, but that the specifiers for scanf
and not what they are for printf. When you supply printf with x an
argument, the value of x is promoted to a double, whether x was a float
or a double, so a single specifier ("%f") works for both. But scanf
gets the address of that x supplied as a argument. When x is a float,
&x is the address of a float; when x is a double, &x is the address of a
double. Those are different things, which possibly different sizes and
possibly different internal forms, so need different specifiers. See
code below:

#include <stdio.h>

int main(void)
{
double x;
char input_string[] = "2";

/* similar to your posted code */
printf("Enter number:");
fflush(stdout);
#if 0
scanf("%f", &x); /* replaced so not dependent on
keyboard typing */
#endif
sscanf(input_string, "%f", &x); /* gcc should give a diagnostic if
you invoke it with reasonable
options. */
printf("%s\n", input_string); /* to look like you typed it */
printf("The number is %f\n\n", x);

/* notice the change in the sscanf specifier below */
printf("Enter number:");
fflush(stdout);
sscanf(input_string, "%lf", &x);
printf("%s\n", input_string);
printf("The number is %f\n", x);

return 0;
}
 
P

pete

John said:
I'm new to C and I know this is probably one of those "most commonly
mis-interpreted as a problem", newcomer type of question, but for this code:

double x;
printf("Enter number:");
scanf("%f", &x);
printf("The number is %f", x);

If I enter 2 as the number, the following is returned:
-1.997517

This doesn't happen for 'float', only for 'double'.

scanf and printf are not symetric on %f.
%f prints a double.
%f scanfs a float.
%lf scanfs a double.
 
J

John

Martin said:
John said:
I'm new to C and I know this is probably one of those "most commonly
mis-interpreted as a problem", newcomer type of question, but for this
code:


double x;
printf("Enter number:");
scanf("%f", &x);
printf("The number is %f", x);


If I enter 2 as the number, the following is returned:
-1.997517

This doesn't happen for 'float', only for 'double'.

Is there something I'm not getting here? Is there something I'm
supposed to be doing?

I'm teaching myself with GCC v3.3.6, and while I recall reading
somewhere that floating point numbers do slightly different things, I
didn't think they'd be THAT different!


The difference is not where you think, but that the specifiers for scanf
and not what they are for printf. When you supply printf with x an
argument, the value of x is promoted to a double, whether x was a float
or a double, so a single specifier ("%f") works for both. But scanf
gets the address of that x supplied as a argument. When x is a float,
&x is the address of a float; when x is a double, &x is the address of a
double. Those are different things, which possibly different sizes and
possibly different internal forms, so need different specifiers. See
code below:

#include <stdio.h>

int main(void)
{
double x;
char input_string[] = "2";

/* similar to your posted code */
printf("Enter number:");
fflush(stdout);
#if 0
scanf("%f", &x); /* replaced so not dependent on
keyboard typing */
#endif
sscanf(input_string, "%f", &x); /* gcc should give a diagnostic if
you invoke it with reasonable
options. */
printf("%s\n", input_string); /* to look like you typed it */
printf("The number is %f\n\n", x);

/* notice the change in the sscanf specifier below */
printf("Enter number:");
fflush(stdout);
sscanf(input_string, "%lf", &x);
printf("%s\n", input_string);
printf("The number is %f\n", x);

return 0;
}


Ah, so I see. There is a different data type identifier I should use to
scanf a double, "%lf", which I guess stands for "long float"? The book
I'm studying didn't get to that and all previous examples so far have
been "%f".

Anyway, when I add that to my scanf, everything works fine now. THanks!
 
K

Keith Thompson

pete said:
scanf and printf are not symetric on %f.
%f prints a double.
%f scanfs a float.
%lf scanfs a double.

To expand on that:

%f prints a double, but in effect it can print either a float or a
double (because a float is impicitly promoted to double).

No such promotion can occur for scanf, which expects a pointer to a
float or double *object*, not just a float or double *value*.
 
F

Frodo Baggins

The difference is not where you think, but that the specifiers for scanf
and not what they are for printf.

gcc with -Wall catches this easily.

HTH
Regards,
Frodo Baggins
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top