0

I am trying to create an array of doubles with 3 million random elements:

#include <iostream>
#include <cstdlib>
#include <random>
#include <ctime>

using namespace std;

int main(int argc, const char * argv[]) {

    // generating random numbers
    mt19937 rng_engine(0); // seed = 0
    uniform_real_distribution<double> dist2(0,10);    

    clock_t begin = clock();

    // create a random 2d array 1 million x 3
    double coords[1000000][3];
    for (int i=0; i<1000000; i++) {
        for (int j= 0; j<3; j++) {
            coords[i][j] = dist2(rng_engine);
            //cout << "i = " << i << ", j = " << j << ", val = " << coords[i][j] << endl;
        }
    }

    clock_t end = clock();
    double elapsed = double(end - begin) / CLOCKS_PER_SEC;

    cout << "elapsed: " << elapsed << endl;

    return 0;
}

When I try to run this in Xcode, I get EXC_BAD_ACCESS (code=2, address=0x7fff5e51bf9c). I tried to compile it and run it in the command line, which gave Segmentation fault: 11. When I change the array size to [100000][3], making the number of elements 300,000, the code runs. What I don't understand is why is it a problem to have 3 million doubles. Wouldn't the array size be 24 MB? (8 bytes * 3,000,000 = 24 MB) What am I missing?

sodiumnitrate
  • 2,899
  • 6
  • 30
  • 49

4 Answers4

2

You're almost certainly overflowing the stack.

Obvious choices to avoid that would be to make the array static (doesn't really change much when it's in main, but typically allocates it differently) or (usually better) use an std::vector instead.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Thanks. I'm really new to this, could you suggest some reading? What difference does `static` make? – sodiumnitrate Oct 23 '15 at 16:53
  • `static` makes it have static lifetime (like a global) instead of lifetime local to the function in which it's defined. In the case of `main`, the difference in lifetime is almost unnoticeable--but it still means it's allocated statically instead of on the stack. – Jerry Coffin Oct 23 '15 at 16:56
1
double coords[1000000][3];

This is way too big for the stack. Use a std::vector instead,

std::vector<double> coords(1000000 * 3); // flatten vector

or

std::vector<std::vector<double>> coords(1000000, std::vector<double>(3));
vsoftco
  • 55,410
  • 12
  • 139
  • 252
0

You need to dynamically allocate huge arrays with malloc or calloc since declared variables are stored in the stack, which has limited size. malloc or calloc allocate heap space instead.

Magisch
  • 7,312
  • 9
  • 36
  • 52
  • There's almost never a good reason to use `malloc` or `calloc` in C++ (and this doesn't seem to be one of the rare cases where it could make some sense). – Jerry Coffin Oct 23 '15 at 16:50
  • @JerryCoffin It works just as well. Im sorry my background is in c programming and I know little of other methods. But I know that malloc and calloc work in c++ – Magisch Oct 23 '15 at 16:51
  • They work, but not even close to "just as well". Just for one obvious example, exception safety is nearly impossible to achieve unless you wrap them in a `vector`-like class. In addition, in C++ they require ugly, error-prone casts. – Jerry Coffin Oct 23 '15 at 16:54
  • @JerryCoffin I guess a vector class is easier since you don't have to worry about freeing them by hand and exception handling. But malloc and calloc definately work in c++, so my answer does solve the asker's problem, just not as easily, no? – Magisch Oct 23 '15 at 16:55
  • They solve this specific problem, at the expense of introducing others in its place, so it's not really fixing the problem, just replacing one problem with several others. – Jerry Coffin Oct 23 '15 at 16:58
  • @JerryCoffin out of curiosity, what would be some of the problems introduced by this other then have to handle freeing and error handling by hand? – Magisch Oct 23 '15 at 16:59
  • You also have to add a cast because they return `void *` and (unlike in C) you can't convert `void *` to other pointer types without a cast. You also end up with readability problems because correct usage isn't just `a = malloc(size);`, but has to always check for it returning a null pointer. That leads to the fact that you're mixing return error codes with exception handling, which tends to be ugly, unreadable, and hard to reason about (not to mention being all too easy to ignore error returns). – Jerry Coffin Oct 23 '15 at 18:28
0

24 mb is way above the typical stack size. You are walking off your stack.

Try allocating dynamically or using a container class (it will internally allocate dynamically).

dtech
  • 47,916
  • 17
  • 112
  • 190