77

I am trying to take in an input for the dimensions of a 2D matrix. And then use user input to fill in this matrix. The way I tried doing this is via vectors (vectors of vectors). But I have encountered some errors whenever I try to read in data and append it to the matrix.

//cin>>CC; cin>>RR; already done
vector<vector<int> > matrix;
for(int i = 0; i<RR; i++)
{
    for(int j = 0; j<CC; j++)
    {
    cout<<"Enter the number for Matrix 1";
         cin>>matrix[i][j];
    }
}

Whenever I try to do this, it gives me a subscript out of range error. Any advice?

user1487000
  • 1,161
  • 3
  • 12
  • 17

8 Answers8

211

You have to initialize the vector of vectors to the appropriate size before accessing any elements. You can do it like this:

// assumes using std::vector for brevity
vector<vector<int>> matrix(RR, vector<int>(CC));

This creates a vector of RR size CC vectors, filled with 0.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 5
    +1: That's what I do too. Surprised you're the only one who gave this answer. As an aside, I would never use a vector of vectors to represent a matrix. =) – paddy Sep 11 '12 at 22:05
  • 1
    @paddy I wouldn't use it either. The idea of being able to arbitrarily resize any column or row at any time, or changing the dimensions of a matrix after creation, is too scary for me. – juanchopanza Sep 12 '12 at 05:38
  • It's normal to change dimensions of a matrix (in MatLab you do it all the time), but in real-world use, the matrix is a contiguous block, and all you are changing is the rows/cols (basically keeping track of stride-lengths) - to index an element in the matrix, you calculate the linear index from your multi-dimensional index. – paddy Sep 12 '12 at 21:53
  • 2
    @paddy I know it is normal but more often than not it is a bad idea. My matrices have fixed sizes and that dramatically reduces the scope for errors. – juanchopanza Sep 12 '12 at 21:57
  • I think you misunderstood my reply. I was agreeing with you, and providing insight into how real applications do this. You never change the dimension of one row. Most times I've used Matrices outside of MatLab it's been for 3D work, and yes in that case I have a fixed-sized array with no heap allocation. When I really need a 2D dynamic array, I usually grab a single block of memory and dish out my row pointers and data area within that block. – paddy Sep 12 '12 at 22:14
  • 3
    @paddy what I meant to say is that my matrices' dimensions are in the type of the matrix, so they cannot be changed. Since I treat matrices as mathematical objects rather than storage space, it makes sense (to me) to use the compiler to enforce certain constraints, for example, you cannot assign a 2x4 matrix to a 5x1, or you cannot multiply to matrices together that do not have compatible dimensions. The storage itself is a single block, statically allocated in my case since I tend to deal with small matrices, but could be easily adapted to dynamic allocation without affecting the type safety. – juanchopanza Sep 13 '12 at 06:32
  • Hello @juanchopanza yo necessito de ayuda (I nedd help), I have this `vector> mat1(L, std::vector(C));` , and if I making a matrix calculator and I wanna the user write the number of lines and columns and the all elements I try make like this `cin >> L ; cin >> C;` and go on a size for loop `for (int i = 0; i < L; i++)\\ {\\ for (int j = 0; j < C; j++)\\ {\\ cin >> mat1[i][j];}} ` – Leonardo V. De Gasperin Jun 02 '16 at 15:13
  • I know it is a very old thread . I like your solution . please could you add std:: in front of vectors:) – Nadim Farhat Jun 16 '17 at 13:06
  • @NadimFarhat Thanks! I added a comment specifying that it uses to `using std::vector`. – juanchopanza Jun 16 '17 at 16:06
  • But then there will be RR + 1 vectors created. First you create a vector `vector(CC)` and then it will be copied RR times. I want to know how to avoid redundant construction – Xiaofeng Zheng Mar 19 '22 at 17:04
86

As it is, both dimensions of your vector are 0.

Instead, initialize the vector as this:

vector<vector<int> > matrix(RR);
for ( int i = 0 ; i < RR ; i++ )
   matrix[i].resize(CC);

This will give you a matrix of dimensions RR * CC with all elements set to 0.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
13

I'm not familiar with c++, but a quick look at the documentation suggests that this should work:

//cin>>CC; cin>>RR; already done
vector<vector<int> > matrix;
for(int i = 0; i<RR; i++)
{
    vector<int> myvector;
    for(int j = 0; j<CC; j++)
    {
        int tempVal = 0;
        cout<<"Enter the number for Matrix 1";
        cin>>tempVal;
        myvector.push_back(tempVal);
    }
    matrix.push_back(myvector);
}
Shmiddty
  • 13,847
  • 1
  • 35
  • 52
4

Assume we have the following class:

#include <vector>

class Matrix {
 private:
  std::vector<std::vector<int>> data;
};

First of all I would like suggest you to implement a default constructor:

#include <vector>

class Matrix {
 public:
  Matrix(): data({}) {}

 private:
  std::vector<std::vector<int>> data;
};

At this time we can create Matrix instance as follows:

Matrix one;

The next strategic step is to implement a Reset method, which takes two integer parameters that specify the new number of rows and columns of the matrix, respectively:

#include <vector>

class Matrix {
 public:
  Matrix(): data({}) {}

  Matrix(const int &rows, const int &cols) {
    Reset(rows, cols);
  }

  void Reset(const int &rows, const int &cols) {
    if (rows == 0 || cols == 0) {
      data.assign(0, std::vector<int>(0));
    } else {
      data.assign(rows, std::vector<int>(cols));
    }
  }

 private:
  std::vector<std::vector<int>> data;
};

At this time the Reset method changes the dimensions of the 2D-matrix to the given ones and resets all its elements. Let me show you a bit later why we may need this.

Well, we can create and initialize our matrix:

Matrix two(3, 5);

Lets add info methods for our matrix:

#include <vector>

class Matrix {
 public:
  Matrix(): data({}) {}

  Matrix(const int &rows, const int &cols) {
    Reset(rows, cols);
  }

  void Reset(const int &rows, const int &cols) {
    data.resize(rows);
    for (int i = 0; i < rows; ++i) {
      data.at(i).resize(cols);
    }
  }

  int GetNumRows() const {
    return data.size();
  }

  int GetNumColumns() const {
    if (GetNumRows() > 0) {
      return data[0].size();
    }

    return 0;
  }

 private:
  std::vector<std::vector<int>> data;
};

At this time we can get some trivial matrix debug info:

#include <iostream>

void MatrixInfo(const Matrix& m) {
  std::cout << "{ \"rows\": " << m.GetNumRows()
            << ", \"cols\": " << m.GetNumColumns() << " }" << std::endl;
}

int main() {
  Matrix three(3, 4);
  MatrixInfo(three);
}

The second class method we need at this time is At. A sort of getter for our private data:

#include <vector>

class Matrix {
 public:
  Matrix(): data({}) {}

  Matrix(const int &rows, const int &cols) {
    Reset(rows, cols);
  }

  void Reset(const int &rows, const int &cols) {
    data.resize(rows);
    for (int i = 0; i < rows; ++i) {
      data.at(i).resize(cols);
    }
  }

  int At(const int &row, const int &col) const {
    return data.at(row).at(col);
  }

  int& At(const int &row, const int &col) {
    return data.at(row).at(col);
  }

  int GetNumRows() const {
    return data.size();
  }

  int GetNumColumns() const {
    if (GetNumRows() > 0) {
      return data[0].size();
    }

    return 0;
  }

 private:
  std::vector<std::vector<int>> data;
};

The constant At method takes the row number and column number and returns the value in the corresponding matrix cell:

#include <iostream>

int main() {
  Matrix three(3, 4);
  std::cout << three.At(1, 2); // 0 at this time
}

The second, non-constant At method with the same parameters returns a reference to the value in the corresponding matrix cell:

#include <iostream>

int main() {
  Matrix three(3, 4);
  three.At(1, 2) = 8;
  std::cout << three.At(1, 2); // 8
}

Finally lets implement >> operator:

#include <iostream>

std::istream& operator>>(std::istream& stream, Matrix &matrix) {
  int row = 0, col = 0;

  stream >> row >> col;
  matrix.Reset(row, col);

  for (int r = 0; r < row; ++r) {
    for (int c = 0; c < col; ++c) {
      stream >> matrix.At(r, c);
    }
  }

  return stream;
}

And test it:

#include <iostream>

int main() {
  Matrix four; // An empty matrix

  MatrixInfo(four);
  // Example output:
  //
  // { "rows": 0, "cols": 0 }

  std::cin >> four;
  // Example input
  //
  // 2 3
  // 4 -1 10
  // 8 7 13

  MatrixInfo(four);
  // Example output:
  //
  // { "rows": 2, "cols": 3 }
}

Feel free to add out of range check. I hope this example helps you :)

serghei
  • 3,069
  • 2
  • 30
  • 48
2

try this. m = row, n = col

vector<vector<int>> matrix(m, vector<int>(n));

for(i = 0;i < m; i++)
{
   for(j = 0; j < n; j++)
   {
      cin >> matrix[i][j];
   }
   cout << endl;
}
cout << "::matrix::" << endl;
for(i = 0; i < m; i++)
{
    for(j = 0; j < n; j++)
    {
        cout << matrix[i][j] << " ";
    }
    cout << endl;
}
cristid9
  • 1,070
  • 1
  • 17
  • 37
1

Vector needs to be initialized before using it as cin>>v[i][j]. Even if it was 1D vector, it still needs an initialization, see this link

After initialization there will be no errors, see this link

Partho63
  • 3,117
  • 2
  • 21
  • 39
Mohit
  • 590
  • 5
  • 13
0

What you have initialized is a vector of vectors, so you definitely have to include a vector to be inserted("Pushed" in the terminology of vectors) in the original vector you have named matrix in your example.

One more thing, you cannot directly insert values in the vector using the operator "cin". Use a variable which takes input and then insert the same in the vector.

Please try this out :

int num;
for(int i=0; i<RR; i++){

      vector<int>inter_mat;       //Intermediate matrix to help insert(push) contents of whole row at a time

      for(int j=0; j<CC; j++){
           cin>>num;             //Extra variable in helping push our number to vector
           vin.push_back(num);   //Inserting numbers in a row, one by one 
          }

      v.push_back(vin);          //Inserting the whole row at once to original 2D matrix 
}
0

I did this class for that purpose. it produces a variable size matrix ( expandable) when more items are added

'''

#pragma once
#include<vector>
#include<iostream>
#include<iomanip>
using namespace std;
template <class T>class Matrix
{
public:
    Matrix() = default;
    bool AddItem(unsigned r, unsigned c, T value)
    {
        if (r >= Rows_count)
        {
            Rows.resize(r + 1);
            Rows_count = r + 1;
        }
        else
        {
            Rows.resize(Rows_count);
        }
        if (c >= Columns_Count )
        {
            for (std::vector<T>& row : Rows)
            {
                row.resize(c + 1);
            }
            Columns_Count = c + 1;
        }
        else
        {
            for (std::vector<T>& row : Rows)
            {
                row.resize(Columns_Count);
            }
        }
        if (r < Rows.size())
            if (c < static_cast<std::vector<T>>(Rows.at(r)).size())
            {
                (Rows.at(r)).at(c) = value;
            }
            else
            {
                cout << Rows.at(r).size() << " greater than " << c << endl;
            }
        else
            cout << "ERROR" << endl;
        return true;
    }
    void Show()
    {
        std::cout << "*****************"<<std::endl;
        for (std::vector<T> r : Rows)
        {
            for (auto& c : r)
                std::cout << " " <<setw(5)<< c;
            std::cout << std::endl;
        }
        std::cout << "*****************" << std::endl;
    }
    void Show(size_t n)
    {
        std::cout << "*****************" << std::endl;
        for (std::vector<T> r : Rows)
        {
            for (auto& c : r)
                std::cout << " " << setw(n) << c;
            std::cout << std::endl;
        }
        std::cout << "*****************" << std::endl;
    }
//  ~Matrix();
public:
    std::vector<std::vector<T>> Rows;
    unsigned Rows_count;
    unsigned Columns_Count;
};

'''

Amr1318
  • 71
  • 1
  • 2