欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > 【C/C++】C语言内存操作与字符串处理汇总

【C/C++】C语言内存操作与字符串处理汇总

2025/5/20 20:29:13 来源:https://blog.csdn.net/YZJincsdn/article/details/148060951  浏览:    关键词:【C/C++】C语言内存操作与字符串处理汇总

文章目录

  • C语言内存操作与字符串处理
    • 1 内存操作函数
      • 1.1 普通版本
      • 1.2 安全版本
    • 2 字符串函数
      • 2.1 普通版本
      • 2.2 安全版本
    • 3 其他安全替代方案
    • 4 注意事项总结
    • 5 最佳实践

C语言内存操作与字符串处理


C 语言中常见的内存操作和字符串处理函数


1 内存操作函数

1.1 普通版本

  1. memcpy - 内存复制
    原型
#include <string.h>
void* memcpy(void* dest, const void* src, size_t n);

功能:将 src 指向的内存区域的n 个字节复制到 dest 指向的内存区域。
参数

  • dest:目标内存地址。
  • src:源内存地址。
  • n:复制的字节数。
    返回值:返回 dest 的指针。
    注意事项
  • 内存重叠问题:若 srcdest 的内存区域有重叠,行为未定义(需用 memmove 替代)。
  • 目标空间必须足够大,否则导致缓冲区溢出。

示例

int src[] = {1, 2, 3};
int dest[3];
memcpy(dest, src, sizeof(src)); // 复制整个数组

  1. memmove - 安全内存复制
    原型
void* memmove(void* dest, const void* src, size_t n);

功能:与 memcpy 类似,但能正确处理内存重叠问题。
适用场景:当 srcdest 内存区域可能重叠时(如数组元素移位)。

示例

char str[] = "Hello World";
memmove(str + 6, str, 5); // 将前5字节复制到第6字节位置
// 结果:str 变为 "Hello Hello"

  1. memset - 内存填充
    原型
void* memset(void* ptr, int value, size_t n);

功能:将 ptr 指向的内存区域的n 个字节设置为 value(实际按字节填充)。
典型用途

  • 初始化数组为零:memset(arr, 0, sizeof(arr))
  • 设置内存块的特定模式。

注意事项

  • value 的范围应为 0~255(一个字节)。

示例

char buffer[10];
memset(buffer, 'A', 5); // 前5字节填充为 'A'
memset(buffer + 5, 0, 5); // 后5字节填充为0

1.2 安全版本

  1. memcpy_s(C11 标准)
    原型:
#include <string.h> // C11 起支持
errno_t memcpy_s(void* dest, rsize_t dest_size, const void* src, rsize_t src_size);

功能:安全版本的 memcpy,在复制前检查目标缓冲区大小。
参数:

  • dest_size:目标缓冲区的总大小(字节)。
  • src_size:要复制的字节数(必须 ≤ dest_size 且 ≤ src 的实际大小)。
    返回值:
  • 0:成功。
  • 非零:失败(如参数无效或缓冲区溢出风险)。

示例:

char dest[10];
const char* src = "Hello";
errno_t err = memcpy_s(dest, sizeof(dest), src, 6); // 包括 '\0'
if (err != 0) { /* 处理错误 */ }

  1. memset_s(C11 标准)
    原型:
errno_t memset_s(void* dest, rsize_t dest_size, int value, rsize_t count);

功能:安全版本的 memset,检查填充范围是否超出目标缓冲区。
规则:

  • count(填充字节数)必须 ≤ dest_size
  • 若检测到错误(如 dest 为空或 count 过大),可能触发运行时约束处理函数。

示例:

char buffer[10];
errno_t err = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)); // 安全清零

2 字符串函数

2.1 普通版本

  1. strcpy - 字符串复制
    原型
char* strcpy(char* dest, const char* src);

功能:将 src 指向的字符串(含 \0)复制到 dest
注意事项

  • 高危函数:不检查 dest 的空间是否足够,易导致缓冲区溢出。
  • 推荐使用更安全的 strncpysnprintf

示例

char src[] = "Hello";
char dest[10];
strcpy(dest, src); // dest 内容为 "Hello\0"

  1. strncpy - 安全字符串复制
    原型
char* strncpy(char* dest, const char* src, size_t n);

功能:复制 src最多前 n 个字符dest
规则

  • src 长度 >= n:复制前 n 个字符,不添加 \0
  • src 长度 < n:复制全部字符并补 \0n 字节。

示例

char dest[5];
strncpy(dest, "Hello World", sizeof(dest)); 
// dest 内容为 {'H','e','l','l','o'}(无终止符!)

  1. strcat / strncat - 字符串拼接
    原型
char* strcat(char* dest, const char* src); // 危险:不检查长度
char* strncat(char* dest, const char* src, size_t n); // 安全:限制拼接长度

功能:将 src 字符串拼接到 dest 末尾(覆盖 dest\0)。
注意事项

  • dest 必须足够大以容纳拼接后的结果。
  • strncat自动添加终止符

示例

char dest[20] = "Hello";
strncat(dest, " World!", 7); // dest 变为 "Hello World!\0"

  1. strcmp / strncmp - 字符串比较
    原型
int strcmp(const char* s1, const char* s2); // 比较整个字符串
int strncmp(const char* s1, const char* s2, size_t n); // 比较前n个字符

返回值

  • 0:字符串内容相同。
  • 正/负数:根据 ASCII 码差异决定。

示例

if (strcmp("apple", "apple") == 0) { /* 相等 */ }
if (strncmp("apple", "app", 3) == 0) { /* 前3字符相同 */ }

  1. strlen - 字符串长度
    原型
size_t strlen(const char* s);

功能:返回字符串长度(不含 \0)。
注意:若 s 未以 \0 结尾,行为未定义。

示例

int len = strlen("Hello"); // len = 5

  1. strdup - 字符串复制(动态分配)
    原型
char* strdup(const char* s); // 非标准但广泛支持

功能:复制字符串到新分配的内存(需手动 free)。
示例

char* copy = strdup("Hello");
free(copy); // 必须释放内存

2.2 安全版本

  1. strcpy_s(C11 标准)
    原型:
errno_t strcpy_s(char* dest, rsize_t dest_size, const char* src);

功能:安全版本的 strcpy,确保目标缓冲区足够容纳 src(含终止符 \0)。
规则:

  • dest_size 必须大于 strlen(src)
  • dest_size 不足,函数会将 dest[0] 设为 \0 并返回错误。

示例:

char dest[6];
errno_t err = strcpy_s(dest, sizeof(dest), "Hello");
if (err != 0) { /* 目标缓冲区过小 */ }

  1. strncpy_s(C11 标准)
    原型:
errno_t strncpy_s(char* dest, rsize_t dest_size, const char* src, rsize_t count);

功能:安全版本的 strncpy,限制复制的字符数并确保目标缓冲区有效性。
规则:

  • count 需 ≤ dest_size - 1(为终止符预留空间)。
  • src 长度 ≥ count,复制 count 字符并在末尾添加 \0

示例:

char dest[5];
errno_t err = strncpy_s(dest, sizeof(dest), "Hello World", 4); 
// dest 内容为 "Hell\0"

  1. strcat_s(C11 标准)
    原型:
errno_t strcat_s(char* dest, rsize_t dest_size, const char* src);

功能:安全版本的 strcat,确保拼接后字符串不超过目标缓冲区大小。
规则:

  • 剩余空间(dest_size - strlen(dest) - 1)必须 ≥ strlen(src)

示例:

char dest[12] = "Hello"; // 剩余空间为 6
errno_t err = strcat_s(dest, sizeof(dest), " World!");
if (err == 0) { /* 拼接成功 */ }

  1. strnlen(非 C11,但广泛支持)
    原型:
size_t strnlen(const char* s, size_t maxlen);

功能:安全版本的 strlen,限制最大检查长度以防止未终止字符串导致的越界。
返回值:返回字符串长度(不含 \0),若未找到 \0 则返回 maxlen

示例:

char s[10] = "Hello";
size_t len = strnlen(s, sizeof(s)); // len = 5

3 其他安全替代方案

  1. snprintf(格式化字符串安全写入)
    原型:
int snprintf(char* dest, size_t size, const char* format, ...);

功能:将格式化字符串写入 dest,最多写入 size-1 个字符,并自动添加 \0
返回值:成功时返回欲写入的字符数(不含 \0),若空间不足则返回所需字符数(可判断是否需要扩容)。

示例:

char dest[10];
int needed = snprintf(dest, sizeof(dest), "Pi=%.2f", 3.14159);
if (needed >= sizeof(dest)) { /* 缓冲区不足 */ }

  1. 动态内存分配 + strdup(需手动释放)
    原型:
char* strdup(const char* s); // POSIX 标准

功能:复制字符串到新分配的内存(自动计算长度),避免静态缓冲区溢出风险。
注意:需调用 free() 释放内存。

示例:

const char* src = "Dynamic string";
char* dest = strdup(src);
if (dest != NULL) { /* 使用 dest */free(dest); 
}
  • 非标准但实用的安全函数
  1. strlcpy / strlcat(BSD 扩展)
    原型:
size_t strlcpy(char* dest, const char* src, size_t size); // 复制
size_t strlcat(char* dest, const char* src, size_t size); // 拼接

特点:

  • 保证目标字符串以 \0 结尾。
  • 返回源字符串长度,便于判断是否截断。
  • 广泛用于 Linux/BSD,但 Windows 默认不支持。

示例:

char dest[5];
size_t len = strlcpy(dest, "Hello", sizeof(dest)); // len=5, dest="Hell\0"


4 注意事项总结

函数主要风险安全替代方案
strcpy缓冲区溢出strncpy, snprintf
strcat缓冲区溢出strncat
memcpy内存重叠导致未定义行为memmove
gets缓冲区溢出(已废弃)fgets
  • 安全函数的使用原则
  1. 显式指定缓冲区大小:所有安全版本函数均需传递目标缓冲区大小。
  2. 检查返回值:正确处理错误码(如 errno_t 或返回的字符数)。
  3. 避免魔法数值:使用 sizeof(buffer) 而非硬编码长度。
  4. 编译器支持:需启用 C11 标准(如 GCC 使用 -std=c11)。
  5. 跨平台注意:部分安全函数(如 *_s)在非 Windows 环境可能需额外库支持。
场景危险函数安全替代方案
字符串复制strcpystrcpy_s, snprintf
字符串拼接strcatstrcat_s, strlcat
内存复制memcpymemcpy_s, memmove
用户输入读取getsfgets, getline
未初始化内存操作直接访问指针calloc, memset_s

5 最佳实践

  1. 优先使用带长度限制的函数(如 strncpystrncat)。
  2. 检查目标内存大小,避免溢出。
  3. 处理内存重叠时用 memmove
  4. 动态分配内存后记得释放(如 strdup)。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词