Search code examples
c++arraysc++11stlstdarray

2-Dimensional std::array woes


I thought I liked the idea of std::array from C++11, but it looks like it has some quarks. I found this out because the following code gives a segmentation fault:

#include<array>
#include<iostream>

int main() {
        std::array<std::array<int*, 5>, 4> sum;

        //Initialize sum array
        std::cout << sum.size() << " " << sum[0].size() << "\n";
        for (size_t i = 0; i < sum.size(); i++) {
                for (size_t j = 0; j < sum[0].size(); j++) {
                        if (i == 0 || j == 0)
                                *(sum[i][j]) = 0;
                        else
                                sum[i][j] = nullptr;
                }
        }

    return 0;
}

This outputs:

4 5
Segmentation fault (core dumped)

sum.size() returns 4, as expected, and sum[0].size() returns 5, as expected; IE it seems like we have an array with 4 rows and 5 columns. However, I get a segmentation fault when I try to execute this program (as shown above). This link suggests that reversing the order of the way I access my array (as in change sum[i][j] to sum[j][i]) should work, but I also get a seg-fault then too. This made me think I might have been doing something wrong with my pointers (I'm a little rusty with my C++), so I changed sum to be an array of integers, so it read as follows:

#include<array>
#include<iostream>

int main() {
        std::array<std::array<int, 5>, 4> sum;

        //Initialize sum array
        std::cout << sum.size() << " " << sum[0].size() << "\n";
        for (size_t i = 0; i < sum.size(); i++) {
                for (size_t j = 0; j < sum[0].size(); j++) {
                        if (i == 0 || j == 0)
                                sum[i][j] = 0; //works as sum[j][i] too!!!
                        else
                                sum[i][j] = 1;

        std::cout << sum[i][j];
                }
     std::cout << "\n";
        }

        std::cout << "here\n";
    return 0;
}

Which works, and outputs:

4 5
00000
01111
01111
01111
here

However, I'm confused, because if I switch the sum[i][j]'s to sum[j][i]'s, it also works and outputs the same thing! I would expect to get a seg-fault when I try sum[5][0] during the final iteration of the inner loop the first time that it is run! I am now willing to call myself hella confused. What is going on?

Extra info: I am using g++ 4.8.4 with the -std=c++11 flag set.


Solution

  • The first snippet doesn't work because you are accessing random memory locations. You declared (essentially) a bidimensional array of (uninitialized) pointers, and in your code you are dereferencing them, which is undefined behavior and very likely to cause a segfault (you are trying to write on random memory locations, which are most likely non mapped in the current virtual address space).

    The second snippet is fine; reversing the two indexes is wrong, but you don't get any error because no explicit bound checking is performed by std::array (or by the compiler on the underlying C arrays). What happens when you get to the invalid index (4 on the first index) is technically still undefined behavior; in practice, you are probably overwriting unrelated variables on the stack, and the program keeps on going by chance.