You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中ctypes二维字符串数组内存异常及C++调用段错误求助

问题分析与解决方案

1. 不同字符串显示同一内存地址的原因

你看到所有字符串指向同一地址,核心原因是ctypes的临时缓冲区复用机制:

当直接将Python的bytes对象赋值给c_char_p类型变量时,ctypes不会为每个字符串分配独立的持久化C内存,而是使用一个内部临时缓冲区。每次赋值都会覆盖这个缓冲区的内容,因此所有x[i][j]存储的指针都指向这个相同的临时缓冲区。

虽然打印x[i][j]时能得到正确结果(ctypes会实时从缓冲区读取内容返回给Python),但这些指针本质上指向同一块内存,自然地址完全相同。

修复方法

要为每个字符串分配独立的C内存,需使用create_string_buffer显式创建持久化的C字符串:

from ctypes import *
from random import randint

class uni(Union):
    _fields_ = [('p', c_char_p),
                ('a', c_longlong)]

# 初始化二维字符串数组,为每个字符串分配独立内存
x = ((c_char_p * 3) * 10)()
for i in range(10):
    for j in range(3):
        s = str(randint(100, 999)).encode('utf-8')
        # 显式创建C风格字符串,分配独立内存
        x[i][j] = create_string_buffer(s)

# 打印字符串
for i in range(10):
    for j in range(3):
        print(x[i][j].value, end=' ')
    print()

# 打印地址与对应内容
print("addresses")
for i in range(10):
    for j in range(3):
        t = uni()
        t.p = x[i][j]
        print(hex(t.a), end=' - ')
        print(string_at(t.a), end=' | ')
    print()

修改后每个字符串都会有独立的内存地址,输出的地址会各不相同。

2. C++调用时**arr触发段错误的解决建议

段错误的根源和上述问题直接相关:你的Python代码中,x数组里的指针指向的是ctypes的临时缓冲区,当传递给C共享对象时,这些临时内存可能已被Python垃圾回收机制释放,或者本身就是复用的无效地址,导致C程序访问非法内存。

解决步骤

  1. 为字符串分配持久化C内存:按照上面的修复方法,用create_string_buffer为每个字符串创建独立的持久化C内存,确保传递到C++时内存仍然有效。

  2. 显式匹配ctypes与C++的参数类型:
    在Python中调用C++函数时,需显式指定函数的参数类型,避免类型不匹配导致的错误:

    # 加载共享对象
    lib = CDLL('./your_shared_lib.so')
    # 指定函数参数类型
    lib.print2d.argtypes = [POINTER(POINTER(POINTER(c_char))), c_int, c_int]
    # 传递数组
    lib.print2d(x, 10, 3)
    
  3. 保留Python端内存引用:
    确保在C函数执行期间,Python端的x数组和所有create_string_buffer创建的对象都不会被垃圾回收,不要在调用C函数前丢弃这些变量的引用。

补充说明

如果C函数需要长期持有这些字符串指针(比如函数返回后还要访问),需在C中显式复制字符串内容,而非直接保存指针——因为Python的内存管理可能在后续回收这些内存。


内容的提问来源于stack exchange,提问作者God I Am Clown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:57:03