所有高級語言的字符串類別,本質上都追溯至 C 語言的字符數組。C 語言本身並無專屬字符串類型,而是以以空字符(\0) 結尾的字符數組來表示字符串。這一設計雖然簡潔,卻為後續語言的字符串實現奠定了基礎。
C++ 繼承了 C 風格字符串,並引入了標準庫 std::string,提供更安全、便捷的操作介面。實務上建議優先使用 std::string,但在與 C API 交互、處理舊代碼時,仍不可避免地需使用 C 風格字符串。
本質是字符指針或數組,以 \0 結尾:
const char* str = "zhangdan"; // 記得末尾隱含 \0
const char* p = str; // 通過指針操作字符串
操作依賴 <cstring> 函數(strcpy、strcmp、strcat 等),開發者需自行管理內存,易發生緩衝區溢出、野指針等問題。
std::string需引入 <string> 標頭。核心優勢在於封裝了內存管理,提供豐富的成員函數:
= 操作符,無需 strcpy。[] 與 at()(帶邊界檢查)。==、!=、< 等運算符,語義直觀。+、+=、append() 一體化。size()、length() 常數時間複雜度。示例:
string str1 = "111111", str2 = "222222";
string str3 = str1 + str2; // 自動管理內存,無需手動拼接
// string -> C 字符串(只讀)
const char* cstr = str2.c_str();
// C 字符串 -> string(隱式轉換)
const char* src = "zhangdan";
string str2 = src; // 安全拷貝
cin >> str(遇空白停止)或 getline(cin, str)(讀整行)。atoi、atol(<cstdlib>),C++11 推薦 stoi、stol 等,提供異常處理。Java 中 String 是不可變對象(final 類),非基本類型,默認值 null。
new 的差異
String str = "xxx"; // 常量池
String str2 = new String("xxx"); // 堆內存
System.out.println(str == str2); // false(地址不同)
System.out.println(str.equals(str2)); // true(內容相同)
核心機制:字符串常量池
new String() 強制在堆上創建新對象,不入池(除非調用 intern())。
String str3 = "zhangpeng";
String str4 = "zhangpeng"; // true(同一常量池引用)
String str = "zhang" + "peng"; // 編譯期常量折疊,同樣指向常量池 "zhangpeng"
Java 保證編譯期可確定的字符串常量在常量池中唯一,這是 == 返回 true 的關鍵。
String vs StringBuffer/StringBuilder| 特性 | String | StringBuffer / StringBuilder |
|---|---|---|
| 可變性 | 不可變 | 可變 |
| 線程安全 | 天然安全 | Buffer 同步安全 / Builder 非同步 |
| 拼接性能 | 頻繁創建臨時對象,低 | 內部字符數組擴容,高 |
| 適用場景 | 少量操作、鍵值、常量 | 大量拼接、構建動態字符串 |
編譯器會將 str += "xx" 優化為 StringBuilder.append().toString(),但顯式使用 StringBuilder 仍更可控。
'...'、雙引號 "..."、三引號 """...""" / '''...'''(多行、文檔字符串)。\,原始字符串 r"..." 忽略轉義。split、join、format、f-string 等),操作極為便捷。理解各語言字符串的底層實現(C 數組、C++ 封裝、Java 不可變對象+常量池、Python 動態對象),有助於選擇恰當工具、避開性能陷阱、編寫更健壯的代碼。