First as a beginner, you should try to write correct code that raises no warning before trying to understand what happens under the hood and why some incorrect expressions still give correct results.
C is a very permissive language, that is as long as the compiler can translate what it reads it generally assumes that the programmer knows why he wrote it. It's what happens here.
In C, the address of a struct
can be cast to an address to its first element. So (void *) &curr
is the same as (void *) &(curr->val)
. Here I cast everything to void *
to make sure to have compatible pointer types.
That means that *((int *) curr)
is a perfectly defined C expression and its value is indeed curr->val
. But it is correct, because I wrote an explicit pointer cast.
What you wrote works only by accident, because as curr
is an aggregate type; you pass an int
and an item *
to printf
and use only its first value - this is no longer standard C and I can only assume a classic implementation to guess that. But just replace your print commands by that:
printf("%d - %d\n", curr->val, 12);
printf("%d - %d\n", *curr, 15);
You should see garbage in the second printf
, because with %d
you declare that you pass a simple int
and actually pass an aggregate. Here again, nothing is explicitly mandated per standard, but common implementation should give this result.
TL;DR: As *curr
is not an int
, printf("%d\n", *curr);
is Undefined Behaviour. This means that anything can happen, even the expected result, but a different version of same compiler, or another compiler, or even a change in compilation parameters could give a different result, as could a minor change in the code.
And C allows automatic pointer cast to and from void *
and you should never cast the return value of malloc
as it can hide bugs. Please write:
curr = malloc(sizeof(item));
It is no longer C++ compatible, but is it correct C.