2

This C file:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Foo {
        char *s;
        int i;
};

struct Bar {
        struct Foo *f;
        int n;
};

void func(struct Bar *b)
{
        for(int i = 0; i < b->n; i++) {
                printf("s:%s i:%i\n", b->f[i].s, b->f[i].i);
        }
}

//int main()
//{
//      struct Foo *f = malloc(sizeof(*f) * 2);
//      f[0].s = strdup("asd");
//      f[0].i = 1;
//      f[1].s = strdup("qwe");
//      f[1].i = 2;
//      struct Bar *b = malloc(sizeof(*b));
//      b->f = f;
//      b->n = 2;
//      func(b); // works as expected
//}

And corresponding Python:


import ctypes

clibrary = ctypes.CDLL('clibrary.so')

class Foo(ctypes.Structure):
    _fields_ = [
        ('s', ctypes.c_char_p),
        ('i', ctypes.c_int32)
    ]

class Bar(ctypes.Structure):
    _fields_ = [
        ('f', ctypes.POINTER(Foo)),
        ('n', ctypes.c_int32)
    ]

b = Bar()
# b.f = ctypes.Array(2)
b.f[0] = Foo(b'asd', 4)
b.f[1] = Foo(b'qwe', 5)
b.n = 2
clibrary.func(ctypes.byref(b))

gives:

ValueError: NULL pointer access

I know that the Bar.f is just not-allocated pointer, and that's why I make allocations in test main() (commented out). But how can I do allocations in python? I am using the Bar.f as a dynamic array in func(), because I don't know the size, or how many Foos will I need in that array. How to tackle this scenario with ctypes?

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
milanHrabos
  • 2,010
  • 3
  • 11
  • 45
  • Might be helpful: [\[SO\]: Dynamically defining/updating ctypes structure in Python (@CristiFati's answer)](https://stackoverflow.com/a/57438020/4788546). – CristiFati May 18 '23 at 17:45

1 Answers1

0

Use the following pattern to allocate an array of structures:

array_n = (Structure * array_size)()

Structure * array_size is a type and calling it with () makes it an instance:

>>> Foo * 2   # sized array type
<class '__main__.Foo_Array_2'>
>>> (Foo * 2)()  # instance of sized array
<__main__.Foo_Array_2 object at 0x000001F57FF4F5D0>

So make the following change to the code:

b.f = (Foo * 2)()

It works as expected after the change:

s:asd i:4
s:qwe i:5
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251