I am working on a programing that needs to accept a text file as input and read that data into an NxM matrix. The only given size limitation is that the max row length is 1024. Additionally, the program needs to produce an error if all rows do not contain the same number of columns.
I figure that I need a 2D array to store the values, but I can't figure out how to do it, since I don't know the size to begin with.

int MAX_COLS=1024;
void readInput(ifstream & in)
{
	int rows=1, cols=0;
	float temp=0;
	while (in.peek()!='\n') 
       //counts columns in first row
	{
		in>>temp;
		cols++;
	}
	while (!in.eof()) 
	{
		int col_count=0;
		if (in.peek()=='\n') //at the end of a line
		{
			in.ignore(3,'\n'); //ignore newline character
			rows++;//increment rows
		}
		else
		{
			while (in.peek()!='\n')
                  //while not at end of line, count columns in current row
			{
				in>>temp;
				col_count++;
				if (in.eof()) 
					break;
			}
			if (col_count!=cols) //if the columns in current row aren't equal to columns in first row, output Error and exit
			{
				cout<<"Error invalid data"<<endl;
				exit(1);
			}
		}
	}
	
	cout<<"Rows "<<rows<<" Cols "<<cols<<endl;
	in.close();
		
}

My code shows my function that computes rows and columns, and checks that each row has the same number of columns. In the code, I'm storing values in temp, but I need to change that to store them in a way that I can access them outside the loops.

Could someone please help me figure out a way to store these values?

Dani AI

Generated

Nice start, . The tricky parts here are (1) not relying on peek()/EOL for layout (Windows uses \r\n, blank lines happen, etc.), (2) avoiding while (!in.eof()), and (3) storing as you read so the data is available after the loop. I agree with : vectors make this simple. Also, is right that a size header is ideal, but if the file does not have one, you can still read robustly in a single pass with std::getline and an istringstream.

Here is a compact pattern that enforces the 1024-column cap and consistency, and stores in a flat, contiguous buffer for fast indexing:

#include <vector>
#include <string>
#include <sstream>
#include <stdexcept>

struct Matrix {
    size_t rows = 0, cols = 0;
    std::vector<double> data; // row-major
    double& at(size_t r, size_t c) { return data[r*cols + c]; }
    const double& at(size_t r, size_t c) const { return data[r*cols + c]; }
};

Matrix read_matrix(std::istream& in) {
    Matrix M;
    std::string line;
    std::vector<double> tmp;
    size_t expected_cols = 0, line_no = 0;

    while (std::getline(in, line)) {
        ++line_no;
        if (!line.empty() && line.back() == '\r') line.pop_back();       // handle CRLF
        if (line.find_first_not_of(" \t\r") == std::string::npos) continue; // skip blank

        std::istringstream row(line);
        std::vector<double> vals;
        for (double x; row >> x; ) vals.push_back(x);
        if (row.fail() && !row.eof()) throw std::runtime_error("Non-numeric token on line " + std::to_string(line_no));

        if (vals.size() > 1024) throw std::runtime_error("Too many columns (max 1024) on line " + std::to_string(line_no));
        if (expected_cols == 0) expected_cols = vals.size();
        else if (vals.size() != expected_cols) throw std::runtime_error("Inconsistent column count on line " + std::to_string(line_no));

        tmp.insert(tmp.end(), vals.begin(), vals.end());
        ++M.rows;
    }

    if (M.rows == 0 || expected_cols == 0) throw std::runtime_error("Empty matrix");
    M.cols = expected_cols;
    M.data.swap(tmp);
    return M;
}

Notes:

  • This avoids ignore(3,'\n') pitfalls and handles stray spaces and CRLF cleanly.
  • If you prefer ’s staging idea, you can still read rows into a temporary std::vector<double> per line and then append to the flat buffer as shown.
  • If you ever control the format, add a header rows cols at the top and validate against it for an extra safety check as suggested.

Recommended Answers

All 4 Replies

If you do not know the size ahead of time, you can use the MAXIMUM size to make sure you have now overflow. There is no maximum size for this. There's a maximum number of columns, but not a maximum number of rows. So you are left with a few options:

  1. Go through the file, count the number of rows and columns, but don't store the matrix values. Declare the 2-D array to be the (now known) number or rows and columns, then go through the file again and read in the values.
  2. Dynamically resize your array as needed as you read through the file (i.e. have enough storage to handle ten rows, then when you hit row 11, resize the array to something larger, and keep going (will potentially involve a deep copy of the array to another location).
  3. Use vector(s), which also resize, but they do all the resizing and deep copying work for you.

Use std::list to read data from file, than copy all data to std::vector.

Hi, have you tried this?

ifstream mat2(matrix2); 
int      nrows2=0, ncols2=0,col_count=0;
const    char EOL = '\n'; float    temp;
while   ( mat2.peek()!=EOL){mat2>>temp;  ncols2++; }
while   (!mat2.eof())      { if (mat2.peek()==EOL){ mat2.ignore(3,EOL); nrows2++; }
			  else{ while (mat2.peek()!=EOL){ mat2 >>temp;col_count++; if (mat2.eof()) break;}}}
	mat2.close();

ifstream mat4(matrix2); 
for (row=0; row<nrows2; row++){for (col=0; col<ncols2; col++){mat4 >> parameters[row][col];}}

It seems like a risky set up for a problem. You are really counting on no hiccups within the system. I read matrices from text files quite often, and I like to have the matrix dimension entered in the file as the very first entry. It might not create the perfect set up, but it provides one more level of redundancy for checking the system. I mean, if the user enters a 2 for the matrix dimension, but the file has 23 entries, that indicates that perhaps a typo has been made, or the file is wrong, or something, so I output an error message and prompt the user to re-check the data. If the user is up at 3 am and they are getting absent-minded, forcing them to give the data file a second look can't hurt.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.