You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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工具:

  1. 编译代码时添加调试符号:gcc -g stack.c -o stack
  2. 运行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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 02:30:57