Large 2D array gives segmentation fault - c++

I am writing some C++ code in Linux where I have declared a few 2D arrays like so:
double x[5000][500], y[5000][500], z[5000][500];
During compilation there is no error. When I execute it says "segmentation fault".
Wen I reduce the size of the array from 5000 to 50, the program runs fine. How can I protect myself against this problem?

If your program looks like this ...
int main(int, char **) {
double x[5000][500],y[5000][500],z[5000][500];
// ...
return 0;
}
... then you are overflowing the stack. The fastest way to fix this is to add the word static.
int main(int, char **) {
static double x[5000][500],y[5000][500],z[5000][500];
// ...
return 0;
}
The second fastest way to fix this is to move the declaration out of the function:
double x[5000][500],y[5000][500],z[5000][500];
int main(int, char **) {
// ...
return 0;
}
The third fastest way to fix this is to allocate the memory on the heap:
int main(int, char **) {
double **x = new double*[5000];
double **y = new double*[5000];
double **z = new double*[5000];
for (size_t i = 0; i < 5000; i++) {
x[i] = new double[500];
y[i] = new double[500];
z[i] = new double[500];
}
// ...
for (size_t i = 5000; i > 0; ) {
delete[] z[--i];
delete[] y[i];
delete[] x[i];
}
delete[] z;
delete[] y;
delete[] x;
return 0;
}
The fourth fastest way is to allocate them on the heap using std::vector. It is fewer lines in your file but more lines in the compilation unit, and you must either think of a meaningful name for your derived vector types or tuck them into an anonymous namespace so they won't pollute the global namespace:
#include <vector>
using std::vector
namespace {
struct Y : public vector<double> { Y() : vector<double>(500) {} };
struct XY : public vector<Y> { XY() : vector<Y>(5000) {} } ;
}
int main(int, char **) {
XY x, y, z;
// ...
return 0;
}
The fifth fastest way is to allocate them on the heap, but use templates so the dimensions are not so remote from the objects:
include <vector>
using namespace std;
namespace {
template <size_t N>
struct Y : public vector<double> { Y() : vector<double>(N) {} };
template <size_t N1, size_t N2>
struct XY : public vector< Y<N2> > { XY() : vector< Y<N2> > (N1) {} } ;
}
int main(int, char **) {
XY<5000,500> x, y, z;
XY<500,50> mini_x, mini_y, mini_z;
// ...
return 0;
}
The most performant way is to allocate the two-dimensional arrays as one-dimensional arrays, and then use index arithmetic.
All the above assumes that you have some reason, a good one or a poor one, for wanting to craft your own multidimensional array mechanism. If you have no reason, and expect to use multidimensional arrays again, strongly consider installing a library:
A plays-nicely-with-STL way is to
use the Boost Multidimensional
Array.
A speed way is to use Blitz++.

These arrays are on the stack. Stacks are quite limited in size. You probably run into a ... stack overflow :)
If you want to avoid this, you need to put them on the free store:
double* x =new double[5000*5000];
But you better start the good habit of using the standard containers, which wrap all this for you:
std::vector< std::vector<int> > x( std::vector<int>(500), 5000 );
Plus: even if the stack fits the arrays, you still need room for functions to put their frames on it.

You may want to try and use Boost.Multi_array
typedef boost::multi_array<double, 2> Double2d;
Double2d x(boost::extents[5000][500]);
Double2d y(boost::extents[5000][500]);
Double2d z(boost::extents[5000][500]);
The actual large memory chunk will be allocated on the heap and automatically deallocated when necessary.

Your declaration should appear at top level, outside any procedure or method.
By far the easiest way to diagnose a segfault in C or C++ code is to use valgrind. If one of your arrays is at fault, valgrind will pinpoint exactly where and how. If the fault lies elsewhere, it will tell you that, too.
valgrind can be used on any x86 binary but will give more information if you compile with gcc -g.

One reservation about always using vector: as far as I understand it, if you walk off the end of the array it just allocates a larger array and copies everything over which might create subtle and hard to find errors when you are really tying to work with a fixed size array. At least with a real array you'll segfault if you walk off the end making the error easier to catch.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
typedef double (*array5k_t)[5000];
array5k_t array5k = calloc(5000, sizeof(double)*5000);
// should generate segfault error
array5k[5000][5001] = 10;
return 0;
}

Looks to me like you have an honest-to-Spolsky stack overflow!
Try compiling your program with gcc's -fstack-check option. If your arrays are too big to allocate on the stack, you'll get a StorageError exception.
I think it's a good bet, though, as 5000*500*3 doubles (8 bytes each) comes to around 60 megs - no platform has enough stack for that. You'll have to allocate your big arrays on the heap.

Another solution to the previous ones would be to execute a
ulimit -s stack_area
to expand the maximum stack.

You may want to try the Multi library for multidimensional arrays (C++17).
#include<multi/array.hpp>
#include<cassert>
namespace multi = boost::multi;
int main() {
using Double2D = multi::array<double, 2>;
Double2D X({5000, 500}, 999.0);
Double2D Y({5000, 500});
Double2D Z({5000, 500});
assert( X.size() == 5000 );
auto [m, n] = X.extensions();
assert( m == 5000 );
assert( n == 500 );
Y = X;
assert( Y[0][0] == 999.0 );
}
https://godbolt.org/z/rh5M463Y1
Similarly to the Boost.MultiArray library (other answer), allocates memory in the heap instead of using (overflowing) the stack.
It provides other features, like assignment and iteration.

Related

Qt not working when my array reach a certain size

For testing purposes, I'm trying different sizes of arrays in Qt.
Here is the code:
#include <QCoreApplication>
#include <iostream>
using namespace std;
int const sizeArray = 519199;
int main()
{
string arr[sizeArray];
for(int i = 0; i < sizeArray; i++)
{
arr[i] = i;
}
arr[499999] = "Test";
cout << arr[499999] << endl;
}
When sizeArray is 519999, the program runs quickly and displays "Test". But when sizeArray is 519200 or more, the program takes longer to run (approx 5s) then finishes without displaying "Test".
Is this a memory limit by the OS or by Qt?
When you write:
string arr[sizeArray];
You're creating an array of std::string type with size sizeArray on the stack. Don't create such big arrays on the stack, as you're going to fill it very quickly; and, you won't be able to do much in your program, as you keep all your local variables on the stack. Use dynamic arrays, such as std::vector or QVector instead.
Here's an example of std::vector:
std::vector<std::string> arr(sizeArray);
Also, don't use C-style arrays. If you want a stack-array that you know the size of, and that it won't be very large (i.e. it shouldn't exhaust the stack), use std::array instead, like so:
const int size_of_the_array = 10;
std::array<std::string, size_of_the_array> arr;
You're probably just getting a stack overflow at string arr[sizeArray];
The array is too big to fit in your program's stack address space.
If you allocate the array on the heap, then it should be fine, assuming your machine has enough memory.
string *arr = new string[sizeArray];
But remember that, once usage of arr is done, it will be required you to delete[] the array as below:
delete[] arr;
As previous answer, you can use vectors too, instead of using large array on Stack. To get better clarity you can check here
Anything other than automatic storage for the data of the array will work fine, though - and that's what you should use instead:
#include <QtCore>
#include <algorithm>
#include <array>
#include <memory>
static constexpr int N = 1000000;
static constexpr size_t pageSize = 4096;
template <typename R> void fill(R &range) {
std::generate(range.begin(), range.end(), [i = 0]() mutable {
return QString::number(i++);
});
qDebug() << *std::prev(std::cend(range));
}
int main() {
static QVector<QString> array1(N);
QVector<QString> array2(N);
QVarLengthArray<QString> array3(N);
auto array4 = std::make_unique<std::array<QString, N>>();//(new std::array<QString, N>);
static_assert(sizeof(array1) < pageSize);
static_assert(sizeof(array2) < pageSize);
static_assert(sizeof(array3) < pageSize);
static_assert(sizeof(array4) < pageSize);
fill(array1);
fill(array2);
fill(array3);
fill(*array4);
}
did you mean that it’s ok when the size is 519199 and not 519999?
anyway to check if it’s limit of the stack try to do it with new.
string *arr = new string[sizeArray]

Why my I can't return an array?

I'm trying to return a pointer to an array from a function but I have an issue. When I try to output like this:
#include <iostream>
using namespace std;
int* Somma_Array(int[],int[],int);
int main()
{
int n;
cin>>n;
int A[n],B[n];
for(int i=0;i<n;i++)cin>>A[i];
for(int i=0;i<n;i++)cin>>B[i];
int *c=Somma_Array(A,B,n);
for(int i=0;i<n*2;i++)cout<<c[i];
}
int* Somma_Array(int v[],int p[],int size)
{
int r[size*2];
for(int i=0;i<size;i++)r[i]=v[i];
for(int i=0;i<size;i++)r[i+size]=p[i];
return r;
}
it prints weird numbers instead of the actual number. I tried to do what this question says but it does not work. It gives me the following warning:
[Warning] address of local variable 'r' returned [enabled by default]
I'm using bloodshed dev-c++.
You define a stack allocated array r, which is destroyed when you exit the function Soma_Array. This is one of the (many) reasons vectors are preferred to plain arrays - they handle allocation and deallocation for you.
#include <vector>
std::vector<int> getArray()
{
std::vector<int> a = {1, 2, 3};
return a;
}
The following:
int r[size*2];
defines r locally. When the function exits (as in the scope of the function expires), r will be destroyed since it is bound to the function's scope. You are likely seeing junk data from the stack frame.
you could fix this by doing the following:
int* r = new int[size * 2];
The variable r will now be heap allocated and exist beyond the scope of the function.
IMPORTANT by doing this, you now must manually free r when you are done with it. So for instance, your calling code will look something like this:
int* result = Somma_Array(v, p, size);
/* ... do stuff ... */
delete[] result;
Since r is an array, note the use of delete[] instead of delete. delete[] is the correct way to destroy arrays.
A Better Alternative
Would std::vector be more what you are after? This is a much safer alternative to hand-rolled arrays. The vector is safer to use, scales automatically as you add elements, and cleans itself up nicely when it leaves scope (assuming you are using a value-type instance). Additionally, vectors can be copied and moved out of functions easily.
You cannot return arrays in C++. Especially, you should not return a pointer to a local array. You can however return a std::vector<int>:
std::vector<int> Somma_Array(int v[], int p[], int size)
{
std::vector<int> r(2 * size);
std::copy(v, v + size, r.begin());
std::copy(p, p + size, r.begin() + size);
return r;
}

2D array as instance variable of class

So if I have a class with a 2D array that I want to initialize with two parameters passed into the constructor, how would I do that, I keep running into errors because it won't let me update the two-d array at all in the constructor.
-- Update from the comments:
In my header file I tried both
int array[][]
and
int **array
and then in the .cpp file in the constructor I'm trying to do
array = new int[arg1][arg2]
Neither declaration of the array in the header file worked.
in the constructor I'm trying to do array = new array[arg1][arg2]
You need to specify the array type, like
array = new int[arg1][arg2];
Note that this works in C++11 only - when using older standards, the second array size needs to be const (which is probably not what you want).
There are also some additional articles discussing the same issue:
Multi-Dimensional Arrays
How to "new" a two-dimension array in C++?
Ideally, since you are using C++ anyway, you should use std::vector as proposed in another answer.
Vectors use a lot of overhead though, don't they? I'm trying to keep my memory use light. –
Start with std::vector. Once your application is running properly from a functional perspective, if you are still concerned about memory usage and/or performance, do benchmarking. If you properly encapsulate your 2D array in a class, you can always change the actual implementation of the array with no impact on the code which uses it.
Technically, if you want to make sure that you have one flat memory area which contains your array, you could use a 1-dimensional array to simulate a 2-dimensional array, like in the following code (just to get you the idea, certainly needs some improvement, especially copy construction and assignment operators are missing):
class Array2D {
private:
int *array;
int size1;
public:
Array2D(int arg1, int arg2) {
size1 = arg1;
array = new int[arg1 * arg2];
}
~Array2D() {
delete[] array;
}
int& at(int i1, int i2) {
return array[i1 * size1 + i2];
}
};
int main() {
Array2D array(10, 10);
array.at(2, 2) = 42;
std::cerr << array.at(2, 2);
return 0;
}
Simplest solution would be:
std::vector<std::vector<VALUE>> arr2(X, std::vector<VALUE>(Y));
Here is an 2d array example with bounds check and custom type, based upon the example from Andreas Fester.
#include <stdexcept>
template <typename T>
class Array2D {
private:
T *array;
unsigned int sizeX;
unsigned int sizeY;
public:
Array2D(unsigned int X, unsigned int Y) {
sizeX = X;
sizeY = Y;
array = new T[X * Y];
}
~Array2D() {
delete[] array;
}
T& at(unsigned int X, unsigned int Y) {
if((X > sizeX) || (Y > sizeY))
throw std::out_of_range("Bla bla");
return array[X * sizeX + Y];
}
};
int main() {
double MyValue;
Array2D<double> *MyArray = new Array2D<double>(10, 100);
MyArray->at(1,1) = 10.1;
MyValue = MyArray->at(1,1);
printf("Array value = %3.3f\n", MyValue);
return 0;
}

Array Initialization from a struct

I was wondering if there was a way to initialize an array out of a variable from a struct. Say you have a struct like this-
struct Test{
int Number;
};
And you wanted to initialize the int Number to become an array.
I've already tried this, and it doesn't work:
Test t1;
t1.Number = new int[3];
t1.Number[3] = 6;
I know ISO C++ forbids resizing arrays, but if there was a way to initialize the integer to be an array, that's not really resizing(isn't it?)
Also, vectors don't work inside of structs. I get a "Vector does not name a type" error.
P.S., I can't do this either:
struct Test{
int Number[5];
};
Because at that time I don't know the size of the array I want.
vector works just fine in structs:
#include <vector>
struct Test {
std::vector<int> Numbers;
};
I'm not sure what you're really trying to do but I think this comes close.
One trick to do this
struct Test {
int Numbers[1];
};
when you initialize the struct, you need to use your own allocation function.
struct Test *NewTest(int sizeOfNumbers) {
return (struct Test*)malloc(sizeof(struct Test) + sizeof(int)*(sizeOfNumbers - 1));
}
then, you will be able to access the numbers by using,
struct Test *test1 = NewTest(10);
test1->Numbers[0]...
test1->Numbers[1]...
test1->Numbers[9]...
The return value of new int[3] is an int* not an int. To make your code work you can do:
struct Test {
int* Number;
};
int main() {
Test t1;
t1.Number = new int[4]; // Note this should be 4 so that index 3 isn't out of bounds
t1.Number[3] = 6;
delete t1.Number;
return 0;
}
However you should really use a std::vector rather than a static array. Vectors work just fine inside structs:
#include <vector>
struct Test {
std::vector<int> Number;
};
int main() {
Test t1;
t1.Number.resize(4);
t1.Number[3] = 6;
return 0;
}
You can use a pointer to int -- i.e.,
struct Test{
int *Number;
};
Then you can assign this at any future time to point to an array of your preferred size:
t.Number = new int[5];
But as other posters have already said, std::vector, with a small "v", works fine; be sure to #include <vector> so the compiler knows what you're talking about.

A way of allocating multidimensional arrays dynamically

salute..
I am learning dynamic allocations for multidimensional arrays in a book and I found some ways for that, And now haven't problem in it.
But the author of the book shows us a way, but it doesn't work correctly. It is this:
pbeans = new double [3][4]; // Allocate memory for a 3x4 array
And this is the error:
error C2440: '=' : cannot convert from 'int (*)[4]' to 'int *'
how should i define pbeans ( if this type of coding is legal)?
and what is the problem exactly?
Regards.
This is covered in my FAQ on arrays:
double (*pbeans)[4];
pbeans = new double[3][4];
// ...
delete[] pbeans;
For the "C declarator impaired", you could make that more readable with a typedef:
typedef double row[4];
row *pbeans;
pbeans = new row[3];
// ...
delete[] pbeans;
But in C++, we prefer RAII containers over raw pointers:
#include <vector>
#include <array>
std::vector<std::array<double, 4> > beans(3);
Note the complete absence of delete[] which makes this solution exception-safe.
You need to allocate each dimension of the array separately:
double **pbeans = new double*[3];
for (int i = 0; i < 3; ++i) {
pbeans[i] = new double[4];
}
Here is a way to do it that allocates the memory contiguously on the heap:
typedef double MyGrid[3][4];
int main(int argc, char* argv[])
{
MyGrid& x = *(reinterpret_cast<Grid*>(new double[12]));
...
x[1][2] = 0.3333;
...
delete[] &x;
return 0;
}
Which you could easily turn into a more generic solution:
template<typename T, int x, int y>
struct Array2D
{
typedef T CArrayType[x][y];
typedef CArrayType& RefType;
static CArrayType& New()
{
return *(reinterpret_cast<CArrayType*>(new T[x * y]));
}
static void Delete(RefType x)
{
delete[] &x;
}
};
typedef Array2D<double, 3, 4> MyGrid;// define your 2d array with 3 rows / 4 columns.
int main(int argc, char* argv[])
{
MyGrid::RefType j = MyGrid::New();
...
j[1][2] = 0.3333;
...
MyGrid::Delete(j);
return 0;
}
The idea is to just generate the elements in 1D (x*y), and cast it to a 2D array. But since array types are value types, you need to deal in pointers-to-arrays. Using a reference makes it almost transparent.
Boost probably has something like this but I don't know boost well enough to say...