C语言memcpy无法复制数据问题排查及void指针复制方法咨询
链表实现栈的void*复制问题与修复方案
问题根源
你代码里的StackObject_t结构体中,void* obj只是一个指针,没有指向任何已分配的内存空间。当调用malloc(sizeof(StackObject_t))时,仅为结构体本身(包含指针和next成员)分配了内存,但obj指针仍为空。直接用memcpy往空指针指向的地址写数据,属于访问非法内存,会导致未定义行为(复制失败、程序崩溃等)。
修复后的完整代码
以下是修复后的代码,包含内存分配修正、栈销毁函数(解决内存泄漏),以及简化的入栈逻辑:
#include <stdlib.h> #include <string.h> // 需引入string.h才能使用memcpy typedef struct stackObject { void* obj; struct stackObject *next; } StackObject_t; typedef struct stackMeta { StackObject_t *stack; size_t objsize; int numelem; } StackMeta_t; // 创建栈 StackMeta_t *mystack_create(size_t objsize) { StackMeta_t *elem = malloc(sizeof(StackMeta_t)); if(elem == NULL) { return NULL; } elem->stack = NULL; elem->objsize = objsize; elem->numelem = 0; return elem; } // 入栈 int mystack_push(StackMeta_t *data_stack, void* obj) { if(data_stack == NULL || obj == NULL) { return -1; } StackObject_t *nodeObject = malloc(sizeof(StackObject_t)); if(nodeObject == NULL) { return -1; } // 为obj分配对应大小的内存 nodeObject->obj = malloc(data_stack->objsize); if(nodeObject->obj == NULL) { free(nodeObject); // 避免节点内存泄漏 return -1; } // 复制数据到节点的obj内存中 memcpy(nodeObject->obj, obj, data_stack->objsize); // 链表插入头部(栈顶) nodeObject->next = data_stack->stack; data_stack->stack = nodeObject; data_stack->numelem++; return 0; } // 出栈(可选,完善栈操作) int mystack_pop(StackMeta_t *data_stack, void* out_obj) { if(data_stack == NULL || data_stack->stack == NULL || out_obj == NULL) { return -1; } StackObject_t *top_node = data_stack->stack; // 复制栈顶数据到输出参数 memcpy(out_obj, top_node->obj, data_stack->objsize); // 更新栈顶指针 data_stack->stack = top_node->next; // 释放节点内存和obj内存 free(top_node->obj); free(top_node); data_stack->numelem--; return 0; } // 销毁栈,释放所有内存 void mystack_destroy(StackMeta_t *data_stack) { if(data_stack == NULL) { return; } StackObject_t *current = data_stack->stack; while(current != NULL) { StackObject_t *next = current->next; free(current->obj); // 先释放obj指向的内存 free(current); // 再释放节点本身 current = next; } free(data_stack); // 释放栈元数据 } int main() { StackMeta_t *METADATA = mystack_create(sizeof(int)); int obj = 1; mystack_push(METADATA, &obj); // 测试出栈 int popped_val; mystack_pop(METADATA, &popped_val); // 销毁栈,避免内存泄漏 mystack_destroy(METADATA); return 0; }
内存泄漏检查说明
要检测内存泄漏,可以使用valgrind工具:
- 编译代码时添加调试符号:
gcc -g stack.c -o stack - 运行valgrind检查:
valgrind --leak-check=full ./stack
修复后的代码在调用mystack_destroy后,不会产生任何内存泄漏。
void指针复制示例
以下是几种常见的void指针复制场景:
1. 复制int类型
int src = 100; void* dest = malloc(sizeof(int)); memcpy(dest, &src, sizeof(int)); int val = *(int*)dest; // 取值时需强制类型转换 free(dest);
2. 复制字符串(char数组)
const char* src = "hello world"; size_t len = strlen(src) + 1; // 需包含终止符 void* dest = malloc(len); memcpy(dest, src, len); char* str = (char*)dest; free(dest);
3. 复制自定义结构体
typedef struct { int id; char name[20]; } User; User src = {1, "Alice"}; void* dest = malloc(sizeof(User)); memcpy(dest, &src, sizeof(User)); User user = *(User*)dest; free(dest);
内容的提问来源于stack exchange,提问作者Heroking18
相关产品推荐
相关产品推荐

