Does %p print the address of the variable as a pointer, or does it print what it points to?
Categories:
Understanding %p in C: Address or Value?

Demystify the behavior of the %p format specifier in C's printf function, clarifying whether it prints a variable's address or the value it points to.
In C programming, pointers are fundamental for direct memory manipulation. When working with pointers, it's common to want to inspect their values, particularly their memory addresses. The printf function offers the %p format specifier for this purpose, but its exact behavior can sometimes lead to confusion. This article will clarify what %p prints and how it relates to the address of a variable versus the value a pointer holds.
The Role of %p in printf
The %p format specifier in printf is specifically designed to print pointer values. According to the C standard, %p expects an argument of type void * and prints it in an implementation-defined format, which is typically hexadecimal. The crucial point here is that it prints the value of the pointer itself, which is a memory address. It does not dereference the pointer to print the value stored at that address.
#include <stdio.h>
int main() {
int x = 10;
int *ptr = &x;
printf("Value of x: %d\n", x); // Prints the integer value of x
printf("Address of x: %p\n", (void *)&x); // Prints the memory address of x
printf("Value of ptr (address it holds): %p\n", (void *)ptr); // Prints the memory address stored in ptr
printf("Value pointed to by ptr: %d\n", *ptr); // Dereferences ptr to print the value at that address
return 0;
}
Demonstrating %p with an integer variable and a pointer.
From the example above, you can observe that printf("%p\n", (void *)&x); and printf("%p\n", (void *)ptr); will output the same memory address. This is because &x yields the address of x, and ptr stores that very same address. Both are memory addresses, and %p is used to display them.
(void *) when using %p. While many compilers might implicitly convert other pointer types, explicitly casting to void * is the correct and portable way to use %p as per the C standard.Distinguishing Address from Pointed-to Value
It's vital to understand the difference between a pointer's own address, the address it holds, and the value at the address it holds. Let's break this down:
flowchart LR
A["Variable 'x' (int)"]
B["Pointer 'ptr' (int*)"]
C["Memory Address of x"]
D["Value of x (10)"]
E["Memory Address of ptr"]
A -- "Has address" --> C
A -- "Holds value" --> D
B -- "Has address" --> E
B -- "Holds address of x" --> C
C -- "Contains value" --> D
subgraph printf output
P1["printf(\"%p\", (void*)&x)"]
P2["printf(\"%p\", (void*)ptr)"]
P3["printf(\"%d\", *ptr)"]
P4["printf(\"%p\", (void*)&ptr)"]
end
P1 --> C
P2 --> C
P3 --> D
P4 --> E
style C fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
style E fill:#f9f,stroke:#333,stroke-width:2pxVisualizing the relationship between a variable, its pointer, and their addresses/values.
- Address of the variable itself (
&x): This is the memory location where the variablexis stored.%pprints this. - Value of the pointer (
ptr): This is the memory address that the pointerptrstores. Sinceptrwas assigned&x, its value is the address ofx.%pprints this. - Value pointed to by the pointer (
*ptr): This is the data stored at the memory address thatptrholds. To access this, you must dereference the pointer using the*operator. This value is printed using format specifiers appropriate for its data type (e.g.,%dforint). - Address of the pointer itself (
&ptr): Just like any other variable, the pointerptralso occupies memory.&ptrgives you the memory address where the pointer variableptris stored.%pcan also print this.
#include <stdio.h>
int main() {
int value = 42;
int *pointer_to_value = &value;
printf("1. Address of 'value': %p\n", (void *)&value);
printf("2. Value stored in 'pointer_to_value' (which is address of 'value'): %p\n", (void *)pointer_to_value);
printf("3. Value *pointed to* by 'pointer_to_value': %d\n", *pointer_to_value);
printf("4. Address of the 'pointer_to_value' variable itself: %p\n", (void *)&pointer_to_value);
return 0;
}
Further clarifying the different addresses and values involved with pointers.
%p is implementation-defined, meaning it can vary between compilers and operating systems (e.g., 0x7ffee5a0a3a8, 0x00007ffee5a0a3a8, or 0x7ffee5a0a3a8L). However, it will always represent a memory address.Conclusion
In summary, the %p format specifier in C's printf function is used to print the value of a pointer, which is a memory address. It does not automatically dereference the pointer to show the data it points to. To view the data pointed to by a pointer, you must use the dereference operator (*) and an appropriate format specifier for the data type. Understanding this distinction is crucial for debugging and correctly manipulating memory in C.