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

C中malloc内存经Python ctypes传递后free遇段错误,求解决方案

问题描述

我想在C语言中编写包含malloc操作的函数,通过Python 3.10的ctypes调用该函数,之后再在C中释放对应内存,但运行时出现段错误。

我的C代码

#include <stdlib.h>

struct QueueItem {
    void *value;
    struct QueueItem *next;
};

struct Queue {
    struct QueueItem* head;
    struct QueueItem* tail;
};

struct Queue * new_queue(void * value) {
    struct Queue* queue = malloc(sizeof(struct Queue));

    struct Queue queue_ = { value, NULL };

    return queue;
}

void delete_queue(struct Queue* queue) {
    free(queue);
};

编译命令:gcc -fPIC -shared src/queue.c -o queue.so

Python端代码

import ctypes

queue = ctypes.CDLL("./queue.so")

q = ctypes.POINTER(queue.new_queue(1))
print(q)
print(type(q))

queue.delete_queue(q)

运行输出

-1529189344
<class 'int'>
Segmentation fault

核心问题:如何在C中malloc内存,将指针通过Python传递后,再在C中正确free该内存?


错误原因分析
  1. C代码逻辑错误:new_queue函数中,malloc分配内存后,并没有将初始化好的queue_结构体内容拷贝到分配的内存中,返回的是未初始化的野指针,后续操作必然出错。
  2. Python端类型处理错误:ctypes默认将C函数的返回值当作int处理,指针被截断为整型值,传递给delete_queue时变成无效内存地址,触发段错误。同时没有显式声明函数的参数和返回类型,导致类型不匹配。

修正方案

步骤1:修复C代码的内存初始化问题

修改new_queue函数,确保malloc的内存被正确初始化:

#include <stdlib.h>
#include <string.h> // 需要memcpy的头文件

struct QueueItem {
    void *value;
    struct QueueItem *next;
};

struct Queue {
    struct QueueItem* head;
    struct QueueItem* tail;
};

struct Queue * new_queue(void * value) {
    struct Queue* queue = malloc(sizeof(struct Queue));
    if (queue == NULL) { // 增加malloc失败的判断,避免返回空指针
        return NULL;
    }
    // 将value转为QueueItem*类型(匹配Queue结构体的成员类型),初始化结构体
    struct Queue queue_ = { (struct QueueItem*)value, NULL };
    memcpy(queue, &queue_, sizeof(struct Queue));
    return queue;
}

void delete_queue(struct Queue* queue) {
    if (queue != NULL) { // 增加空指针判断,避免非法free
        free(queue);
    }
};

步骤2:Python端正确声明函数类型

在Python中定义对应C结构体的类型,并显式声明C函数的参数和返回类型,避免类型截断:

import ctypes

# 定义C端的QueueItem结构体
class QueueItem(ctypes.Structure):
    _fields_ = [
        ("value", ctypes.c_void_p),
        ("next", ctypes.POINTER(QueueItem))
    ]

# 定义C端的Queue结构体
class Queue(ctypes.Structure):
    _fields_ = [
        ("head", ctypes.POINTER(QueueItem)),
        ("tail", ctypes.POINTER(QueueItem))
    ]

# 加载动态库
queue_lib = ctypes.CDLL("./queue.so")

# 声明new_queue的参数和返回类型
queue_lib.new_queue.argtypes = [ctypes.c_void_p]
queue_lib.new_queue.restype = ctypes.POINTER(Queue)

# 声明delete_queue的参数类型
queue_lib.delete_queue.argtypes = [ctypes.POINTER(Queue)]
queue_lib.delete_queue.restype = None

# 调用函数
# 将int值包装为void*类型传递
value = ctypes.c_void_p(1)
q = queue_lib.new_queue(value)

print(q)
print(type(q))

# 释放内存
queue_lib.delete_queue(q)

关键注意事项
  • 永远不要在Python中直接释放C分配的内存,必须通过C提供的释放函数操作,两者内存管理体系不兼容。
  • 必须显式声明ctypes函数的argtypes和restype,避免因类型默认转换导致的指针截断或非法内存访问。
  • C代码中要增加malloc返回值和空指针的判断,提升代码健壮性。

内容的提问来源于stack exchange,提问作者npengra317

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:15:36