(C++) Is there a way to create different matrices in a loop?

Viewed 90

I'm writing a code that reads a text file to create a matrix dinamically. I will then get the information from this matrix to write it in another text file.

I put in a 'for' loop that will create a matrix for each chunk of text that it reads, here it is:

    for (cont = 0; cont < nPares; cont++){
        
        ResultFile >> FlowOri;
        ResultFile >> FlowDest;
        ResultFile >> nPaths;
        ResultFile >> largestPath;

        double** iPathMatrix = (double**) new double[nPaths];
        for (i = 0; i < nPaths; i++) {
            iPathMatrix[i] = (double*) new double[largestPath + 2];
        }

        for (i = 0; i < nPaths; i++) {
            for (j = 0; j < largestPath + 2; j++) {
                ResultFile >> iPathMatrix[i][j];
            }
        }

        for (i = 0; i < nPaths; i++) {
            for (j = 0; j < largestPath + 2; j++) {
                cout << iPathMatrix[i][j] << " ";
            }
            cout << "\n";
        }

        free(iPathMatrix);
    }

'ResultFile' is an ifstream. That 'cout' near the end was put there to check if it was creating the matrices as intended, which it is.

As you can see, I'm creating the matrix and then freeing the memory at the end of the loop to create it again, since it will have the same name. I can probably figure a way to work with this, but it'd be way easier if I could create a different matrix with each loop, perhaps naming each with the 'FlowOri' and 'FlowDest' variables, if that's possible, and after the loop stops, access them and write in my output file.

Is there a way to do it? How would I reference it afterwards?

2 Answers

As you can see, I'm creating the matrix and then freeing the memory at the end of the loop to create it again,

No you aren't (at least not correctly). Each new[] must be paired with a delete[], so the correct code is

   for (i = 0; i < nPaths; i++) {
        delete[] iPathMatrix[i];
   }
   delete[] iPathMatrix;

Now since you are programming C++, you could avoid this by using vectors.

   std::vector<std::vector<double>> iPathMatrix(nPaths, std::vector<double>(largestPath + 2));

Now you don't need to allocate or free anything, but the rest of your code is unchanged.

Now as for your actual question. If I understand it correctly you want to associate a matrix with the value of the flowOri variable. That's easy to do, you should use a std::map.

You haven't said what type flowOri is, I'm going to assume it's a std::string but you should be able to get this to work whatever type it is.

#include <vector>
#include <map>
#include <string>

// lets give a shorter name for the vector type
using MatrixRowType = std::vector<double>;
using MatrixType = std::vector<MatrixRowType>;

// and this is the map type that holds the matrices
using MatrixMapType = std::map<std::string, MatrixType>;

...

MatrixMapType matrixMap;
for (cont = 0; cont < nPares; cont++){
    // read stuff
    ResultFile >> FlowOri;
    ...
    // read the matrix
    MatrixType iPathMatrix(nPaths, MatrixRowType(largestPath + 2));
    ...
    // save the matrix in the map keyed by FlowOri
    matrixMap[FlowOri] = iPathMatrix;
}

Now later when you want to retrieve a matirx you just write matrixMap[something] where something is a variable with the name of the matrix you want to retrieve.

Variable names only have a meaning for the programmer and disappear from the executable unless you use a debug mode, so C++ does not allow to create dynamically named variables. Anyway even with languages that allow it, it is a terrible design.

But you can always create an array (or better a vector) of any object type. So if you want to store everything in the loop and process later the whole data, you could use a 3 level vector. With the magic of references, little has to be changed from your code:

std::vector<std::vector<std::vector<double>>> matrixes(nPares);
for (auto& iPathMatrix : matrixes) {    // iPathMatrix is a reference inside matrixes
    ResultFile >> FlowOri;
    ResultFile >> FlowDest;
    ResultFile >> nPaths;
    ResultFile >> largestPath;

    iPathMatrix = std::vector<std::vector<double>>(nPaths);
    for (i = 0; i < nPaths; i++) {
        iPathMatrix[i] = std::vector<double>(largestPath + 2];
    }

    for (i = 0; i < nPaths; i++) {
        for (j = 0; j < largestPath + 2; j++) {
            ResultFile >> iPathMatrix[i][j];
        }
    }

}
// control:
for (int i = 0; i < nPares; i++) {
    for (int j = 0; j < matrixes[i].size(); j++) {
        for (int k = 0; k < matrixes[i][j].size(); k++) {
            std::cout << matrixes[i][j][k] << " ";
        }
        std::cout << '\n';
    }
    std::cout << '\n';
}    

matrixes now contain all of your data

Related