一、C 標準庫 <string.h> 核心函數
1. 複製與拼接
| 函數 | 原型 | 說明 |
| strcpy | char *strcpy(char *dest, const char *src) | 複製含結束符,需保證 dest 足夠大 |
| strncpy | char *strncpy(char *dest, const char *src, size_t n) | 複製前 n 字符,不足補 \0,超長不加 \0 |
| strcat | char *strcat(char *dest, const char *src) | 拼接到 dest 末尾,覆蓋原 \0 |
| strncat | char *strncat(char *dest, const char *src, size_t n) | 拼接前 n 字符 |
2. 長度與比較
| 函數 | 原型 | 說明 |
| strlen | size_t strlen(const char *s) | 不含 \0 的長度 |
| strcmp | int strcmp(const char *s1, const char *s2) | 字典序比較,返回 <0, =0, >0 |
| strncmp | int strncmp(const char *s1, const char *s2, size_t n) | 比較前 n 字符 |
| strcasecmp | int strcasecmp(const char *s1, const char *s2) | 忽略大小寫比較 (POSIX) |
3. 查找
| 函數 | 原型 | 說明 |
| strchr | char *strchr(const char *s, int c) | 正向查找字符 c 首次位置 |
| strrchr | char *strrchr(const char *s, int c) | 反向查找字符 c 最後位置 |
| strstr | char *strstr(const char *haystack, const char *needle) | 查找子串首次位置 |
| strpbrk | char *strpbrk(const char *s, const char *accept) | 查找 accept 中任一字符首次位置 |
| strspn | size_t strspn(const char *s, const char *accept) | s 開頭連續屬於 accept 的長度 |
| strcspn | size_t strcspn(const char *s, const char *reject) | s 開頭連續不屬於 reject 的長度 |
4. 字符串轉數值
| 函數 | 原型 | 說明 |
| atoi | int atoi(const char *s) | 轉 int,錯誤返回 0 |
| atol | long atol(const char *s) | 轉 long |
| atof | double atof(const char *s) | 轉 double |
| strtol | long strtol(const char *s, char **endptr, int base) | 健壯轉換,base=0 自動識別 0x/0 前綴 |
| strtod | double strtod(const char *s, char **endptr) | 健壯轉 double |
5. 字符分類 <ctype.h>
isalpha(c) isupper(c) islower(c) isdigit(c) isxdigit(c)
isspace(c) iscntrl(c) ispunct(c) isalnum(c) isprint(c) isgraph(c)
參數為 int(實為 unsigned char 或 EOF),返回非 0 表示真。
二、記憶體操作 <string.h>
| 函數 | 原型 | 說明 |
| memset | void *memset(void *s, int c, size_t n) | 前 n 字節置為 c |
| memcpy | void *memcpy(void *dest, const void *src, size_t n) | 複製 n 字節,**不處理重疊** |
| memmove | void *memmove(void *dest, const void *src, size_t n) | 複製 n 字節,**安全處理重疊** |
| memcmp | int memcmp(const void *s1, const void *s2, size_t n) | 比較前 n 字節 |
| memchr | void *memchr(const void *s, int c, size_t n) | 查找前 n 字節中首個 c |
三、常見扩展函數(非標準,常見於 GCC/MSVC)
| 函數 | 說明 |
| strdup | malloc 並複製字符串,需 free |
| strrev | 原地反轉字符串 |
| strupr / strlwr | 原地大/小寫轉換 |
| strset / strnset | 設置字符串所有/前 n 字符為指定值 |
| strtok | 分割字符串,**會修改原串**,非線程安全 |
四、C++ std::string 完整指南
1. 核心特點
- 非序列容器,無
front()/back()
- 支援
operator[]、at() 訪問
size_type 為 size_t,npos = -1 表示無效位置
2. 構造方式(13 種)
// 1. 默認
string s1;
// 2. 複製
string s2(s1);
// 3. 部分複製
string s3(s1, pos, len);
// 4. C 字符串
string s4("hello");
// 5. C 字符串 + 長度
string s5("hello", 3); // "hel"
// 6. 重複字符
string s6(5, 'a'); // "aaaaa"
// 7. 迭代器範圍
string s7(s1.begin(), s1.end());
// 8. 移動構造 (C++11)
string s8(std::move(s1));
3. 容量管理
size() // 有效長度
capacity() // 緩衝區容量
reserve(n) // 預留至少 n 字節
resize(n) // 改變長度,可指定填充字符
shrink_to_fit() // 釋放多餘容量 (C++11)
4. 修改操作
// 追加
s += "tail"; s.append("tail");
s.push_back('c');
// 插入
s.insert(pos, "mid");
s.insert(pos, 3, 'x'); // 插入 3 個 'x'
s.insert(pos, it_begin, it_end);
// 替換
s.replace(pos, len, "new");
s.replace(it_begin, it_end, "new");
// 刪除
s.erase(pos, len);
s.erase(it);
s.erase(it_begin, it_end);
s.clear();
5. 查找與子串
// 查找(返回位置或 npos)
s.find("sub", pos);
s.rfind("sub", pos); // 反向
s.find_first_of("chars", pos); // 任一字符
s.find_last_of("chars", pos);
s.find_first_not_of("chars", pos);
s.find_last_not_of("chars", pos);
// 子串
string sub = s.substr(pos, len);
// C 風格指針
const char* cstr = s.c_str(); // 含 \0
const char* data = s.data(); // C++11 保證含 \0
6. 比較
s.compare(s2); // -1/0/1
s.compare(pos, len, s2);
s.compare(pos, len, s2, pos2, len2);
s.compare(pos, len, "cstr");
s.compare(pos, len, "cstr", len2);
7. 迭代器
s.begin(), s.end(), s.rbegin(), s.rend()
s.cbegin(), s.cend() // C++11 常量迭代器
8. 輸入輸出
getline(cin, s); // 讀整行
cin >> s; // 讀單詞
cout << s;
五、最佳實踐與避坑指南
- 緩衝區溢出:用
strncpy/snprintf/strncat 替代無界版本
- 重疊複製:
memmove 安全,memcpy 未定義行為
- 字符串字面量不可修改:
char *p = "hello"; p[0] = 'H'; // UB,用 char p[] = "hello";
- strtok 破壞原串且非線程安全:C++ 用
stringstream 或 std::getline + 分割
- atoi 族無錯誤檢測:優先用
strtol/strtod 檢查 endptr
- C++ string 避免頻繁擴容:大量拼接前
reserve()
- 嵌入 \0 的字符串:C 風格以 \0 結尾,
std::string 可包含 \0,用 data()+size() 安全處理
- 字節序無關:字符串操作不涉及網絡字節序
六、速查表:常用操作對照
| 操作 | C 風格 | C++ string |
| 複製 | strcpy/strncpy | s2 = s1 / s2.assign(s1) |
| 拼接 | strcat/strncat | s1 += s2 / s1.append(s2) |
| 長度 | strlen | s.size() |
| 比較 | strcmp/strncmp | s1.compare(s2) / s1 == s2 |
| 查找字符 | strchr/strrchr | s.find(c) / s.rfind(c) |
| 查找子串 | strstr | s.find(sub) |
| 轉整數 | strtol | stoi / stol / stoll |
| 轉浮點 | strtod | stof / stod / stold |
| 分割 | strtok | stringstream + getline |
| 大小寫轉換 | strupr/strlwr (非標準) | transform + ::toupper/tolower |
總結
- C 風格:
<string.h> + <ctype.h>,掌握核心 10 個函數覆蓋 90% 場景
- 記憶體操作:
memmove > memcpy(安全性),memset 只能填單字節值
- C++
std::string:功能豐富、異常安全、支援嵌入 \0,現代 C++ 首選
- 避坑關鍵:緩衝區大小、重疊複製、字面量只讀、錯誤檢測、線程安全
熟練這些工具,字符串處理不再是痛點。