指標涉及兩個可修改性:
const 的位置決定鎖定哪一維度:
const 在 * 左側 (或類型右側) → 鎖定 內容const 在 * 右側 → 鎖定 指標本身int* pint i = 1, j = 100;
int* p = &i;
*p = 2; // ✅ 修改內容
p = &j; // ✅ 改變指向
const int* p / int const* p
int i = 1, j = 100;
const int* p = &i; // 或 int const* p = &i; 兩者完全等價
*p = 2; // ❌ 編譯錯誤:assignment of read-only location
p = &j; // ✅ 指標本身可變
i = 2; // ✅ 原變量直接修改合法 (const 只限制通過 p 訪問)
printf("%d", *p); // 輸出 2
核心語義:「我承諾不通過這個指標修改數據」,適用於只讀參數、字符串字面量、查找表。
int* const p
int i = 1, j = 100;
int* const p = &i; // 必須初始化,之後不可改指向
*p = 2; // ✅ 可修改內容
p = &j; // ❌ 編譯錯誤:assignment of read-only variable 'p'
核心語義:「這個指標終身綁定這個地址」,適用於硬件寄存器映射、固定內存池起始地址、嵌入式外設基址。
const int* const p
int i = 1, j = 100;
const int* const p = &i; // 內容不可改、指向不可改
*p = 2; // ❌ 錯誤
p = &j; // ❌ 錯誤
i = 2; // ✅ 原變量直接修改合法
核心語義:「完全只讀視圖」,適用於常量表導出、不可變配置結構體。
* 右邊 有無 const → 決定指標本身能否變 (身)* 左邊 (含類型修飾符) 有無 const → 決定指向內容能否變 (值)
const int * p; // * 左有 const → 值鎖定;* 右無 const → 身自由
int const * p; // 同上 (const 修飾 int)
int * const p; // * 右有 const → 身鎖定;* 左無 const → 值自由
const int * const p; // 兩邊都有 → 雙鎖定
| 實參類型 | 形參類型 | 合法性 | 說明 |
|---|---|---|---|
int* | const int* | ✅ 隱式轉換 | 「可寫」→「只讀」安全收窄 |
const int* | int* | ❌ 需強制轉型 | 「只讀」→「可寫」危險擴大,編譯器禁止 |
int* const | int* | ✅ 值傳遞 | 指標副本,const 屬性不傳遞 |
const int* const | const int* | ✅ 隱式轉換 | 雙鎖定 → 單鎖定 (值) |
void Foo(const int** pp) { /* ... */ }
int main()
{
int* p = NULL;
Foo(&p); // ❌ 警告/錯誤:int** 不能隱式轉為 const int**
// 正確:const int* const* pp 或 const int* p; Foo(&p); (C++允許,C標準嚴格禁止)
}
原因:允許 int** → const int** 會破壞 const 承諾 (可通過修改中間指標指向 const 數據,再通過原 int* 修改)。
typedef struct { const int* data; size_t len; } Buffer;
void Process(Buffer* buf)
{
buf->data[0] = 1; // ❌ 錯誤:data 指向 const int
buf->data = NULL; // ✅ 合法:指標本身非 const
}
char* s = "hello"; // ❌ C++非法,C警告:字面量類型是 const char[]
const char* s = "hello"; // ✅ 正確
s[0] = 'H'; // ❌ 運行時崩潰 (只讀段)
void Func(const int* p)。int* const p = &x; 讓編譯器幫你防禦誤賦值。const T* 表示只讀視圖,返回 T* 表示調用方擁有所有權 (需 free)。static const int* const TABLE[] = { ... }; 雙重保護。搞清 const int*、int const*、int* const、const int* const 的語義邊界,是 C 程序員從「能跑通」進階到「寫得穩」的分水嶺。記住 「右定身,左定值」,配合編譯器警告 -Wwrite-strings -Wcast-qual,讓 const 成為你代碼中最忠實的靜態分析器。