Python, ctypes, multi-Dimensional Array

12,570

Here's an example of how you can use a multidimensional array with Python and ctypes.

I wrote the following C code, and used gcc in MinGW to compile this to slib.dll:

#include <stdio.h>

typedef struct TestStruct {
    int     a;
    float   array[30][4];
} TestStruct;

extern void print_struct(TestStruct *ts) {
    int i,j;
    for (j = 0; j < 30; ++j) {
        for (i = 0; i < 4; ++i) {
            printf("%g ", ts->array[j][i]);
        }
        printf("\n");
    }
}

Note that the struct contains a 'two-dimensional' array.

I then wrote the following Python script:

from ctypes import *

class TestStruct(Structure):
    _fields_ = [("a", c_int),
                ("array", (c_float * 4) * 30)]

slib = CDLL("slib.dll")
slib.print_struct.argtypes = [POINTER(TestStruct)]
slib.print_struct.restype = None

t = TestStruct()

for i in range(30):
    for j in range(4):
        t.array[i][j] = i + 0.1*j

slib.print_struct(byref(t))

When I ran the Python script, it called the C function, which printed out the contents of the multidimensional array:

C:\>slib.py
0.1 0.2 0.3 0.4
1.1 1.2 1.3 1.4
2.1 2.2 2.3 2.4
3.1 3.2 3.3 3.4
4.1 4.2 4.3 4.4
5.1 5.2 5.3 5.4
... rest of output omitted

I've used Python 2, whereas the tags on your question indicate that you're using Python 3. However, I don't believe this should make a difference.

Share:
12,570
shestakoffvs
Author by

shestakoffvs

Updated on June 14, 2022

Comments

  • shestakoffvs
    shestakoffvs almost 2 years

    I have structure in Python code and in C code. I fill these fields

    ("bones_pos_vect",((c_float*4)*30)),
    ("bones_rot_quat",((c_float*4)*30))
    

    in python code with the right values, but when I request them in C code, I get only 0.0 from all array cells. Why do I lose the values? All other fields of my structures work fine.

    class SceneObject(Structure):
        _fields_ = [("x_coord", c_float),
                    ("y_coord", c_float),
                    ("z_coord", c_float),
                    ("x_angle", c_float),
                    ("y_angle", c_float),
                    ("z_angle", c_float),
                    ("indexes_count", c_int),
                    ("vertices_buffer", c_uint),
                    ("indexes_buffer", c_uint),
                    ("texture_buffer", c_uint),
                    ("bones_pos_vect",((c_float*4)*30)),
                    ("bones_rot_quat",((c_float*4)*30))]
    
    typedef struct
    {
        float x_coord;
        float y_coord;
        float z_coord;
        float x_angle;
        float y_angle;
        float z_angle;
        int indexes_count;
        unsigned int vertices_buffer;
        unsigned int indexes_buffer;
        unsigned int texture_buffer;
        float bones_pos_vect[30][4];
        float bones_rot_quat[30][4];    
    } SceneObject;
    
    • Sebastian Hoffmann
      Sebastian Hoffmann almost 12 years
      Multidimensional arrays are not mapped one to one in memory in c. Thus float[30][4] is actually an array (size=30) of float pointers (pointing to the beginning of the float array). The (c_float*4)*30) might be really a array of arrays (first 4 floats then the second 4 floats etc.) though. You should test that out.
    • shestakoffvs
      shestakoffvs almost 12 years
      So, I must send simply (c_float*(4*30))?
    • Sebastian Hoffmann
      Sebastian Hoffmann almost 12 years
      no i think it should be POINTER(c_float)*30; use [i] to access the single values then. e.g pbase = bones_pos_vect[17]; p = pbase[3] #third float in array; value = p.contents
    • shestakoffvs
      shestakoffvs almost 12 years
      No it's not working, i get only 0.0. Also, I tryed use (c_float*(4*30) and have same result((( i want to cry, cause it's not workin
    • shestakoffvs
      shestakoffvs almost 12 years
      and i want to send values to C code
    • Sebastian Hoffmann
      Sebastian Hoffmann almost 12 years
      if you iterate over the array after you filled it does it prints the correct values?
    • shestakoffvs
      shestakoffvs almost 12 years
      yes but only in C code, in python all good
    • Mark Tolonen
      Mark Tolonen almost 12 years
      @Paranaix, float[30][4] is not an array of float pointers. @shestakoffvs has the correct definition.
    • Mark Tolonen
      Mark Tolonen almost 12 years
      @shestakoffvs You must have a mistake in either your Python code calling C or in the C code displaying the array. Your definition is correct.
  • Mark Tolonen
    Mark Tolonen almost 12 years
    Ah, beat me to it. I wrote basically the same code with the OP's structure and definition.
  • shestakoffvs
    shestakoffvs almost 12 years
    Oh guys, i'm so stupid))) And big thx for example code, with it i'm understand what wrong with my)))) insted of assign to every varing in structure field array i just assigned it whole new array: scene_object.bones_pos_vects = import_content["bones_pos_vects"] now i do this so: for n in range(len(import_content["bones_pos_vects"])): for u in range(3): scene_object.bones_pos_vects[n][u] = import_content["bones_pos_vects"][n][u] scene_object.bones_rot_quats[n][u] = import_content["bones_rot_quats"][n][u] Now all work very well))) big thx)))