The following code works:

test.py:

import ctypes
lib = ctypes.CDLL("./libtest.so")
string_buffers = [ctypes.create_string_buffer(8) for i in range(4)]
pointers = (ctypes.c_char_p*4)(*map(ctypes.addressof, string_buffers))
lib.test(pointers)
results = [s.value for s in string_buffers]
print results

test.c (compiled to libtest.so with gcc test.c -o libtest.so -shared -fPIC):

#include <string.h>
void test(char **strings) {
    strcpy(strings[0],"this");
    strcpy(strings[1],"is");
    strcpy(strings[2],"a");
    strcpy(strings[3],"test!");
}

As Aya said, you should make sure there is room for the terminating zero. But I think your main problem was that the string buffer was garbage collected or something similar, as there was no direct reference to it anymore. Or something else is causing trouble in the creation process of the string buffers when no references are stored for them. For example this results in four times the same address instead of different addresses:

import ctypes
pointers = [ctypes.addressof(ctypes.create_string_buffer(8)) for i in range(4)]
print pointers
Answer from Florian Rhiem on Stack Overflow
🌐
Python
docs.python.org › 3 › library › ctypes.html
ctypes — A foreign function library for Python
This function creates a mutable unicode character buffer. The returned object is a ctypes array of c_wchar.
Top answer
1 of 3
12

The following code works:

test.py:

import ctypes
lib = ctypes.CDLL("./libtest.so")
string_buffers = [ctypes.create_string_buffer(8) for i in range(4)]
pointers = (ctypes.c_char_p*4)(*map(ctypes.addressof, string_buffers))
lib.test(pointers)
results = [s.value for s in string_buffers]
print results

test.c (compiled to libtest.so with gcc test.c -o libtest.so -shared -fPIC):

#include <string.h>
void test(char **strings) {
    strcpy(strings[0],"this");
    strcpy(strings[1],"is");
    strcpy(strings[2],"a");
    strcpy(strings[3],"test!");
}

As Aya said, you should make sure there is room for the terminating zero. But I think your main problem was that the string buffer was garbage collected or something similar, as there was no direct reference to it anymore. Or something else is causing trouble in the creation process of the string buffers when no references are stored for them. For example this results in four times the same address instead of different addresses:

import ctypes
pointers = [ctypes.addressof(ctypes.create_string_buffer(8)) for i in range(4)]
print pointers
2 of 3
4

In this line:

results = (c_char_p * 4)(addressof(create_string_buffer(7)))

You're creating a single buffer of 7 bytes, then trying to use it to hold 4 character pointers (which are probably 4 bytes each), and then also copying 4 8-byte strings into the random addresses it might happen to point to. You need to allocate a buffer for each string, and also allocate the array of pointers. Something like this:

s = []
for i in range(4):
    s[i] = create_string_buffer(8)
results = (c_char_p * 4)(s);
🌐
ProgramCreek
programcreek.com › python › example › 3579 › ctypes.c_char
Python Examples of ctypes.c_char
def _createShader(self, strings, shadertype): # create the shader handle shader = gl.glCreateShader(shadertype) # convert the source strings into a ctypes pointer-to-char array, and upload them # this is deep, dark, dangerous black magick - don't try stuff like this at home! strings = tuple(s.encode('ascii') for s in strings) # Nick added, for python3 src = (c_char_p * len(strings))(*strings) gl.glShaderSource(shader, len(strings), cast(pointer(src), POINTER(POINTER(c_char))), None) # compile the shader gl.glCompileShader(shader) # retrieve the compile status compile_success = c_int(0) gl.glGe
🌐
Python.org
discuss.python.org › python help
Dealing with char*** in ctypes - Python Help - Discussions on Python.org
December 13, 2023 - I have this function in C library that I want to access from python using ctypes: static const char *names[] = {"Backplane", "ADC", "External", "Reserved"}; int test_char_ptr(const char ***names_, int *count_) { …
🌐
ProgramCreek
programcreek.com › python › example › 1243 › ctypes.c_char_p
Python Examples of ctypes.c_char_p
def c_str_array(strings): """Create ctypes const char ** from a list of Python strings. Parameters ---------- strings : list of string Python strings. Returns ------- (ctypes.c_char_p * len(strings)) A const char ** pointer that can be passed to C API.
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.char.chararray.ctypes.html
numpy.char.chararray.ctypes — NumPy v2.4 Manual
Return the strides tuple as an array of some other c-types type. For example: self.strides_as(ctypes.c_longlong).
🌐
SciPy
docs.scipy.org › doc › numpy-1.15.1 › reference › generated › numpy.chararray.ctypes.html
numpy.chararray.ctypes — NumPy v1.15 Manual
... >>> import ctypes >>> x array([[0, 1], [2, 3]]) >>> x.ctypes.data 30439712 >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)) <ctypes.LP_c_long object at 0x01F01300> >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)).contents c_long(0) >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_lo
🌐
University of Texas at Austin
het.as.utexas.edu › HET › Software › Numpy › reference › generated › numpy.chararray.ctypes.html
numpy.chararray.ctypes — NumPy v1.9 Manual
... >>> import ctypes >>> x array([[0, 1], [2, 3]]) >>> x.ctypes.data 30439712 >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)) <ctypes.LP_c_long object at 0x01F01300> >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)).contents c_long(0) >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_lo
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.char.chararray.ctypes.html
numpy.char.chararray.ctypes — NumPy v2.5.dev0 Manual
This ctypes array contains the strides information from the underlying array. This strides information is important for showing how many bytes must be jumped to get to the next element in the array. ... Return the data pointer cast to a particular c-types object. For example, calling self._as_parameter_ is equivalent to self.data_as(ctypes.c_void_p).
Find elsewhere
🌐
SciPy
docs.scipy.org › doc › numpy-1.14.0 › reference › generated › numpy.core.defchararray.chararray.ctypes.html
numpy.core.defchararray.chararray.ctypes — NumPy v1.14 Manual
... >>> import ctypes >>> x array([[0, 1], [2, 3]]) >>> x.ctypes.data 30439712 >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)) <ctypes.LP_c_long object at 0x01F01300> >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)).contents c_long(0) >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_lo
🌐
SciPy
docs.scipy.org › doc › numpy-1.13.0 › reference › generated › numpy.chararray.ctypes.html
numpy.chararray.ctypes — NumPy v1.13 Manual
... >>> import ctypes >>> x array([[0, 1], [2, 3]]) >>> x.ctypes.data 30439712 >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)) <ctypes.LP_c_long object at 0x01F01300> >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)).contents c_long(0) >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_lo
🌐
NumPy
numpy.org › doc › 2.1 › reference › generated › numpy.char.chararray.ctypes.html
numpy.char.chararray.ctypes — NumPy v2.1 Manual
This ctypes array contains the strides information from the underlying array. This strides information is important for showing how many bytes must be jumped to get to the next element in the array. ... Return the data pointer cast to a particular c-types object. For example, calling self._as_parameter_ is equivalent to self.data_as(ctypes.c_void_p).
🌐
NumPy
numpy.org › doc › 2.3 › reference › generated › numpy.char.chararray.ctypes.html
numpy.char.chararray.ctypes — NumPy v2.3 Manual
Return the strides tuple as an array of some other c-types type. For example: self.strides_as(ctypes.c_longlong).
🌐
SciPy
docs.scipy.org › doc › › numpy-1.9.2 › reference › generated › numpy.chararray.ctypes.html
chararray.ctypes - Numpy and Scipy Documentation
... >>> import ctypes >>> x array([[0, 1], [2, 3]]) >>> x.ctypes.data 30439712 >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)) <ctypes.LP_c_long object at 0x01F01300> >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)).contents c_long(0) >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_lo
🌐
GitHub
gist.github.com › nzjrs › 990493
Python ctypes example · GitHub
Show hidden characters · Copy link · how to alloc bytes buffer from python side? Copy link · You can define a function which calls malloc() in your shared object and call it through ctypes.
🌐
Crankuptheamps
devnull.crankuptheamps.com › documentation › html › 5.2.1.0 › dev-guides › python › html › chapters › advanced-topics.html
12. Advanced Topics — Python Developer Guide 5.2.1.0 documentation
In this case, the module passes the underlying Python client as the first argument of the C function. The two Python strings are passed as NULL-terminated char * arrays. The ctypes module also handles more complicated signatures and correctly passes arrays. For example, you could implement ...
🌐
Bytes
bytes.com › topic › python › answers › 837648-ctypes-get-full-contents-character-array
ctypes: Get full contents of character array - Python
December 12, 2008 - Your requests are coming too fast. Please slow down your access rate to continue browsing our site
🌐
The Coding Forums
thecodingforums.com › archive › archive › python
ctypes: Get full contents of character array | Python | Coding Forums
September 14, 2008 - _fields_ = [...("array", c_char * 12)...] however, ctypes seems to try to return struct.array as a Python string rather than a character array, and stops as soon as it encounters a null within the character array.
🌐
NumPy
numpy.org › doc › 2.0 › reference › generated › numpy.char.chararray.ctypes.html
numpy.char.chararray.ctypes — NumPy v2.0 Manual
Return the strides tuple as an array of some other c-types type. For example: self.strides_as(ctypes.c_longlong).