The Ultimate Combination of C Language Pointers and const

The Ultimate Combination of C Language Pointers and const

Hello everyone, I am the Information Guy~

Today, I will introduce the intricacies of the const keyword and pointers in the C language. As we all know, the flexibility of pointers is the core charm of C, but it is also a double-edged sword—any slight misstep can lead to memory overflow, data corruption, and other issues.

The addition of the <span><span>const</span></span> keyword gives pointers the ability of “selective freedom”: it retains the dynamic operation of pointers while precisely controlling the modifiability of data. Today, we will reveal the core techniques of combining <span><span>const</span></span> with pointers based on practical engineering scenarios, helping you write safer and more robust code.

1. Technical Essence: Three “Contracts” of const and Pointers

Before diving into applications, let’s clarify the three combinations of <span>const</span> when modifying pointers (using the <span>int</span> type as an example):

Syntax Pointer Mutability Content Mutability Core Meaning
<span>const int *p</span> ✔️ Read-only data, pointer is flexible
<span>int *const p</span> ✔️ Fixed address, data can be modified
<span>const int *const p</span> Completely read-only

Memory Mnemonic:<span><span>const</span></span> on the left (<span><span>const T *p</span></span><code><span><span>) → Data is immutable</span></span>

<span><span>const</span></span> on the right (<span><span>T *const p</span></span><code><span><span>) → Pointer is immutable</span></span>

• Both sides have <span><span>const</span></span> → Double lock seal

2. Practical Scenarios: Five Highlights of const Pointers

Function Parameters: A Tool for Defensive ProgrammingScenario: Designing a function to print the length of a string, ensuring that the internal content of the string will not be modified.

size_t safe_strlen(const char *str) {
    // str[0] = 'A';  // Compilation error! Modification of data is prohibited
    size_t len = 0;
    while (str[len] != '\0') len++;
    return len;
}

Value:• Clearly defines the function’s responsibility: <span>const char *</span> informs the caller that “this function will not modify your data.”

• Prevents internal misoperations: even if the function has complex logic, it cannot modify data through pointers.

Accessing Hardware Registers: A Mandatory Constraint on Address ImmutabilityScenario: Operating the registers of embedded devices, requiring fixed pointer addresses but allowing data to be written.

#define HW_REG_ADDR 0x40000000

volatile uint32_t *const reg = (uint32_t *)HW_REG_ADDR;

void set_register() {
    *reg = 0x55AA;    // Correct: write data
    // reg = (void*)0x50000000;  // Compilation error! Address is immutable
}

Value:• Prevents the pointer from being accidentally modified, ensuring the absolute correctness of hardware operation addresses.

• The combination of <span>volatile</span> and <span>const</span> ensures that the address is fixed while avoiding compiler optimizations.

Embedded Configuration Tables: Double Protection for Sensitive DataScenario: Read-only configuration parameters for storage devices (such as baud rate, parity).

const struct UartConfig {
    int baud_rate;
    char parity;
} *const config_table = (const struct UartConfig*)0x8000;

void init_uart() {
    // config_table-&gt;baud_rate = 115200;  // Error: data cannot be modified
    // config_table = NULL;               // Error: pointer cannot be modified
    set_uart(config_table-&gt;baud_rate, config_table-&gt;parity);
}

Value:• Both data and pointer are <span>const</span>, preventing accidental overwriting of the configuration table at runtime.

• Mapped to a fixed memory address, suitable for configuration data stored in ROM or Flash.

Dynamic Memory Management: Preventing Pointer “Drift”Scenario: Allocating fixed blocks in a memory pool, ensuring that management pointers do not go out of bounds.

uint8_t memory_pool[1024];
uint8_t *const pool_start = memory_pool;
uint8_t *const pool_end = memory_pool + sizeof(memory_pool);

void* allocate_mem(size_t size) {
    static uint8_t *current = memory_pool;
    if (current + size &gt; pool_end) return NULL;
    void *ptr = current;
    current += size;
    return ptr;
}

Value:<span>pool_start</span> and <span>pool_end</span> act as boundary sentinels, prohibiting modification and ensuring the memory pool range remains constant.

String Constants: Avoiding Wild Pointer TrapsScenario: Defining read-only global string constants.

const char *const LOG_HEADER = "[SYSTEM]: ";

void log_message(const char *msg) {
    printf("%s%s\n", LOG_HEADER, msg);
    // LOG_HEADER[0] = '(';       // Error: data cannot be modified
    // LOG_HEADER = "[ERROR]: ";  // Error: pointer cannot be modified
}

Value:• Prevents string constants from being accidentally modified (which could otherwise trigger segmentation faults).

3. Advanced Techniques: The Game of const and Type Casting

Breaking through const restrictions? Beware of UB!Question: Can you modify <span>const</span> data through other pointers?

const int a = 100;
int *p = (int*)&amp;a;
*p = 200;  // Undefined behavior (UB)! May crash or silently fail

Conclusion:<span>const</span> is a “gentleman’s agreement” among developers; breaking it may lead to unpredictable consequences.

Passing const through Multi-level PointersRules: <span>const</span> modifications should follow the “right to left” binding principle:

const int **pp1;     // pp1 is mutable, *pp1 is mutable, **pp1 is immutable
int *const *pp2;     // pp2 is mutable, *pp2 is immutable, **pp2 is mutable
int **const pp3;     // pp3 is immutable, *pp3 is mutable, **pp3 is mutable

Application: Gradually constraining mutability in complex data structures (such as linked lists, trees).

4. Conclusion: The Engineering Philosophy of const Pointers

  1. Safety First: By checking at compile time, runtime errors are eliminated at the bud stage.
  2. Code as Documentation:<span>const</span> clearly conveys data usage permissions, reducing collaboration costs within teams.
  3. Resource Contracts: In embedded and system-level development, const pointers are the “guardians” of hardware, memory, and data.

Finally

I have collected some embedded learning materials. Reply with [1024] in the public account to find the download link!

Recommended Articles
Click the blue text to jump
☞ Collection | Comprehensive Programming of Linux Applications
☞ Collection | Learn Some Networking Knowledge
☞ Collection | Handwritten C Language

☞ Collection | Handwritten C++ Language
☞ Collection | Experience Sharing
☞ Collection | From Microcontrollers to Linux
☞ Collection | Power Control Technology
☞ Collection | Essential Mathematics for Embedded Systems
☞ Collection | MCU Advanced Collection

☞ Collection | Embedded C Language Advanced Collection

☞ Collection | Experience Sharing

Leave a Comment