tags:

views:

177

answers:

8

I want to write something like 2d strings in C++. I tried with :

vector< vector<string> > table;
        int m,n,i,j;
        string s;
        cin>>n>>m;
        for(i=0;i<n;i++) {
                for(j=0;j<m;j++) {
                        cin>>s;
                        table[i][j] = s;
                }
        }
        cout << "\n\n\n\n";
        for(i=0;i<n;i++) {
                for(j=0;j<m;j++) {
                        cout<<table[i][j]<<" ";
                }
                cout<<"\n";
        }

no compile errors, but when i enter input like:

10 20
.....#..............
.....#..............
.....#..............
.....#..............
######..............
.......###..........
.......#.#..........
.......###...#######
.............#.....#
.............#######

It gives me segmentation fault. Why ? What's wrong ? And how it should be done so it would work correctly ? Thank you.

+7  A: 

The question seems to imply that the data structure needed is a set of n lines with m characters each. There are two ways to think of this -- as an nxm char matrix, or as n m-character vectors (and a string is similar but not identical to vector<char>).

So it seems you don't want a vector of vectors of strings, you want either a vector of vectors of chars, or just a vector of strings.

In any event, you have to allocate the appropriate amount of space before using table[i][j] or (slightly more idiomatic c++, but not necessary in this case since m and n are known beforehand) use something like push_back to add to the end.

Note also that the cin>>s reads an entire line from stdin (which makes the vector<string> solution a bit easier to deal with, I think).

Andrew Jaffe
Not necessarily, consider a grid/table in a spreadsheet with a formula in each cell. That's a 2d array of strings
Martin Beckett
But in this case (i.e., from the sample input) the questioner seems to want a 2d array of chars.
Andrew Jaffe
The problem isn't that he couldn't get away with a `vector<vector<string>>` -- part of the problem is that `cin>>s` is going to read in a whole line at a time. If he wasn't segfaulting, he'd run out of input before he filled everything up.
Ken Bloom
agreed; the point about pre-allocation or push_back is actually more important, although the fact that the questioner didn't really understand the correct data structure implies fuzzy thinking in general!...
Andrew Jaffe
Although it's true that `cin >> s` will read an entire line given the input in the question, it might be worth pointing out that it really only reads up to the first whitespace character - for reading a line even in the presence of whitespace there's the global `std::getline` function.
Mike Dinsdale
+1  A: 

It is an error to index a vector that you haven't inserted into yet.

So taking a more easy example:

std::vector<int> v;
v[0] = 3;//bad, v[0] doesn't exist yet

Correct:

std::vector<int> v;
v.push_back(3);
int x = v[0];//ok

But in your case you are first inserting into a vector and then pushing the whole vector into the other vector.

Brian R. Bondy
+3  A: 

When inserting something new into a vector, you can't just allocate by index - you need to use the push_back method or something similar.

    for(i=0;i<n;i++) {
            vector<string> row;
            for(j=0;j<m;j++) {
                    cin>>s;
                    row.push_back(s);
            }
            table.push_back(row);
    }
Samir Talwar
A: 

You must create vector of elements, to add elements you must use v.insert(v.end(), s). and finnaly (when you have full row data). you must write tables.insert(tables.end(), v)

Svisstack
+1  A: 

I think a vector<vector<char> > would be better suitable for your purposes.

Gabe
+1  A: 

You vectors are still empty and you probably wan't to . You can either append values using e.g. push_back() or init them with a suitable size:

std::cin >> n >> m;
typedef std::vector<std::string> StringVec;
std::vector<StringVec> table(n, StringVec(m));

As others mentioned though, std::string might not be what you really need.

Georg Fritzsche
+1  A: 

The vector class has a ctor that takes the size and an element, so:

vector< vector<char> > table(ROW_COUNT, vector<char>(COLUMN_COUNT, '.'));

would initialize a vector containing ROW_COUNT copies of the vector passed as the second argument, which contains COLUMN_COUNT times ..

nikie
A: 

You need to use char s; cin.get(s); instead of string s; cin>>s;, becuase cin>>s will read a whole word (in your sample this is equivalent to a whole line) at a time.

Additionally, you need to do something to get the size of each array right. In your code you have a vector of 0 vectors of 0 strings. For example:

vector< vector<string> > table;
int m,n,i,j;
char s;
cin>>n>>m;
for(i=0;i<n;i++) {
    table.push_back(vector<string>());
        for(j=0;j<m;j++) {
                cin.get(s);
                table[i].push_back(string(1,s));
        }
}
cout << "\n\n\n\n";
for(i=0;i<n;i++) {
        for(j=0;j<m;j++) {
                cout<<table[i][j]<<" ";
        }
        cout<<"\n";
}
Ken Bloom