-2

In below code, how can void pointer p store address of i? What is the meaning of "*(float *)p" inside printf() ?

#include
void main()
{
  int i = 10;
  void *p = &i;
  printf("%f\n", *(float *)p);
}
Anjani Kumar
  • 396
  • 1
  • 5
  • 23

3 Answers3

5

A void* can store any address. It's a "generalized pointer" basically. You can cast back the void* to the type you saved into it to get a useful type out of it and do things with it like pointer arithmetic or dereferencing the pointer. The pointer itself doesn't know anything about what type it stores and thus you have to tell it what type it's pointing to so. It's lack of type makes it dangerous since it's the programmer's job to remember what type the pointer points to.

In your case, you make p point to the address of i which is an int and then you try to print out the pointee of p as a float while you didn't assign it to the address of a float in the first place. This is undefined behaviour and a good example of the dangers of a void* in inexperienced hands.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
1

In C void* can point to any type of memory location. You can assign void* to a variable of type int*, double*, char*.., etc. Generally void* is used to pass parameters to the function who type is not know at the time of defining.

But You can have any variable of type void. So at the time of dereferencing you have to cast a void* to some pointer type but not void*.

so by *(float *)p (which is undefined) you are casting p(which is void* type) to float* type, then you are dereferencing it to double(But memory is actually int). So that it expects float type variable at the memory it is pointing to.

hrishi
  • 443
  • 2
  • 12
  • 1
    Any answer to this question needs to mention that the code invokes undefined behavior. Otherwise the answer is misleading people into thinking that the code is fine. – Lundin Nov 18 '16 at 10:46
1

how can void pointer p store address of i?

A void pointer can point to any data pointer. See C11 draft, 6.3.2.3. So,

void *p = &i;

simply makes p point to the address of object i. You can later safely convert it back to an int*. For example,

int i = 10;
void *p = &i;
int *j = p; /* j now point to &i */

or you can directly cast p and use it:

printf("%d\n", *((int*) p));

This is all fine.

What is the meaning of "*(float *)p" inside printf() ?

It's an attempt to reinterpret an int object as a float object which isn't allowed. In this statement:

printf("%f\n", *(float *)p);

You are casting p, a void*, to a float* which may be undefined because the object p points to is an int and you are attempting to reinterpret it as if it's a float object. From C11 draft, 6.3.2.3:

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.

This also violates C11 draft, 6.5.7 as int* and float* are distinct types and are not compatible with each other.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
P.P
  • 117,907
  • 20
  • 175
  • 238
  • The quote only hold true if you never dereference this "different object type" pointer. – Hatted Rooster Nov 18 '16 at 10:10
  • @GillBates No, the pointer must also be correctly aligned. If it isn't the mere assignment causes undefined behavior. – 2501 Nov 18 '16 at 10:12
  • @2501 I know, I was talking about the case where that was true. Even then, it's still UB trying to deref it. – Hatted Rooster Nov 18 '16 at 10:15
  • @GillBates Then you should have mentioned that. And sometimes you can dereference the pointer even with a different type. – 2501 Nov 18 '16 at 10:16
  • 1
    This isn't the whole truth though. The code violates strict aliasing since the pointers point to non-compatible objects of different _effective type_. See C11 6.5. – Lundin Nov 18 '16 at 10:48