多次调用memcpy出现输出异常 咨询动态长度数据处理方法
问题分析:memcpy动态长度数据处理异常
问题代码
// Powered by Judge0 #include <stdio.h> #include <string.h> #include <stdint.h> typedef struct { char data[500]; uint32_t len; } payload; void at_start(payload* payloadData) { char p1[20] = "HI\r\n"; memcpy(payloadData->data, p1, 4); payloadData->len = 4; } void at_net(payload* payloadData) { char p1[20] = "HI CMDCMD\r\n"; memcpy(payloadData->data, p1, 14); payloadData->len = 14; } int main(void) { payload* payloadData; at_start(payloadData); printf("Data : %s \n", payloadData->data); at_net(payloadData); printf("Data : %s \n", payloadData->data); at_start(payloadData); printf("Data : %s \n", payloadData->data); printf("Hello Judge0!\n"); return 0; }
运行输出
Data : HI Data : HI CMDCMD Data : HI MDCMD
问题根源
- 指针未分配有效内存:main函数中
payload* payloadData;仅声明了指针,未指向任何合法内存区域,直接通过该指针操作结构体属于未定义行为,可能引发内存越界、数据覆盖等随机错误。 - 缺少字符串结束符:memcpy仅复制指定长度的字节,但未在有效数据末尾添加
'\0'。printf("%s")会从起始地址一直读取到'\0'才停止,当后续写入的数据长度短于之前的内容时,内存中残留的旧数据会被错误输出。比如最后一次调用at_start仅写入4字节,但之前at_net写入的14字节中,第4字节之后的内容仍留在内存中,就会被printf一并输出。
正确处理方案
1. 为结构体分配有效内存
有两种可靠方式:
- 栈上分配:直接声明结构体变量,避免指针空悬问题,适合小内存结构体:
payload payloadData; // 栈上分配完整结构体 at_start(&payloadData); // 传入结构体地址 - 堆上动态分配:适合大内存或需要长期持有的结构体,记得使用后释放:
payload* payloadData = malloc(sizeof(payload)); if (payloadData == NULL) { // 内存分配失败的异常处理 return 1; } // 使用完成后释放内存 free(payloadData);
2. 确保字符串以'\0'结尾
每次调用memcpy写入数据后,在有效长度的下一个位置添加字符串结束符,让printf能正确识别数据边界:
void at_start(payload* payloadData) { char p1[20] = "HI\r\n"; memcpy(payloadData->data, p1, 4); payloadData->len = 4; payloadData->data[payloadData->len] = '\0'; // 添加结束符 } void at_net(payload* payloadData) { char p1[20] = "HI CMDCMD\r\n"; memcpy(payloadData->data, p1, 14); payloadData->len = 14; payloadData->data[payloadData->len] = '\0'; // 添加结束符 }
修改后的完整代码
// Powered by Judge0 #include <stdio.h> #include <string.h> #include <stdint.h> typedef struct { char data[500]; uint32_t len; } payload; void at_start(payload* payloadData) { char p1[20] = "HI\r\n"; memcpy(payloadData->data, p1, 4); payloadData->len = 4; payloadData->data[payloadData->len] = '\0'; } void at_net(payload* payloadData) { char p1[20] = "HI CMDCMD\r\n"; memcpy(payloadData->data, p1, 14); payloadData->len = 14; payloadData->data[payloadData->len] = '\0'; } int main(void) { payload payloadData; at_start(&payloadData); printf("Data : %s \n", payloadData.data); at_net(&payloadData); printf("Data : %s \n", payloadData.data); at_start(&payloadData); printf("Data : %s \n", payloadData.data); printf("Hello Judge0!\n"); return 0; }
修改后运行输出会正常显示每次的有效数据,不会出现残留内容。
内容的提问来源于stack exchange,提问作者Durga Suthar
相关产品推荐
相关产品推荐

