0

I know this is the incorrect way to use scanf( ). But I want an expert in C to answer this question:

#include <stdio.h>
int main(int argc, char *argv[])
{
    int *a;
    printf("please input one number:\n");
    scanf("%d", &a);
    printf("your input is %d\n", a);
    return 0;
}

the output:

please input one number:
30
your input is 30

since *a already exist, it won't bring segment fault while executing. and scanf( ) magically fill correct data into *a, made (int *) into (int); then printf( ) will output correctly.

I think this code could work because of sizeof(int*) and sizeof(int) is the same value on my system. So I also do check some type size on my system:

sizeof(short) return 2
sizeof(short*) return 4
sizeof(int) return 4
sizeof(int*) return 4
sizeof(long) return 4
sizeof(long*) return 4
sizeof(float) return 4
sizeof(float*) return 4
sizeof(double) return 8
sizeof(double*) return 4
sizeof(char) return 1
sizeof(char*) return 4

seems this code could also work when float, but it doesn't. the code I try is here:

#include <stdio.h>
int main(int argc, char *argv[])
{
    float *a;
    printf("please input one number:\n");
    scanf("%f", &a);
    printf("your input is %f\n", a);
    return 0;
}

the output:

please input one number:
3.5
your input is -0.034267

scanf( ) should work since I use %f when calling scanf( ). since I still give it a 4-bytes memory address.

I can't figure it out. could someone who is knowing the whole scanf( ) thing explain why these two codes(almost the same) works different way?

Wally
  • 37
  • 6
  • I think `float` is promoted to `double` when passed as one of variable length arguments. – zch Mar 06 '16 at 13:09
  • What do you expect the result to be and what is the actual result? The address should be an integer number, therefore using %f to read it as float doesn't seem right. – Filkolev Mar 06 '16 at 13:13
  • You invoked *undefined behavior* and it *happened* to work. – MikeCAT Mar 06 '16 at 13:15
  • a is already an address -> `scanf("%d", a);` and `%d` should receive value `*a`, not address. – Aleksandar Makragić Mar 06 '16 at 13:16
  • @AleksandarMakragić It is an usual way to use `scanf()` and `printf()`, but not for this experiment. Since `a` is not initialized, there will be big chance to get Segmentation Fault. – MikeCAT Mar 06 '16 at 13:20
  • I know a is already an address, if I want scanf("%d", a), I'll call malloc() for it. but the scanf() seems only careing the address is initialized or not. if you do reserve enough memory for it, it should work anyway. isn't it? – Wally Mar 06 '16 at 13:20
  • Typically it might "work", but do not try to cause *undefined behavior* except for experiment! – MikeCAT Mar 06 '16 at 13:24
  • `scanf()` treats parameters as being addresses of whatever type the format string specifies, regardless of what is actually passed. `printf()`, similarly, treats parameters as being of whatever type is specified in the format string, regardless of what is actually passed - hence undefined behaviour if types don't match. The only exception, for `printf()`, is that a `float` parameter is promoted to `double` before being passed so - when the format string specifies a `float` - `printf()` assumes a `double` was passed as the corresponding argument. – Peter Mar 06 '16 at 13:58

1 Answers1

0

Usually data having type float is passed as variable length argument are promoted to double as @zch says, and printf() expects for it.

In this case, what is passed is float* and it won't become double magically.

That is why printf() get wrong data -- both data and size are wrong.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • Right. A four-byte `float *` gets passed, but `printf` tries to read an 8-byte double so that it can print it out as `%f`. – Steve Summit Mar 06 '16 at 13:22
  • thanks, you're right. I search the entire forum gets this thread: http://stackoverflow.com/questions/210590/why-does-scanf-need-lf-for-doubles-when-printf-is-okay-with-just-f?rq=1 – Wally Mar 06 '16 at 13:35