Scan the code to follow Chip Dynamics and say goodbye to “chip” congestion!

Search WeChat
Chip Dynamics
In the realm of C language, if pointers are the “swordsmen” who dominate the scene, then const is their “golden shield”. Today, we will unveil four magical protective combinations:
const int *p, int *const p, int const *p, const int *const p——
They are like different armors worn by pointers, some protect the sword (data), some protect the swordsman (pointer), and some protect both!
As a core feature of C language, pointers empower programmers to directly manipulate memory. However, this power comes with risks: accidental data modification, illegal memory access, dangling pointers, and other issues abound. The const keyword is a safety mechanism tailored for pointers, intercepting illegal operations at compile time to avoid runtime disasters.
const int *p (data cannot be modified)1.1 Armor Characteristics
int treasure = 100;const int *p = &treasure; // Wearing "data protection armor"*p = 200; // Error! Modification of treasure content is prohibited (compile error)treasure = 200; // Correct! The owner of the treasure can modify itp = &new_treasure; // Correct! The swordsman can change the treasure
-
Protects the data being pointed to: the target value cannot be modified through the pointer (*p cannot be modified)
-
Does not protect the pointer itself: the pointer can point to other addresses (p can point to other addresses)
1.2 Principle Analysis
The compiler will prevent any attempts to modify data through this pointer:
*p = 200; // Compile error! Armor is effective
But the original variable itself can still be modified:
treasure = 200; // Allowed! Bypasses the armor for direct modification
The pointer can also freely point to a new address:
int new_treasure = 300;p = &new_treasure; // Allowed! Change target
1.3 Usage Scenarios
Function parameter protection: ensures that internal functions do not accidentally modify external data
// Safely view data, preventing accidental modificationvoid display_data(const int *data) { printf("Data value: %d", *data); // *data = 0; // Armor prevents this operation!}
Accessing hardware registers: prevents accidental writes to read-only registers
const volatile uint32_t *REG_STATUS = (uint32_t*)0x40000000;// Can only read the status register, cannot modifyuint32_t status = *REG_STATUS;
Protecting critical configurations: safeguarding constant configurations in the program
const float PI = 3.14159;const float *pi_ptr = Π// Ensure that pi is not accidentally modified
int *const p (pointer cannot be modified)2.1 Armor Characteristics
int gold = 100;int silver = 200;int *const p = &gold; // Wearing "pointer fixed armor"*p = 150; // Correct! Can modify treasure contentp = &silver; // Error! Changing treasure is prohibited (compile error)
-
Protects the pointer itself: the pointer address cannot be changed (p cannot be modified)
-
Does not protect the data being pointed to: the data content can be modified (*p can be modified)
2.2 Principle Analysis
The compiler will prevent any attempts to modify the pointer address:
int silver = 200;p = &silver; // Compile error! Armor is effective
But data can be freely modified through the pointer:
*p = 150; // Allowed! Modify the treasury content
2.3 Usage Scenarios
Hardware register mapping: operations on fixed address hardware
#define LED_REG (*(volatile int *const)0x1234)LED_REG = 1; // Write register// LED_REG = &other; // Prohibited from modifying address!
Secure critical pointers: ensure that critical pointers are not tampered with
int security_flag = 0;int *const sec_ptr = &security_flag;// Ensure that the security flag pointer remains valid
Function return pointer protection: prevent returned pointers from being modified
int* get_protected_ptr() { static int value = 42; int *const p = &value; return p; // Return protected pointer}
int const *p (data cannot be modified)
int diamond = 500;int const *p = ⋄ // Wearing "invisible protection armor"printf("%d", *p); // 500*p = 600; // Error! Modification prohibited (equivalent to const int *p)
Important Truth:
int const *p and const int *p are twin brothers!
-
Both have the same functionality: protect data, do not protect the pointer
-
Only the position of const is different (the compiler treats them as equivalent)
const int *const p (double protection)4.1 Armor Characteristics
int crown = 1000;const int *const p = &crown; // Wearing "supreme holy armor"*p = 2000; // Error! Modification of treasure is prohibitedp = &other; // Error! Changing treasure is prohibited
-
Protects the data being pointed to: cannot modify the value through the pointer (*p cannot be modified)
-
Protects the pointer itself: cannot change the pointer’s direction (p cannot be modified)
4.2 Principle Analysis
The compiler will prevent any modification attempts:
*p = 2000; // Error! Data cannot be modifiedp = &other; // Error! Pointer cannot be modified
4.3 Usage Scenarios
Global constants: protect read-only global variables
const char *const SECRET = "OpenSesame";// SECRET[0]='X'; // Error!// SECRET = "New"; // Error!
Hardware read-only areas: mapping ROM or flash memory areas
const uint32_t *const BOOT_ROM = (uint32_t*)0x08000000;uint32_t first_instruction = BOOT_ROM[0];
Comparison Table of Four Armors
|
Armor Type |
Data Protection |
Pointer Protection |
|
const int *p |
✅ |
❌ |
|
int *const p |
❌ |
✅ |
|
int const *p |
✅ |
❌ |
|
const int *const p |
✅ |
✅ |
Understanding the Golden Rules of const and Pointers
The combinations of const are simply four types:
1.int * const p; // const between * and p2.const int *p; // const in front of int3.int const *p; // const between int and *4.const int * const p;// const before *, between * and p
Step 1: Ignore the variable type (like int)
When analyzing the relationship between const and pointers, we can first ignore the specific variable type (like int), as the type does not affect the semantic analysis of const. Simplifying gives us four forms:
1. * const p;2. const * p;3. const * p; 4. const * const p;
We find that after crossing out int, 2 and 3 become the same, making it simpler and clearer.
Step 2: Find the object immediately adjacent to const on the right
The const modifies the object immediately adjacent to it on the right. Based on this principle:
-
* const p → the object immediately adjacent to const is p (pointer variable) → p cannot be modified (pointer direction cannot change)
-
Example: int *const p = &a;
-
p = &b; // Error! p cannot be modified
-
*p = 100; // Allowed! Data pointed to can be modified
-
const * p → the object immediately adjacent to const is * (dereference operator) → *p cannot be modified (data pointed to cannot change)
-
Example: const int *p = &a;
-
*p = 100; // Error! Data cannot be modified
-
p = &b; // Allowed! Pointer direction can be modified
-
const * const p → the first const is immediately adjacent to * (dereference operator), the second const is immediately adjacent to p (pointer variable) → both *p and p cannot be modified
-
Example: const int *const p = &a;
-
*p = 100; // Error! Data cannot be modified
-
p = &b; // Error! Pointer direction cannot be modified
Key Summary
-
const modifies the pointer (p): pointer direction cannot change → int *const p
-
const modifies the dereference (*p): data pointed to cannot change → const int *p or int const *p
-
Double const: both pointer direction and data cannot change → const int *const p
Hands-on Challenge: Armor Testing Ground
#include <stdio.h>void test_const() { int a = 10, b = 20; // 1. Test const int *p const int *p1 = &a; // *p1 = 30; // Uncommenting will cause an error p1 = &b; // Allowed // 2. Test int *const p int *const p2 = &a; *p2 = 30; // Allowed // p2 = &b; // Uncommenting will cause an error // 3. Test ultimate armor const int *const p3 = &a; // *p3 = 40; // Uncommenting will cause an error // p3 = &b; // Uncommenting will cause an error}int main() { test_const(); printf("All armor tests passed!"); return 0;}

If you find this article helpful, click “Like”, “Share”, “Recommend”!