const 出現在 * 左邊 → 修飾指向的值(常量指針/指向常量的指針)
const 出現在 * 右邊 → 修飾指針本身(指針常量)
const int* p1; // 或 int const* p1 int const* p2; // 等價寫法
*p1 = 10; // ❌ 編譯錯誤p1 = &other; // ✅ 合法int a = 10, b = 20; const int* p = &a; // p 指向 a // *p = 30; // ❌ 錯誤:不能通過 p 修改值 p = &b; // ✅ 合法:p 可指向別處 cout << *p; // 輸出 20 const int c = 100; const int* q = &c; // ✅ 合法:常量指針指向常量 // int* r = &c; // ❌ 錯誤:非常量指針不能指向常量(丟棄 const)
int* const p3; // 必須初始化
p3 = &other; // ❌ 編譯錯誤*p3 = 10; // ✅ 合法int a = 10, b = 20; int* const p = &a; // 必須初始化 *p = 30; // ✅ 合法:修改 a 為 30 // p = &b; // ❌ 錯誤:p 是常量指針,不能改變指向 cout << a; // 輸出 30
const int* const p4 = &a; // 或 int const* const p4 // *p4 = 10; // ❌ 值不可變 // p4 = &b; // ❌ 指針不可變 // 完全只讀,類似引用但可為空
| 聲明 | 值可改? | 指針可改? | 俗稱 |
|---|---|---|---|
int* p | ✅ | ✅ | 普通指針 |
const int* p / int const* p | ❌ | ✅ | 常量指針 / 指向常量的指針 |
int* const p | ✅ | ❌ | 指針常量 |
const int* const p | ❌ | ❌ | 常量指針常量 |
void printArray(const int* arr, size_t n) {
// 保證不修改 arr 指向的數據
for (size_t i = 0; i < n; ++i) cout << arr[i] << ' ';
}
// 只讀迭代器 using const_iterator = const T*; // 可寫迭代器 using iterator = T*;
volatile uint32_t* const UART_DR = (uint32_t*)0x40004000; // 地址固定(指針常量),值可讀寫但編譯器不優化(volatile)
const int* p = nullptr; // 類型安全的空指針 int* const q = nullptr; // 指針常量初始化為空 // 建議統一使用 nullptr 替代 NULL/0
「const 修飾左邊的東西;若左邊沒東西,修飾右邊」
const int* p → const 修飾 int → 指向 const int 的指針int* const p → const 修飾 * → const 指針const int* const p → 兩個 const 分別修飾 int 和 *掌握這一規則,再複雜的聲明(如函數指針、多重指針)也能秒懂。建議配合 cdecl 工具練習:cdecl> explain const int* const* p。