1

I have a file named matrices.txt that has two matrices that are 3 by 3. They are:

1 2 3
4 5 6
7 8 9
1 2 3 
4 5 6 
7 8 9

I'm trying the read from this file and store it into an array proto_matrix to later split that into two matrices.

The problem I'm having is that I can't store the numbers in the array.

My code is

#include <iostream>
#include <fstream>

using namespace std;

void main()
{
    int i = 0, j, k = 0, n, dimension;
    cout << "Enter the dimension of square matrices (3 by 3 would be 3) \n";
    cin >> n;
    dimension = n * n;
    int proto_matrix[2 * dimension];

    // make array of two matrices combined, this will be split into two matrices
    ifstream matrix_file("matrices.txt");

    while(matrix_file)
    {
        matrix_file >> proto_matrix[i];
    }
    matrix_file.close();
}

I tried debugging the code and it seems like the no integer is stored in the array, just random numbers.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 1
    `int proto_matrix[2 * dimension];` isn't standard C++; you'll have to dynamically allocate enough memory for `2 * dimension` `int`s. – frslm Nov 29 '17 at 19:23
  • Always make sure the file `is_open()` before reading. – NathanOliver Nov 29 '17 at 19:23
  • 1
    give `while(matrix_file >> proto_matrix[i];) { i++; }` a shot. You weren't incrementing `i` as you were reading so all of the values read, if any, went into the same slot in the array, and you want to test the read for success before counting it. – user4581301 Nov 29 '17 at 19:23
  • Use `std::vector proto_matrix(2 * dimensions);` instead of the non-standard C++ syntax you're using. – PaulMcKenzie Nov 29 '17 at 19:40
  • BTW, the `main` function returns `int`. Always. – Thomas Matthews Nov 29 '17 at 19:57

4 Answers4

0

This:

int proto_matrix[2 * dimension];

is a Variable Length Array (VLA), which is not Standard C++, but is supported by some compiler extensions. If compile with g++ -pedantic main.cpp, you will surely get an error.

That means that you need to dynamically allocate your memory, if you had to use an array.

You really don't though, C++ offers std::vector, which can achieve what you want relatively easily. I say relatively, because you have two matrices in one file, which makes parsing the file a bit tricky. Usually we put the one matrix in one file, and the other matrix to another file.

  • A 2D array can be represented as a 2D vector.
  • You want two matrices, thus two 2D vectors.

For that reason, I will use an array of size 2 (fixed size!), where every element is going to be a 2D vector.

Moreover, I will keep track of which matrix I am reading from the file right now (the first or the second), and how many rows I have read currently, in order to populate the correct cell of the matrix.

index is going to be equal to 0 or 1, to index the array.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>

using namespace std;

int main()
{
    int i = 0, j, k = 0, n, dimension;
    cout << "Enter the dimension of square matrices (3 by 3 would be 3) \n";
    cin >> n;
    dimension = n * n;
    vector< vector<int> > v[2];
    v[0].resize(n);
    v[1].resize(n);
    // make array of two matrices combined, this will be split into two matrices
    ifstream matrix_file("matrices.txt");
    string line;
    int rows_read = 0, cols_read = 0, index = 0;
    while (std::getline(matrix_file, line))
    {
        std::istringstream iss(line);
        int a, b, c;
        if (!(iss >> a >> b >> c)) { break; } // error
        // process tuple (a, b, c)
        if(index == 0 && rows_read >= n)
        {
            rows_read = 0;
            index = 1;
        }
        //cout<<"rows = " << rows_read << " " << index<<endl;

        v[index][rows_read].push_back(a);
        v[index][rows_read].push_back(b);
        v[index][rows_read++].push_back(c);
    }
    matrix_file.close();

    for(int i = 0; i < 2; ++i)
    {
        cout << "Printing matrix " << i << endl;
        for(auto& matrix: v[i])
        {
            for(auto& number: matrix)
                cout << number << " ";
            cout << endl;
        }
    }
    return 0;
}

Output:

Printing matrix 0
1 2 3 
4 5 6 
7 8 9 
Printing matrix 1
1 2 3 
4 5 6 
7 8 9 

PS: Unrelated to your problem, but What should main() return in C and C++? An int.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
0

Based on my answer, I will post here a cleaner example, which achieves what your code tries to achieve: Read all the numbers in a 1D data structure (which will be split in two matrices somehow later).

So for that case, the code boils down to just this:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>

using namespace std;

int main()
{
    int i = 0, j, k = 0, n, dimension;
    cout << "Enter the dimension of square matrices (3 by 3 would be 3) \n";
    cin >> n;
    dimension = n * n;
    // make array of two matrices combined, this will be split into two matrices
    vector<int> proto_matrix;
    ifstream matrix_file("matrices.txt");
    string line;
    while (std::getline(matrix_file, line))
    {
        std::istringstream iss(line);
        int a, b, c;
        if (!(iss >> a >> b >> c)) { break; } // error
        proto_matrix.push_back(a);
        proto_matrix.push_back(b);
        proto_matrix.push_back(c);
    }
    matrix_file.close();

    for(auto& number: proto_matrix)
        cout << number << "\n";
    return 0;
}
gsamaras
  • 71,951
  • 46
  • 188
  • 305
0

You don't increment i, thus always writing to the first element. It should be:

matrix_file >> proto_matrix[i++];
Pedro
  • 842
  • 6
  • 16
0

You could just read all the values into a flat container (such as std::vector) and do the re-arrangement at a later point. The following code may give you an idea:

#include <vector>
#include <fstream>
#include <iostream>

int main() {
  std::vector<int> values;

  std::ifstream fp("matrices.txt");

  for (int value; fp >> value; ) {
    values.emplace_back(value);
  }

  std::cout << "I read " << values.size() << " values:\n";

  for (auto && value : values) std::cout << value << " ";

  std::cout << "\n";
}

Result:

$ clang++ matrixread.cpp -std=c++17
$ ./a.out 
I read 18 values:
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 
Escualo
  • 40,844
  • 23
  • 87
  • 135