0

I use this to allocate a 2D array in cpp:

int s[n][2];

but it seems that when n is very big ( up to 1e6 ), this creates a Runtime error (exitcode: 11).

How to solve this problem?

ssd
  • 83
  • 6
  • 4
    That's not dynamic allocation. – Mysticial Jun 23 '15 at 22:04
  • Globally, or in a function (in which case you run out of stack)? – Jongware Jun 23 '15 at 22:06
  • I made a mistake. I tried to avoid dynamic allocation like new int [], so I used this. So now it's not dynamic any more. – ssd Jun 23 '15 at 22:09
  • @ssd See my answer - there are two issues with your code if `n` is a non-const `int` type. First, it is the size of the data, second, is the C++ language issue. – PaulMcKenzie Jun 23 '15 at 22:17
  • it is dynamic allocation, just not on the heap. – pm100 Jun 23 '15 at 22:18
  • If `n` is a variable, then your C++ compiler is providing an extension called VLA (variable length array). This is from C1999, but it is an optional feature in C2011. – jxh Jun 23 '15 at 22:30
  • Yes, there is always a size limit for allocations. On Unbuntu 14.04 and 15.04, the default thread stack size is 8 MBytes. Yes it can be changed, but I think heap would be more appropriate for anything big. The heap probably provides access to most of the rest of unused ram in your hardware. On my machine, about 3 GBytes. – 2785528 Jun 24 '15 at 00:31

4 Answers4

3

You are allocating on the stack, and you are getting stack overflow.

You need to allocate your 2d array like this

int** ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i)
ary[i] = new int[sizeX];

See How do I declare a 2d array in C++ using new?

Or better yet, use Boost::ublas::matrix or Eigen Vector2d, or as Paul McKenzie suggested, use std::vector (easiest of them all)

Community
  • 1
  • 1
The Vivandiere
  • 3,059
  • 3
  • 28
  • 50
  • If I use this, and say I want to pass ary to some function, how to declare this function's parameter? For int ary[n][2], I can do void f(int [ ][2]), but how about this? Is it the same? – ssd Jun 23 '15 at 22:14
  • Do as Paul McKenzie says, use a `std::vector`. It's quite simple to use. For passing to a function, pass by reference to const. Just read about it, you will see. If you need to update the 2d array, then pass by reference. – The Vivandiere Jun 23 '15 at 22:17
  • @ssd you can pass it in as `void func(int ** ary)`, but be warned that you lose all sizing information. You know where ary is in memory, but have no clue how big it is unless you also pass sizeY with it. – user4581301 Jun 23 '15 at 22:25
3

That is not dynamic allocation. Also, if n is a variable, it isn't even valid ANSI C++, since you cannot declare arrays with a variable number of entries.

To properly allocate dynamically, consider using a std::vector.

#include <vector>
//...
// Simulate s[n]
std::vector<std::vector<int>> s(n, std::vector<int>(2));
//..
// You can now use s similar to a 2 dimensional array.

If for some reason, you require the data to be contiguous for the 2-d array, consider the answers here:

how to create a contiguous 2d array in c++?

Community
  • 1
  • 1
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • I am doing practice problems, STL is prohibited. So I cannot use this method. – ssd Jun 23 '15 at 22:20
  • 1
    `n` can be a variable as long as it is `const`. – NathanOliver Jun 23 '15 at 22:20
  • Also, take a look at the implementation of Boost.MultiArray (http://www.boost.org/doc/libs/1_58_0/libs/multi_array/doc/user.html). It's a bit more complex, but should also be quite educational. – Roger Leigh Jun 23 '15 at 22:39
  • @ssd I doubt that using the C++ standard library would be prohibited for any kind of exercise; if so your teacher has no idea what he/she is doing and you should run far away as fast as you can. – Jonathan H Jun 23 '15 at 23:22
  • @ssd `I am doing practice problems` Is the actual practice problem you're trying to solve a dynamic array problem? I bet it isn't -- it probably is a higher level problem. You just happened to have stumbled into a roadblock when trying to solve the problem, that roadblock being that you can't declare large arrays. The answer given is how you can get past this roadblock so that you can actually move on and solve your real problem. – PaulMcKenzie Jun 24 '15 at 00:22
  • @ssd: Note that even when "STL" is prohibited, you still should use the same pattern and wrap each memory allocation in a class of its own. But I suspect your teacher is a bit behind the times - the STL became redundant 17 years ago! It's succeeded by the Standard Library. (`std::`) – MSalters Jun 24 '15 at 08:23
1

That type of declaration allocated memory on the stack. That's probably too big. Use REAL dynamic allocation (new int[n]).

Amit
  • 45,440
  • 9
  • 78
  • 110
  • what's the difference between this method and new int [] ? – ssd Jun 23 '15 at 22:13
  • If by "*this method*" you're referring to your original code, than the difference as I stated is that you code tried to allocate memory on the stack, and that's too big. – Amit Jun 23 '15 at 22:17
1

As the other said, the "problem" you're having is because you're not using dynamic memory allocation.

@{Straight Line} showed you a C-like solution to create 2d arrays, and @PaulMcKenzie showed you one using vectors and raised the issue of contiguous storage. However, the latter is different because it doesn't constrain the size of the columns (assuming a [row][col] indexing).

The answer of @dasblinkenlight shows you how to create your own 2d array class; I think this is the essence of C++, getting to define yourself how you intend the memory to be managed, and expose a set of publicly accessible methods to interact with this "object" in your code. A 2d array of size n x p is nothing else than np elements indexed by two subscripts, so that's what you should code. Here a close-to-minimal example of how to do that:

#include <new>

template <class T>
class Array2D
{
public:

    Array2D() 
        : m_ptr(NULL)
        { clear() }
    ~Array2D()
        { clear(); }

    void clear() 
    { 
        // free current allocation if any
        if (m_ptr) 
            delete[] m_ptr; 

        // reset member variables
        m_ptr = NULL; 
        m_nrows = m_ncols = 0; 
    }

    inline unsigned nrows() const { return m_nrows; }
    inline unsigned ncols() const { return m_ncols; }

    void set_size( unsigned nr, unsigned nc ) 
    { 
        // clear any previous allocation
        clear(); 

        // new allocation
        m_ptr   = new T[nr*nc];
        m_nrows = nr;
        m_ncols = nc;
    }

    // access elements using [row][col]
    inline T* operator[] ( unsigned row )
        { return &m_ptr[ row*n_cols ]; }

    // access elements using (row,col)
    inline T& operator() ( unsigned r, unsigned c )
        { return m_ptr[ c + n_cols*r ]; }

protected:

    T *m_ptr;
    unsigned m_nrows, m_ncols;
};

If you know you're going to use matrices a lot though, your first reflex should be to check out what already exists. There are many mature C++ libraries that implement 2d arrays (see eg this comparison), dealing with features, issues and optimisations that you do not want to revisit on your own (unless you really know what you're doing or you really need something simple). You just need to find the library that fits your need for each particular application.

Community
  • 1
  • 1
Jonathan H
  • 7,591
  • 5
  • 47
  • 80
  • 1
    If you want to further refine this, I suggest going through the `grid` example in this chapter - http://web.stanford.edu/class/cs106l/course-reader/Ch10_OperatorOverloading.pdf – The Vivandiere Jun 23 '15 at 23:29