将char数组传入void指针出现异常行为的原因排查
自定义strcpy指针实现的地址偏移问题分析
问题现象
实现自定义strcpy时,采用指针递增赋值的方案出现未预期行为:复制过程的中间打印显示字符赋值正常,但最终打印的内存地址和对应值不符合预期,无法正确输出目标字符串。
指针实现的代码
#include <stdio.h> #include <stdint.h> void mystrcpy(void *dest, void *src) { char *_dest = (char*)dest; char *_src = (char*)src; *_dest = *_src; printf("%c %c\n",*_src,*_dest); printf("%p %p\n",_src,_dest); _src++ ; _dest++; *_dest = *_src; printf("%c %c\n",*_src,*_dest); printf("%p %p\n",_src,_dest); _src++ ; _dest++; *_dest = *_src; printf("%c %c\n",*_src,*_dest); printf("%p %p\n",_src,_dest); _src++ ; _dest++; *_dest = '\0'; printf("Final - %d %d %d %p %p %p\n",_dest[0],_dest[1],_dest[2],&_dest[0],&_dest[1],&_dest[2]); } int main() { char *src = "ABC"; char dest[20]; printf("%p %p\n",src,dest); mystrcpy(dest,src); return 0; }
输出结果
0000000000404034 000000000061FE00
A A
0000000000404034 000000000061FE00
B B
0000000000404035 000000000061FE01
C C
0000000000404036 000000000061FE02
Final - 0 0 0 000000000061FE03 000000000061FE04 000000000061FE05
问题原因
核心错误是最终打印时使用的_dest指针已经经过多次递增,不再指向目标数组的起始位置:
- 初始时
_dest指向dest数组的起始地址0x61FE00 - 每完成一次字符赋值后,
_dest都会执行递增操作:- 第一次赋值后,
_dest指向0x61FE01 - 第二次赋值后,
_dest指向0x61FE02 - 第三次赋值后,
_dest指向0x61FE03
- 第一次赋值后,
- 最后给
*_dest赋值'\0',此时_dest仍指向0x61FE03 - 打印
_dest[0]、_dest[1]、_dest[2]时,实际访问的是0x61FE03、0x61FE04、0x61FE05这几个位置——而真正的A、B、C存储在0x61FE00、0x61FE01、0x61FE02,你访问的是未初始化的内存(或仅赋值了'\0'的位置),所以输出异常。
修正方案
只需要保存_dest的初始地址,最终打印时使用初始地址即可:
#include <stdio.h> #include <stdint.h> void mystrcpy(void *dest, void *src) { char *_dest = (char*)dest; char *start_dest = _dest; // 保存初始地址 char *_src = (char*)src; *_dest = *_src; printf("%c %c\n",*_src,*_dest); printf("%p %p\n",_src,_dest); _src++ ; _dest++; *_dest = *_src; printf("%c %c\n",*_src,*_dest); printf("%p %p\n",_src,_dest); _src++ ; _dest++; *_dest = *_src; printf("%c %c\n",*_src,*_dest); printf("%p %p\n",_src,_dest); _src++ ; _dest++; *_dest = '\0'; // 使用初始地址打印正确的内容 printf("Final - %c %c %c %p %p %p\n",start_dest[0],start_dest[1],start_dest[2],&start_dest[0],&start_dest[1],&start_dest[2]); // 直接打印字符串 printf("Final String - %s\n", start_dest); } int main() { char *src = "ABC"; char dest[20]; printf("%p %p\n",src,dest); mystrcpy(dest,src); return 0; }
修正后的输出会正确显示A、B、C以及对应的起始地址,并且可以正常打印字符串ABC。
内容的提问来源于stack exchange,提问作者Vishnu CS
相关产品推荐
相关产品推荐

