135

The following code gives me a segmentation fault when run on a 2Gb machine, but works on a 4GB machine.

int main()
{
   int c[1000000];
   cout << "done\n";
   return 0;
}

The size of the array is just 4Mb. Is there a limit on the size of an array that can be used in c++?

sth
  • 222,467
  • 53
  • 283
  • 367
Mayank
  • 1,481
  • 2
  • 10
  • 4

7 Answers7

154

You're probably just getting a stack overflow here. The array is too big to fit in your program's stack region; the stack growth limit is usually 8 MiB or 1 MiB for user-space code on most mainstream desktop / server OSes. (Normal C++ implementations use the asm stack for automatic storage, i.e. non-static local variables arrays. This makes deallocating them happen for free when functions return or an exception propagates through them.)

If you dynamically allocate the array you should be fine, assuming your machine has enough memory.

int* array = new int[1000000];    // may throw std::bad_alloc

But remember that this will require you to delete[] the array manually to avoid memory leaks, even if your function exits via an exception. Manual new/delete is strongly discouraged in modern C++, prefer RAII.


A better solution would be to use std::vector<int> array (cppreference). You can reserve space for 1000000 elements, if you know how large it will grow. Or even resize it to default-construct them (i.e. zero-initialize the memory, unlike when you declare a plain C-style array with no initializer), like std::vector<int> array(1000000)

When the std::vector object goes out of scope, its destructor will deallocate the storage for you, even if that happens via an exception in a child function that's caught by a parent function.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Charles Salvia
  • 52,325
  • 13
  • 128
  • 140
  • 4
    Thanks for the answer, but could you explain me why arrays are allocated on the stack and why not in the main program memory. – Mayank Dec 04 '09 at 15:51
  • 23
    The given code allocates on the stack because it's specified as an array with a constant number of elements at compile time. Values are only put on the heap with malloc, new, etc. – Seth Johnson Dec 04 '09 at 16:05
  • 7
    All automatic varables are allocated on the stack. If you look at the disasseble you will see the size of your local variables subtracted from the stack pointer. When you call malloc or calloc or any of the memory fuctions the fuctions go and find blocks of memory large enough to sataisfy your reqest. – rerun Dec 04 '09 at 16:12
  • @Charles why we could allocate more memory from heap, not from stack? from my understanding, both stack and heap moves in opposite direction in allocated address space in the memory. – saurabh agarwal Feb 24 '15 at 06:58
  • 2
    @saurabhagarwal The heap doesn't move. It's not even a contiguous memory region. The allocator simply returns a free memory block that fits your size requirement [What and where are the stack and heap?](http://stackoverflow.com/q/79923/995714) – phuclv Jun 23 '15 at 04:45
  • @Charles, one additional question: I reproduced the problem but found out that this is actually a running time error, and if the array is only allocated but not written, the code runs fine. The only time error pops seems to be when initializing their values. What do you think of this? – dragonxlwang Oct 16 '15 at 05:33
63

In C or C++ local objects are usually allocated on the stack. You are allocating a large array on the stack, more than the stack can handle, so you are getting a stackoverflow.

Don't allocate it local on stack, use some other place instead. This can be achieved by either making the object global or allocating it on the global heap. Global variables are fine, if you don't use the from any other compilation unit. To make sure this doesn't happen by accident, add a static storage specifier, otherwise just use the heap.

This will allocate in the BSS segment, which is a part of the heap. Since it's in static storage, it's zero initialized if you don't specify otherwise, unlike local variables (automatic storage) including arrays.

static int c[1000000];
int main()
{
   cout << "done\n";
   return 0;
}

A non-zero initializer will make a compiler allocate in the DATA segment, which is a part of the heap too. (And all the data for the array initializer will take space in the executable, including all the implicit trailing zeros, instead of just a size to zero-init in the BSS)

int c[1000000] = {1, 2, 3};
int main()
{
   cout << "done\n";
   return 0;
}

This will allocate at some unspecified location in the heap:

int main()
{
   int* c = new int[1000000];  // size can be a variable, unlike with static storage
   cout << "done\n";
   delete[] c;            // dynamic storage needs manual freeing
   return 0;
}
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Gunther Piez
  • 29,760
  • 6
  • 71
  • 103
  • 1
    If you use the third pattern, allocating on the heap, don't forget to delete[] the pointer at some stage or you'll leak memory. Or look into smart pointers. – davidA Sep 05 '12 at 01:20
  • 10
    @meowsqueak Of course it is good practice to `delete` everywhere you allocate with `new`. But if you are sure you allocate memory only once (like in main) it is strictly not needed - the memory is guaranteed to be freed at the exit of main even without explicit `delete`. – Gunther Piez Sep 05 '12 at 08:11
  • 'at'drhirsch (how do you do an at-character anyway?) - yes, fair comment. As the OP appears new to the language I just wanted to make sure that they, and anyone else seeing your good answer, were aware of the implications of the third option if used generally. – davidA Sep 05 '12 at 12:19
22

Also, if you are running in most UNIX & Linux systems you can temporarily increase the stack size by the following command:

ulimit -s unlimited

But be careful, memory is a limited resource and with great power come great responsibilities :)

Usman.3D
  • 1,791
  • 3
  • 16
  • 27
RSFalcon7
  • 2,241
  • 6
  • 34
  • 55
  • 2
    This is the solution but I advise all to be extremely cautious when removing this default limits on the program's stack size. You will experience not only severe performance drop but your system might crash. For example I tried to sort an array with 16 000 000 integer elements with quicksort on a machine with 4GB RAM and my system was almost killed. LOL – rbaleksandar Oct 16 '14 at 16:51
  • 1
    @rbaleksandar I think you ~16MB program almost kill your machine because you were working with several copies of the array (may be one per function call?) try a more memory aware implementation ;) – RSFalcon7 Oct 16 '14 at 23:20
  • I'm pretty sure the array handling is okay since I'm passing by reference and not by value. The same thing happens with bubblesort. Hell, even if my implementation of quicksort sucks bubblesort is something that you cannot possibly implement incorrectly. LOL – rbaleksandar Oct 17 '14 at 10:07
  • LOL you could try radix sort, or simply use std::sort :) – RSFalcon7 Oct 17 '14 at 16:54
  • 1
    No chance. It's a lab assignment. :D – rbaleksandar Oct 17 '14 at 17:00
3

You array is being allocated on the stack in this case attempt to allocate an array of the same size using alloc.

rerun
  • 25,014
  • 6
  • 48
  • 78
3

Because you store the array in the stack. You should store it in the heap. See this link to understand the concept of the heap and the stack.

evotopid
  • 5,288
  • 2
  • 26
  • 41
Narek
  • 38,779
  • 79
  • 233
  • 389
1

Your plain array is allocated in stack, and stack is limited to few magabytes, hence your program gets stack overflow and crashes.

Probably best is to use heap-allocated std::vector-based array which can grow almost to size of whole memory, instead of your plain array.

Try it online!

#include <vector>
#include <iostream>

int main() {
   std::vector<int> c(1000000);
   std::cout << "done\n";
   return 0;
}

Then you can access array's elements as usual c[i] and/or get its size c.size() (number of int elements).

If you want multi-dimensional array with fixed dimensions then use mix of both std::vector and std::array, as following:

Try it online!

#include <vector>
#include <array>
#include <iostream>

int main() {
   std::vector<std::array<std::array<int, 123>, 456>> c(100);
   std::cout << "done\n";
   return 0;
}

In example above you get almost same behavior as if you allocated plain array int c[100][456][123]; (except that vector allocates on heap instead of stack), you can access elements as c[10][20][30] same as in plain array. This example above also allocates array on heap meaning that you can have array sizes up to whole memory size and not limited by stack size.

To get pointer to the first element in vector you use &c[0] or just c.data().

Arty
  • 14,883
  • 6
  • 36
  • 69
0

there can be one more way that worked for me! you can reduce the size of array by changing its data type:

    int main()
        {
        short c[1000000];
        cout << "done\n";
        return 0;
        }

or

  int main() 
  {
      unsigned short c[1000000];
      cout << "done\n";
      return 0;
  }