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

使用Python将C指针转换为numpy数组时遇问题求助

问题分析与解决方案

错误根源

  1. 指针地址处理错误:你用ctypes.addressof(data_ptr.contents)取的是指针变量自身的地址,而非数组数据的起始地址。data_ptr本身就是指向Fortran分配数组的指针,直接使用即可定位数据内存。
  2. 内存释放不完整:仅释放data_ptr会导致xyz_ptr指向的内存泄漏。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:21:21