使用Python将C指针转换为numpy数组时遇问题求助
问题分析与解决方案
错误根源
- 指针地址处理错误:你用
ctypes.addressof(data_ptr.contents)取的是指针变量自身的地址,而非数组数据的起始地址。data_ptr本身就是指向Fortran分配数组的指针,直接使用即可定位数据内存。 - 内存释放不完整:仅释放
data_ptr会导致xyz_ptr指向的内存泄漏。 - numpy数组构造冗余:无需手动构造ctypes数组再通过
from_address转换,np.ctypeslib.as_array是更安全便捷的方式。
修正后的Python代码
import ctypes import numpy as np # 加载编译后的库 lib = ctypes.CDLL('./reader.so') # 声明函数参数与返回类型 readdata = lib.readdata readdata.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_int)), ctypes.POINTER(ctypes.POINTER(ctypes.c_float))] readdata.restype = None # 显式指定返回值为void # 初始化接收数组的指针变量 data_ptr = ctypes.POINTER(ctypes.c_int)() xyz_ptr = ctypes.POINTER(ctypes.c_float)() # 调用Fortran子程序 readdata(ctypes.byref(data_ptr), ctypes.byref(xyz_ptr)) # 数组尺寸(实际场景建议从Fortran返回,而非硬编码) size = 17 # 正确转换为numpy数组:直接映射指针指向的内存区域 data = np.ctypeslib.as_array(data_ptr, shape=(size,)) xyz = np.ctypeslib.as_array(xyz_ptr, shape=(size,)) # 输出结果 print("整数数据:", data) print("浮点数据:", xyz) # 释放Fortran分配的内存 libc = ctypes.CDLL(None) libc.free(data_ptr) libc.free(xyz_ptr)
优化方案:动态获取数组尺寸
硬编码数组尺寸缺乏灵活性,建议修改Fortran代码,新增输出参数返回数组长度,让Python动态获取:
修改后的Fortran代码
subroutine readdata(length, data1, data2) bind(c, name='readdata') use iso_c_binding implicit none integer(c_int), intent(out) :: length ! 新增:返回数组长度 integer(c_int), intent(out), dimension(:), allocatable :: data1 real(c_float), intent(out), dimension(:), allocatable :: data2 integer :: i length = 17 allocate(data1(length)) allocate(data2(length)) do i = 1, length data1(i) = i * 10 end do do i = 1, length data2(i) = real(i * 10, kind=4) end do end subroutine readdata
对应修改的Python代码
import ctypes import numpy as np lib = ctypes.CDLL('./reader.so') readdata = lib.readdata # 更新参数类型:第一个参数为输出的数组长度 readdata.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.POINTER(ctypes.c_int)), ctypes.POINTER(ctypes.POINTER(ctypes.c_float))] readdata.restype = None # 初始化长度变量与数组指针 length = ctypes.c_int() data_ptr = ctypes.POINTER(ctypes.c_int)() xyz_ptr = ctypes.POINTER(ctypes.c_float)() # 调用子程序并获取长度 readdata(ctypes.byref(length), ctypes.byref(data_ptr), ctypes.byref(xyz_ptr)) # 动态转换为numpy数组 size = length.value data = np.ctypeslib.as_array(data_ptr, shape=(size,)) xyz = np.ctypeslib.as_array(xyz_ptr, shape=(size,)) print("整数数据:", data) print("浮点数据:", xyz) # 释放所有内存 libc = ctypes.CDLL(None) libc.free(data_ptr) libc.free(xyz_ptr)
关键注意事项
np.ctypeslib.as_array会直接映射ctypes指针指向的内存,无需复制数据,效率更高且避免地址处理错误。- Fortran通过
bind(c)分配的可分配数组,内存分配逻辑与C兼容,因此可以用C标准库的free函数释放。 - 必须释放所有由Fortran分配的指针,否则会造成内存泄漏。
内容的提问来源于stack exchange,提问作者Michael Leanza
相关产品推荐
相关产品推荐

