Thanks to @ErykSun the solution:

Python code

string1 = "my string 1"
string2 = "my string 2"

# create byte objects from the strings
b_string1 = string1.encode('utf-8')
b_string2 = string2.encode('utf-8')

# send strings to c function
my_c_function.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
my_c_function(b_string1, b_string2)
Answer from MorphieBlossom on Stack Overflow
🌐
ProgramCreek
programcreek.com › python › example › 1243 › ctypes.c_char_p
Python Examples of ctypes.c_char_p
def c_str(string): """Create ctypes char * from a Python string. Parameters ---------- string : string type Python string. Returns ------- str : c_char_p A char pointer that can be passed to C API.
🌐
Python.org
discuss.python.org › python help
Which string type is faster for ctypes - Python Help - Discussions on Python.org
February 1, 2024 - Hi all, I am writing a gui library for python in Odin. Odin is a C like language with manual memory management. I tested some string functions. b"Python string" is working with c_char_p and "Python wide string" is worki…
🌐
Intel Community
community.intel.com › t5 › Intel-Fortran-Compiler › Passing-by-reference-a-Python-string-to-Fortran-function › m-p › 1297543 › highlight › true
Re: Passing (by reference) a Python string to Fortran function (subroutine) - Intel Community
July 11, 2021 - The c_char_p object will stay around as long as there is at least one reference to it (the in_ptr name being such a reference), and the byte string object will similarly stay around as long as there is at least one reference to it. As a result of the call to create_string_buffer, Python creates an "managing" object that in turn allocates 11 bytes of arbitrary memory (length of the Hello World byte string - but this will be used to get the output from the Fortran code), and binds a reference to that managing object to the name out_ptr.
🌐
Runebook.dev
runebook.dev › en › docs › python › library › ctypes › ctypes.c_char_p
Working with C Strings in Python: Tips for ctypes.c_char_p
October 23, 2025 - Before passing a Python str to a C function via c_char_p, you must encode it into a bytes object, usually using a standard encoding like UTF-8 or ASCII. import ctypes # 1. Python string (str) python_str = "Hello ctypes!"
Top answer
1 of 2
17
from ctypes import *

charptr = POINTER(c_char)

test = CDLL('test.so')
test.initializetest.argtypes = []
test.initializetest.restype = charptr
test.searchtest.argtypes = [charptr]
test.searchtest.restype = c_int

buf = test.initializetest()
test.searchtest(buf)
print cast(buf, c_char_p).value
# TODO Release the "buf" memory or it will leak.

EDIT

Initially I used c_char_p to pass the buffer between the functions but c_char_p is like a const pointer. If used as a restype, you will actually get a Python str back. So for initializetest it will create a string from the allocated memory (by copying data) and throw the pointer away.

Now we're creating a new type, a POINTER to c_char. This is then used in both functions.

For Python, this type points to a single char so we have to cast it to get the whole string after searchtest is done. We cast to c_char_p because we just want to read the value so a const pointer is OK.

As a side note, this illustrates the disastrous effect of using c_char_p with functions that modify the array (as searchtest above does):

>>> libc.memset.argtypes = [c_char_p, c_int, c_int]
>>> foo = 'Python'
>>> foo
'Python'
>>> libc.memset(foo, ord('x'), 3)
44808532
>>> foo
'xxxhon'
>>>

Note how we've managed to change an immutable Python string!

The argtypes setup line isn't even needed because ctypes assumes c_char_p if Python str is used as argument.

2 of 2
1

Maybe by using restype like described here

class Test(object):
    def __init__(self):
        self.test_library=CDLL("./test.so")
        self.test_initialize = self.test_library.initializetest
        self.test_initialize.argtypes = []
        self.test_initialize.restype = c_char_p # c_char_p is a pointer to a string
        self.test_search = self.test_library.searchtest
        self.test_search.restype = c_int
        self.test_search.argtypes = [c_char_p]
        self.m = c_char_p(self.test_initialize())

    def search(self):
        return self.test_search(self.m).value

r = Test()
print r.search()

EDIT: corrected after test :)

🌐
CodersLegacy
coderslegacy.com › home › python › python ctypes tutorial
Python ctypes Tutorial - CodersLegacy
October 27, 2022 - Before: c_char_p(2200599049040) b'Hello' After: c_char_p(2200599049040) b'Ifmmp' As you can see, the string was properly modified. Creating a string buffer with ctypes, gives us mutable memory which we can use with C functions. You can also choose to pass in an integer “n” instead of a string into the create_string_buffer() function which will create an empty string buffer of “n” size. If you have turned to ctypes in the hope of speeding up your Python code, by writing some of it in C/C++, there is another option to consider.
Find elsewhere
🌐
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
I believe this will cause a memory leak, unless ctypes is smart enough to free the string itself after the copy... which I doubt. Is there some way to tell ctypes to return an actual c_char_p, or is my best bet to return a c_void_p and cast to c_char_p when I'm reading to convert to a string? Thanks Brendan -- http://mail.python.org/mailman/listinfo/python-list
🌐
Runebook
runebook.dev › english › articles › python
Mastering ctypes.c_char_p in Python: Examples and Best Practices
Conversion from Python String You can create a ctypes.c_char_p object from a Python string. ctypes will handle the conversion to a null-terminated byte string (often using UTF-8 encoding by default, but this can be controlled).
🌐
GitHub
gist.github.com › helinwang › 4f287a52efa4ab75424c01c65d77d939
Call go (or c) code from python with string as argument and string as return value · GitHub
import ctypes lib = ctypes.cdll.LoadLibrary('./liba.so') lib.concat.restype = ctypes.c_char_p print(lib.concat("apple", "orange")) ... Can you help me with this? https://stackoverflow.com/questions/65248236/call-go-string-return-function-from-python ... @wangkuiyi you must call encode("utf-8") with the string being passed from Python as it will convert it into bytes · So print(lib.concat("apple", "orange")) will be changed to print(lib.concat("apple".encode("utf-8"), "orange".encode("utf-8")))
🌐
Google Groups
groups.google.com › g › python-cffi › c › Y5wXOJPsfFk
Re: [pypy-dev] How to convert python string to C char*?
May 14, 2015 - The following would work in all cases but leak the strings by never releasing them: ALL_RESULTS = [] @ffi.callback("char *(char *, char *)") def strconcat(x, y): x1 = ffi.string(x) y1 = ffi.string(y) print x1 + y1 p = ffi.new("char[]", x1 + y1) ALL_RESULTS.append(p) return p There are chances that it works as expected if you only keep alive the last returned result; try it out, but no guarantee. A bientôt, Armin. ... Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message · to pytho...@googlegroups.com, ar...@tunes.org, pypy...@python.org
🌐
Runebook.dev
runebook.dev › en › docs › python › library › ctypes › ctypes.c_char
Mastering c_char, c_char_p, and create_string_buffer in Python ctypes
October 20, 2025 - Friendly Tip Always remember the b! Without it, Python gives you a Unicode string, which ctypes might try to convert to c_wchar_p or just fail, especially in Python 3. When you need a writable memory block—either to pass a string that the C function will modify, or to pass a buffer for the C function to write its output into—you should use ctypes.create_string_buffer(). This creates a mutable array of c_char.
🌐
Numba Discussion
numba.discourse.group › community support
Accelerate loops that use ctypes, c_char_p, numpy str_? - Community Support - Numba Discussion
June 13, 2020 - I wrote a python library that wraps a c shared-library with over 600 functions using pure ctypes and numpy. The functions are typically simple, say given a string return a float, and for some functions I allow users to p…
🌐
Intel Community
community.intel.com › t5 › Intel-Fortran-Compiler › Passing-by-reference-a-Python-string-to-Fortran-function › m-p › 1297350
Passing (by reference) a Python string to Fortran function (subroutine) - Intel Community
July 11, 2021 - The c_char_p object will stay around as long as there is at least one reference to it (the in_ptr name being such a reference), and the byte string object will similarly stay around as long as there is at least one reference to it. As a result of the call to create_string_buffer, Python creates an "managing" object that in turn allocates 11 bytes of arbitrary memory (length of the Hello World byte string - but this will be used to get the output from the Fortran code), and binds a reference to that managing object to the name out_ptr.
🌐
Cython
cython.readthedocs.io › en › latest › src › tutorial › strings.html
Unicode and passing strings — Cython 3.3.0 documentation
Cython compilation enables this, but there is no support for this from plain Python. Trying to run this code from Python (without compilation) will fail when accessing the external library. This is described in more detail in Calling C functions. ... from libc.stdlib cimport malloc from libc.string cimport strcpy, strlen cdef char* hello_world = 'hello world' cdef size_t n = strlen(hello_world) cdef char* c_call_returning_a_c_string(): cdef char* c_string = <char *> malloc( (n + 1) * sizeof(char)) if not c_string: return NULL # malloc failed strcpy(c_string, hello_world) return c_string cdef int get_a_c_string(char** c_string_ptr, Py_ssize_t *length): c_string_ptr[0] = <char *> malloc( (n + 1) * sizeof(char)) if not c_string_ptr[0]: return -1 # malloc failed strcpy(c_string_ptr[0], hello_world) length[0] = n return 0
🌐
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 ... 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 ...