In ctypes, the type c_char means exactly that - a single character - and a POINTER to that really points specifically at that character and not anything subsequent. There is not a general “understanding” of how pointer decay, strings etc. work in C - that’s why, for example, the atomic types impleme… Answer from kknechtel on discuss.python.org
🌐
Cppreference
en.cppreference.com › w › cpp › locale › ctype_char.html
std::ctype<char> - cppreference.com
November 20, 2024 - This specialization of std::ctype encapsulates character classification features for type char.
🌐
Python
docs.python.org › 3 › library › ctypes.html
ctypes — A foreign function library for Python
Objects instantiated from c_char_p can only have their value set to bytes or integers. Why is it printing False? ctypes instances are objects containing a memory block plus some descriptors accessing the contents of the memory.
🌐
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_) { *names_ = names; *count_ = 4; return 0; } I can then do this in C app: const char **items; unsigned nr_items; result = test_char_ptr(&items, &nr_items); for (unsigned i = 0; i
🌐
LinkedIn
linkedin.com › pulse › calling-c-from-python-using-ctypes-warren-jitsing
Calling C from Python Using Ctypes
August 27, 2021 - >>> in_buffer: ctypes.Array[ctypes.c_char] = ctypes.create_string_buffer(b"Hello World!") >>> out_buffer: ctypes.Array[ctypes.c_char] = ctypes.create_string_buffer(20) >>> in_buffer.raw b'Hello World!\x00' >>> out_buffer.raw b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
🌐
GitHub
gist.github.com › nzjrs › 990493
Python ctypes example · GitHub
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters ... You can define a function which calls malloc() in your shared object and call it through ctypes.
🌐
Turing
turing.com › kb › ctypes-modules-and-their-implementation-in-python
Ctypes Modules and their implementation in Python.
Each ctypes data type has an attribute that returns a native Python object that will help you return a string from the char pointer.
Find elsewhere
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);
🌐
BestDivision
bestdivision.com › spread your knowledge - bestdivision › questions - bestdivision › python questions - categories - bestdivision › what is the "ctypes.c_char" type in python? - bestdivision
What is the "ctypes.c_char" type in Python? | BestDivision
July 14, 2023 - This type is primarily used to represent single character values or bytes when calling C functions from Python or working with C-based structures. The ctypes.c_char type is a Python representation of the C char data type, which stores a single byte (often used for ASCII characters).
🌐
CodersLegacy
coderslegacy.com › home › python › python ctypes tutorial
Python ctypes Tutorial - CodersLegacy
October 27, 2022 - Instead of using a Python string, we use a char pointer (the string equivalent) from ctypes. Hence it worked! Every ctype datatype has a value attribute, which returns a native python object.
🌐
Runebook
runebook.dev › english › articles › python
Mastering ctypes.c_char_p in Python: Examples and Best Practices
Passing to C Functions Once you have a ctypes.c_char_p object, you can pass it as an argument to a C function that expects a char*. ctypes will handle the necessary conversion so that the C function receives a valid C string.
🌐
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
The ctypes module handles type conversions between Python and C types. 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.
Top answer
1 of 1
26

c_char_p is a subclass of _SimpleCData, with _type_ == 'z'. The __init__ method calls the type's setfunc, which for simple type 'z' is z_set.

In Python 2, the z_set function (2.7.7) is written to handle both str and unicode strings. Prior to Python 3, str is an 8-bit string. CPython 2.x str internally uses a C null-terminated string (i.e. an array of bytes terminated by \0), for which z_set can call PyString_AS_STRING (i.e. get a pointer to the internal buffer of the str object). A unicode string needs to first be encoded to a byte string. z_set handles this encoding automatically and keeps a reference to the encoded string in the _objects attribute.

>>> c = u'spam'
>>> a = c_char_p(c)
>>> a._objects
'spam'
>>> type(a._objects)
<type 'str'>

On Windows, the default ctypes string encoding is 'mbcs', with error handling set to 'ignore'. On all other platforms the default encoding is 'ascii', with 'strict' error handling. To modify the default, call ctypes.set_conversion_mode. For example, set_conversion_mode('utf-8', 'strict').

In Python 3, the z_set function (3.4.1) does not automatically convert str (now Unicode) to bytes. The paradigm shifted in Python 3 to strictly divide character strings from binary data. The ctypes default conversions were removed, as was the function set_conversion_mode. You have to pass c_char_p a bytes object (e.g. b'spam' or 'spam'.encode('utf-8')). In CPython 3.x, z_set calls the C-API function PyBytes_AsString to get a pointer to the internal buffer of the bytes object.

Note that if the C function modifies the string, then you need to instead use create_string_buffer to create a c_char array. Look for a parameter to be typed as const to know that it's safe to use c_char_p.

🌐
Python
docs.python.org › 2 › library › ctypes.html
15.17. ctypes — A foreign function library for Python — Python 2.7.18 documentation
There are, however, enough ways to crash Python with ctypes, so you should be careful anyway. None, integers, longs, byte strings and unicode strings are the only native Python objects that can directly be used as parameters in these function calls. None is passed as a C NULL pointer, byte strings and unicode strings are passed as pointer to the memory block that contains their data (char * or wchar_t *).
🌐
University of New Brunswick
cs.unb.ca › ~bremner › teaching › cs2613 › books › python3-doc › library › ctypes.html
ctypes — A foreign function library for Python — Python 3.9.2 documentation
Why is it printing False? ctypes instances are objects containing a memory block plus some descriptors accessing the contents of the memory. Storing a Python object in the memory block does not store the object itself, instead the contents of the object is stored.
🌐
Python
python-list.python.narkive.com › pJK2bMLY › ctypes-delay-conversion-from-c-char-p-to-string
ctypes: delay conversion from c_char_p to string
Permalink I have a function exposed through ctypes that returns a c_char_p. Since I need to deallocate that c_char_p, it's inconvenient that ctypes copies the c_char_p into a string instead of giving me the raw pointer. I believe this will cause a memory leak, unless ctypes is smart enough to free the string itself after the copy...
🌐
dbader.org
dbader.org › blog › python-ctypes-tutorial
Extending Python With C Libraries and the “ctypes” Module – dbader.org
September 5, 2017 - The ctypes.POINTER objects are not overly useful, but they can be converted to objects which are useful. Once we convert our string to a ctypes.c_char, we can access it’s value attribute to get the bytes in Python.
🌐
Runebook
runebook.dev › english › articles › python
Python ctypes.c_wchar: Performance Optimization Tips
Representing Unicode Characters You can use ctypes.c_wchar to create Python objects that hold Unicode characters.