The (char *) is the cast command it tells the compiler what cawst you wish to make, in this case float* to char*. Note that casts of this type are not necessarily safe although I have seen such casts reasonbly often.
The at line 7 you tell printf you are passing it a parameter with type double with %f but what you actually pass is a variable of type char which is then automatically converted to int. This int has the value of the first byte in the memory that was being used to store the float. There is also a chance, depending on your Platform/OS, that the int is only 4 bytes long where as printf will be expecting a double of 8 bytes long so printf may well be reading more data off the stack than you put onto it which would be undefined behaviour.
The type specified by your printf format string (%f) must match the type actually passed to printf following the format string, many modern compilers parse the format string and emit warnings if they do not. For example mingw emits this message for line 7
test.c:7:5: warning: format '%f' expects type 'double', but argument 2 has type 'int'
Looking at memory
c contains the following 4 bytes (in hex on my system)
69 00 20 41
&c == p == 0x0028FF08 (When I ran it on my system this could be anything really)
Since p is a char* then *p is the first byte of c or 69
When *p is passed to printf it is converted to an int (little endian because I use an intel system)
69 00 00 00
But what printf was expecting you to pass in order to print the value of c was
00 00 00 20 0d 00 24 40
It is not cast to a float type because it is not a float type, since the type of p is char* the type of *p is char. This is an integer type and in the absence of a prototype indicating what type the parameter should be (which printf doesn't give because it accepts parameters of any type) this is then promoted using C rules about automatic promotion which basically means it gets promoted to an int.
Remember that the compiler does not store the type of the thing used originally to get the address stored in p so although you know that p points to a memory location that contains a float the compiler does not.