这几个C语言函数在处理字符串和内存时容易混淆,我来帮你梳理清楚它们的用法和区别。

1. strlen - 获取字符串长度

函数原型:

size_t strlen(const char *s);

功能: 计算字符串的长度(不包括结尾的 \0

特点:

  • 遇到 \0 才停止计数

  • 如果字符串没有 \0,会一直计数直到崩溃

示例:

char str[] = "Hello";
size_t len = strlen(str);  // len = 5

2. strcpy - 字符串拷贝(不安全)

函数原型:

char *strcpy(char *dest, const char *src);

功能: 将 src 字符串(包括结尾的 \0)复制到 dest

特点:

  • 不检查缓冲区大小,可能造成缓冲区溢出

  • 如果 dest 空间不足,会覆盖后续内存,非常危险

示例:

char dest[10];
strcpy(dest, "Hello");  // 没问题
strcpy(dest, "Hello World!");  // 危险!dest只有10字节,但需要13字节

3. strncpy - 带长度限制的拷贝(有陷阱)

函数原型:

char *strncpy(char *dest, const char *src, size_t n);

功能: 最多复制 n 个字符到 dest

陷阱:

  1. 不会自动添加 \0:如果 src 长度 ≥ n,dest 不会以 \0 结尾

  2. 填充 \0:如果 src 长度 < n,会用 \0 填充剩余空间

示例:

char dest[10];
strncpy(dest, "Hello", 10);     // dest = "Hello\0\0\0\0\0"
strncpy(dest, "Hello World!", 5); // dest = "Hello"(没有\0!)
dest[5] = '\0';                  // 需要手动添加\0

4. strlcpy - BSD 安全拷贝(非标准C)

函数原型:

size_t strlcpy(char *dest, const char *src, size_t size);

功能: 安全地复制字符串,保证以 \0 结尾

特点:

  • 复制最多 size-1 个字符

  • 保证 dest 以 \0 结尾(如果 size > 0)

  • 返回 src 的长度(用于检测截断)

  • 不是标准C函数,是 BSD 扩展,Linux 需要定义 _BSD_SOURCE

示例:

char dest[10];
size_t len = strlcpy(dest, "Hello World!", sizeof(dest));
// dest = "Hello Worl"(自动添加\0)
// len = 12(原始字符串长度,可用于检测截断)
if (len >= sizeof(dest)) {
    printf("字符串被截断了!\n");
}

5. memcpy - 内存拷贝

函数原型:

void *memcpy(void *dest, const void *src, size_t n);

功能: 从 src 复制 n 个字节到 dest

特点:

  • 不关心内容,纯粹按字节复制

  • 不处理 \0 字符

  • src 和 dest 不能重叠(重叠用 memmove

示例:

char src[] = "Hello\0World";
char dest[20];
memcpy(dest, src, 12);  // 复制12字节,包括中间的\0
// dest = "Hello\0World"(\0后面内容也复制了)

对比总结

函数 安全性 终止符处理 适用场景
strcpy ❌ 危险 自动添加 确定目标足够大时使用
strncpy ⚠️ 有陷阱 不一定添加 不推荐,容易出错
strlcpy ✅ 安全 保证添加 推荐(如果可用)
memcpy ⚠️ 需谨慎 不处理 任意内存块复制
strlen ⚠️ 需谨慎 遇到\0停止 获取字符串长度

推荐用法

安全字符串拷贝(标准C)

char dest[10];
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';  // 手动添加终止符

安全字符串拷贝(有 strlcpy)

#ifdef __linux__
#define _BSD_SOURCE
#endif
#include <string.h>
​
char dest[10];
strlcpy(dest, src, sizeof(dest));

内存复制

// 确保不重叠
memcpy(dest, src, size);
​
// 可能重叠时使用
memmove(dest, src, size);

常见错误示例

// ❌ 错误1:strncpy 忘记添加\0
char buf[5];
strncpy(buf, "Hello", sizeof(buf));
printf("%s", buf);  // 可能打印出"Hello"后跟垃圾数据
​
// ❌ 错误2:strcpy 溢出
char small[5];
strcpy(small, "Too long");  // 缓冲区溢出!
​
// ❌ 错误3:strlen 用于非字符串
char no_null[3] = {'a', 'b', 'c'};
size_t len = strlen(no_null);  // 未定义行为,会继续读内存直到遇到\0

选择哪个函数取决于你的需求:需要安全字符串操作优先考虑 strlcpy 或手动处理 strncpy;处理二进制数据用 memcpy;简单场景且确定安全时可用 strcpy

posted on 2022-10-12 10:21  轩~邈  阅读(145)  评论(0)    收藏  举报