Introduction
Working with memory addresses represents a fundamental skill in systems programming. When developers first encounter pointers in C, distinguishing between referencing and dereferencing operations often creates confusion. Two operators—the ampersand (&) and asterisk (*)—form the foundation of pointer manipulation, yet their distinct roles frequently lead to implementation errors.
This article examines the address-of operator (referencing) and the indirection operator (dereferencing), demonstrating their correct usage through original code examples and memory diagrams. You will gain a practical understanding of how these operators interact with variables, pointers, and memory addresses. The concepts presented apply equally to embedded systems, operating system development, and performance-critical applications where direct memory access proves essential.
(toc) #title=(Table of Content)
What Are Pointer Operators in C?
Pointer operators enable programs to manipulate memory addresses directly. The C language provides two primary operators for this purpose: the address-of operator (&) and the indirection operator (*). These operators serve complementary but distinct functions.
The Address-of Operator (&)
The address-of operator, also known as the referencing operator, returns the memory address of any variable. When placed before a variable name, &variable produces the location where that variable resides in memory.
Consider a standard integer declaration:
int counter = 42;
The expression &counter yields the memory address where the value 42 is stored. This address might appear as 0x7ffd5a8b2c14 on a modern 64-bit system.
The Indirection Operator (*)
The indirection operator, commonly called the dereferencing operator, accesses the value stored at a specific memory address. When applied to a pointer variable, *pointer retrieves the content located at the address contained within that pointer.
For a pointer ptr holding address 0x1000, writing *ptr instructs the processor to fetch whatever value resides at memory location 0x1000.
Components of Pointer Operations
Understanding pointer operators requires familiarity with three interconnected components:
| Component | Description | Example |
|---|---|---|
| Variable | Named storage location holding a value | int score = 100; |
| Address | Numeric location of a variable in memory | &score produces 0x7ffeeb2c |
| Pointer | Variable that stores an address | int *ptr = &score; |
When these components work together, programs can indirectly access and modify data. A pointer variable contains an address; dereferencing that pointer retrieves or modifies the value at that address.
Pointer Size and Memory Architecture
The storage size of a pointer depends on the target architecture. On a 16-bit compiler, pointers occupy 2 bytes. For 32-bit systems, pointer size increases to 4 bytes. Modern 64-bit environments typically use 8-byte pointers.
This size uniformity means a pointer to char consumes the same memory as a pointer to a 64-byte struct. The pointer stores only the starting address of the data, regardless of the data type's size.
Practical Examples: Using & and * Operators
The following examples demonstrate correct operator usage through original code scenarios.
Initializing and Using Pointers
#include <stdio.h>
int main() {
int temperature = 27; // Ordinary variable
int *ptr; // Pointer declaration
ptr = &temperature; // ptr now holds address of temperature
printf("Value: %d\n", temperature); // Prints: 27
printf("Address: %p\n", &temperature); // Prints memory address
printf("Pointer value: %p\n", ptr); // Same address as above
printf("Dereferenced: %d\n", *ptr); // Prints: 27
return 0;
}
In this pattern, &temperature obtains the address, while *ptr accesses the stored value. The pointer stores the address; the indirection operator retrieves the value at that address.
Modifying Values Through Pointers
Changing a variable through its pointer uses the indirection operator on the left side of an assignment:
int quantity = 50;
int *ptr = &quantity;
printf("Before: %d\n", quantity); // Output: 50
*ptr = 75; // Changes quantity through the pointer
printf("After: %d\n", quantity); // Output: 75
The statement *ptr = 75 writes the value 75 to the memory address stored in ptr, which is exactly where quantity resides. This technique enables functions to modify caller variables without returning values.
Common Pitfalls and Misunderstandings
The Comma Operator Confusion
When multiple assignments appear with comma operators, precedence rules affect pointer initialization. Consider:
int a = 5, b = 8;
int *p;
p = &a, &b; // Only &a assigns to p (comma as operator)
The comma operator evaluates left to right but returns the rightmost value. However, assignment has higher precedence than the comma operator. The expression becomes (p = &a), &b. Only &a assigns to p.
For correct multiple assignments, use separate statements or parentheses:
p = &a; // Clear and explicit
Multiple Pointers to the Same Variable
Multiple pointers can store addresses of the same variable. This creates multiple paths to access the same memory location:
int value = 100;
int *first_ptr = &value;
int *second_ptr = &value;
*first_ptr = 200; // value becomes 200
printf("%d\n", *second_ptr); // Prints: 200
Both first_ptr and second_ptr point to value. Modifying through one pointer affects the value visible through the other.
Practical Application: Using Pointers with scanf
The address-of operator appears frequently with scanf because the function requires memory addresses to store input values:
int user_age;
float user_height;
printf("Enter age: ");
scanf("%d", &user_age); // & passes address of user_age
printf("Enter height: ");
scanf("%f", &user_height); // & passes address of user_height
The scanf function writes input values directly to these memory addresses. Without the address-of operator, scanf would receive the variable's current value instead of its location.
Printing Addresses and Values
Formatted output for addresses typically uses %p (pointer format) or %x for hexadecimal representation:
int data = 42;
int *ptr = &data;
printf("Value of data: %d\n", data); // 42
printf("Address of data: %p\n", &data); // Hexadecimal address
printf("Pointer contains: %p\n", ptr); // Same address
printf("Dereferenced pointer: %d\n", *ptr); // 42
printf("Address of pointer: %p\n", &ptr); // Where ptr itself lives
The address of the pointer (&ptr) differs from the address stored in the pointer (ptr). The pointer variable occupies its own memory location, separate from the variable it points to.
Value Retrieval Through Indirection
The expression *pointer evaluates to the value stored at the contained address. This forms the inverse operation of &:
int x = 25;
int *p = &x; // p = address of x
int y = *p; // y = value at that address (25)
The relationship can be expressed as: *&x == x. Taking the address of x then dereferencing that address returns the original x value.
Conclusion
The address-of and indirection operators provide fundamental memory access capabilities in C programs. The & operator retrieves variable addresses for pointer initialization, while the * operator accesses or modifies values at those addresses. Understanding these operators enables developers to write efficient systems software, implement data structures, and interface with hardware registers.
Mastery requires practice with pointer arithmetic, array-pointer relationships, and function parameter passing. The concepts presented here form the foundation for advanced topics including dynamic memory allocation, data structure implementation, and performance optimization.