Как статически инициализировать двумерный массив указателем на указатели? - PullRequest
0 голосов
/ 19 марта 2019

У меня есть структура, скажем, foo, которая выглядит следующим образом:

struct foo {
    size_t n;
    size_t **point;
};

В структуре есть другие члены, которые не важны для вопроса.Теперь я хочу статически инициализировать структуру.

int main(void)
{
    struct foo *bar = &(struct foo){
                       .n=4,
    /* ERROR HERE */   .point=(size_t[][n]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
    };
    return 0;
}

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

/* Variation 1 */   .point=(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
/* Variation 2 */   .point=(size_t**)(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
/* Variation 3 */   .point=&(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}

Ответы [ 3 ]

2 голосов
/ 19 марта 2019

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

Вам нужно разделить массивы на одномерные массивы неизвестного размера и использовать для них отдельные составные литералы:

struct foo * bar = &(struct foo){
    .n = 4,
    .point = (size_t*[]){
        (size_t[]){1, 2, 3, 4}, 
        (size_t[]){5, 6, 7, 8}
    }
};
1 голос
/ 19 марта 2019

Прежде всего size_t **point имеет смысл, только если вы намереваетесь указывать на массив size_t*.Это, похоже, не так, поэтому вам нужно изменить тип на 2D-массив или указатель массива.

Следующая проблема в том, что C здесь довольно громоздкий - прямо скажем, вы можете 'У него не должно быть статического динамического массива, это должно быть либо.Вы можете иметь это:

#define N 4

struct foo {
  size_t n;
  size_t (*point)[N]; // pointer to first array of an array of size_t[4]
};

struct foo bar = 
{
  .n=N,
  .point= (size_t[][N]){ {1, 2, 3, 4}, {5, 6, 7, 8} }
};

...
bar.point[x][y] = ...; // access element of the 2D array

или, альтернативно, возможно, гибкий член массива в виде массива указателей, например:

struct foo {
  size_t n;
  size_t* point[];
};

const size_t n = 4;
struct foo* bar = malloc ( sizeof(*bar) + sizeof (size_t*[n]) );
bar->n = n;
bar->point[0] = (size_t []) { 1, 2, ... /* any number of elements*/ };
bar->point[1] = ...
...
bar->point[0][0] = 0; // access element in the lookup-table
...
free(bar);

Ни один из этих вариантов не является особенно хорошимсинтаксис беспорядочный и подвержен ошибкам.Здесь просто не хватает языка.

0 голосов
/ 19 марта 2019

Чтобы статически инициализировать указатель, сущности, на которые вы указываете, должны быть объявлены. Только в редких случаях, например, во встроенной системе, в которой вы знаете адрес чего-либо во время компиляции, вы узнаете фактическое значение указателя, которое будет статически инициализировано.

Я вижу пару проблем с тем, что вы делаете: 1) Компилятор не может определить значение n, когда вы пытаетесь использовать его для объявления размера вашего массива. Массивы должны иметь размер, указанный в их объявлении, в отличие от C #. 2) Точечный член структуры является указателем на указатели, но вы пытаетесь инициализировать его массивом массивов. Если вы хотите указать на массив массивов, вам нужен только адрес элемента [0] [0], поэтому * указать, а не ** указать. Оттуда вы можете использовать запись массива для доступа к элементам.

Вам нужно сделать что-то вроде этого:

struct foo
{
    size_t n;
    size_t *point;
};


size_t values[2][4] = {{1,2,3,4}, {5,6,7,8}};

struct foo bar = 
{
    4,
    &values
}

Затем вы можете получить доступ к массиву:

size_t kk;
kk = bar.point[ii][jj];

Если вам действительно нужны указатели на указатели, то значения инициализации должны быть либо адресными ссылками (& name), либо значениями, которые приводятся как указатели, но я не советую делать это.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...