2

Okay, I was going through a few programming exercises, and got stuck with one involving reading a file. What I need to do is read in a certain set of lines into a 2D array, the lines length and amount of line varies, but I know it beforehand.

So the file is formatted like this:

There are two numbers, n and m, where 1 <= n, m <= 20,

Now n and m come in the file formatted like so: n m (there is a space between the two numbers)

Now after that line there are n lines of integers with m elements each. So for example an input is like so: (The numbers are in the range) 0 <= # <= 50

5 3
2 2 15
6 3 12
7 3 2
2 3 5
3 6 2

So from this the program knows there are 15 elements, and can be held in an array like so: int foo[5][3]

So how do I read in the file like this? And, lastly, the file has multiple sets of input after one another. So it might go: (2, 2 is info for first set, and 3, 4 for the second set of inputs)

2 2
9 2
6 5
3 4
1 2 29
9 6 18
7 50 12

How do I read this kind of input from a file in C++?

Rivasa
  • 6,510
  • 3
  • 35
  • 64

2 Answers2

2

First, you should have a matrix/grid/2darray class of some sort

//A matrix class that holds objects of type T
template<class T>
struct matrix {
    //a constructor telling the matrix how big it is
    matrix(unsigned columns, unsigned rows) :c(columns), data(columns*rows) {}
    //construct a matrix from a stream
    matrix(std::ifstream& stream) {
        unsigned r;
        stream >> c >> r;
        data.resize(c*r);
        stream >> *this;
        if (!stream) throw std::runtime_error("invalid format in stream");
    }
    //get the number of rows or columns
    unsigned columns() const {return c;}
    unsigned rows() const {return data.size()/c;}
    //an accessor to get the element at position (column,row)
    T& operator()(unsigned col, unsigned row) 
    {assert(col<c && row*c+col<data.size()); return data[data+row*c+col];}
protected:
    unsigned c; //number of columns
    std::vector<T> data; //This holds the actual data
};

And then you simply overload operator<<

template<class T>
std::istream& operator>>(std::istream& stream, matrix<T>& obj) {
    //for each row
    for(int r=0; r<obj.rows(); ++r) {
        //for each element in that row
        for(int c=0; c<obj.cols(); ++c)
            //read that element from the stream
            stream >> obj(c, r);  //here's the magic line!
    }
    //as always, return the stream
    return stream;
}

Fairly straightforward.

int main() {
   std::ifstream input("input.txt");
   int r, c;
   while(input >> c >> r) { //if there's another line
       matrix<char> other(c, r); //make a matrix
       if (!(input >> other)) //if we fail to read in the matrix
           break;  //stop
       //dostuff
   }
   //if we get here: invalid input or all done 
}
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • Thanks, really useful, but can you comment it a bit? Since I'm having some difficulty understanding the first part. – Rivasa Sep 18 '12 at 20:59
  • @Link: Done. Keep in mind, your actual matrix class should probably have more methods, iterators, and other such. I go over members that containers should have [here](http://stackoverflow.com/a/7759622/845092) – Mooing Duck Sep 18 '12 at 21:13
  • So, on usage, do I just open the file and do something like file >> array? – Rivasa Sep 18 '12 at 21:18
  • so one sec, how is the main function working? And how would it work in my example, where the test cases are right behind another? – Rivasa Sep 18 '12 at 21:46
  • @Link: I added a simpler input demo for reading in several arrays and processing them. Note that my `operator>>` merely reads in data, but not sizes. Once a matrix is made, mine never changes size. (You could make resizable matrix's if you want) – Mooing Duck Sep 18 '12 at 21:56
0

You need a way to dynamically allocate memor at run-time, since that is when you know how much data you need to read from the file. There are (at least) two ways to do this:

  1. Use std:vector as suggested by @MooingDuck

  2. Dynamically allocate your array with the new or new[]operators. You also need to be sure to release any memory using the delete or delete[] operators.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268