Memory Addressing and Pointer Fundamentals in C
Memory addresses serve as unique identifiers for data storage locations in RAM. In C programming, a pointer represents a variable specifically designed to contain these memory addresses, enabling indirect data manipulation.
Address Retrieval and Storage
When declaring a varible, the compiler allocates contiguous memory bytes to hold its value. The address-of operator & retrieves the starting address of this allocated region.
#include <stdio.h>
int main(void) {
int counter = 100;
printf("Address: %p\n", (void*)&counter);
return 0;
}
The & operator yields the lowest address among the bytes occupied by the operand. For multi-byte types like integers, the system utilizes this base address combined with type information to access the complete data range.
Pointer Declaration and Indirection
Pointer variables require explicit type declarations that match the data they reference:
double salary = 5000.50;
double *salary_ptr = &salary;
The asterisk in the declaration double *salary_ptr establishes the variable as a pointer, while the preceding type specifier double indicates the type of data residing at the target adress. This type association determines memory access boundaries during dereferencing operations.
The indirection operator * accesses or modifies values at the stored address:
*salary_ptr = 5500.75; // Modifies the original variable
Memory Access Patterns and Type Significance
Pointer types govern byte-level access permissions. Consider the following contrast:
unsigned int flags = 0x12345678;
unsigned int *int_view = &flags;
*int_view = 0; // Clears all 4 bytes (on typical 32-bit systems)
Versus narrow access:
unsigned int flags = 0x12345678;
unsigned char *byte_view = (unsigned char*)&flags;
*byte_view = 0; // Only modifies the least significant byte: 0x12345600
This demonstrates how type casting alters the memory footprint of write operations. Character pointers provide single-byte granularity, while integer pointers operate on word-sized chunks.
Generic Pointers
The void* type represents a generic pointer capable of storing any address without type enforcement. However, arithmetic operations and dereferencing require explicit casting to a concrete type:
void *generic = &flags;
// *generic = 5; // Invalid: cannot dereference void*
*(unsigned int*)generic = 5; // Valid with cast
Pointer Arithmetic
Arithmetic operations on pointers scale according to the underlying type size. Incrementing an integer pointer advances the address by sizeof(int) bytes:
int dataset[] = {10, 20, 30, 40, 50};
int *cursor = dataset;
size_t elements = sizeof(dataset) / sizeof(dataset[0]);
for (size_t i = 0; i < elements; i++) {
printf("%d ", *cursor);
cursor++; // Advances to next integer element
}
Subtracting two pointers yields the element count between their addresses, useful for computing offsets:
ptrdiff_t span = &dataset[4] - &dataset[0]; // Results in 4
Relational operators compare memory locations:
int *boundary = dataset + elements;
while (cursor < boundary) {
printf("%d ", *cursor++);
}
Undefined Behavior and Memory Safety
Dangling pointers create undefined behavior through several mechanisms:
Uninitialized Storage:
int *uninitialized;
*uninitialized = 10; // Dangerous: random memory target
Bounds Violation:
int buffer[5];
int *iter = buffer;
for (int i = 0; i <= 5; i++) { // Erroneous: iter exceeds allocation
*iter++ = i;
}
Stack Lifetime Violation:
int* create_dangling(void) {
int temporary = 99;
return &temporary; // Returns address of expiring stack frame
}
Immutable References with const
The const qualifier restricts modification capabilities. When applied to the pointed-to data:
const int *read_only; // Data immutable, pointer mutable
int const *alternate_syntax; // Equivalent to above
When applied to the pointer itself:
int *const fixed_address; // Pointer immutable, data mutable
For complete immutability:
const int *const immutable_both;
This distinction enables fine-grained control over memory access permissions, preventing accidental modifications while maintaining pointer flexibility.