復合類型是構建複雜數據結構的基石。本文深入剖析 C++ 中數組與字符串的底層機制、常見陷阱,並重點對比 C 風格字符串與 std::string 的異同,幫助你寫出更安全、高效的代碼。
int n = 10; int arr[n]; // 錯誤 (C++ 標準),需用 constexpr 或宏。int scores[5] = {90, 85}; // {90, 85, 0, 0, 0}
char name[] = "Hello"; // 自動推導大小 6 (含 '\0')
C++ 不進行邊界檢查。arr[100] = 0; 不會編譯報錯,但可能破壞棧內存、導致難以復現的崩潰。務必確保下標在 [0, size-1] 範圍內。
數組名在多數表達式中隱式轉換為指向首元素的指針(退化),失去大小信息。因此:
int a[5], b[5]; a = b; // 錯誤sizeof(arr) 返回指針大小而非數組大小。對策:傳遞數組時同時傳遞大小,或改用 std::array/std::vector/std::span (C++20)。
本質是 char[],必須以空字符 '\0' (ASCII 0) 結尾。標準庫函數 (strlen, strcpy, strcat, cout) 均依賴 '\0' 判定結束。
char a[10] = {'H', 'i'}; // 非字符串,無 '\0'
char b[10] = "Hi"; // 字符串,自動補 '\0' -> {'H','i','\0',0...}
char c[] = "Hi"; // 大小 3
sizeof vs strlen 易混淆點sizeof(arr):整個數組佔用的字節數(包含未使用空間與 '\0')。strlen(str):字符串實際長度(遇 '\0' 停止,不含 '\0')。char s[20] = "Hello";
sizeof(s); // 20
strlen(s); // 5
| 方法 | 行為 | 風險 |
|---|---|---|
cin >> arr | 讀單詞(遇空白停止),自動加 '\0' | ① 丟失空白 ② 易溢出(無長度限制) |
cin.getline(arr, n) | 讀整行(含空白),遇 '\n' 停止,丟棄 '\n',加 '\0' | 最多讀 n-1 字符,安全 |
cin.get(arr, n) | 讀整行,保留 '\n' 在緩衝區 | 連續調用需手動清理 '\n' (cin.get() 或 .ignore()) |
最佳實踐:優先使用 cin.getline(arr, size) 讀取整行;混合 >> 與 getline 時,先用 cin.ignore() 清理殘留換行符。
s1 = s2)、拼接 (s1 + s2, s1 += s2)、比較 (==, <)。size(), length(), empty(), clear(), substr(), find(), c_str() 等。c_str() 返回以 '\0' 結尾的 const char*。std::string s1, s2 = "panther";
s1 = s2; // 賦值
std::string s3 = s1 + s2; // 拼接
s1 += "!"; // 追加
std::cout << s1.size(); // 長度 (無參數)
std::getline(cin, s1); // 安全讀取整行 (含空白)
// C -> C++
char cstr[] = "Hello";
std::string cpp_str(cstr); // 或 cpp_str = cstr;
// C++ -> C
const char* p = cpp_str.c_str(); // 指針生命週期綁定 cpp_str
// 注意:不可對 c_str() 返回值修改,cpp_str 修改/銷毀會導致指針失效
std::string 和 std::vector/array,避免手動內存管理與邊界錯誤。'\0' 結尾約定、sizeof/strlen 差異 是避開經典坑的關鍵。