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:2px
Visualizing the relationship between a variable, its pointer, and their addresses/values.
- Address of the variable itself (
&x
): This is the memory location where the variablex
is stored.%p
prints this. - Value of the pointer (
ptr
): This is the memory address that the pointerptr
stores. Sinceptr
was assigned&x
, its value is the address ofx
.%p
prints this. - Value pointed to by the pointer (
*ptr
): This is the data stored at the memory address thatptr
holds. 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.,%d
forint
). - Address of the pointer itself (
&ptr
): Just like any other variable, the pointerptr
also occupies memory.&ptr
gives you the memory address where the pointer variableptr
is stored.%p
can 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.