Python中的Ctypes 2d字符串数组在同一内存地址存储不同的字符串

ntjbwcob  于 2023-11-15  发布在  Python
关注(0)|答案(1)|浏览(113)

我的python代码很简单:

from ctypes import *
from random import randint

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

#initializing the array of strings
x = ((c_char_p * 3) * 10) ()
for i in range(10):
    for j in range(3):
        x[i][j] = str(randint(100, 999)).encode('utf-8')

#it prints what i expect it to print
for i in range(10):
    for j in range(3):
        print(x[i][j], end = ' ')
    print()
    
print("addresses")
for i in range(10):
    for j in range(3):
        t = uni()
        # getting an integer that points to the string to print string's address
        t.p = x[i][j] 
        print(hex(t.a), end = ' - ')
        print(string_at(t.a), end = ' | ')
    print()

字符串
这将输出以下内容:

b'475' b'912' b'805' 
b'107' b'986' b'191' 
b'389' b'525' b'921' 
b'441' b'869' b'452' 
b'505' b'788' b'571' 
b'111' b'974' b'758' 
b'447' b'975' b'671' 
b'322' b'633' b'332' 
b'924' b'633' b'174' 
b'677' b'611' b'431' 
addresses
0x7fdfbbbcad80 - b'475' | 0x7fdfbbbcad80 - b'912' | 0x7fdfbbbcad80 - b'805' | 
0x7fdfbbbcad80 - b'107' | 0x7fdfbbbcad80 - b'986' | 0x7fdfbbbcad80 - b'191' | 
0x7fdfbbbcad80 - b'389' | 0x7fdfbbbcad80 - b'525' | 0x7fdfbbbcad80 - b'921' | 
0x7fdfbbbcad80 - b'441' | 0x7fdfbbbcad80 - b'869' | 0x7fdfbbbcad80 - b'452' | 
0x7fdfbbbcad80 - b'505' | 0x7fdfbbbcad80 - b'788' | 0x7fdfbbbcad80 - b'571' | 
0x7fdfbbbcad80 - b'111' | 0x7fdfbbbcad80 - b'974' | 0x7fdfbbbcad80 - b'758' | 
0x7fdfbbbcad80 - b'447' | 0x7fdfbbbcad80 - b'975' | 0x7fdfbbbcad80 - b'671' | 
0x7fdfbbbcad80 - b'322' | 0x7fdfbbbcad80 - b'633' | 0x7fdfbbbcad80 - b'332' | 
0x7fdfbbbcad80 - b'924' | 0x7fdfbbbcad80 - b'633' | 0x7fdfbbbcad80 - b'174' | 
0x7fdfbbbcad80 - b'677' | 0x7fdfbbbcad80 - b'611' | 0x7fdfbbbcad80 - b'431' |


如何在同一地址存储不同的字符串?
注意:我在调试一个程序时发现了这个问题,该程序将一个2d字符串数组传递给C共享对象。C函数定义如下:

extern "C" 
void print2d(char*** arr, int len, int inner_len)
{
  std::cout << arr << '\n';   //ok
  std::cout.flush(); 
  std::cout << *arr << '\n';  //ok
  std::cout.flush();
  std::cout << **arr << '\n'; //this segfaults
}


如果任何人有任何建议来解决这个问题,我很乐意听他们说出来。

ubbxdtey

ubbxdtey1#

为每个字符串分配唯一的内存地址,并将它们与它们的值一起沿着打印出来。

#include <iostream>
#include <cstring>

extern "C" {
    void print2d(char*** arr, int rows, int cols) {
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                std::cout << arr[i][j] << " ";
            }
            std::cout << std::endl;
        }
    }
}

字符串
假设你的c代码是print2d.cpp,确保你的python脚本和print2.cdd在同一个路径或目录下,然后将这个C代码编译到Ubuntu上的共享库中,使用带有-shared和-fPIC标志的g++

g++ -fPIC -shared -o libprint2d.so print2d.cpp


g++将创建一个名为libprint2d.so的共享库。

from ctypes import *
from random import randint

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

# Function to manually allocate memory for a string
def allocate_string(s):
    size = len(s) + 1  # Add 1 for the null terminator
    buffer = create_string_buffer(size)
    buffer.raw = s + b'\x00'  # Add null terminator explicitly
    return buffer

# Initializing the array of strings
buffers = []  # Store references to buffers
x = ((POINTER(c_char) * 3) * 10)()
for i in range(10):
    for j in range(3):
        random_string = str(randint(100, 999)).encode('utf-8')
        buffer = allocate_string(random_string)
        buffers.append(buffer)  # Keep a reference to the buffer
        x[i][j] = cast(buffer, POINTER(c_char))  # Store the pointer to the buffer

# Print the strings and their addresses
for i in range(10):
    for j in range(3):
        t = uni()
        t.p = cast(x[i][j], c_char_p)  # Cast the pointer to c_char_p
        print(hex(t.a), end=' - ')
        print(string_at(t.a), end=' | ')
    print()
# Load the shared library
lib = CDLL('./libprint2d.so')

# Define the argument and return types of the print2d function
lib.print2d.argtypes = [POINTER(POINTER(POINTER(c_char))), c_int, c_int]
lib.print2d.restype = None

# Convert the 2D array x to the required type for the C++ function
array_type = POINTER(POINTER(c_char)) * 10
array = array_type(*[cast(row, POINTER(POINTER(c_char))) for row in x])

# Call the C++ function
lib.print2d(array, 10, 3)


你应该得到类似于下面的输出
0x7fe3bae66290 - b'640'|0x7fe3bae66390 - b'626'| 0x7fe3bae66410 - b'582'|
0x7fe3bae66490 - b'732'|0x7fe3bae66510 - b'184'| 0x7fe3bae66590 - b'305'|
0x7fe3bae66610 - b'503'|0x7fe3bae66690 - b'441'| 0x7fe3bae66710 - b'791'|
0x7fe3bae66810 - b'292'|0x7fe3bae66890 - b'133'| 0x7fe3bae66910 - b'541'|
0x7fe3bae66990 - b'624'|0x7fe3bae66a10 - b'973'| 0x7fe3bae66a90 - b'817'|
0x7fe3bae66b10 - b'322'|0x7fe3bae66b90 - b'314'| 0x7fe3bae66790 - b'630'|
0x7fe3bae66c10 - b'834'|0x7fe3bae66c90 - b'458'| 0x7fe3bae66d10 - b'489'|
0x7fe3bae66d90 - b'277'|0x7fe3bae66e10 - b'362'| 0x7fe3bae66e90 - b'313'|
0x7fe3bae66f10 - b'534'|0x7fe3bae66f90 - b'131'| 0x7fe3bae66210 - b'366'|
0x7fe3bae75110 - b'960'|0x7fe3bae75190 - b'594'| 0x7fe3bae75210 - b'110'|
640 626 582
732 184 305
503 441 791
292 133 541
624 973 817
322 314 630
834 458 489
277 362 313
534 131 366
960 594 110

相关问题