You need to enable JavaScript to run this app. 如何安全实现字符数组开头的字符增删?解决memmove数组重叠内存问题
优惠活动
大模型
产品
解决方案
定价
更多

如何安全实现字符数组开头的字符增删?解决memmove数组重叠内存问题

核心认知澄清

你对memmove的功能存在典型误解:memmove 本身就是C标准库专门为内存重叠场景设计的安全拷贝接口。C语言标准明确规定,当源内存和目标内存存在重叠时,memmove 的行为是完全定义良好的;反而 memcpy 不处理重叠场景,遇到重叠才会触发未定义行为。
你遇到的相邻buf被意外损坏的问题,根本不是memmove处理重叠导致的,本质是调用过程中没有做边界校验,出现了缓冲区越界写,冲到了相邻内存的其他缓冲区上。

原有实现的隐患点

  • 开头加字符的逻辑中,没有校验当前缓冲区是否预留了足够的额外空间:如果buf_t只分配了刚好存msgLen_t长度数据的内存,直接往后挪1个字节就会直接写到缓冲区边界外,刚好把相邻的其他buf内容覆盖掉。
  • 删除首字符的逻辑中,用strlen(buf_s + 1)计算拷贝长度存在硬伤:如果buf_s没有以合法的\0结尾,strlen会无限制向后读取直到遇到内存中的随机\0,算出一个完全错误的拷贝长度,自然会破坏相邻内存。

更安全的实现方案

优化的核心思路是:用自己维护的明确的有效数据长度替代隐式的字符串长度计算,在每一步操作前加硬边界校验,从根源上避免越界访问。

开头添加单个字符的安全实现

// 参数说明:
// buf: 指向的缓冲区起始地址
// cur_len: 当前缓冲区中有效数据的长度
// buf_cap: 缓冲区的总分配容量(必须提前明确)
// c: 要添加到开头的字符
int prepend_char(char *buf, size_t *cur_len, size_t buf_cap, char c) {
    // 第一步做硬边界校验,空间不足直接返回错误,不做任何写操作
    if (*cur_len + 1 > buf_cap) {
        return -1;
    }
    // memmove在这里的操作是完全安全的,自身会处理重叠区间的拷贝方向
    memmove(buf + 1, buf, *cur_len);
    buf[0] = c;
    (*cur_len)++;
    return 0;
}

删除开头单个字符的安全实现

int remove_first_char(char *buf, size_t *cur_len, size_t buf_cap) {
    if (*cur_len == 0) {
        return -1;
    }
    // 直接用维护好的有效长度计算剩余数据长度,不要依赖strlen
    size_t remain_len = *cur_len - 1;
    memmove(buf, buf + 1, remain_len);
    // 如果是字符串场景,手动补结束符,保证后续使用时不会出现越界读
    buf[remain_len] = '\0';
    (*cur_len)--;
    return 0;
}

为什么这套方案更可靠

  • 所有操作的长度都来自你明确维护的有效数据长度,不会因为字符串没有合法结尾出现越界读的问题
  • 每一次写操作前都会校验缓冲区的总容量,空间不足时直接拒绝操作,从根源上避免越界写到相邻内存
  • 没有抛弃memmove的使用,而是用对了它的设计能力——本身重叠拷贝是memmove的核心功能,不需要自己手写逐字节的移位逻辑,反而比手写循环的出错概率更低。很多人写这类逻辑的时候总想着“避开memmove就更安全”,其实是舍本逐末,memmove是经过几十年工业界验证的接口,只要传入的长度和边界是正确的,它的可靠性远高于非专业开发者手写的移位代码。

内容的提问来源于stack exchange,提问作者Lloyd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.25 04:24:02