STRUCT_ARRAY in your code should be a pointer to a pointer array, not a pointer to an element in the array, as you are appending STRUCT_2 pointers to the array.

In C, STRUCT_ARRAY can be defined as *STRUCT_2[length], aka an array of STRUCT_2 pointers

import ctypes
from random import randint

class STRUCT_2(ctypes.Structure):
    #_pack_=2
    _fields_ = [('field_1', ctypes.c_short),
                ('field_2', ctypes.c_short),
                ('field_3', ctypes.c_short),
                ('field_4', ctypes.c_short),
                ('field_5', ctypes.c_short),
                ('field_6', ctypes.c_short),
                ('field_7', ctypes.c_short),
                ('field_8', ctypes.c_short)]

class STRUCT_1(ctypes.Structure):
    #_pack_=2
    _fields_ = [('elements', ctypes.c_short),
                #an array of pointers
                ('STRUCT_ARRAY', ctypes.POINTER(ctypes.POINTER(STRUCT_2)))]

    def __init__(self,num_of_structs):
        elems = (ctypes.POINTER(STRUCT_2) * num_of_structs)()
        self.STRUCT_ARRAY = ctypes.cast(elems,ctypes.POINTER(ctypes.POINTER(STRUCT_2)))
        self.elements = num_of_structs

        for num in range(0,num_of_structs):
            self.STRUCT_ARRAY[num].field_1 = 1
            self.STRUCT_ARRAY[num].field_2 = 2
            self.STRUCT_ARRAY[num].field_3 = 3

for num in range(0,100):
    test = STRUCT_1(num)
    print("%i done" % num)

If instead what you want is an array of structs, use the following code:

import ctypes
from random import randint

class STRUCT_2(ctypes.Structure):
    #_pack_=2
    _fields_ = [('field_1', ctypes.c_short),
                ('field_2', ctypes.c_short),
                ('field_3', ctypes.c_short),
                ('field_4', ctypes.c_short),
                ('field_5', ctypes.c_short),
                ('field_6', ctypes.c_short),
                ('field_7', ctypes.c_short),
                ('field_8', ctypes.c_short)]

class STRUCT_1(ctypes.Structure):
    #_pack_=2
    _fields_ = [('elements', ctypes.c_short),
                #an array of structs
                ('STRUCT_ARRAY', ctypes.POINTER(STRUCT_2))]

    def __init__(self,num_of_structs):
        elems = (STRUCT_2 * num_of_structs)()
        self.STRUCT_ARRAY = ctypes.cast(elems,ctypes.POINTER(STRUCT_2))
        self.elements = num_of_structs

        for num in range(0,num_of_structs):
            self.STRUCT_ARRAY[num].field_1 = 1
            self.STRUCT_ARRAY[num].field_2 = 2
            self.STRUCT_ARRAY[num].field_3 = 3
            self.STRUCT_ARRAY[num].field_4 = 4

for num in range(0,100):
    test = STRUCT_1(num)
    print("%i done" % num)
Answer from simonzack on Stack Overflow
Top answer
1 of 1
20

STRUCT_ARRAY in your code should be a pointer to a pointer array, not a pointer to an element in the array, as you are appending STRUCT_2 pointers to the array.

In C, STRUCT_ARRAY can be defined as *STRUCT_2[length], aka an array of STRUCT_2 pointers

import ctypes
from random import randint

class STRUCT_2(ctypes.Structure):
    #_pack_=2
    _fields_ = [('field_1', ctypes.c_short),
                ('field_2', ctypes.c_short),
                ('field_3', ctypes.c_short),
                ('field_4', ctypes.c_short),
                ('field_5', ctypes.c_short),
                ('field_6', ctypes.c_short),
                ('field_7', ctypes.c_short),
                ('field_8', ctypes.c_short)]

class STRUCT_1(ctypes.Structure):
    #_pack_=2
    _fields_ = [('elements', ctypes.c_short),
                #an array of pointers
                ('STRUCT_ARRAY', ctypes.POINTER(ctypes.POINTER(STRUCT_2)))]

    def __init__(self,num_of_structs):
        elems = (ctypes.POINTER(STRUCT_2) * num_of_structs)()
        self.STRUCT_ARRAY = ctypes.cast(elems,ctypes.POINTER(ctypes.POINTER(STRUCT_2)))
        self.elements = num_of_structs

        for num in range(0,num_of_structs):
            self.STRUCT_ARRAY[num].field_1 = 1
            self.STRUCT_ARRAY[num].field_2 = 2
            self.STRUCT_ARRAY[num].field_3 = 3

for num in range(0,100):
    test = STRUCT_1(num)
    print("%i done" % num)

If instead what you want is an array of structs, use the following code:

import ctypes
from random import randint

class STRUCT_2(ctypes.Structure):
    #_pack_=2
    _fields_ = [('field_1', ctypes.c_short),
                ('field_2', ctypes.c_short),
                ('field_3', ctypes.c_short),
                ('field_4', ctypes.c_short),
                ('field_5', ctypes.c_short),
                ('field_6', ctypes.c_short),
                ('field_7', ctypes.c_short),
                ('field_8', ctypes.c_short)]

class STRUCT_1(ctypes.Structure):
    #_pack_=2
    _fields_ = [('elements', ctypes.c_short),
                #an array of structs
                ('STRUCT_ARRAY', ctypes.POINTER(STRUCT_2))]

    def __init__(self,num_of_structs):
        elems = (STRUCT_2 * num_of_structs)()
        self.STRUCT_ARRAY = ctypes.cast(elems,ctypes.POINTER(STRUCT_2))
        self.elements = num_of_structs

        for num in range(0,num_of_structs):
            self.STRUCT_ARRAY[num].field_1 = 1
            self.STRUCT_ARRAY[num].field_2 = 2
            self.STRUCT_ARRAY[num].field_3 = 3
            self.STRUCT_ARRAY[num].field_4 = 4

for num in range(0,100):
    test = STRUCT_1(num)
    print("%i done" % num)
🌐
DaniWeb
daniweb.com › programming › software-development › threads › 351774 › passing-pointer-to-array-of-structures-in-ctypes
Passing pointer to array of structures in ctypes - python
To call pyArrayFiller, I need to generate the python version of the `void *pRecord` which is a pointer to an array of four structures as defined below: ... typedef struct tagMyStruct { double x; double y; double z; double a; double e; double r; double time; USHORT quality; } MyStruct; So I constructed a python version of the same structure: class pyMyStructure(ctypes.Structure): _fields_ = [("x", ctypes.c_double), ("y", ctypes.c_double), ("z", ctypes.c_double), ("a", ctypes.c_double), ("e", ctypes.c_double), ("r", ctypes.c_double), ("time", ctypes.c_double), ("quality", ctypes.c_double)]
Discussions

python - ctypes struct containing arrays - Stack Overflow
Bring the best of human thought and AI automation together at your work. Explore Stack Internal ... I'm trying to use ctypes. I'm interested in manipulating C structs containing arrays. More on stackoverflow.com
🌐 stackoverflow.com
May 21, 2018
ctypes create arrays in struct
Try: math := ctypes.struct([float(cosvar), float(sinvar)])({ cosvar:= [0.0], sinvar:= [0.0] }) ? Maybe ? More on reddit.com
🌐 r/AutoHotkey
9
1
May 17, 2024
python - ctypes and array of structs - Stack Overflow
I'd like to read an array of structs defined in a C library using ctypes and python. The C struct is simply struct particle { double x; double y; } I have a function that returns a pointer t... More on stackoverflow.com
🌐 stackoverflow.com
Python ctype struct with array of structs - Stack Overflow
I have some struct, with dynamic entries count. I receiving bytearray from UDP and parsing this message as follows: class MsgStruct(Structure): _pack_ = 1 def __init__(self, data=None): ... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Chris Heydrick
chrisheydrick.com › 2016 › 02 › 06 › passing-a-ctypes-array-of-struct-from-python-to-dll
Passing a ctypes array of struct from Python to .dll | Chris Heydrick
February 6, 2016 - // #include "stdafx.h" #ifdef STRUCTTEST_EXPORTS #define STRUCTTEST_API __declspec(dllexport) #else #define STRUCTTEST_API __declspec(dllimport) #endif extern "C" { struct structtest { char x; int y; long z; }; STRUCTTEST_API void fillonestruct(struct structtest *t) { t->x = 'A'; t->y = 1234; t->z = 5678; } STRUCTTEST_API void fillmultiplestruct(struct structtest *t, int n) { for (int i = 0; i < n; i++) { t->x = (char)((int)'A' + i); t->y = i; t->z = i; t++; } } } ... from ctypes import * class structtest(Structure): _fields_ = [("x", c_char), ("y", c_int), ("z", c_long)] if __name__ == "__mai
🌐
CSDN
devpress.csdn.net › python › 62fee900c677032930804a21.html
python ctypes array of structs - DevPress官方社区
August 19, 2022 - In C, STRUCT_ARRAY can be defined as *STRUCT_2[length], aka an array of STRUCT_2 pointers · import ctypes from random import randint class STRUCT_2(ctypes.Structure): #_pack_=2 _fields_ = [('field_1', ctypes.c_short), ('field_2', ctypes.c_short), ('field_3', ctypes.c_short), ('field_4', ...
🌐
Python
docs.python.org › 3 › library › ctypes.html
ctypes — A foreign function library for Python
The recommended way to create array types is by multiplying a data type with a positive integer: ... Here is an example of a somewhat artificial data type, a structure containing 4 POINTs among other stuff: >>> from ctypes import * >>> class ...
Top answer
1 of 1
5

There were 2 problems with the code (as I stated in the comment):

  1. print_array_struct.argtype - which is incorrect (and might have disastrous effects). Check (newer) [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for more details

  2. In C the arrays are double based, while in Python they are ctypes.c_int (int) based

For more details, check [Python.Docs]: ctypes - A foreign function library for Python.
I modified your Python code, to correct the above mistakes (and some other minor stuff).

code00.py:

#!/usr/bin/env python

import ctypes as ct
import sys


DLL_NAME = DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")

DOUBLE_10 = ct.c_double * 10


class ArrayStruct(ct.Structure):
    _fields_ = (
        ("first_array", DOUBLE_10),
        ("second_array", DOUBLE_10),
    )


def main(*argv):
    dll_handle = ct.CDLL(DLL_NAME)
    print_array_struct = dll_handle.print_array_struct
    print_array_struct.argtypes = (ArrayStruct,)
    print_array_struct.restype = None

    x1 = DOUBLE_10()
    x2 = DOUBLE_10()
    x1[:] = range(1, 11)
    x2[:] = range(11, 21)
    print([item for item in x1])
    print([item for item in x2])
    arg = ArrayStruct(x1, x2)
    print_array_struct(arg)


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

dll00.c (dummy):

#include <stdio.h>

#if defined(_WIN32)
#  define DLL00_EXPORT_API __declspec(dllexport)
#else
#  define DLL00_EXPORT_API
#endif

#define DIM 10


typedef struct {
    double first_array[DIM];
    double second_array[DIM];
} ArrayStruct;


#if defined(__cplusplus)
extern "C" {
#endif

DLL00_EXPORT_API void print_array_struct(ArrayStruct array_struct);

#if defined(__cplusplus)
}
#endif


void print_array_struct(ArrayStruct array_struct)
{
    printf("From C:\n");
    for (int i = 0; i < DIM; ++i) {
        printf("  %2.1lf\n", array_struct.first_array[i]);
    }
}

Output:

(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q050447199]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[064bit prompt]> ls
code00.py  dll00.c
[064bit prompt]> gcc -fPIC -shared -o dll00.so dll00.c
[064bit prompt]> ls
code00.py  dll00.c  dll00.so
[064bit prompt]>
[064bit prompt]> python3.5 ./code00.py
Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit on linux

[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
[11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0]
From C:
  1.0
  2.0
  3.0
  4.0
  5.0
  6.0
  7.0
  8.0
  9.0
  10.0

Done.
🌐
Reddit
reddit.com › r/autohotkey › ctypes create arrays in struct
r/AutoHotkey on Reddit: ctypes create arrays in struct
May 17, 2024 -

I am using this script in my AHK code but while attempting to create a list in a struct, I got an error. I don't know if there is a specific prefix to to the variable I need to use so I am just using the prefix that would go for the values in the array. This is my code:

math := ctypes.struct("float cosvar; float sinvar;")({
    cosvar: [0.0],
    sinvar: [0.0]
})

How should I fix this?

🌐
SageMath
doc.sagemath.org › html › en › thematic_tutorials › numerical_sage › ctypes_examples.html
More complicated ctypes example - Thematic Tutorials
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
Find elsewhere
🌐
Bytes
bytes.com › home › forum › topic › python
ctypes - pointer to array of structs? - Post.Byes
January 3, 2008 - Using ctypes I reference a structure which contains a pointer to an array of another structure: > class SYMBOL(Structur e): _fields_ = [("symbol", c_char_p), ("num", c_int), ("units", c_int), ("baseprice" , c_int), ("active", c_int)] SYMBOL_PTR = POINTER(SYMBOL) > class TABLE(Structure ): _fields_ = [("map", SYMBOL_PTR), ("nsymbols", c_uint), ...] > Effectively, TABLE.map is an array of TABLE.nsymbols SYMBOLS.
Top answer
1 of 1
1

I want to start with the note that I don't see where is the entry_count attribute initialized.

Iterating over a pointer as if it was a sized array is conceptually wrong (as also pointed out in [Python 3]: ctypes - A foreign function library for Python). In C, it's possible to go beyond an array bounds, but ctypes forbids it.
Here's a simpler example that uses ctypes.c_char as the base type (MessageEntry correspondent).

code.py:

#!/usr/bin/env python3

import sys
import ctypes


def main():
    CharArr5 = ctypes.c_char * 5
    b5 = b"12345"
    ca5 = CharArr5(*b5)
    print("Print array ...")
    for c in ca5:
        print(c)

    cp = ctypes.cast(ca5, ctypes.POINTER(ctypes.c_char))
    max_values = 10
    print("\nPrint pointer (max {:d} values) ...".format(max_values))
    for idx, c in enumerate(cp):
        print(c)
        if idx >= max_values:
            print("Max value number reached.")
            break


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Output:

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054178876>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Print array ...
b'1'
b'2'
b'3'
b'4'
b'5'

Print pointer (max 10 values) ...
b'1'
b'2'
b'3'
b'4'
b'5'
b'\x00'
b'\x00'
b'\x00'
b'\x00'
b'\x00'
b'\x00'
Max value number reached.

As seen, it is possible to iterate over the pointer, but the loop never ends (it will end when reaching an unavailable / invalid memory address, and the program will segfault (Access Violation)).

Assuming that entry_count is properly initialized (if not, make sure to initialize it), use it to keep the loop inside bounds (as shown below):

for idx in range(msg.entry_count):
    msg.entries[idx]  # Do smth with it
    # ...


for idx, entry in enumerate(msg.entries):
    if idx >= msg.entry_count:
        break
    entry  # Do smth with it
    # ...

Or you could use one of the above to implement Iterator Protocol for Message.

🌐
Stack Overflow
stackoverflow.com › questions › 75739510 › python-ctypes-pointer-to-array-of-structs
Python ctypes pointer to array of structs - Stack Overflow
#create instances data = ctypes.POINTER(NIComplexNumberF32_struct_data)() wfmInfo = ctypes.POINTER(niRFSA_wfmInfo_struct_data)() ... It only creates NULL pointers and causes the RuntimeError you see. Instead, create instances of each structure and pass them by address using ctypes.byref().
Top answer
1 of 1
2

Here's a way but it isn't pretty. ctypes doesn't do variable arrays in a structure so to access the variable data requires some casting.

test.c Implements a test function returning the variable structure data. In this case I hard-coded a return array of size 4 but it could be any size.

#include <stdlib.h>

typedef struct STATE {
    int a;
    int b;
} STATE;

typedef struct DXYZ {
    int count;
    STATE state[];
} DXYZ, *PDXYZ;

__declspec(dllexport) PDXYZ get(void)
{
    PDXYZ pDxyz = malloc(sizeof(DXYZ) + sizeof(STATE) * 4);
    pDxyz->count = 4;
    pDxyz->state[0].a = 1;
    pDxyz->state[0].b = 2;
    pDxyz->state[1].a = 3;
    pDxyz->state[1].b = 4;
    pDxyz->state[2].a = 5;
    pDxyz->state[2].b = 6;
    pDxyz->state[3].a = 7;
    pDxyz->state[3].b = 8;
    return pDxyz;
}

__declspec(dllexport) void myfree(PDXYZ pDxyz)
{
    free(pDxyz);
}

test.py

from ctypes import *
import struct

class State(Structure):
    _fields_ = [('a',c_int),
                ('b',c_int)]

class DXYZ(Structure):
    _fields_ = [('count',c_int),      # Number of state objects
                ('state',State * 0)]  # Zero-sized array

# Set the correct arguments and return type for the DLL functions.
dll = CDLL('test')
dll.get.argtypes = None
dll.get.restype = POINTER(DXYZ)
dll.myfree.argtypes = POINTER(DXYZ),
dll.myfree.restype = None

pd = dll.get()    # Get the returned pointer
d = pd.contents   # Dereference it.

print('count =',d.count)
# Cast a pointer to the zero-sized array to the correct size and dereference it.
s = cast(byref(d.state),POINTER(State * d.count)).contents

for c in s:
    print(c.a,c.b)

dll.myfree(pd)

Output:

count = 4
1 2
3 4
5 6
7 8
🌐
ProgramCreek
programcreek.com › python › example › 1122 › ctypes.Structure
Python Examples of ctypes.Structure
def compile(self, structure): source = self.gen_struct_class(structure) c = compile(source, '<compiled>', 'exec') env = { 'OrderedDict': OrderedDict, 'Structure': Structure, 'Instance': Instance, 'Expression': Expression, 'EnumInstance': EnumInstance, 'PointerInstance': PointerInstance, 'BytesInteger': BytesInteger, 'BitBuffer': BitBuffer, 'struct': struct, 'xrange': xrange, } exec(c, env) sc = env[structure.name](self.cstruct, structure, source) return sc ... def as_ctypes_type(dtype): r""" Convert a dtype into a ctypes type. Parameters ---------- dtype : dtype The dtype to convert Returns ------- ctype A ctype scalar, union, array, or struct Raises ------ NotImplementedError If the conversion is not possible Notes ----- This function does not losslessly round-trip in either direction.
Top answer
1 of 1
8

The error explains exactly the problem, but in a slightly convoluted manner:

The correct way to initialize such an array is as follows:

structs = [A(1, 2), A(1, 2)]
array = (A * 2)(*structs)

Or, if you can define them all during the array constructor, as follows:

array = (A * 2)(A(1, 2), A(1, 2))

Now, why does this work and your solution not? Since I am passing an instance of A for each argument to the constructor of A * 2, which is an array of A. The array requires an instance of A for each argument passed, which is precisely the error message. It does not expect to convert arguments into A, it expects an instance of A itself.

The step-by-step way is as follows:

from ctypes import *
class A(Structure):
    _fields_ = [('a', c_int), ('b', c_int)]

# this create a class which expects 2 A instances
a_array_factory = A * 2
# our first A instance
struct_1 = A(1, 2)
# our second A instance
struct_2 = A(2, 3)
# initialize our array
array = a_array_factory(struct_1, struct_2)

EDIT:

Since a structure does not have a native Python type, there is no solution, to my knowledge, without creating intermediary structs. According to the Python documentation, the only native types with C primitives are the following:

ctypes type     C type                                      Python type
c_bool          _Bool                                       bool (1)
c_char          char                                        1-character string
c_wchar         wchar_t                                     1-character unicode string
c_byte          char                                        int/long
c_ubyte         unsigned char                               int/long
c_short         short                                       int/long
c_ushort        unsigned short                              int/long
c_int           int                                         int/long
c_uint          unsigned int                                int/long
c_long          long                                        int/long
c_ulong         unsigned long                               int/long
c_longlong      __int64 or long long                        int/long
c_ulonglong     unsigned __int64 or unsigned long long      int/long
c_float         float                                       float
c_double        double                                      float
c_longdouble    long double                                 float
c_char_p        char * (NUL terminated)                     string or None
c_wchar_p       wchar_t * (NUL terminated)                  unicode or None
c_void_p        void *                                      int/long or Nonee or None
🌐
Stack Overflow
stackoverflow.com › questions › 29929920 › how-to-pass-a-list-array-of-structs-from-python-to-c
How to pass a list/array of structs from python to C - Stack Overflow
April 28, 2015 - I solved my problem by: 1. Declaring an array of pointers to my struct: nodeArrayType = ctypes.POINTER(STATION_MM_NODE) * 1024 nodeArray = nodeArrayType() nstn = 0
🌐
Stack Overflow
stackoverflow.com › questions › 53967546 › how-to-build-a-ctypes-array-of-structure-in-python
How to build a ctypes array of structure in python - Stack Overflow
There is another error as well. depth is declared as c_uint8 which has a range of 0-255, but the values in the dictionary are all greater than 255. I suggest defining __repr__ in the structure so Node can print itself, and using more "pythonic" looping: from ctypes import * class Node(Structure): _fields_ = [("id", c_uint16), ("version", c_uint8), ("depth", c_uint8)] def __repr__(self): return f'Node(id={self.id}, version={self.version}, depth={self.depth})' dics = [{'ID': '3', 'VERSION': '180', 'DEPTH': '924'}, {'ID': '9', 'VERSION': '180', 'DEPTH': '269'}, {'ID': '2', 'VERSION': '180', 'DEPTH': '537'}] nodeNum = len(dics) NODES = Node * nodeNum nodes = NODES() for node,dic in zip(nodes,dics): node.id = int(dic['ID']) node.version = int(dic['VERSION']) node.depth = int(dic['DEPTH']) for node in nodes: print(node)
🌐
GitHub
github.com › python › cpython › issues › 110190
ctypes array cannot be returned by value on ARM64 · Issue #110190 · python/cpython
October 1, 2023 - import os import subprocess import ctypes def compile(): """Compile the c file using gcc.""" subprocess.call(["gcc","-c","-Wall","-Werror","-fpic","ctypesexample.c"]) subprocess.call(["gcc","-shared","-o","libctypesexample","ctypesexample.o"]) assert os.path.isfile('libctypesexample') # Three ways to wrap the struct: class Example1(ctypes.Structure): _fields_ = [ ('coords', ctypes.c_double * 3) ] class CoordType(ctypes.Array): _type_ = ctypes.c_double _length_ = 3 class Example2(ctypes.Structure): _fields_ = [('coords', CoordType)] class Example3(ctypes.Structure): _fields_ = [ ('x', ctypes.c_
Author: python