Преобразование массива строк C в массив строк Swift

Я не знаком со способом преобразования двумерного массива из C в массив строк, который я могу использовать в Swift. Насколько мне известно, в Swift нет быстрого и простого способа сделать это.

Это заголовок моей функции C:

char **getAllFilePaths(const char path []);

Я пробовал следующее:

//Get the pointer of the String array
if var ptr = getAllFilePaths(a) {

     //Check if the current String is null
     while let s = ptr.pointee {

        //Copy the String into an array
        a_paths.append(String(cString: s)) //<- Crash: Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

        //Go to the next adress
        ptr += 1
     }

    print(a_paths)
}

(У меня есть этот код от Martin R: https://stackoverflow.com/a/38422783/10269733. К сожалению, он больше не работает в Swift 4.2)

Я весь день ищу решение этой проблемы, поэтому открыт для любых творческих идей!

Обновлено:

Этот код отлично работает

char paths [FILES_MAX][PATH_MAX];
static size_t i = 0;

char **getAllFilePaths(const char path []){
    PrintFile(path);

    size_t j;

    for(j = 0; j < i; j++){
        printf("%s\n", paths[j]);
    }

    return paths;
}
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
0
220
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема не в коде Swift (и не в каких-либо изменениях Swift 4.2). Настоящая проблема в том, что функция C возвращает переменную «2-мерный массив».

char paths[FILES_MAX][PATH_MAX];

как char ** для вызывающего - но это несовместимые типы: один из них массив массивов (все символы находятся в непрерывной памяти), другой - указатель на указатель. Должно появиться предупреждение компилятора, например

incompatible pointer types returning 'char [...][...]' from a function with result type 'char **'

Вы мог возвращаете paths из функции, если вы объявляете что-то вроде

typedef char PathName[PATH_MAX];

PathName *getAllFilePaths(const char path []) { ... }

Но это будет импортировано в Swift как

typealias PathName = (Int8, Int8, ... , Int8)

public func getAllFilePaths(_ path: UnsafePointer<Int8>!) -> UnsafeMutablePointer<PathName>!

где PathName - это кортеж символов PATH_MAX - довольно громоздко использовать из Swift! Еще проблема в том, что звонящий не знает сколько элементов массива было заполнено.

Лучше определите paths как массив указателей char:

static char *paths[FILES_MAX] = { NULL };

и заполните его списком указателей char с завершающим нулем. Вот чрезмерно упрощенный пример:

char **getAllFilePaths(const char path []) {
    paths[0] = "foo";
    paths[1] = "bar";
    paths[2] = NULL;
    return paths;
}

В вашем реальном приложении вы не добавляете строку литералы, поэтому вы, вероятно, нужно дублировать строки

    paths[j] = strdup(someString);

это означает, что в какой-то момент строки должны быть снова free()d, чтобы избежать утечки памяти.

кредиты на "https://oleb.net/blog/2016/10/swift-array-of-c-strings/"

C:

int myCFunc(char *const argv[], size_t howmany )
{
    int i;
    for(i=0; i < howmany; i++){
        printf("\n%s", argv[i]);
    }
    return 1;
}

Помимо заголовков / мостов:

// Swift:

import Foundation

public func withArrayOfCStrings<R>(
    _ args: [String],
    _ body: ([UnsafeMutablePointer<CChar>?]) -> R
) -> R {
    var cStrings = args.map { strdup($0) }
    cStrings.append(nil)
    defer {
        cStrings.forEach { free($0) }
    }
    return body(cStrings)
}


func goLowlevel(arguments: [String]) -> Int {

    let count = arguments.count
    return withArrayOfCStrings(arguments) {
        argv in

        myCFunc(argv, count)
        return 10
    }
}


let arr = ["AA", "BBB", "CCCC"]
goLowlevel(arguments: arr)

Другие вопросы по теме