指針聲明中,const 修飾緊鄰其右側的實體 (或左側無右側實體時修飾左側)。
| 聲明 | 讀法 (右→左) | 含義 | 可修改項 |
|---|---|---|---|
const int *pint const *p | p → * → int → const | 指向常量的指針 (Pointer to const int) 數據不可變,指針可變 | p = &other; ✓ *p = 10; ✗ |
int *const p | p → const → * → int | 常量指針 (Const pointer to int) 指針不可變,數據可變 | p = &other; ✗ *p = 10; ✓ |
const int *const p | p → const → * → int → const | 指向常量的常量指針 指針與數據均不可變 | p = &other; ✗ *p = 10; ✗ |
int n = 100;
int m = 200;
// 1. const int *p1 (指向常量的指針)
const int *p1 = &n;
p1 = &m; // ✓ 改變指向
// *p1 = 300; // ✗ 編譯錯誤:不能通過 p1 修改數據
n = 300; // ✓ n 本身非 const,可直接修改
// 2. int *const p2 (常量指針)
int *const p2 = &n;
// p2 = &m; // ✗ 編譯錯誤:p2 地址不可變
*p2 = 300; // ✓ 修改指向的數據
// 3. const int *const p3 (雙重 const)
const int *const p3 = &n;
// p3 = &m; // ✗
// *p3 = 300; // ✗
// 承諾不修改輸入緩衝區
void print_array(const int *arr, size_t len) {
for (size_t i = 0; i < len; i++)
printf("%d ", arr[i]);
}
const char* get_error_msg(int code) {
static const char *msgs[] = {"OK", "FAIL", "OOM"};
return msgs[code]; // 調用者不可修改返回的字串字面量
}
void process(int *const begin, int *const end) {
// begin/end 在函數內不可重新賦值,防止邏輯錯誤
for (int *p = begin; p != end; p++) { ... }
}
const int *p = new int(10); // 合法!
// p 指向的內存內容不可變 (通過 p)
// 但內存本身在堆上,非靜態區
// 釋放時需轉型:
delete const_cast(p); // C++ 風格
// C 風格:
free((int*)p); // 強制轉型,因為 free 接受 void*
關鍵:const 是編譯期訪問權限約束,不改變內存分配區域 (堆/棧/靜態區)。new int(10) 分配堆內存,返回地址賦給 const int* 只是限制通過該指針的寫入權限。
typedef int *IntPtr;
const IntPtr p; // 等價於 int *const p (常量指針)!
// 非 const int *p (指向常量的指針)
// 因為 const 修飾整個 IntPtr 類型 (即 "int *")
需要保護數據不被修改? → const int *p (或 int const *p) 需要保護指針不被改向? → int *const p 兩者都要保護? → const int *const p 函數參數只讀? → const Type *ptr 返回內部狀態只讀? → const Type *func() 循環迭代器固定範圍? → Type *const begin, *const end