How do you make a 2D Vector?

So is this the way you declare the size of a 2D Vector?

#include <vector>
using namespace std;

vector<vector<int> > items[5][5];

I didn't get a syntax error on it. So does it create a 5x5 vector?

And how would you access individual parts of the vector? Like [3][4] 3 being the third row and 4 being the fourth column.

No, you're working with vector objects, so if you want to set the size beforehand, you do it with a constructor:

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;

int main()
{
  vector<vector<int> > items ( 5, vector<int> ( 5 ) );
  int k = 0;

  for ( int i = 0; i < 5; i++ ) {
    for ( int j = 0; j < 5; j++ )
      items[i][j] = k++;
  }

  for ( int i = 0; i < 5; i++ ) {
    for ( int j = 0; j < 5; j++ )
      cout<< setw ( 3 ) << items[i][j] <<' ';
    cout<<'\n';
  }
}

Alternatively, you can build the vectors dynamically:

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;

int main()
{
  vector<vector<int> > items;
  int k = 0;

  for ( int i = 0; i < 5; i++ ) {
    items.push_back ( vector<int>() );

    for ( int j = 0; j < 5; j++ )
      items[i].push_back ( k++ );
  }

  for ( int i = 0; i < 5; i++ ) {
    for ( int j = 0; j < 5; j++ )
      cout<< setw ( 3 ) << items[i][j] <<' ';
    cout<<'\n';
  }
}

Not that it's important or anything, but you can initialize all the elements to a specific value:

vector< vector< double > > matrix( row, vector<double>(row, int_val));

I checked out the C++ Standard Library book from my college to see if they had anything on 2D vectors. To my surprise there were none.

I also did some research on the net to find anything 2D vector related and that didn't turn up anything.

Is there not that much support for 2D or 3D vectors?

I know that vectors have a performance issue when you want to add or delete from the beginning or in the middle. Since your computer has to find another spot in memory to place your new container.

I am currently working on a "backpack" for a human_player class for an RPG. I needed to place several values for each item in the backpack that needed to dynamically resize the container in case you got a bigger backpack during the game.

So thanks for you help Narue :lol:

>Is there not that much support for 2D or 3D vectors?
Any compiler that claims to implement C++ must support vectors of vectors for a suitable number of dimensions. The syntax can be awkward, so most people end up using wrapper libraries such as boost::multi_array rather than coding it by hand.

I'd like to bump this old thread since 2d arrays are a huge problem for the majority of C/C++ programmers. If one needs the array to be dynamic, the nightmare is there.
This page has good explanations: http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
But it never mentions the real problem, that is, the vector resize when using the standard notation:

my_vector[i][j].push_back(some_value);    // This won't work
my_vector[i][j] = some_value;    // This works

The first assigment would take care of the container population and memory handling, but it won't compile with this syntax.
The second assigment will compile and work, but won't keep track of the vector size and capacity, needing external counters to tell you the right time to resize the container.
Sadly 100% of the tutorials that I found don't use the power of vectors, i.e. memory handling, when it comes to 2d vectors. Instead, they assume one doesn't need to resize the stuff, thus rendering the container useless for this matter.
Anyone would like to discuss it a little further?

I'd like to bump this old thread since 2d arrays are a huge problem for the majority of C/C++ programmers. If one needs the array to be dynamic, the nightmare is there.
This page has good explanations: http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
But it never mentions the real problem, that is, the vector resize when using the standard notation:

my_vector[i][j].push_back(some_value);    // This won't work
my_vector[i][j] = some_value;    // This works

The first assigment would take care of the container population and memory handling, but it won't compile with this syntax.
The second assigment will compile and work, but won't keep track of the vector size and capacity, needing external counters to tell you the right time to resize the container.
Sadly 100% of the tutorials that I found don't use the power of vectors, i.e. memory handling, when it comes to 2d vectors. Instead, they assume one doesn't need to resize the stuff, thus rendering the container useless for this matter.
Anyone would like to discuss it a little further?

The first version doesn't work because you are trying to push onto a third, non-existent dimension. The second works, because you are storing directly to an element of the second dimension.

Fbody, thanks for the input.
What is the correct way to use push_back() with a 2d array of vectors?
The traditional assignment working is unfortunate, because the operator = is not overloaded to take care of memory management.

See post #4... Second code block, lines 12-17. The outer loop populates the first dimension, the inner loop populates the second dimension.

Edited 6 Years Ago by Fbody: n/a

Wow, you got it. I think 2d vector is not easy but now I just realized how can make it an easy way. Good info for me.

I've tried something similar reading from a file, but it collapse.
Could you tell me why, please?
Thanks in advance!

Here's the code:

#include <vector.h>
#include <iomanip>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

main(){
 
 char c; 
 int i=0,j=0,n;
 vector<vector<int> > items;
 
 FILE *archivo;
 archivo = fopen ("listas.dat", "r");
 
    if(archivo == NULL) {
        printf("\nError de apertura del archivo.");
        getchar();
                        }
    else{
            
        while (feof(archivo) == 0)  {
              
        c = fgetc(archivo);
        
        if(c=='\n'){
        items.push_back ( vector<int>() );
        i++;
        }
                
        if(c!=EOF && c!='\n' && c!=' '){   
        items[i].push_back ( atoi(&c) );
        //printf("Dentro del vector tengo: %d\n", items[i][j]);
        getchar();
                }
                                    j++;}//cierre while
    
        }//cierre else              

return 0;
 
        }

Edited 5 Years Ago by Narue: Added code tags

typedef vector< vector< double > > matrix;
typedef vector< double > row;

matrix M;
row R;

/* Add some numbers to a row */
R.push_back( 1 );
R.push_back( 4 );
R.push_back( 2 );

/* Add the row to the matrix */
M.push_back( R );   // Repeat for all your rows

/* Access an element */
double N = M[0][2];

/* Set an element */
M[0][1] = N;

/* Resize a row */
M[0].resize( newSize );

This is not really a complete and proper matrix type, since all the rows are independent and can have different sizes etc. but it's a simple start.

Edited 5 Years Ago by ravenous: n/a

Hialek, at least one problem is in lines 27-30 of your code:

if(c=='\n'){
    items.push_back ( vector<int>() );
    i++;
}

The first time through, you don't have anything in items (assuming you don't have a blank line at the start of your file). The first time you do get a '\n' you add a first item (items[0]) and then immediately increment i so that at line 33 you're referencing items[1], which doesn't exist yet.

An approach like ravenous' will probably save you a lot of headache. Fill a single item object at a time, and when you get to a '\n' push that onto the back of your items vector and create a new item.

Your program is basically C, not really C++. A more C++-like way of doing this might be:

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

int strToInt( const std::string& s ){   return atoi( s.c_str() );   }

int main(){

    std::vector< std::vector< int > > items;

    /* Use a file stream object to access the file */
    std::ifstream archivo;
    archivo.open("listas.dat", std::ios::in);

    /* check if the file opened properly */
    if( archivo.is_open() == false ){
        std::cerr << "\nError de apertura del archivo." << std::endl;
        return 1;
    }

    /* go through the file until we fail to read from it any more */
    while ( archivo.fail() == false ){
        /* Get a line from the file */
        std::string lineFromFile;
        getline( archivo, lineFromFile );

        /* "Tokenize" the contents of the line */
        std::stringstream ss( lineFromFile );
        std::istream_iterator<std::string> it( ss );
        std::istream_iterator<std::string> end;
        std::vector< std::string > itemsOnLine( it, end );  // The contents will end up in here

        /* Convert the strings that were on the line to ints */
        std::vector< int > row( itemsOnLine.size() );       // The result will end up in here
        std::transform( itemsOnLine.begin(), itemsOnLine.end(), row.begin(), strToInt );

        /* Add this row to the matrix */
        items.push_back( row );
    }

    /* Print the results */
    for( std::vector< std::vector< int > >::const_iterator it_row = items.begin();
         it_row != items.end(); ++it_row )
    {
        std::copy( it_row->begin(), it_row->end(), std::ostream_iterator< int >(std::cout, ","));
        std::cout << std::endl;
    }

    return 0;
}

Thanks to all of you.
Every answer was very and really useful and it finally worked.
It's true that my code was basically C, 'cause i was programming on it when I remembered vectors as a way to evade pointers, hehe.
Now I checked my code and i have that C++ way to do it
Well, thanks again, you saved me :)

A lot of "likes" for this forum and its users!

This article has been dead for over six months. Start a new discussion instead.