Search code examples
pythonctypespython-bindings

How to correctly initialize ctypes char***?


I'm using ctype to call C code from Python.

The C function I need to call takes a char***, and so it's bind as using a ctypes.POINTER(ctypes.POINTER(ctypes.c_char)).

I don't understand how I should safely create and initialize such objects, because if I create one and immediatly try to iterate it, the Python program crashs:

import ctypes
names = ctypes.POINTER(ctypes.POINTER(ctypes.c_char))()
if names != None:
    for name in names:
        pass

Error is:

Traceback (most recent call last):
  File "example_sdetests_lib_bind_python_string_array.py", line 6, in <module>
    for name in names:
ValueError: NULL pointer access

How can I safely check a ctypes.POINTER(ctypes.POINTER(ctypes.c_char)) is NULL or not?


Solution

  • FYI: char*** does need three ctypes.POINTER.

    To test for null, test like any other "falsey" object:

    import ctypes as ct
    
    # define char*** type
    PPPCHAR = ct.POINTER(ct.POINTER(ct.POINTER(ct.c_char)))
    
    # instantiate (default null)
    names = PPPCHAR()
    if not names:
        print('NULL')
        
    # Simple initialization
    c = ct.c_char(b'a')
    # pointer(obj) creates a ctypes pointer instance to a ctypes object.
    pc = ct.pointer(c)
    ppc = ct.pointer(pc)
    pppc = ct.pointer(ppc)
    
    if pppc:
        print('non-NULL')
    
    print(pppc.contents.contents.contents)
    

    Output:

    NULL
    non-NULL
    c_char(b'a')