更复杂的ctype示例¶
在这里,我们将查看一个更复杂的示例。首先考虑下面的C代码。
#include <stdio.h>
#include <stdlib.h>
struct double_row_element_t {
double value;
int col_index;
struct double_row_element_t * next_element;
};
typedef struct double_row_element_t double_row_element;
typedef struct {
int nrows;
int ncols;
int nnz;
double_row_element** rows;
} double_sparse_matrix;
double_sparse_matrix * initialize_matrix(int nrows, int ncols)
{
int i;
double_sparse_matrix* new_matrix;
new_matrix = (double_sparse_matrix *) malloc(sizeof(double_sparse_matrix));
new_matrix->rows= (double_row_element **) malloc(sizeof(double_row_element *)*nrows);
for(i=0;i<nrows;i++)
{
(new_matrix->rows)[i]=(double_row_element *) malloc(sizeof(double_row_element));
(new_matrix->rows)[i]->value=0;
(new_matrix->rows)[i]->col_index=0;
(new_matrix->rows)[i]->next_element = 0;
}
new_matrix->nrows=nrows;
new_matrix->ncols=ncols;
new_matrix->nnz=0;
return new_matrix;
}
int free_matrix(double_sparse_matrix * matrix)
{
int i;
double_row_element* next_element;
double_row_element* current_element;
for(i=0;i<matrix->nrows;i++)
{
current_element = (matrix->rows)[i];
while(current_element->next_element!=0)
{
next_element=current_element->next_element;
free(current_element);
current_element=next_element;
}
free(current_element);
}
free(matrix->rows);
free(matrix);
return 1;
}
int set_value(double_sparse_matrix * matrix,int row, int col, double value)
{
int i;
i=0;
double_row_element* current_element;
double_row_element* new_element;
if(row> matrix->nrows || col > matrix->ncols || row <0 || col <0)
return 1;
current_element = (matrix->rows)[row];
while(1)
{
if(current_element->col_index==col)
{
current_element->value=value;
return 0;
}
else
if(current_element->next_element!=0)
{
if(current_element->next_element->col_index <=col)
current_element = current_element->next_element;
else
if(current_element->next_element->col_index > col)
{
new_element = (double_row_element *) malloc(sizeof(double_row_element));
new_element->value=value;
new_element->col_index=col;
new_element->next_element=current_element->next_element;
current_element->next_element=new_element;
return 0;
}
}
else
{
new_element = (double_row_element *) malloc(sizeof(double_row_element));
new_element->value=value;
new_element->col_index=col;
new_element->next_element=0;
current_element->next_element=new_element;
break;
}
}
return 0;
}
double get_value(double_sparse_matrix* matrix,int row, int col)
{
int i;
double_row_element * current_element;
if(row> matrix->nrows || col > matrix->ncols || row <0 || col <0)
return 0.0;
current_element = (matrix->rows)[row];
while(1)
{
if(current_element->col_index==col)
{
return current_element->value;
}
else
{
if(current_element->col_index<col && current_element->next_element !=0)
current_element=current_element->next_element;
else
if(current_element->col_index >col || current_element ->next_element==0)
return 0;
}
}
}
将其放在名为link_list_parse.c的文件中并使用以下命令进行编译
$ gcc -c linked_list_sparse.c
$ gcc -shared -o linked_list_sparse.so linked_list_sparse.o
接下来,请考虑下面的python助手代码。
from ctypes import *
class double_row_element(Structure):
pass
double_row_element._fields_=[("value",c_double),("col_index",c_int),("next_element",POINTER(double_row_element) )]
class double_sparse_matrix(Structure):
_fields_=[("nrows",c_int),("ncols",c_int),("nnz",c_int),("rows",POINTER(POINTER(double_row_element)))]
double_sparse_pointer=POINTER(double_sparse_matrix)
sparse_library=CDLL("/home/jkantor/linked_list_sparse.so")
initialize_matrix=sparse_library.initialize_matrix
initialize_matrix.restype=double_sparse_pointer
set_value=sparse_library.set_value
get_value=sparse_library.get_value
get_value.restype=c_double
free_matrix=sparse_library.free_matrix
让我们来讨论一下上面的代码。原始的C代码将稀疏矩阵存储为链表。Python代码使用ctype Structure类来创建与C代码中的结构相对应的结构。要创建表示C结构的Python对象,只需创建从Structure派生的类。这个 _fields_ 属性必须设置为字段名和值的元组列表。请注意,如果您需要在完全定义结构之前引用它(如在链表中),您可以首先使用“pass”声明它,然后指定如上所述的字段内容。还要注意指针操作符,它从任何ctype类型创建指针。我们可以直接调用我们的库,如下所示。
m=double_sparse_pointer()
m=initialize_matrix(c_int(10),c_int(10))
set_value(m,c_int(4),c_int(4),c_double(5.0))
a=get_value(m,c_int(4),c_int(4))
print("%f"%a)
free_matrix(m)
请注意,您只需通过(Struct_Object).field name就可以访问结构的内容。然而,对于指针,有一个内容属性。因此,在上面的代码中,m.contents.nrow将允许您访问nrow字段。实际上,您可以手动遍历链表,如下所示。
m=double_sparse_pointer()
m=initialize_matrix(c_int(10),c_int(10))
set_value(m,c_int(4),c_int(4),c_double(5.0))
a=m.contents.rows[4]
b=a.contents.next_element
b.contents.value
free_matrix(m)