How To Print A Pointer In C

5 min read

Pointers are the backbone of C programming, offering direct memory manipulation capabilities that define the language’s power and efficiency. Even so, for beginners and even intermediate developers, correctly displaying the value of a pointer variable remains a surprisingly common source of confusion, warnings, and subtle bugs. Understanding how to print a pointer in C requires more than just memorizing a format specifier; it demands a grasp of memory addresses, type safety, and the specific requirements of the C standard library.

The Fundamental Format Specifier: %p

The single most important rule when printing a pointer address in C is to use the %p format specifier with the printf family of functions. This specifier is designed specifically to handle void * (generic pointer) types and prints the address in an implementation-defined format, typically hexadecimal with a 0x prefix Took long enough..

This changes depending on context. Keep that in mind Simple, but easy to overlook..

Consider this basic example:

#include 

int main() {
    int value = 42;
    int *ptr = &value;

    printf("Address of value: %p\n", (void *)ptr);
    return 0;
}

Output (example):

Address of value: 0x7ffd1a2b3c4c

Why the Cast to (void *) is Mandatory

You might wonder why the cast (void *) is used in the example above. The C standard dictates that the %p specifier expects an argument of type void *. While pointers to object types (like int *, char *, struct node *) are implicitly convertible to void * in assignment contexts, variadic functions like printf do not perform implicit conversions for arguments corresponding to ... (ellipsis) parameters due to default argument promotions That alone is useful..

Passing an int * directly to %p without a cast is technically undefined behavior according to the C standard (though it works on virtually all modern architectures because pointers share the same representation). To write strictly conforming, portable code, always cast your pointer to void * when using %p Simple, but easy to overlook..

It sounds simple, but the gap is usually here It's one of those things that adds up..

// Correct and Portable
printf("%p\n", (void *)my_pointer);

// Technically Undefined Behavior (avoid this)
printf("%p\n", my_pointer); 

Common Pitfalls: %x, %lu, and %d

A frequent mistake is treating a pointer as an integer and printing it with integer format specifiers like %x (hexadecimal), %lu (unsigned long), or %d (decimal). This approach is fraught with danger That's the part that actually makes a difference..

1. Size Mismatch

On 64-bit systems (LP64 data model), pointers are 64 bits (8 bytes), while int is often 32 bits (4 bytes) and long might be 32 or 64 bits depending on the OS (Windows vs. Linux/macOS). Using %x or %d truncates the upper bits of the address, printing a wrong value. Using %lu might work on Linux/macOS (where long is 64-bit) but fails on 64-bit Windows (where long is 32-bit).

2. Type Safety and Promotions

printf is a variadic function. Default argument promotions convert float to double and narrow integers (char, short) to int. Pointers are not promoted to integers. If you use %lx (expecting unsigned long) but pass a pointer (64-bit), the register usage or stack layout expected by printf will not match the actual argument passed, leading to garbage output or crashes Worth knowing..

3. The uintptr_t Solution (C99 and later)

If you absolutely must treat a pointer as an integer—for example, to perform bitwise arithmetic on the address or store it in an integer variable—use the uintptr_t type defined in <stdint.h>. This is an unsigned integer type guaranteed to be capable of holding a pointer.

To print it, use the PRIuPTR macro from <inttypes.h>:

#include 
#include 
#include 

int main() {
    int val = 10;
    int *p = &val;
    
    // Safe conversion to integer
    uintptr_t addr = (uintptr_t)p;
    
    // Correct printing using PRIuPTR macro
    printf("Address as integer: 0x%" PRIxPTR "\n", addr); // Hex
    printf("Address as decimal: %" PRIuPTR "\n", addr);   // Decimal
    
    return 0;
}

The official docs gloss over this. That's a mistake.

This is the only portable way to print a pointer address as a raw number without using %p.

Printing Different Pointer Types

The %p specifier handles void * generically, but you will encounter specific pointer types frequently. Here is how to handle them correctly.

Character Pointers (char *) and Strings

This is the most notorious trap in C. If you pass a char * to printf with %p, it prints the address. If you pass it with %s, printf treats it as a string and prints characters until it hits a null terminator (\0).

char *str = "Hello";
char c = 'A';
char *char_ptr = &c;

printf("String content (%%s): %s\n", str);      // Prints: Hello
printf("String address (%%p): %p\n", (void *)str); // Prints address

// DANGER: char_ptr points to a single char, not a null-terminated string
// printf("%s\n", char_ptr); // UNDEFINED BEHAVIOR: reads past 'A' until random \0
printf("Single char address (%%p): %p\n", (void *)char_ptr); // Safe

Rule of thumb: Always cast to (void *) and use %p for the address. Only use %s when you are certain the pointer references a valid, null-terminated string It's one of those things that adds up. Surprisingly effective..

Function Pointers

Printing function pointers is a gray area in the C standard. The %p specifier is only guaranteed to work for object pointers (data pointers). Function pointers may have a different size or representation (e.g., Harvard architecture, or x86 far pointers in legacy 16-bit code) Worth keeping that in mind..

On modern common architectures (x86-64, ARM64), function pointers and data pointers share the same representation, so casting to void * usually works:

void my_func() {}

int main() {
    // Common workaround, not strictly standard-guaranteed for function pointers
    printf("Function address: %p\n", (void *)my_func); 
    return 0;
}

Strictly speaking, the standard does not require function pointers to be convertible to void *. For maximum portability on exotic architectures, avoid printing function pointers or cast via an integer type like uintptr_t if the platform supports it.

void * (Generic Pointers)

Since %p expects void *, a void * variable requires no cast.

void *generic_ptr = malloc(100);
printf("Allocated memory at: %p\n", generic_ptr); // No cast needed
free(generic_ptr);

Advanced Formatting Control

The output format of %p is implementation-defined. Practically speaking, the C standard does not mandate the 0x prefix, lowercase vs uppercase hex digits, or leading zeros. On the flip side, most modern compilers (GCC, Clang, MSVC) output lowercase hex with 0x prefix (e. g., 0x7ffc12345678).

You cannot force uppercase hex (%P does not exist) or remove the prefix using standard printf flags. If you need a specific format (

Fresh Picks

Just Finished

Close to Home

More on This Topic

Thank you for reading about How To Print A Pointer In C. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home