搞懂 const 與 * 的相對位置,掌握「從右向左讀」口訣,避免面試與實戰中的常見錯誤。
| 宣告 | 俗稱 | 指標可改 | 指向值可改 | 口訣 (右→左) |
|---|---|---|---|---|
const int *pint const *p | 指標常量 (Pointer to const) | ✅ | ❌ | p is a pointer to const int |
int *const p | 常量指標 (Const pointer) | ❌ | ✅ | p is a const pointer to int |
const int *const p | 雙重常量 | ❌ | ❌ | p is a const pointer to const int |
int *p | 普通指標 | ✅ | ✅ | p is a pointer to int |
// 步驟:找出變數名,然後向左讀 const int *p; // ↑ p 是變數名 // ← * : pointer to (指向...) // ← int : int // ← const : const (修飾 int) // 結論:p is a pointer to const int int *const p; // ↑ p // ← const : const (修飾 pointer) // ← * : pointer to // ← int : int // 結論:p is a const pointer to int
#includevoid test_const_pointer() { int a = 10, b = 20; const int *p = &a; // 指標常量:指向常數的指標 printf("*p = %d\n", *p); // 10 p = &b; // ✅ 可改變指向 printf("*p = %d\n", *p); // 20 // *p = 30; // ❌ 編譯錯誤:不能修改指向的值 } void test_pointer_const() { int a = 10, b = 20; int *const p = &a; // 常量指標:指標本身是常數 printf("*p = %d\n", *p); // 10 *p = 30; // ✅ 可修改指向的值 printf("*p = %d\n", *p); // 30 // p = &b; // ❌ 編譯錯誤:不能改變指向 } void test_const_pointer_const() { int a = 10; const int *const p = &a; // 雙重常量 printf("*p = %d\n", *p); // 10 // *p = 20; // ❌ // p = &b; // ❌ } int main() { test_const_pointer(); test_pointer_const(); test_const_pointer_const(); return 0; }
// 1. 不修改指向內容 (唯讀輸入)
void printArray(const int *arr, int n) {
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
}
// 2. 不修改指向關係 (輸出參數常用)
void setPointer(int *const ptr, int value) {
*ptr = value; // 修改值 OK
// ptr = ...; // ❌ 不能改 ptr 本身
}
// 3. 完全不可修改
void safeFunc(const int *const ptr) {
// 既不改值,也不改指向
}
const int arr[5] = {1,2,3,4,5};
// arr 退化為 const int* (指標常量)
// arr = other_arr; // ❌ 陣列名不可修改
// arr[0] = 10; // ❌ 內容不可修改
int *const ptr = arr; // ❌ 編譯警告:丟棄 const
const int *ptr2 = arr; // ✅ 正確
const char *strvoid f(const int *p) 可接收 int* 或 const int*,反之不行constexpr:編譯期常數constinit (C++20):靜態儲存期變數編譯期初始化std::as_const(obj) (C++17):獲得 const 引用const:void foo() const 不修改 this 指向物件