Как я могу объявить и распаковать массив пар пустых указателей? - PullRequest
1 голос
/ 13 апреля 2020

Я хотел бы написать функцию, которая принимает массив из void* "пар" - каждый из них является парой указателей на что-то. Первый элемент в каждой паре будет строкой, а второй будет указателем на что-то еще.

Я бы хотел, чтобы передаваемый в функцию массив был объявлен так:

<what type?> argument = {
        { "some string", <some pointer>},
        { "some other string", <some other pointer>},
        // ... etc
        NULL // To signal ending
}

function(argument);

Внутри function, я бы хотел перебрать массив, получить доступ к каждой «паре», привести членов «пары» к их соответствующим типам (известным мне) и использовать эти члены.

У меня проблемы с этим. Сначала я попытался объявить аргумент void* thing[][]. Думая, что это массив массивов void указателей.

Однако простая попытка доступа к индексу в таком массиве дает мне ошибку: expression must be a pointer to a complete object type.

Чтение на SO я понял компилятор думает, что я пытаюсь разыменовать void*. Но я думал, что выполнение a[0] для такого массива приведет к доступу к первой «паре» в массиве, которая должна разыменовывать void** - что является законным. Я не прав?

Каков правильный подход к go по этому поводу с точки зрения типа массива, его инициализации и способа распаковки массива во время итерации?

1 Ответ

3 голосов
/ 13 апреля 2020

Вы хотите void *argument[][2] = { /* ... */ };. У вас есть массив неопределенного размера, элементами которого являются массивы фиксированного размера 2, а элементами являются указатели на void. Ваша первоначальная ошибка компилятора состояла в том, что когда у вас есть несколько квадратных скобок, только первый набор из них может быть пустым, поэтому добавление 2 исправило его.

Кстати, он может затухать как указатель, в в этом случае это будет void *(*argument)[2].

Обратите внимание, что ваш дозорный NULL не делает то, что вы ожидаете, поскольку он находится в массиве массивов, а массивы не совсем указатели. Обратите внимание на это предупреждение:

warning: suggest braces around initialization of subobject [-Wmissing-braces]
        NULL // To signal ending
        ^~~~
        {   }

Вот пример программы, которая использует тип:

#include <stdio.h>

void *g[][2] = {
        { "some string", (void*)0x1234},
        { "some other string", (void*)0x5678},
        { "some third string", (void*)0x9abc},
        // ... etc
        {NULL} // To signal ending
};


void print_things(void *argument[][2]) {
    for(int i = 0; argument[i][0] /* using just argument[i] instead of argument[i][0] here would not work as intended */; ++i) {
        printf("%s %p\n", (char*)argument[i][0], argument[i][1]);
    }
}

int main(void) {
    print_things(g);
    return 0;
}

В качестве заключительного замечания я бы сказал, что ваша жизнь, вероятно, будет проще с пользовательским struct:

#include <stdio.h>

struct pair {
    char *str;
    void *ptr;
} g[] = {
        { "some string", (void*)0x1234},
        { "some other string", (void*)0x5678},
        { "some third string", (void*)0x9abc},
        // ... etc
        {NULL, NULL} // To signal ending
};


void print_things(struct pair argument[]) {
    for(int i = 0; argument[i].str; ++i) {
        printf("%s %p\n", argument[i].str, argument[i].ptr);
    }
}

int main(void) {
    print_things(g);
    return 0;
}
...