我的二维数组在 Ctypes 中不能正常工作
My 2D array does not work properly in Ctypes
main.c:
#include <stdlib.h>
int **function() {
int **information = malloc(5 * sizeof(int));
for (int k = 0; k < 5; k++) {
information[k] = malloc(5 * sizeof(int));
for (int j = 0; j < 5; j++) {
information[k][j] = j;
}
}
return information;
}
main.py
import ctypes
from numpy.ctypeslib import ndpointer
lib = ctypes.CDLL("C:\Users\.....\Desktop\test9\a.dll")
lib.function.restype = ndpointer(dtype=ctypes.c_int, shape=(5,5),flags='C')
res = lib.function()
print(res)
结果:
[[222866112 368 222866144 368 222866176]
[ 368 222866208 368 222866672 368]
[ 2 3 4 0 389116888]
[201333630 0 1 2 3]
[ 4 0 389116888 201333630 0]]
不知道为什么会这样输出,一维模式下同样的方法没问题
我该如何解决这个问题?
已编辑:
两种方法都有用
您的代码将一个包含 5 个指针的数组分配给包含 5 个 int
的数组。指针数组的分配不正确:你应该写 int **information = malloc(5 * sizeof(*information));
而不是 int **information = malloc(5 * sizeof(int));
然而,就您的目的而言,类型 int **
不正确。您应该分配一个实际的二维数组 int array[5][5]
.
指向动态分配的二维数组的指针的语法很麻烦,returns这样的指针的函数语法是一个真正的挑战:
#include <stdlib.h>
int (*function(void))[5] {
// allocate an array of 5 arrays of 5 int
int (*information)[5] = malloc(5 * sizeof(*information));
// initialize all 5 rows to identical vectors { 0, 1, 2, 3, 4 }
for (int k = 0; k < 5; k++) {
for (int j = 0; j < 5; j++) {
information[k][j] = j;
}
}
return information;
}
可以使用螺旋规则阅读函数原型:从名称开始,阅读后缀运算符,然后是前缀运算符,在括号处切换方向:
function
是一个没有参数的函数,返回指向 5
int
.
数组的指针
要将 ctypes
与 int**
一起使用,您可以使用 POINTER(POINTER(c_int))
作为类型并使用切片来访问数组的元素。要将 ctypes
与 C-contiguous 5x5 数组一起使用 int*
,则可以有效地使用 numpy
。
test.c
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API int **function() {
int **information = malloc(5 * sizeof(int*)); // Note row element is int*
for (int k = 0; k < 5; k++) {
information[k] = malloc(5 * sizeof(int)); // Note col element is int
for (int j = 0; j < 5; j++) {
information[k][j] = k * 5 + j;
}
}
return information;
}
API int *function2() {
int *information = malloc(5 * 5 * sizeof(int)); // 5 x 5 C contiguous shape
for (int k = 0; k < 5; k++) {
for (int j = 0; j < 5; j++) {
information[k * 5 + j] = k * 5 + j;
}
}
return information;
}
test.py
import ctypes as ct
import numpy as np
from pprint import pprint
lib = ct.CDLL('./test')
lib.function.argtypes = ()
lib.function.restype = ct.POINTER(ct.POINTER(ct.c_int))
lib.function2.argtypes = ()
lib.function2.restype = np.ctypeslib.ndpointer(dtype=ct.c_int, shape=(5, 5), flags='C')
def function():
res = lib.function()
# slicing used to extract the correct number of items
return [row[:5] for row in res[:5]]
pprint(function())
pprint(lib.function2())
输出:
[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]]
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
在这两种情况下,malloc 的内存都已泄漏。理想情况下,让Python管理内存,让C知道形状。使用下面的 np.empty
分配内存而不初始化,然后 C 初始化它。这更灵活,可以与 different-sized 数组一起使用:
test.c
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API void function3(int* information, int row, int col) {
for (int k = 0; k < row; k++) {
for (int j = 0; j < col; j++) {
information[k * row + j] = k * 5 + j;
}
}
}
test.py
import ctypes as ct
import numpy as np
lib = ct.CDLL('./test')
lib.function3.argtypes = np.ctypeslib.ndpointer(dtype=ct.c_int),
lib.function3.restype = None
info = np.empty(dtype=ct.c_int,shape=(5,5))
lib.function3(info,5,5)
print(info)
输出:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]]
main.c:
#include <stdlib.h>
int **function() {
int **information = malloc(5 * sizeof(int));
for (int k = 0; k < 5; k++) {
information[k] = malloc(5 * sizeof(int));
for (int j = 0; j < 5; j++) {
information[k][j] = j;
}
}
return information;
}
main.py
import ctypes
from numpy.ctypeslib import ndpointer
lib = ctypes.CDLL("C:\Users\.....\Desktop\test9\a.dll")
lib.function.restype = ndpointer(dtype=ctypes.c_int, shape=(5,5),flags='C')
res = lib.function()
print(res)
结果:
[[222866112 368 222866144 368 222866176]
[ 368 222866208 368 222866672 368]
[ 2 3 4 0 389116888]
[201333630 0 1 2 3]
[ 4 0 389116888 201333630 0]]
不知道为什么会这样输出,一维模式下同样的方法没问题
我该如何解决这个问题?
已编辑: 两种方法都有用
您的代码将一个包含 5 个指针的数组分配给包含 5 个 int
的数组。指针数组的分配不正确:你应该写 int **information = malloc(5 * sizeof(*information));
int **information = malloc(5 * sizeof(int));
然而,就您的目的而言,类型 int **
不正确。您应该分配一个实际的二维数组 int array[5][5]
.
指向动态分配的二维数组的指针的语法很麻烦,returns这样的指针的函数语法是一个真正的挑战:
#include <stdlib.h>
int (*function(void))[5] {
// allocate an array of 5 arrays of 5 int
int (*information)[5] = malloc(5 * sizeof(*information));
// initialize all 5 rows to identical vectors { 0, 1, 2, 3, 4 }
for (int k = 0; k < 5; k++) {
for (int j = 0; j < 5; j++) {
information[k][j] = j;
}
}
return information;
}
可以使用螺旋规则阅读函数原型:从名称开始,阅读后缀运算符,然后是前缀运算符,在括号处切换方向:
function
是一个没有参数的函数,返回指向 5
int
.
要将 ctypes
与 int**
一起使用,您可以使用 POINTER(POINTER(c_int))
作为类型并使用切片来访问数组的元素。要将 ctypes
与 C-contiguous 5x5 数组一起使用 int*
,则可以有效地使用 numpy
。
test.c
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API int **function() {
int **information = malloc(5 * sizeof(int*)); // Note row element is int*
for (int k = 0; k < 5; k++) {
information[k] = malloc(5 * sizeof(int)); // Note col element is int
for (int j = 0; j < 5; j++) {
information[k][j] = k * 5 + j;
}
}
return information;
}
API int *function2() {
int *information = malloc(5 * 5 * sizeof(int)); // 5 x 5 C contiguous shape
for (int k = 0; k < 5; k++) {
for (int j = 0; j < 5; j++) {
information[k * 5 + j] = k * 5 + j;
}
}
return information;
}
test.py
import ctypes as ct
import numpy as np
from pprint import pprint
lib = ct.CDLL('./test')
lib.function.argtypes = ()
lib.function.restype = ct.POINTER(ct.POINTER(ct.c_int))
lib.function2.argtypes = ()
lib.function2.restype = np.ctypeslib.ndpointer(dtype=ct.c_int, shape=(5, 5), flags='C')
def function():
res = lib.function()
# slicing used to extract the correct number of items
return [row[:5] for row in res[:5]]
pprint(function())
pprint(lib.function2())
输出:
[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]]
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
在这两种情况下,malloc 的内存都已泄漏。理想情况下,让Python管理内存,让C知道形状。使用下面的 np.empty
分配内存而不初始化,然后 C 初始化它。这更灵活,可以与 different-sized 数组一起使用:
test.c
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API void function3(int* information, int row, int col) {
for (int k = 0; k < row; k++) {
for (int j = 0; j < col; j++) {
information[k * row + j] = k * 5 + j;
}
}
}
test.py
import ctypes as ct
import numpy as np
lib = ct.CDLL('./test')
lib.function3.argtypes = np.ctypeslib.ndpointer(dtype=ct.c_int),
lib.function3.restype = None
info = np.empty(dtype=ct.c_int,shape=(5,5))
lib.function3(info,5,5)
print(info)
输出:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]]