1

I read the following program code:

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


int main () {
    int *p;
    p= malloc(sizeof(int)); 
    *p=42; 

    printf("Pointer p has address %p and points to %p\n",
    (void*)&p, (void*)p);

   free(p);    

}

My question refers to the following part:

printf("Pointer p has address %p and points to %p\n", (void*)&p, (void*)p);

I don't understand what the (void*) is doing. Is this a cast? What's the point of doing this?

What is the difference of the above to simply writing the following?

 printf("Pointer p has address %p and points to %p\n", &p, p);
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
steady_progress
  • 3,311
  • 10
  • 31
  • 62

2 Answers2

10

This is because, %p explicitly expects an argument of type void *.

Quoting C11, chapter §7.21.6.1, fprintf()

p The argument shall be a pointer to void. [....]

Since printf() is a variadic function and there is no default argument promotion for pointers, the cast is required.

Strictly speaking, as per the standard mandate, from same chapter, paragraph 7

[...] If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

That said, to make the answer complete,

  • p = malloc(sizeof(int)); can be rewritten as p= malloc(sizeof*p); to make it more robust.
  • You should always check against the success of malloc() before using the returned pointer.
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • @Sourav Ghoush: Thank you for your answer. However, the program also works without the (void*) cast. So, it does not seem to be necessary for %p to be supplied a void pointer (instead of, say, an int pointer) – steady_progress Dec 12 '16 at 16:53
  • 2
    Sometimes you get "lucky" and UB does what you expect. – George Dec 12 '16 at 16:55
  • 2
    @steady_progress: without the cast, the behavior is *undefined*, since the type of the argument doesn't match what the conversion specifier expects - it may work, it may not. If `sizeof (int *) != sizeof (void *)`, then you'll probably get garbled output. – John Bode Dec 12 '16 at 16:55
  • 2
    @steady_progress Technically speaking, the cast is required, as mandated in the standard. Without that, it invokes [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior). – Sourav Ghosh Dec 12 '16 at 16:56
  • 1
    and undefined behavior includes working right up to the moment when it doesnt (usually in production, at midnight) – pm100 Dec 12 '16 at 16:58
1

I don't understand what the (void*) is doing. Is this a cast? What's the point of doing this?

Yes, it's a cast. It doesn't seem to be necessary with my compiler (llvm), which gives the following output even if I remove the casts:

Pointer p has address 0x7fff501357d8 and points to 0x7fcb38c00390

Other compilers may not be so forgiving.

Caleb
  • 124,013
  • 19
  • 183
  • 272