char * const p1; // (1)
char const * p2; // (2)
const char * p3; // (3)
從變量名向左讀:
| 聲明 | 讀法 | 指針可改? | 內容可改? | 必須初始化? |
|---|---|---|---|---|
char * const p1 | p1 是 const 指針,指向 char | 否 | 是 | 是 |
char const * p2 | p2 是指針,指向 const char | 是 | 否 | 否 |
const char * p3 | p3 是指針,指向 const char | 是 | 否 | 否 |
(2) 和 (3) 完全等價,const 在 * 左邊修飾基類型。
char c1 = 'a', c2 = 'b';
// (1) 指針常量
char * const p1 = &c1;
// p1 = &c2; // 錯誤:不能改指向
*p1 = 'c'; // 正確:可改內容
c1 = 'd'; // 正確
// (2)/(3) 常量指針
const char *p2 = &c1;
p2 = &c2; // 正確:可改指向
// *p2 = 'c'; // 錯誤:不能通過指針改內容
c1 = 'e'; // 正確:可通過原變量改
void UpperCase(char str[]) { // 實際為 char *str
for (size_t i = 0; i < sizeof(str)/sizeof(str[0]); ++i) // 錯誤!
if (str[i] >= 'a' && str[i] <= 'z') str[i] -= 'a' - 'A';
}
char str[] = "aBcDe";
cout << sizeof(str)/sizeof(str[0]) << endl; // 正確:6(含 \0)
UpperCase(str);
char str[] 在參數中**等價於** char *str,失去數組長度信息sizeof(str) 在函數內返回**指針大小**(4 或 8),而非數組長度str 是真正數組,sizeof 返回整個數組字節數
// 1. 顯式傳長度
void UpperCase(char *str, size_t len) { ... }
// 2. C++ 用引用保持數組類型(僅限固定長度)
template
void UpperCase(char (&str)[N]) { ... }
// 3. 字符串專用:strlen
void UpperCase(char *str) {
for (size_t i = 0, n = strlen(str); i < n; ++i) ...
}
| 操作數 | 結果 | 備註 |
|---|---|---|
類型 sizeof(int) | 類型大小 | 需括號 |
變量 sizeof x | 變量類型大小 | 無括號可 |
字面量 sizeof "abc" | 4(含 \0) | 字符串字面量是數組 |
| 數組名(定義處) | 整個數組字節數 | 不退化 |
| 數組參數 | 指針大小 | 已退化 |
| 動態分配指針 | 指針大小 | 無法獲取堆塊大小 |
sizeof 優先級極高(同 *、&、++),屬於一元運算符。
sizeof int * p 解析為 (sizeof int) * p,若想對指針取 sizeof 需 sizeof (int *) 或 sizeof *p。
const 位置決定修飾對象,**數組參數退化為指針**是 C 語言最大的「坑」之一。面試必考,工程中慣用 指針+長度 或 std::span/string_view (C++20) 避免丟失長度信息。