字符串解析與格式化是 C 開發高頻任務。本文系統整理 sscanf 掃描匹配技巧、sprintf/snprintf 安全格式化、以及 strlen/memset 基礎操作,附豐富實戰模式與避坑指南。
函數原型:int sscanf(const char *str, const char *format, ...);
核心優勢:格式字符串支持集合操作(%[...]),可替代簡單正則,效率極高。
| 模式 | 含義 | 示例輸入 → 結果 |
|---|---|---|
%s | 跳過空白,讀單詞 | "123456 " → "123456" |
%4s | 最大讀 4 字符 | "123456" → "1234" |
%[^ ] | 讀到空格為止 | "123456 abcd" → "123456" |
%[1-9a-z] | 僅匹配集合內字符(貪婪) | "123abcDEF" → "123abc" |
%[^A-Z] | 遇大寫字母停止 | "123abcDEF" → "123abc" |
%*[^/]/%[^@] | 跳過 / 前內容,取 / 到 @ 間 | "iios/12DDWDFF@122" → "12DDWDFF" |
%*s%s | 跳過第一個詞,取第二個 | "hello, world" → "world" |
%[^=]=%s:提取 key=value 中的 value(如 notepad=1.0.0 → 1.0.0)%*[^:]:跳過冒號前所有字符,不保存%[^;]:讀到分號為止(適合解析 email:xxx@yy.com;)%Ns 限寬。scanf 族函數存在浮點解析 bug,關鍵路徑建議手寫解析器。| 函數 | 原型 | 關鍵差異 | 返回值 |
|---|---|---|---|
sprintf | int sprintf(char *buf, const char *fmt, ...) | 無長度檢查,極易溢出 | 寫入字符數(不含 \0) |
snprintf | int snprintf(char *buf, size_t size, const char *fmt, ...) | 最多寫 size-1 字符,末尾補 \0 | 格式化後完整長度(可能 ≥ size) |
char buf[32]; int len = snprintf(buf, sizeof(buf), "Hello %s %d", "World", 2024); // len = 14, buf = "Hello World 2024" (安全截斷如果超長) // 替代 itoa:整數轉字符串 snprintf(buf, sizeof(buf), "%d", 12345); // "12345"
關鍵點:snprintf 返回「完整格式化長度」,而非實際寫入長度。判斷是否截斷:if (len >= size) truncated = true;
| 函數 | 原型 | 核心語義 | 常見錯誤 |
|---|---|---|---|
strlen | size_t strlen(const char *s) | 返回 首個 \0 前的字符數 | 傳非 \0 結尾指針 → UB;統計含 \0 長度應用 sizeof |
memset | void *memset(void *s, int c, size_t n) | 按字節填充 c(取低 8 位) | 用於非字符數組(如 int[])清零以外數值 → 錯誤;結構體填充可能破壞 padding |
// 清零結構體/數組(最常用) memset(&struct_obj, 0, sizeof(struct_obj)); memset(int_arr, 0, sizeof(int_arr)); // 僅適合清 0 或 -1 (0xFF) // 錯誤示範:memset(arr, 1, sizeof(arr)) → 每字節變 0x01,int 變 0x01010101 ≠ 1
sscanf + %[] 模式,複雜場景轉正則或手寫狀態機。snprintf 或 C++ std::format/fmt::format。strlen 只能用於合法 C 字符串;二進制數據長度用 sizeof 或顯式長度字段。memset 僅用於「按字節置 0/0xFF」,其他數值請用循環或 std::fill。