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

如何使用Cython处理C函数返回的二维数组?

在Cython中接收C函数返回的二维int数组

你已经搞定了一维numpy数组传C函数的操作,现在要处理C返回的int**二维数组,其实核心是把C的指针结构转换成numpy能识别的数组,还要注意内存泄漏的问题,我给你一步步拆解:

首先先补全你那没写完的C代码(加上测试数据和配套的释放函数,这很重要):

// your_array_code.h 或者.c文件里的内容
#include <stdlib.h>

int **make_array() {
    int nrows = 3;
    int ncols = 5;
    // 先分配存储行指针的数组
    int **ret = malloc(nrows * sizeof(int *));
    // 为每一行分配数据内存并填充测试值
    for (int i = 0; i < nrows; i++) {
        ret[i] = malloc(ncols * sizeof(int));
        for (int j = 0; j < ncols; j++) {
            ret[i][j] = i * ncols + j; // 比如生成0-14的连续数
        }
    }
    return ret;
}

// 必须配套释放函数,不然会内存泄漏
void free_array(int **arr, int nrows) {
    for (int i = 0; i < nrows; i++) {
        free(arr[i]);
    }
    free(arr);
}

接下来分两种常用的处理方式,推荐第一种:

方式一:复制到连续的numpy数组(首选)

numpy最偏好连续内存的数组,操作效率更高,而且内存管理更省心:

在你的Cython文件(比如array_wrapper.pyx)里这么写:

import numpy as np
cimport numpy as np

# 声明C函数的接口,要对应你的头文件路径
cdef extern from "your_array_code.h":
    int** make_array()
    void free_array(int** arr, int nrows)

def get_c_2d_array():
    cdef int** c_arr
    cdef int nrows = 3, ncols = 5
    cdef np.ndarray[np.int_t, ndim=2] np_arr
    
    # 调用C函数拿到二维指针数组
    c_arr = make_array()
    
    # 创建一个空的numpy二维数组,指定好形状和类型
    np_arr = np.empty((nrows, ncols), dtype=np.int32)
    
    # 逐行逐列把C数组的数据复制到numpy数组里
    cdef int i, j
    for i in range(nrows):
        for j in range(ncols):
            np_arr[i, j] = c_arr[i][j]
    
    # 重点!用完C的数组一定要释放内存,不然会泄漏
    free_array(c_arr, nrows)
    
    return np_arr

方式二:直接包装非连续内存(不推荐,仅特殊场景用)

如果你的数据特别大,不想复制,可以直接让numpy包装C的内存,但要注意内存管理的坑:

def get_c_2d_array_no_copy():
    cdef int** c_arr
    cdef int nrows = 3, ncols = 5
    cdef np.ndarray[np.int_t, ndim=2] np_arr
    
    c_arr = make_array()
    
    # 先创建一个数组存行指针,防止C的指针被Python的GC干扰
    row_ptrs = np.empty(nrows, dtype=np.intp)
    for i in range(nrows):
        row_ptrs[i] = <np.intp>c_arr[i]
    
    # 创建numpy数组,用行指针数组作为缓冲区,指定非连续的步长
    np_arr = np.ndarray(
        shape=(nrows, ncols),
        dtype=np.int32,
        buffer=row_ptrs,
        strides=(sizeof(np.intp), sizeof(np.int32))
    )
    
    # 这里要注意:numpy不会自动释放C的内存,所以得手动处理
    # 我这里返回数组和对应的释放函数,你用完数组后要调用这个释放函数
    return np_arr, lambda: free_array(c_arr, nrows)

几个关键注意事项:

  • 内存泄漏是头号敌人:C函数用malloc分配的内存,Python的GC管不到,所以必须调用配套的free_array函数释放
  • 类型要匹配:如果C里用的是long而不是int,那numpy要对应np.int64,不然会出现类型错误
  • 连续vs非连续:方式一的数组是连续的,能正常使用numpy的所有操作;方式二的数组是非连续的,部分numpy函数会变慢甚至出错,除非你确定必须用这种方式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:32:11