# Where do the values of the following variables come from?

4

Could you explain how the variables x, y, z get this value in this code:

``````    #include <stdio.h>
#include <stdlib.h>

main(){

float x=1, *y, z=3;
y= &x;
x=z+5;
y++;

printf("%f\n",x); /*8.000000*/
printf("%f\n",y); /*8.000000*/
printf("%f\n",z); /*3.000000*/
printf("%f\n",&y); /*3.000000*/

}
``````

asked by user105251 29.10.2018 в 17:51
source

4

I have verified that the same thing happens to me. I'm going to try to explain what I think should come out, and a possible conjecture why that does not work out.

``````float x=1, *y, z=3;
y= &x;
x=z+5;
y++;
``````

The variable `x` is clear. Take the value 1 initially, but then change the value when you do `x=z+5` , so it ends with the value 8.0. No surprises in that.

The variable `y` is a pointer type. By doing `y=&x` you are assigning the memory address of variable `x` . The memory addresses are in the background numbers, 32 bits or 64 bits, depending on the architecture of the CPU and the operation.

Let's say they are 64 bits. Then the variable `x` could be stored for example in memory address `00007ffffa19b704` , and when doing `y=&x` , you are assigning `y` the value `00007ffffa19b704` . These numbers are not invented. They are the ones that have come out when running on Linux.

When you print `y` in the second `printf()` the compiler should give you a warning since you are specifying `%f` as a format string, so expect a variable of type float, but find instead `y` , which is type `float*` . Still "swallow". When the time comes to execute that call, `printf()` will receive the number `00007ffffa19b704` in binary, and will try to decode it according to the IEEE754 standard of floating point of simple precision.

To begin with we have a problem, because according to that standard what you expect is 32 bits, and you are receiving 64. It will possibly interpret only the lower part of that data, that is% `fa19b704` . But it is that decoding this number (for example using this shows that the represented number is `-1.9953335E35` and not 8.00000. First WTF?

Then print `z` . There are no surprises here either, since `z` is a `float` that you originally assigned the value `3.0` , and that's exactly what comes out.

Finally you print `&y` . Again we are doing something wrong, since `&y` is not a `float` but the address of a pointer to float, that is, a `float**` . But it matters little whether it is a `float*` or a `float**` . The important thing is that it is (again) a memory address. In this case a different address, since it is the address where the variable `y` is stored. Let's say it's `00007ffffa19b708` .

I can say the same as before. When attempting to print that data as if it were float, it may stay with only its low part ( `fa19b708` ) and decode it as an IEEE754 float. But it should give `-1.9953343E35` and not `3.0` . Second WTF?

## My guess

I think that, since what we are giving `printf()` in the second and fourth cases are "broken" data (memory addresses instead of floating), if those addresses result in decoding a floating point error (an invalid number, out of range, infinity, or NaN), possibly `printf()` "break" and print anything . (I no longer think this, see update)

My hypothesis is that it returns what it had in a local variable on which the resulting string is built. And that variable is static and therefore contains the result of the previous execution. And that therefore prints the same thing that had printed the `printf()` previous.

## My proof of concept

To verify if my guess is correct, I ran the following program:

``````#include<stdio.h>
#include<math.h>
main(){

float x=1, *y;
y= &x;

printf("%f\n",M_PI);
printf("%f\n",y);

}
``````

Result:

``````3.141593
3.141593
``````

What corroborates my hypothesis. Now we only have to clarify why the address of `x` is not a valid IEEE754 number: -)

## Update

Although the "proof of concept" still points in the direction that `printf()` is showing the buffer of a previous conversion, the reasons for this are less clear. Initially I thought that could be due to a bug in the implementation of `printf_fp` (the function of the libc that deals with formatting floating point numbers), which behaved badly against certain numbers. But this is not the cause.

The following program copies those same numbers that caused problems (that is, a copy of the pointer value) to another variable, this time of type `double` , and `printf()` shows it without problems.

``````#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main(){
double x=8.0, *y;
double zz;
y= &x;

printf("%g\n", 3.14);
printf("%g\n", y);
memcpy(&zz, &y, sizeof(y));
printf("%g\n", zz);
}
``````

Exit:

``````3.14
3.14
6.95285e-310
``````

Therefore the cause of the mystery is not in the bytes that `printf()` receives in the variable, but in the type of this variable. In a way, what is a pointer instead of a `float` makes a difference in what `printf_fp()` receives. From there we have undefined behavior (although very consistent).