Назначить 2D массиву 2D массив в структуре - PullRequest
3 голосов
/ 21 июля 2011

У меня есть функция, которая пытается пройти через двумерный массив в структуре:

typedef struct node
{
    int grid[3][3];
} Node;


void someFunction(Node *node) {
     int grid[3][3] = node->grid;
     //loop through
}

Когда я пытаюсь скомпилировать это, я получаю

mp.c: 42: ошибка: неверный инициализатор

Ответы [ 3 ]

11 голосов
/ 21 июля 2011

Вы не можете назначать массивы в C. Это просто не разрешено. Когда вы написали:

int grid[3][3] = node->grid;

вы пытались инициализировать локальный массив, grid, из переданного в node. Если бы это было разрешено (а это не так), то вам не понадобился бы цикл впоследствии.

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

Node local = *node;

Для инициализации local.

вам не нужно будет последовательно проходить по массивам.

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

for (int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
        grid[i][j] = node->grid[i][j];

Вы также можете использовать memmove() или memcpy():

int grid[3][3];

assert(sizeof(grid) == sizeof(node->grid));
memcpy(grid, node->grid, sizeof(grid));

Одно время предлагался другой ответ:

Изменить строку:

int grid[3][3] = node->grid;

до:

int **grid = node->grid;

Я заметил, что это не сработает - и мне было законно предложено объяснить, почему. Это требует места и форматирования.

Прежде всего, примечания компилятора:

warning: initialization from incompatible pointer type

То есть «ты играешь с огнем».

Предположим, мы игнорируем это предупреждение. Локальный grid теперь указывает на верхний левый угол массива (если вы видите, что массивы растут вниз и поперек слева направо). Сохраненное там значение представляет собой простое число, а не инициализированный указатель, но когда компилятор оценивает grid[0], он вынужден предположить, что будет создан указатель. Если node->grid[0][0] содержит ноль, вы, вероятно, получите ошибку сегментации и дамп ядра для разыменования нулевого указателя (при условии, что указатели и int имеют одинаковый размер, что обычно верно для 32-разрядных систем), или некоторое другое неопределенное поведение. Если node->grid[0][0] содержит другое значение, то поведение все еще не определено, но не настолько предсказуемо.

1 голос
/ 21 июля 2011

Если вы не хотите делать копию, просто хотите указатель на массив в структуре (примечание: если вы присваиваете значения *pointer, содержимое массива в структуре будет изменено), выМожно достичь этой цели двумя способами:

#include <stdio.h>

typedef struct node
{
    int grid[3][3];
} Node;


void someFunction1(Node *node) {
     int i, j;
     int (*grid)[3] = node->grid;
     for(i=0; i<3; i++){
         for(j=0; j<3; j++){
             printf("%d ", grid[i][j]);
         }
         printf("\n");
     }
}

void someFunction2(Node *node) {
     int i, j;
     int *grid = (int*) node->grid;
     for(i=0; i<3; i++){
         for(j=0; j<3; j++){
             printf("%d ", grid[i*3+j]); // i * column_number + j
         }
         printf("\n");
     }
}

int main()
{
    Node t;
    int i, *p;

    //initialization: t.grid[0][0]=0,  ..., t.grid[2][2]=8
    for(i=0, p=(int*)t.grid; i<9; p++, i++){
        *p = i;
    }

    printf("Function1:\n");
    someFunction1(&t);

    printf("Function2:\n");
    someFunction2(&t);

    return 0;
}

Приведенный выше код показывает простую функцию для использования указателей.Все они безопасны и соответствуют стандарту.

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

EDIT

Итак,someFunction3()

void someFunction3(Node *node)
{
    int i, j;
    int **p;

    // 3 is the row number. Ignore checking malloc failure
    p = malloc(sizeof(int)*3);
    for(i=0; i<3; i++) {
        p[i] = (int*) node->grid[i]; //assign address of each row of array to *p
    }

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

    free(p);
}
0 голосов
/ 21 июля 2011

См. Этот другой поток для того же вопроса и ответа, который не включает копирование памяти:

Создание указателя на двумерный массив

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