Nicholas Nicholas - 1 month ago 7
C++ Question

How do I fit in a comma separated number matrix into a dynamically allocated array in C++?

I have a file that stores a number matrix of unknown shape in format like

-1,4,12,5.7
2.1,3,-10,3.3
7.1,1.11,12,10


I attempt to store the matrix in a dynamically allocated array because I cannot hard code the number of row and column. For this part, I used pointer-to-pointer and a demo is as below,

#include <iostream>
using namespace std;

int main()
{
// Rather than user input, I need to change this part to deciding the shape of the matrix myself
int row, col;
cout << "Enter row number and column number, separated with a space:\n";
cin >> row >> col;
int** p_p_grid = new int* [row];
for(int i = 0; i < row; i++)
{
p_p_grid[i] = new int[col];
}

// Fill in the entries
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
// (i + 1) * (j + 1) needs to be replaced by true entries in the matrix
p_p_grid[i][j] = (i + 1) * (j + 1);
}
}
return 0;
}


But what is an efficient way to decide the shape of a comma separated number block before assigning the number one by one? And also how do I import a CSV-structured matrix in C++? (For some reason, I don't want to use a vector type, so please focus on an array)

Answer

what is an efficient way to decide the shape of a comma separated number block before assigning the number one by one?

Assuming you're reading from a file stream, the easiest way, would be to read the file twice: one for counting rows and commas, on for doing the real input.

Here an example of how to detect the end of the matrix, stoping when the number of elements of a new line don't match the format of the matrix:

int nrows=1, ncols=0;
string line; 
while (getline(ifs, line)) {
    int n=1; 
    for (auto x: line)   // count commas in the line 
        if (x==',') 
            n++; 
    if (!ncols) 
        ncols = n;        // first line sets th enumber of columns
    else if (n == ncols)  // subsequent lines increase the row count
        nrows++; 
    else break;          // unless the format does'n match anymore
}
ifs.clear();   // remove eof 
ifs.seekg (0, ifs.beg);  // rewind

Online demo

What causes lack of efficiency in this approach, is that you read the file twice. For this reason, by the way, you can't use this approach for reading cin: you can't rewind.

You can optimize this either by caching the lines read (but you'd need to manage a rowing array of strings, as you're not allowed to use vectors), or by letting the matrix grow dynamically (which no longer correspond to your question as this would not provide the matrix size upfront).

how do I import a CSV-structured matrix in C++

Within each line, just read the doubles, followed by a char (which should be the ','):

char forget_me; 
for (int i=0; i<nrows; i++) 
    for (int j=0; j<ncols; j++) { 
         cin >> p_p_grid[i][j];  
         if (j<ncols-1) 
            cin>>forget_me; 
    }
Comments