Converting multidimensional arrays to pointers in c++

30,157

Solution 1

No, there's no right way to do specifically that. A double[4][4] array is not convertible to a double ** pointer. These are two alternative, incompatible ways to implement a 2D array. Something needs to be changed: either the function's interface, or the structure of the array passed as an argument.

The simplest way to do the latter, i.e. to make your existing double[4][4] array compatible with the function, is to create temporary "index" arrays of type double *[4] pointing to the beginnings of each row in each matrix

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

and pass these "index" arrays instead

MatrixInversion(startRows, 4, inverseRows);

Once the function finished working, you can forget about the startRows and inverseRows arrays, since the result will be placed into your original inverseMatrix array correctly.

Solution 2

For given reason that two-dimensional array (one contiguous block of memory) and an array of pointers (not contiguous) are very different things, you can't pass a two-dimensional array to a function working with pointer-to-pointer.

One thing you could do: templates. Make the size of the second dimension a template parameter.

#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);
}

Another, a bit clumsier way might be to make the function accept a pointer to a single-dimensional array, and both width and height given as arguments, and calculate the indexes into a two-dimensional representation yourself.

#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);
}

Naturally, a matrix is something that deserves a class of its own (but the above might still be relevant, if you need to write helper functions).

Solution 3

Since you are using C++, the proper way to do something like this would be with a custom class and some templates. The following example is rather rough, but it gets the basic point across.

#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);
        }
    }
}

Solution 4

Two dimensional array is not a pointer to pointer or something similar. The correct type for you startMatrix is double (*)[4]. For your function, the signature should be like:

MatrixInversion( double (*A)[4], int order, double (*B)[4] );
Share:
30,157
Alex319
Author by

Alex319

Updated on July 05, 2022

Comments

  • Alex319
    Alex319 almost 2 years

    I have a program that looks like the following:

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

    I now want to calculate the inverse of startMatrix and put it into inverseMatrix. I have a library function for this purpose whose prototype is the following:

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

    that takes the inverse of A and puts it in B. The problem is that I need to know how to convert the double[4][4] into a double** to give to the function. I've tried just doing it the "obvious way":

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

    but that doesn't seem to work. Is that actually the right way to do it?