Присвоить массив двойному указателю - PullRequest
0 голосов
/ 14 января 2020

Это часть задания. Сейчас я нахожусь в той части, где мне нужно прочитать в файле .csv следующую структуру:

typedef struct {
    int n;
    double **data;
} Matrix;

Файл .csv имеет, например, 3 строки и 3 столбца:

1 2 3
4 5 6
7 8 9

и выглядело бы так, как двумерный массив:

double array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};

, и теперь я бы хотел присвоить свой массив матрице следующим образом:

function someFunction(Matrix *m) {
    //...
    double array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};

    A->data = array;
    A->n = 3;
    //...
}

Но присваивая array на data не работает, так как я получаю следующую ошибку, используя gcc -Wall -pedantic-errors:

error: assignment to ‘double **’ from incompatible pointer type ‘double *’ [-Wincompatible-pointer-types] 79 | A->data = array;

Как я могу решить эту проблему? Частью назначения является то, что g cc не может показывать какие-либо предупреждения при использовании -Wall и -pedanti c -erros, поэтому хаки не допускаются.

1 Ответ

3 голосов
/ 14 января 2020

double** - указатель на указатель. Конечно, (внешний) указатель также может указывать на некоторый массив:

double* array[7];
double** pointer = array;

Теперь каждый из указателей в array может указывать и на другие массивы:

double valueArray[12]
double* pointerArray[10];

double** pointer = array;
pointer[0] = valueArray; // equivalent to pointerArray[0] = ...

Двумерные массивы не являются массивами указателей, хотя они являются массивами массивов, и указатель на первый элемент имеет другой тип:

double array[10][12];
double(*pointer)[12] = array;

Попытка охватить матрицы произвольного размера вызывает некоторые проблемы:

struct Matrix
{
    size_t n;
    double(*data)[n]; // you cannot exchange arbitrary pointers,
                      // you need a compile time constant!
};

Имейте в виду, что это отличается от VLA в параметрах функций, где вы могли бы иметь

void f(size_t n, int(*data)[n]);

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

void someFunction(Matrix* m)
{
    double array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};

    m->data = array; // assuming you meant m instead of A
                     // and you did adjust the pointer type already appropriately
}

array имеет локальную продолжительность хранения и будет уничтожена, как только вы вернетесь из функции, что приведет к зависанию указателя в m и неопределенному поведению, если вы разыграете указатель после возврата из функции.

Так что вам нужно вместо этого malloc массив достаточного размера. Но не забудьте освободить его и тогда!

Так что, если вы не хотите go указатель на путь указателя:

double** array = malloc(sizeof(*array) * n);
array[0] = malloc(sizeof(**array) * n);
// ...

который допускает синтаксис m->data[x][y], тогда вам следует придерживаться подхода одномерного массива:

struct Matrix
{
    size_t n;
    double* data;
};

и, возможно, некоторой функции доступа:

double get(struct Matrix* m, size_t row, size_t column)
{
    return m->data[row * m->n + column];
}

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

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