954,504 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

2D Vector

How do you make a 2D Vector?

Geek-Master
Junior Poster
158 posts since Dec 2004
Reputation Points: 12
Solved Threads: 7
 
#include <vector>

std::vector<std::vector<T> > mat;
Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 

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.

Geek-Master
Junior Poster
158 posts since Dec 2004
Reputation Points: 12
Solved Threads: 7
 

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';
  }
}
Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 

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

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

server_crash
Postaholic
2,111 posts since Jun 2004
Reputation Points: 113
Solved Threads: 20
 

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:

Geek-Master
Junior Poster
158 posts since Dec 2004
Reputation Points: 12
Solved Threads: 7
 

>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.

Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 

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?

saulocpp
Newbie Poster
7 posts since Mar 2010
Reputation Points: 9
Solved Threads: 0
 

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
Posting Maven
2,930 posts since Oct 2009
Reputation Points: 833
Solved Threads: 393
 

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.

saulocpp
Newbie Poster
7 posts since Mar 2010
Reputation Points: 9
Solved Threads: 0
 

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

Fbody
Posting Maven
2,930 posts since Oct 2009
Reputation Points: 833
Solved Threads: 393
 

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.

servicecycle09
Newbie Poster
19 posts since Nov 2009
Reputation Points: 10
Solved Threads: 2
 

you should write
my_vector[i].push_back(element);
not my_vector[i][j].push_back(element);

aayushssinghal
Newbie Poster
2 posts since Mar 2010
Reputation Points: 10
Solved Threads: 0
 

Alternatively :

const int ROW_SIZE = 10;
const int COL_SIZE = 10;

int array2d[ROW_SIZE][COL_SIZE] = {0};
firstPerson
Senior Poster
3,923 posts since Dec 2008
Reputation Points: 841
Solved Threads: 608
 

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;
 
        }
Hialek
Newbie Poster
2 posts since May 2011
Reputation Points: 10
Solved Threads: 0
 
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.

ravenous
Posting Pro
516 posts since Jul 2005
Reputation Points: 269
Solved Threads: 92
 

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 youdo 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.

raptr_dflo
Practically a Master Poster
602 posts since Aug 2010
Reputation Points: 76
Solved Threads: 82
 

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;
}
ravenous
Posting Pro
516 posts since Jul 2005
Reputation Points: 269
Solved Threads: 92
 

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!

Hialek
Newbie Poster
2 posts since May 2011
Reputation Points: 10
Solved Threads: 0
 

This article has been dead for over three months

Post: Markdown Syntax: Formatting Help
You