-1

I'd like to convert a Matrix into an array, which I managed to do inside the main function, but when time to come to put it in a function, it stops working and I get an access violation error which didn't show inside the main scope.

Here is the code, I need help to complete the conversion. I need to cast it from a class function for my project.

#include <iostream>

const int rows = 3, cols = 4; //define constant rows and columns

int* MatrixToArray(static int* matrix[rows][cols]) {
    int* array[rows*cols]{};//initialize the array
    int* ptrResult=nullptr;//initialize the return variable

    //First loop to fill the matrix with dissociated values to print out
    for (int i = 0; i < rows-1; i++) {
        for (int j = 0; j < cols-1; j++) {
            if (matrix) {
                *matrix[i][j] = i + j + i * (j + cols); ///exception violation access memory 
            }
            if (matrix) {//debug warning C6011
                std::cout << " [" << *matrix[i][j] << "]";
            }
            
        }
        std::cout << ",\n";
    }
    
    //second reversed loop to get the unified array from the previous matrix
            for (int u = 0; u < 1; u++) {
                for (int i = 0; i < rows; i++) {
                    for (int j = 0; j < cols; j++) {
                        if (array) {//debug warning C6011
                            array[u] = matrix[i][j];
                            if (ptrResult) {//debug warning C6011
                                ptrResult = array[u];
                            }
                        }
                        std::cout << "[" << *array[u] << "] ";
                    }
            }
        }
        free(array);
    
    return ptrResult;
}

int main()
{
    int* matrix[rows][cols];
    std::cout << MatrixToArray(matrix);
}

After adapting the types for the matrix and the array, I get this code :

#include <iostream>

const int rows = 3, cols = 4; //define constant rows and columns

int* MatrixToArray(int** matrix) {
    int* array[rows*cols]{};//initialize the array
    int* ptrResult=nullptr;//initialize the return variable
//allocate memory as requested in the subedit comment field answers
    matrix = new int* [rows];
    for (int i = 0; i < rows; ++i)
        matrix[i] = new int[cols];

    //First loop to fill the matrix with dissociated values to print out
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (matrix) {
                matrix[i][j] = i + j + i * (j + cols); ///exception violation access memory disappear
            }
            if (matrix) {//debug warning C6011
                std::cout << " [" << matrix[i][j] << "]";
            }
            
        }
        std::cout << ",\n";
    }
    
    //second reversed loop to get the unified array from the previous matrix
    if (array) {
            for (int u = 0; u < 1; u++) {
                for (int i = 0; i < rows; i++) {
                    for (int j = 0; j < cols; j++) {
                        if (array) {//debug warning C6011
                            array[u] = &matrix[i][j];
                            if (ptrResult) {//debug warning C6011
                                ptrResult = array[u];
                            }
                        }
                        //std::cout << "[" << *array[u] << "] ";
                    }

            }
        }
        free(array);//File: minkernel crts ucrt src appcrt heap debug_heap.cpp Line:904 expression: _CrtlsValidHeapPointer(block)
    }
    
    return ptrResult;
}

int main()
{
//memory allocation correction
    int** matrix;
    matrix = new int* [rows];
    for (int i = 0; i < rows; ++i)
        matrix[i] = new int[cols];
    std::cout << MatrixToArray(matrix);
}

I still get an exception error, but in the assembly code which ends up into the message copied in the comment next to the line quoted.

z0t_LoD
  • 1
  • 3
  • `int* MatrixToArray(static int* matrix[rows][cols])` isn't a valid function signature to start with. What does the `static` there?? – πάντα ῥεῖ Sep 27 '20 at 18:57
  • `int* matrix[rows][cols];` declares a matrix of pointers, but I don't see that you allocate memory anywhere. – Ted Lyngmo Sep 27 '20 at 18:58
  • It looks like you want to use a [`std::array,rows>`](https://en.cppreference.com/w/cpp/container/array) to represent your matrix type. – πάντα ῥεῖ Sep 27 '20 at 19:01
  • The real problem is that the matrix conversion is not exactly a pointer : https://stackoverflow.com/questions/1403150/how-do-you-dynamically-allocate-a-matrix i checked this page, and I get an error when trying to assign a temporary matrix variable to the matrix parameter... The problem is hard for a beginner, because I get confused between pointers and double pointers. I learn C++, and I don't know very well about dereferencing and so on. Inside a function, the double ** initialization cannot be assigned to the parameter, which makes it strange just to convert a matrix to an array. – z0t_LoD Sep 27 '20 at 19:18
  • The main challenge is to assign the matrix values to the array to return from the function. But I didn't know the matrix type was different from the array in terms of memory allocation. Then, I really need help for that because I really don't know how to correct it on such a way to return the array with all of the values of the matrix without getting any memory issue... That should be fine to make things clear about pointer with one * and matrix with **...and how to link them together when needed ? – z0t_LoD Sep 27 '20 at 19:32
  • The exception mistake still remains after taking into account all of your comments. Please check my answer, and comment back again. The memory allocation has been implemented, the pointer types has been corrected, but an assembly code exception is arisen with this last version. This is an exception issue, but not necessarily a violation access due to the fact that it concerns a matrix to array function conversion... – z0t_LoD Sep 27 '20 at 20:16
  • @z0t_LoD Why are you not using `std::vector`? All of this raw memory manipulation is the underlying reason for all of the issues you're seeing now. Also, if you had built your Matrix [this way](https://stackoverflow.com/questions/21943621/how-to-create-a-contiguous-2d-array-in-c/21944048#21944048), there would be no need for a `MatrixToArray` function. Read the answer at that link to see why. (Almost want to close this as a duplicate). – PaulMcKenzie Sep 27 '20 at 23:24

2 Answers2

0
#include <iostream>

const int rows = 3, cols = 4; //define constant rows and columns

int* MatrixToArray(int** matrix) {
    int* array= new int[rows * cols]{};//initialize the array (with new keyword)
    int* ptrResult=nullptr;//initialize the return variable

    matrix = new int* [rows];
    for (int i = 0; i < rows; ++i)
        matrix[i] = new int[cols];
    std::cout << "[";
    //First loop to fill the matrix with dissociated values to print out
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (matrix) {
                matrix[i][j] = i + j + i * (j + cols); ///exception violation access memory disappeared 
            }
            if (matrix) {//debug warning C6011
                std::cout << " [" << matrix[i][j] << "]";
            }
        }
        if (i != rows - 1) {
            std::cout << ",\n";
        }

    }std::cout << "]";
    
    //second reversed loop to get the unified array from the previous matrix
                for (int i = 0; i < rows; i++) {
                    for (int j = 0; j < cols; j++) {
                        if (array) {//debug warning C6011
                            array[0] = matrix[i][j]; //modified with new initialization
                            if (ptrResult) {//debug warning C6011
                                *ptrResult = array[0];//modified with new initilization
                            }
                        }
            }
        }
    delete[] array;
    return ptrResult;
}

int main()
{
    int** TheMatrix;
    TheMatrix = new int* [rows];
    for (int i = 0; i < rows; ++i)
        TheMatrix[i] = new int[cols];
    std::cout << MatrixToArray(TheMatrix);

    for (int i = 0; i < rows; ++i) {
        delete[] TheMatrix[i];
    }
    delete[] TheMatrix;
}

Finally, I tweaked the pointers, and I got rid of the exception in the assembly mode, But I get a serie of zeros popping out in the end...

z0t_LoD
  • 1
  • 3
0

I'd like to convert a Matrix into an array

Given what you have stated in your question, there is no need to turn a two-dimensional array into a one-dimensional array, if the two-dimensional array is either:

  1. A "traditional" C++ array (i.e. int matrix[10][10];) or
  2. A two-dimensional array built from a T** in a contiguous manner.

Both the items above have the same property, and that is the data is in contiguous memory, no different than a single dimension array. Thus a 2-dimensional array is already a 1 dimensional array.

The only difference between item 1 and item 2 above in terms of contiguousness is that item 1 is "pre-built", while item 2 requires you to build the two-dimensional array.

For item 2). the answer here shows a complete class that builds the matrix from any T** in a contiguous manner. The way you're building the 2-dimensional array does not create the data in contiguous memory, since each row is allocated separately.

Once you have the matrix, the way you use it in a one-dimensional fashion is to pass the address of the items to whatever function or entity requires a pointer to a one-dimensional array.

Here is an example (for the int**, we will use the code in the other linked answer).

#include <iostream>
#include <exception>
#include <numeric>

template <typename T>
T** create2DArray(unsigned nrows, unsigned ncols, const T& val = T())
{
   if (nrows == 0)
        throw std::invalid_argument("number of rows is 0");
   if (ncols == 0)
        throw std::invalid_argument("number of columns is 0");
   T** ptr = nullptr;
   T* pool = nullptr;
   try
   {
       ptr = new T*[nrows];  // allocate pointers (can throw here)
       pool = new T[nrows*ncols]{val};  // allocate pool (can throw here)

       // now point the row pointers to the appropriate positions in
       // the memory pool
       for (unsigned i = 0; i < nrows; ++i, pool += ncols )
           ptr[i] = pool;

       // Done.
       return ptr;
   }
   catch (std::bad_alloc& ex)
   {
       delete [] ptr; // either this is nullptr or it was allocated
       throw ex;  // memory allocation error
   }
}

template <typename T>
void delete2DArray(T** arr)
{
   delete [] arr[0];  // remove the pool
   delete [] arr;     // remove the pointers
}

// The MatrixToArray function takes a pointer to a buffer and prints the info
void MatrixToArray(int data[], int numItems)
{
   for (int i = 0; i < numItems; ++i)
     std::cout << data[i] << " ";
   std::cout << "\n";
}

int main()
{
    int test1[] = {1,2,3,4,5,6,7,8,9,10};  // a 1-dimensioanl array
    int test2[2][5] = {{1,2,3,4,5},{6,7,8,9,10}}; // a 2-dimensional array

    int **test3 = create2DArray<int>(2,5); // a dynamically created 2-d array
    // quickly fill the above with the same data as the other arrays
    std::iota(&test3[0][0], &test3[1][5], 1);

    // Now test each one to prove that the same MatrixToArray function works for 
    // 1-dimensional and 2-dimensional arrays.
    std::cout << "Output 1:\n";
    MatrixToArray(test1, 10);

    std::cout << "\nOutput 2:\n";
    MatrixToArray(&test2[0][0], 10);

    std::cout << "\nOutput 3:\n";
    MatrixToArray(&test3[0][0], 10);
    
    delete2DArray(test3);
}

Output:

Output 1:
1 2 3 4 5 6 7 8 9 10 

Output 2:
1 2 3 4 5 6 7 8 9 10 

Output 3:
1 2 3 4 5 6 7 8 9 10   

The same output is produced from the MatrixToArray function, regardless if the array is one-dimensional, or if the array is 2-dimensional traditional, or 2-dimensional array built dynamically.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • For some operation such as determinant, it would be fine to get a convert function, so the array becomes a matrix you can add to another one which grants multiple value at the same time, or returns the signum of the determinant of the matrix, which is not possible with a simple array. In the newer version, I can't define arrays with non constant integers...But I get your point, arrays and matrix are very similar, so the difference may not be a problem to extract data cells. Opposedly, if I want the result with another array, the matrix format is limited. It is a kind of custom converter. – z0t_LoD Sep 28 '20 at 11:18
  • This is a forbidden 0 divider extension here. if you want to add two matrix between each other, it is possible. But, you cannot add a Matrix to an Array. The memory structure of the Matrix is different from the memory structure of the array. It seems useless to convert the array to a matrix, but converting the matrix to the array would allow to extract first the determinant, and then combining all of the elements to another array which could be acquired from an integer which was converted to an array as well... The output would be then an array which then can be converted into any value. – z0t_LoD Sep 28 '20 at 11:34
  • Here is a useful link which explains the principle, but doesn't show how to use it as a separated function with dynamic memory allocation : https://www.ce.jhu.edu/dalrymple/classes/602/Class12.pdf – z0t_LoD Oct 01 '20 at 14:29