Подтвердить что ты не робот

Преобразование многомерных массивов в указатели в С++

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

double[4][4] startMatrix;
double[4][4] inverseMatrix;
initialize(startMatrix) //this puts the information I want in startMatrix

Теперь я хочу рассчитать инверсию startMatrix и поместить ее в inverseMatrix. У меня есть библиотека для этой цели, прототипом которой является следующее:

void MatrixInversion(double** A, int order, double** B)

который принимает обратный к A и помещает его в B. Проблема заключается в том, что мне нужно знать, как преобразовать double [4] [4] в double **, чтобы дать функции. Я пробовал просто сделать это "очевидным способом":

MatrixInversion((double**)startMatrix, 4, (double**)inverseMatrix))

но это, похоже, не работает. Это действительно правильный способ сделать это?

4b9b3361

Ответ 1

Нет, нет правильного способа сделать это. Массив double[4][4] не конвертируется в указатель double **. Это два альтернативных, несовместимых способа реализации 2D-массива. Что-то нужно изменить: либо интерфейс функции, либо структуру массива, переданную в качестве аргумента.

Самый простой способ сделать последний, т.е. сделать существующий массив double[4][4] совместимым с этой функцией, заключается в создании временных массивов "index" типа double *[4], указывающих на начало каждой строки в каждой матрице

double *startRows[4] = { startMatrix[0], startMatrix[1], startMatrix[2] , startMatrix[3] };
double *inverseRows[4] = { /* same thing here */ };

и вместо этого передайте эти "индексные" массивы

MatrixInversion(startRows, 4, inverseRows);

После завершения работы функции вы можете забыть о массивах startRows и inverseRows, так как результат будет правильно помещен в исходный массив inverseMatrix.

Ответ 2

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

Одна вещь, которую вы могли бы сделать: шаблоны. Сделайте размер второго измерения параметром шаблона.

#include <iostream>

template <unsigned N>
void print(double a[][N], unsigned order)
{
    for (unsigned y = 0; y < order; ++y) {
        for (unsigned x = 0; x < N; ++x) {
            std::cout << a[y][x] << ' ';
        }
        std::cout << '\n';
    }
}

int main()
{
    double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
    print(arr, 3);
}

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

#include <iostream>

void print(double *a, unsigned height, unsigned width)
{
    for (unsigned y = 0; y < height; ++y) {
        for (unsigned x = 0; x < width; ++x) {
            std::cout << a[y * width + x] << ' ';
        }
        std::cout << '\n';
    }
}

int main()
{
    double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
    print(&arr[0][0], 3, 3);
}

Естественно, что матрица - это то, что заслуживает собственного класса (но вышеупомянутое может быть актуальным, если вам нужно написать вспомогательные функции).

Ответ 3

Поскольку вы используете С++, правильный способ сделать что-то вроде этого будет с пользовательского класса и некоторых шаблонов. Следующий пример довольно груб, но он получает основную точку.

#include <iostream>

using namespace std;

template <int matrix_size>
class SquareMatrix
{
    public:
        int size(void) { return matrix_size; }
        double array[matrix_size][matrix_size];
        void copyInverse(const SquareMatrix<matrix_size> & src);
        void print(void);
};

template <int matrix_size>
void SquareMatrix<matrix_size>::copyInverse(const SquareMatrix<matrix_size> & src)
{
    int inv_x;
    int inv_y;

    for (int x = 0; x < matrix_size; x++)
    {
        inv_x = matrix_size - 1 - x;
        for (int y = 0; y < matrix_size; y++)
        {
            inv_y = matrix_size - 1 - y;
            array[x][y] = src.array[inv_x][inv_y];
        }
    }
}

template <int matrix_size>
void SquareMatrix<matrix_size>::print(void)
{
    for (int y = 0; y < 4; y++)
    {
        for (int x = 0; x < 4; x++)
        {
            cout << array[x][y] << " ";
        }   
        cout << endl;
    }
}

template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix);

int main(int argc, char * argList[])
{
    SquareMatrix<4> startMatrix;
    SquareMatrix<4> inverseMatrix;

    Initialize(startMatrix);

    inverseMatrix.copyInverse(startMatrix);

    cout << "Start:" << endl;
    startMatrix.print();

    cout << "Inverse:" << endl;
    inverseMatrix.print();

    return 0;
}

template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix)
{
    for (int x = 0; x < matrix_size; x++)
    {
        for (int y = 0; y < matrix_size; y++)
        {
            matrix.array[x][y] = (x+1)*10+(y+1);
        }
    }
}

Ответ 4

Двумерный массив не является указателем на указатель или что-то подобное. Правильный тип для startMatrix - double (*)[4]. Для вашей функции подпись должна быть такой:

MatrixInversion( double (*A)[4], int order, double (*B)[4] );

Ответ 5

Существует решение, использующее указатель на пункт bobobobo

Уильям Шериф (bobobobo) использовал версию C, и я просто хочу показать версию ответа bobobobo на С++.

int numRows = 16 ;
int numCols = 5 ;
int **a ;

a = new int*[ numRows* sizeof(int*) ];
for( int row = 0 ; row < numRows ; row++ )
{
    a[row] = new int[ numCols*sizeof(int) ];
}

Остальная часть кода такая же, как у bobobobo.

Ответ 6

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

Итак, ваша функция приема должна быть объявлена ​​как void MatrixInversion(double A[4][], int order, double B[4][]).

Ответ 7

с помощью хорошей кодировки, если С++:

struct matrix {
    double m[4][4];
};

matrix startMatrix;
matrix inverseMatrix;

поэтому интерфейс будет

void MatrixInversion(matrix &A, int order, matrix &B);

и используйте его

MatrixInversion(startMatrix, 4, inverseMatrix);

Пособие

  • интерфейс очень прост и понятен.
  • нужно изменить внутреннюю матрицу "m", вам не нужно обновлять интерфейс.

Или так

struct matrix {
    void Inversion(matrix &inv, int order) {...}
protected:
    double m[4][4];
};

matrix startMatrix;
matrix inverseMatrix;
...

Уродливый путь в c

void MatrixInversion(void *A, int order, void *B);
MatrixInversion((void*)startMatrix, 4, (void*)inverseMatrix);

EDIT: ссылочный код для MatrixInversion, который не будет аварийно:

void MatrixInversion(void *A, int order, void *B)
{
    double _a[4][4];
    double _b[4][4];

    memcpy(_a, A, sizeof _a);
    memcpy(_b, B, sizeof _b);
    // processing data here

    // copy back after done
    memcpy(B, _b, sizeof _b);
}