Инициализация вложенных массивов? - PullRequest
0 голосов
/ 07 октября 2018

Я хочу преобразовать этот код Python:

outsides = [
    {   'baz': 7,
        'foobar': [   {'bar': 2, 'foo': 1},
                      {'bar': 4, 'foo': 3},
                      {'bar': 6, 'foo': 5}]},
    {'baz': 8}]

в C. Я до сих пор придумал этот код:

#include <stdio.h>

struct Inside {
    int foo;
    int bar;
};

struct Outside {
    int baz;
    const struct Inside* foobar;
};

const struct Inside insides[] = {
    { .foo = 1, .bar = 2 },
    { .foo = 3, .bar = 4 },
    { .foo = 5, .bar = 6 },
};

const struct Outside outsides[] = {
    { .baz = 7, .foobar = insides },
    { .baz = 8, .foobar = NULL },
};

int main(int argc, char *argv[])
{
    printf("outsides: %i\n", sizeof(outsides) / sizeof(Outside));
    printf("insides: %i\n", sizeof(outsides[0].foobar));
    return 0;
}

Но есть две проблемы:

  1. Как встроить внутреннюю декларацию в внешнюю декларацию?
  2. Как определить количество внутренних элементов члена foobar?

Для вопроса 2Я мог бы реализовать некоторые обходные пути, такие как инициализация последнего элемента со всеми 0, а затем цикл по нему и тестирование для всех 0, или добавление дополнительного члена count в структуре Outside, но это выглядит неправильно.Было бы идеально, если бы была другая косвенность: если элемент foobar является массивом указателей на элементы Inside, то я мог бы просто добавить нулевой указатель в конце.

Примечание: это упрощенный примеркоторый демонстрирует два основных вопроса, которые у меня есть, но я не могу использовать элемент гибкого массива, потому что в структуре Outside имеется более одного элемента гибкого массива.И, конечно же, число объектов члена foobar может варьироваться.И мне нужно решение, которое работает с C, а не C ++.

1 Ответ

0 голосов
/ 07 октября 2018

Чтобы ответить на вопрос 1, поскольку у вас есть назначенные инициализаторы, у вас также есть составные литералы .Однако, чтобы ответить на вопрос 2, вы должны сообщить своему коду, сколько записей в массиве указано указателем.C не будет записывать информацию для вас.Вы можете использовать значение часового или явно записать счет.В любом случае, вы должны это сделать.Си не делает ничего за кадром для вас.И хотя вы можете вкладывать определение struct Inside в struct Outside, в C ++ нет такой области действия, которая бы помешала вам использовать struct Inside независимо от struct Outside, так что нет никакой пользы от этого - и я бы сохранил структуруопределения разделены, как у вас есть.

Итак, вы можете использовать:

struct Inside
{
    int foo;
    int bar;
};

struct Outside
{
    int baz;
    size_t num_foobar;
    const struct Inside* foobar;
};    

const struct Outside outsides[] =
{
    { .baz = 7, .num_foobar = 3,
      .foobar = (struct Inside[]){
                    { .foo = 1, .bar = 2 },
                    { .foo = 3, .bar = 4 },
                    { .foo = 5, .bar = 6 },
      }
    },
    { .baz = 8, .num_foobar = 0, .foobar = NULL },
};

Последний .num_foobar = 0 может быть опущен, так как неопределенные члены в любом случае инициализируются нулями, но я бы не сталЯ рекомендую это сделать.Вы можете использовать int вместо size_t, если хотите.(Приведенный выше код требует <stddef.h> или один из других заголовков, который определяет size_t (например, <stdio.h>) - но с добавлением #include <stddef.h> он компилируется в объектный код чисто для меня.)

Я пропустил ваш запрос:

Было бы идеально, если бы была другая косвенность: если элемент foobar является массивом указателей на элементы Inside, то я мог бы просто добавить нульуказатель в конце.

Это можно сделать с помощью изменения типа в структурах и немного больше работы в инициализаторе.Я думаю, что приведенный выше код немного легче понять, но то, что следует, тоже не совсем ужасно.

#include <stddef.h>

struct Inside
{
    int foo;
    int bar;
};

struct Outside
{
    int baz;
    const struct Inside **foobar;
};    

const struct Outside outsides[] =
{
    { .baz = 7,
      .foobar = &((const struct Inside*[]){
                    &(struct Inside){ .foo = 1, .bar = 2 },
                    &(struct Inside){ .foo = 3, .bar = 4 },
                    &(struct Inside){ .foo = 5, .bar = 6 },
                    NULL,
                })[0],
    },
    { .baz = 8, .foobar = NULL },
};

Хотя это «выполнимо», я определенно предпочитаю первый код.

...