Z
ZHANK
数组与字符串

字符串处理函数

strlen/strcpy/strcat/strcmp/strtok,缓冲区溢出与安全版本

字符串处理函数

所有字符串函数都在 <string.h> 中,它们都依赖 '\0'——所以确保字符串以 '\0' 结尾是安全使用的前提。

学完本章你将: 掌握 strlen/strcpy/strcat/strcmp/strtok、缓冲区溢出防御。


必备函数速查

c
#include <stdio.h>
#include <string.h>
// ⭐ 对于 MSVC / Windows 环境,strcpy/strcat/strncpy/sprintf 等函数
//    可能触发 C4996 警告(建议使用 _s 安全版本)。
//    可在文件开头加 #define _CRT_SECURE_NO_WARNINGS 抑制,
//    或改用 strcpy_s / strcat_s 等(非标准,仅 MSVC 支持)。
//    本教程使用标准 C 函数,在 gcc/Linux 下无此问题。

int main() {
    char s[50] = "Hello";
    char d[50];

    // 长度
    printf("len = %zu\n", strlen(s));           // 5(不含 '\0')

    // 复制
    strcpy(d, s);                               // d = "Hello"
    strncpy(d, "Hi", sizeof(d) - 1);            // 安全版本,限制长度
    d[sizeof(d) - 1] = '\0';                    // 手动确保终止

    // 拼接
    strcat(s, " World");                        // s = "Hello World"
    strncat(s, "!!!", sizeof(s) - strlen(s) - 1);// 安全版本

    // 比较
    if (strcmp("abc", "abc") == 0) printf("相等\n");
    if (strcmp("abc", "abd") < 0)  printf("abc 小\n");

    // 查找子串
    char *p = strstr("Hello World", "Wo");     // 返回 "World"
    printf("%s\n", p);

    return 0;
}

strtok —— 分割字符串

c
char s[] = "apple,banana,cherry";  // 必须可修改!
char *token = strtok(s, ",");
while (token != NULL) {
    printf("[%s]\n", token);
    token = strtok(NULL, ",");
}
// 输出: [apple] [banana] [cherry]

⚠️ strtok 会修改原字符串(用 '\0' 替换分隔符),所以不能传字符串字面量


安全原则

c
// ❌ 危险模式
char buf[10];
strcpy(buf, "This is way too long");   // 溢出!
strcat(buf, "More data");              // 再溢出!

// ✅ 安全模式
snprintf(buf, sizeof(buf), "%s", "Hello");  // 自动截断
strncpy(buf, src, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';