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
🌐
Python
docs.python.org › 3 › library › ctypes.html
ctypes — A foreign function library for Python
None is passed as a C NULL pointer, bytes objects and strings are passed as pointer to the memory block that contains their data (char* or wchar_t*). Python integers are passed as the platform’s default C int type, their value is masked to fit into the C type. Before we move on calling functions with other parameter types, we have to learn more about ctypes data types.
🌐
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
🌐
Cppreference
en.cppreference.com › w › cpp › locale › ctype_char.html
std::ctype<char> - cppreference.com
November 20, 2024 - The base class std::ctype<char> implements character classification equivalent to the minimal "C" locale. The classification rules can be extended or modified if constructed with a non-default classification table argument, if constructed as std::ctype_byname<char> or as a user-defined derived ...
🌐
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.
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.char.chararray.ctypes.html
numpy.char.chararray.ctypes — NumPy v2.4 Manual
char.chararray.ctypes# An object to simplify the interaction of the array with the ctypes module. This attribute creates an object that makes it easier to use arrays when calling shared libraries with the ctypes module. The returned object has, among others, data, shape, and strides attributes ...
🌐
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.
🌐
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.
🌐
LinkedIn
linkedin.com › pulse › calling-c-from-python-using-ctypes-warren-jitsing
Calling C from Python Using Ctypes
August 27, 2021 - We create mutable character buffers using the ctypes.create_string_buffer. This takes an initial bytes object and length of the buffer, or just a length argument.
Find elsewhere
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.

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);
🌐
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
Note that tmp_char_ptr is of type c_void_p. This should avoid the memory leak, assuming I am interpreting the semantics of the cast correctly. Is there a cleaner way to do this with ctypes? def get_prop_string(self, prop_name): # Have to work with c_void_p to prevent ctypes from copying to a string # without giving me an opportunity to destroy the original 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.
🌐
Runebook
runebook.dev › english › articles › python
Mastering ctypes.c_char_p in Python: Examples and Best Practices
When you're calling a C function that expects a string argument (a char*), you can't directly pass a Python string. Python strings are Unicode, and they're handled differently in memory. ctypes.c_char_p acts as a bridge.
🌐
Chapel-lang
chapel-lang.org › docs › modules › standard › CTypes.html
CTypes — Chapel Documentation 2.9
A c_ptrConst(c_char) that points to the underlying buffer used by this string.
🌐
dbader.org
dbader.org › blog › python-ctypes-tutorial
Extending Python With C Libraries and the “ctypes” Module – dbader.org
September 5, 2017 - We need to convert the original string to bytes using str.encode, and then pass this to the constructor for a ctypes.string_buffer. String_buffers are mutable, and they are passed to C as a char * as you would expect.
🌐
Microsoft Learn
learn.microsoft.com › en-us › cpp › standard-library › ctype-class
ctype Class | Microsoft Learn
June 19, 2025 - CharType The type used within a program to encode characters. As with any locale facet, the static object ID has an initial stored value of zero. The first attempt to access its stored value stores a unique positive value in id.
🌐
Behaviour
behaviour.space › posts › 2021-03-28-ctypes-weird-and-inconvenient-typing.html
The weird and inconvenient typing of Python's ctypes library
March 28, 2021 - In the first graph we’ll use the code from above. Pythas is designed with this issue in mind. It doesn’t actually hand over char-pointers but char-pointer-pointers! Hence, ctypes doesn’t automatically convert the string and we can dereference the pointer after conversion.