C++拆分动态char为20字符块时遇到存储覆盖、乱码、memcpy输出失效问题
两类实现的问题根因分析
初版实现的两处核心错误
- 栈变量生命周期误用:循环内部定义的
char buff[blockSize]是栈上的临时局部变量,每次循环执行结束,这块栈内存就会被系统回收复用,不再保存之前拷贝的字符串内容。循环计算阶段打印时,这块栈空间还没被后续操作覆盖,所以能读到临时的正确拆分内容;进入校验阶段遍历指针数组时,所有存进chunks的栈地址都指向被反复覆写的同一块栈内存,最后就会全变成最后一次循环写入的全0xff残留内容。 - 字符串未补结束符:每次拷贝固定20字节到
buff后,没有在内容末尾添加字符串结束符\0。串口打印字符串的逻辑是从起始地址逐字节读取,直到碰到\0才停止,所以打印完20个拷贝的字符后,会继续读取buff内存后方的随机栈数据,就出现了⸮!这类乱码。
修改后实现的核心错误
- 把存储结构改成
char chunks[6][20]二维数组的方向是正确的,但依然没有给每个块补字符串结束符。每个块20字节的空间全用来存了拷贝的字符,没有预留位置放\0;校验时串口打印的char*指针会持续向后读取内存,直到碰到原长字符串末尾自带的\0才停止,表现出来的效果就是从当前块起始位置一直打印到长串末尾,容易让人误以为memcpy的长度限制没生效。
合规拆分实现方案
- 修正存储逻辑:杜绝把循环内栈临时数组的地址存入长生命周期的指针数组,使用连续的固定存储区(比如全局/静态的二维字符数组)保存拆分后的块内容。
- 适配字符串打印规则:在每个块的存储空间里预留1字节放结束符,拷贝完成后手动在内容末尾补
\0。 - 增加边界判断:拷贝时不能硬凑固定20字节长度,要根据源串剩余的实际长度取较小值,避免读源串越界内存。
参考正确实现片段:
#define BLOCK_SIZE 20 #define MAX_BLOCKS 6 // 每个块多留1字节存结束符 char chunks[MAX_BLOCKS][BLOCK_SIZE + 1]; char* largeWord = "待拆分的长字符串"; size_t srcTotalLen = strlen(largeWord); size_t totalBlocks = (srcTotalLen + BLOCK_SIZE - 1) / BLOCK_SIZE; for (size_t blockIdx = 0; blockIdx < totalBlocks; blockIdx++) { size_t offset = blockIdx * BLOCK_SIZE; // 计算当前块实际需要拷贝的长度 size_t realCopyLen = (srcTotalLen - offset) >= BLOCK_SIZE ? BLOCK_SIZE : (srcTotalLen - offset); memcpy(chunks[blockIdx], largeWord + offset, realCopyLen); // 关键操作:补字符串结束符 chunks[blockIdx][realCopyLen] = '\0'; }
关键注意事项
- 二维字符数组的每一行长度要设置为
块大小 + 1,预留专门的结束符位置,否则20字节全存字符依然会出现打印越界问题。 - 源串长度不足20的最后一块,要按实际剩余长度拷贝,不能硬读20字节的越界内存。
- 如果要保留
char* chunks[]的指针数组结构,必须把每个块的存储空间定义为静态/全局的连续内存,不能使用循环内的栈临时变量。
内容的提问来源于stack exchange,提问作者jLynx
相关产品推荐
相关产品推荐

