Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Memory Addressing and Pointer Fundamentals in C

Tech Apr 30 24

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.

Related Articles

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Comprehensive Guide to Hive SQL Syntax and Operations

This article provides a detailed walkthrough of Hive SQL, categorizing its features and syntax for practical use. Hive SQL is segmented into the following categories: DDL Statements: Operations on...

Understanding the MP4 File Format and Analysis

Table of Contents Overview Fundamentals of the MP4 Format Key Concepts of the Container Format Box Structure Track Samples Sample Tables Chunks Detailed Explanation of Core Boxes Additional Boxes...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.