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该内存?
错误原因分析
- C代码逻辑错误:
new_queue函数中,malloc分配内存后,并没有将初始化好的queue_结构体内容拷贝到分配的内存中,返回的是未初始化的野指针,后续操作必然出错。 - 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
相关产品推荐
相关产品推荐

