# Dealing with char\*\*\* in ctypes

**URL:** <https://discuss.python.org/t/dealing-with-char-in-ctypes/41044>\
**Category:** Python Help\
**Tags:** help\
**Created:** [December 13, 2023, 7:47pm UTC](https://discuss.python.org/t/dealing-with-char-in-ctypes/41044 "2023-12-13T19:47:21Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![hinxx](https://avatars.discourse-cdn.com/v4/letter/h/2bfe46/32.png) [@hinxx](https://discuss.python.org/u/hinxx)\
**Post date:** [December 13, 2023, 7:47pm UTC](https://discuss.python.org/t/dealing-with-char-in-ctypes/41044/1 "2023-12-13T19:47:22Z")

</div>

I have this function in C library that I want to access from python using ctypes:

```auto
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:

```auto
    const char **items;
    unsigned nr_items;
    result = test_char_ptr(&items, &nr_items);
    for (unsigned i = 0; i < nr_items; i++) {
        printf("string[%d]: %s\n", i, items[i]);
    }

```

In python I’m doing the following so far:

```auto
    names_ = C.POINTER(C.POINTER(C.c_char))()
    count_ = C.c_int(123456789) # WORKS!

    pydemolib.test_char_ptr(names_, count_)
    print("count: %d" % count_.value)
    print("names: %s" % names_)
    print("names.contents: %s" % names_.contents)
    print("names.contents.contents: %s" % names_.contents.contents)
    print("names.contents.contents.value: %s" % names_.contents.contents.value)

----
count: 4
names: <pydemolib.LP_LP_c_char object at 0x7f0dd6ed7ac0>
names.contents: <ctypes.LP_c_char object at 0x7f0dd6c9f5c0>
names.contents.contents: c_char(b'B')
names.contents.contents.value: b'B'
names.contents.contents bytes: b'B'

```

How can I access the array of null terminated C strings in names\_ at this point? It would be great if I could convert them to a list.

---

<div class="post-metadata">

**Author:** ![kknechtel](https://avatars.discourse-cdn.com/v4/letter/k/e47c2d/32.png) [@kknechtel](https://discuss.python.org/u/kknechtel)\
**Post date:** [December 13, 2023, 7:58pm UTC](https://discuss.python.org/t/dealing-with-char-in-ctypes/41044/2 "2023-12-13T19:58:17Z")

</div>

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 implement a `*` operator to give you array types. C allows arrays to decay to pointers implicitly all over the place, but Python is more _strongly_ typed despite the _dynamic_ typing - it maintains a strong distinction. So `C.POINTER(C.c_char)` doesn’t have access to any `char` values after the one directly pointed at; and it also doesn’t care if that `char` has a zero value.

To deal with the special case of C’s null-terminated strings, a separate `c_char_p` type is provided. (See also the [full table of types](https://docs.python.org/3/library/ctypes.html#fundamental-data-types)).

You are actually _really_ dealing with `char **`, not `char*** ` in your `ctypes` code - in the C code, the third `*` is only being used in order to simulate pass-by-reference. (You’ll also want to check out the [section on `byref`](https://docs.python.org/3/library/ctypes.html#passing-pointers-or-passing-parameters-by-reference).) But what you really have is an array of `count_` many “strings” (null-terminated C strings). That should look like `c_char_p * count_` if I’m thinking clearly. (You might need to redesign the interface so that you get the count information separately, before the string data.)

---

<div class="post-metadata">

**Author:** ![hinxx](https://avatars.discourse-cdn.com/v4/letter/h/2bfe46/32.png) [@hinxx](https://discuss.python.org/u/hinxx)\
**Post date:** [December 13, 2023, 8:19pm UTC](https://discuss.python.org/t/dealing-with-char-in-ctypes/41044/3 "2023-12-13T20:19:23Z")

</div>

For the sake of testing I’ve hardcoded the `count_` in python to 4 and changed the signature as well as argument as follows:

```auto
test_char_ptr.argtypes = [POINTER(POINTER(c_char_p * 4)), POINTER(c_int)]

names_ = C.POINTER(C.c_char_p * 4)()
count_ = C.c_int(123456789) # WORKS!

pydemolib.test_char_ptr(names_, count_)
print("count: %d" % count_.value)
print("names: %s" % names_)
print("names.contents: %s" % names_.contents)
for name in names_.contents:
    print(name)

```

Results in this:

```auto
count: 4
names: <pydemolib.LP_c_char_p_Array_4 object at 0x7f31086f7ac0>
names.contents: <pydemolib.c_char_p_Array_4 object at 0x7f31084c35c0>
b'Backplane'
b'ADC'
b'External'
b'Reserved'

```

Seems to be exactly was I was looking for!

Thanks!

---

<div class="post-metadata">

**Author:** ![hinxx](https://avatars.discourse-cdn.com/v4/letter/h/2bfe46/32.png) [@hinxx](https://discuss.python.org/u/hinxx)\
**Post date:** [December 13, 2023, 8:43pm UTC](https://discuss.python.org/t/dealing-with-char-in-ctypes/41044/4 "2023-12-13T20:43:12Z")

</div>

Since I can not change the API of the real shared object (this C code was a test code), I think I can get away with changing the signature of the ctypes function.  
First it expects just one `c_char_p` value and after the call the `count_` will be valid. Then I change the signature to expect `count_ * c_char_p` values and make a second call. This time I get all the C strings out.

```auto

pydemolib.test_char_ptr.restype = C.c_int
pydemolib.test_char_ptr.argtypes = [C.POINTER(C.POINTER(C.c_char_p)), C.POINTER(C.c_int)]
names_ = C.POINTER(C.c_char_p)()
count_ = C.c_int(123456789)
pydemolib.test_char_ptr(names_, count_)
print("count: %d" % count_.value)

pydemolib.test_char_ptr.argtypes = [C.POINTER(C.POINTER(C.c_char_p * count_.value)), C.POINTER(C.c_int)]
pydemolib.test_char_ptr.restype = C.c_int
names_ = C.POINTER(C.c_char_p * count_.value)()
count_ = C.c_int(123456789)

pydemolib.test_char_ptr(names_, count_)
# print("count: %d" % count_.value)
print("names: %s" % names_)
print("names.contents: %s" % names_.contents)
for name in names_.contents:
    print(name)

```

Output:

```auto
count: 4
names: < __main__.LP_c_char_p_Array_4 object at 0x7ff8edea35c0>
names.contents: < __main__.c_char_p_Array_4 object at 0x7ff8ee000540>
b'Backplane'
b'ADC'
b'External'
b'Reserved'

```
