簡體   English   中英

將字符串數組從 python 傳遞到 C 並在 for 循環中使用(包括代碼)

[英]Passing string array from python to C and using in for loop (code included)

我試圖將兩個字符串數組從 python 傳遞到 C,在嵌套的 for 循環中使用它們,將它們與一個參數進行比較,如果兩個字符串滿足這個參數,我將它們附加到 C 中的一個新字符串數組中。該函數以我返回比較字符串的新數組結束。 這個函數是在 python 中使用 CDLL 調用的,這個新的字符串數組是我的 python 腳本。

#In Python:

PyOne = ["Apple", "Orange", "Banana"]
PyTwo = ["Cucumber", "Mango", "Pineapple", "Apple"]

我已將這些翻譯用於我的 C 函數,如下所示:

#In Python:

PyOne = ["Apple", "Orange", "Banana"]
PyOne_bytes = []
for i in range(len(PyOne)):
    PyOne_bytes.append(bytes(PyOne[i], 'utf-8'))
One_array = (ctypes.c_char_p * (len(PyOne_bytes)+1))()
One_array[:-1] = PyOne_bytes

PyTwo = ["Cucumber", "Mango", "Pineapple", "Apple"]
PyTwo_bytes = []
for i in range(len(PyTwo)):
    PyTwo_bytes(bytes(PyTwo[i], 'utf-8'))
Two_array = (ctypes.c_char_p * (len(PyTwo_bytes)+1))()
Two_array[:-1] = PyTwo_bytes

上面的代碼將現有的 Python 字符串數組轉換為 C 可以解釋的字符串數組。

這是我的 C 函數:

// In C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SCALING_FACTOR 0.1
#include <ctype.h>

...

char ** mainForLoop(const char ** PyOne, const char ** PyTwo) {
    char ** matches = malloc(100 * sizeof(char*));
    size_t i = 0;
    size_t j = 0;
    for (i = 0; i < sizeof(PyOne)/sizeof(PyOne[0]); i++) {
        for (j = 0; j < sizeof(PyTwo)/sizeof(PyTwo[0]); j++) {
            double v = comparison(PyOne[i], PyTwo[i]);
            if (v > 4) {
                strcat(matches, (PyOne[i]));
                strcat(matches, (";"));
            }
        }
    }
    return matches;
}

在 python 中,我然后打印函數的返回值,如下所示:

c.mainForLoop.argtypes = [POINTER(c_char_p), POINTER(c_char_p)]
c.mainForLoop.restype = ctypes.c_char_p

print(c.mainForLoop(One_array, Two_array))

例如,如果 compare("Apple", "Cucumber") = 5 (ie > 4), compare("Orange", "Mango") = 7 (ie > 4),以及其他所有 compare() < 4,那么我會期望,由於以下原因......

// In C
double v = comparison(PyOne[i], PyTwo[i]);
                if (v > 4) {
                    strcat(matches, (PyOne[i]));
                    strcat(matches, (";"));
                }

為了

#In Python
print(cDoc.mainForLoop(One_array, Two_array))

>>> b'Apple;Orange'

但目前,這會打印:

>>> b'Apple;'

我不知道我的代碼做錯了什么。 我對 C 有點陌生,我已經嘗試了我能想到的一切,任何幫助將不勝感激,解釋也將是王牌!

謝謝!

編輯:根據下面的答案,這是我的新代碼:

// In C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


void free_list(char** list, size_t size) {
    for(size_t i = 0; i < size; ++i) if (list[i]) free(list[i]);
    free(list);
}

char ** mainForLoop(const char ** PyOne, const char ** PyTwo, size_t sizeOne, size_t sizeTwo) {
    size_t i = 0;
    size_t j = 0;

    char ** matches = malloc(sizeOne * sizeof(char *));

    char temp[100] = {0};

    for (i = 0; i < sizeOne; i++) {
        // Cleared on each pass
        temp[0] = 0;
        for (j = 0; j < sizeTwo; j++) {
            double v = similarity(PyOne[i], PyTwo[j]);
            if (v > 4) {
                // Works with the temp buffer
                strcat(temp, (PyOne[i]));
                strcat(temp, (";"));
                int size = strlen(temp) + 1; //+1 for null termination

                char * str = malloc(size);
                memcpy(str, temp, size);
                str[size-1] = 0; //Null termination

                matches[i] = str;
            }
        }
    }
    return matches;
    free_list(matches, sizeOne);
}



#In Python
dll = CDLL("c.file")
dll.mainForLoop.argtypes = POINTER(c_char_p),POINTER(c_char_p),c_size_t,c_size_t
dll.mainForLoop.restype = POINTER(c_char_p)
dll.free_list.argtypes = POINTER(c_char_p),c_size_t
dll.free_list.restype = None

def make_clist(lst):
    return (c_char_p * len(lst))(*[x.encode() for x in lst])

def mainForLoop(list1,list2):
    size = c_size_t()
    result = dll.mainForLoop(make_clist(list1),make_clist(list2),len(list1),len(list2))
    data = [x.decode() for x in result[:size.value]]
    dll.free_list(result,size.value)
    return data

list1 = ["Apple", "Orange", "Banana"]
list2 = ["Apple", "Mango", "Pineapple", "Apple"]
print(mainForLoop(list1,list2))

但是,這將返回:

[]

請注意,C 中的“comparison()”函數是一個字符串距離計算,它通過比較兩個字符串返回一個雙精度值。

任何幫助將不勝感激。

這是一個比您的配置更接近的示例。 請注意,我的main功能只是用於運行示例,在您的情況下它將毫無用處。

主要的解決方法是我為每個新字符串分配了您沒有做的內存(您為指針分配了內存,而不是為字符串本身分配了內存)。 為此,我首先在堆棧上使用一個 100 個字符的臨時緩沖區(如果需要,您可以延長它),一旦知道字符串的長度,我就分配它(注意您准備釋放這些字符串和指針的函數) (free_list) 已經正確):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

double comparison(const char * one, const char * two) {
    int try = rand() % 12;
    return try;
}

char ** mainForLoop(char ** PyOne, char ** PyTwo, int sizeOne, int sizeTwo) {
    size_t i = 0;
    size_t j = 0;
    
    // Allocate an array of N string pointers where N is the size of PyOne
    char ** matches = malloc(sizeOne * sizeof(char *));
    // The temporary buffer
    char temp[100] = {0};
    
    for (i = 0; i < sizeOne; i++) {
        // Cleared on each pass
        temp[0] = 0;
        for (j = 0; j < sizeTwo; j++) {
            double v = comparison(PyOne[i], PyTwo[j]);
            if (v > 4) {
                // Works with the temp buffer
                strcat(temp, (PyOne[i]));
                strcat(temp, (";"));
                int size = strlen(temp) + 1; //+1 for null termination

                // Then allocates a string of the right size
                char * str = malloc(size);
                memcpy(str, temp, size);
                str[size-1] = 0; //Null termination

                // And collects it
                matches[i] = str;
            }
        }
    }
    return matches;
}


void free_list(char** list, size_t size) {
    for(size_t i = 0; i < size; ++i) if (list[i]) free(list[i]);
    free(list);
}


int main() {
    // Initializes random
    srand(time(0));
    int N = 3;
    char * PyOne[3] = {"Apple", "Orange", "Banana"};
    char * PyTwo[4] = {"Cucumber", "Mango", "Pineapple", "Apple"};
    
    char ** matches = mainForLoop(PyOne, PyTwo, N, 4);

    // Prints the result which is possibly (depending on random) :
    // "Apple; Orange; Banana;Banana;"

    for (char i=0; i<N; i++) printf("%s ", matches[i]);
    printf("\n");

    // Frees
    free_list(matches, N);
    return 0; 
}

提供的 C 代碼不正確,因此這里是演示如何傳遞和返回字節數組的演示。 此示例只是將兩個列表附加在一起。 它還處理釋放內存,因此 C 中的內存分配不會導致內存泄漏。

測試.c:

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

#include <stdlib.h>
#include <string.h>

API char** append_lists(const char** list1, size_t size1, const char** list2, size_t size2, size_t* pSize) {
    char** total = malloc((size1 + size2) * sizeof(char*));
    for(size_t i = 0; i < size1; ++i)
        total[i] = _strdup(list1[i]);
    for(size_t i = 0; i < size2; ++i)
        total[size1 + i] = _strdup(list2[i]);
    *pSize = size1 + size2;
    return total;
}

API void free_list(char** list, size_t size) {
    for(size_t i = 0; i < size; ++i)
        free(list[i]);
    free(list);
}

測試.py:

from ctypes import *

dll = CDLL('./test')
dll.append_lists.argtypes = POINTER(c_char_p),c_size_t,POINTER(c_char_p),c_size_t,POINTER(c_size_t)
dll.append_lists.restype = POINTER(c_char_p)
dll.free_list.argtypes = POINTER(c_char_p),c_size_t
dll.free_list.restype = None

# Helper function to turn Python list of Unicode strings
# into a ctypes array of byte strings.
def make_clist(lst):
    return (c_char_p * len(lst))(*[x.encode() for x in lst])

# Helper function to convert the lists, make the call correctly,
# convert the return result back into a Python list of Unicode strings,
# and free the C allocations.
def append_lists(list1,list2):
    size = c_size_t()
    result = dll.append_lists(make_clist(list1),len(list1),make_clist(list2),len(list2),byref(size))
    data = [x.decode() for x in result[:size.value]]
    dll.free_list(result,size.value)
    return data

list1 = ["Apple", "Orange", "Banana"]
list2 = ["Cucumber", "Mango", "Pineapple", "Apple"]
print(append_lists(list1,list2))

輸出:

['Apple', 'Orange', 'Banana', 'Cucumber', 'Mango', 'Pineapple', 'Apple']

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM