Is my 2d array too big? [duplicate] - c++

This question already has answers here:
Large 2D array gives segmentation fault
(8 answers)
Closed 7 years ago.
I run code below and get some strange output:
#include <iostream>
using namespace std;
int main()
{
for(int ll=1444; ll<1450; ++ll)
{
cout<<ll<<endl;
cout<<"###### 0 #######"<<endl;
int mtx[ll][ll];
cout<<"###### 1 #######"<<endl;
}
return 0;
}
The output is:
1444
###### 0 #######
###### 1 #######
1445
###### 0 #######
###### 1 #######
1446
###### 0 #######
###### 1 #######
1447
###### 0 #######
###### 1 #######
1448
###### 0 #######
Segmentation fault
I tried checked one by one with ll's value, when ll reaches 1448, segmentation fault does happen.
Then I changed the array from int to bool, problem disappears.
A calculation based on ll's value:
ll=1447, total space of array is 1447*1447*4 = 8375236 bytes = 8178.95 Kbytes
ll=1448, total space of array is 1448*1448*4 = 8386816 bytes = 8190.25 Kbytes
Could a possible reason be the size of this array is bigger than default page size? (How to check it in Ubunut 14.04..?)
BTW, tried with java and there is no problem.

You are allocating your array into the stack, and the default stack size is usually 8 MB.

What you are doing here is allocating an array of [n][m] on the stack every cycle. Depending on how large the stack is (you can set this, but there are limits) you will eventually run out of memory.
What you want to do is to allocate memory on the heap using the new operator or use a container that will do this for you.
Since you are using C++,
Using STL
#include <vector>
#using std
This creates a vector of vectors, each of dimension ll.
vector<vector<int>> v(ll, vector<int>(ll, 0));
This creates a 1-d vector of the same size as your 2d array. I would typically use this approach because it gets the job done with the least fuss. The drawback here is that you would have to address the vector in the form v[i*ll + j] instead of v[i][j]
vector<int> v(ll*ll, 0)
Without Using STL
This creates an array of arrays on the heap, and is not contiguous. you have to remember to call delete in a loop after you are done with the data structure. This is considered bad because you are creating an array of arrays, which is usually a less efficient data structure as its not contiguous.
int **v = new int *[ll];
for (int i = 0; i < ll; i++)
v[i] = new int[ll];
This creates a contiguous 2d array on the heap, see this for more details
int (*array)[256] = malloc(512 * sizeof *array);
Also see
How do I declare a 2d array in C++ using new?
for creating a 2d array using new
to fix this code I would do the following:
int main()
{
for(int ll=1444; ll<1450; ++ll)
{
cout<<ll<<endl;
cout<<"###### 0 #######"<<endl;
std::vector<int> v(ll * ll, 0);
cout<<"###### 1 #######"<<endl;
}
return 0;
}
code not tested but you get the idea

Related

Memory error at lower limit than expected when implementing Sieve of Eratosthenes in C++

My question is related to a problem described here. I have written a C++ implementation of the Sieve of Eratosthenes that hits a memory overflow if I set the target value too high. As suggested in that question, I am able to fix the problem by using a boolean <vector> instead of a normal array.
However, I am hitting the memory overflow at a much lower value than expected, around n = 1 200 000. The discussion in the thread linked above suggests that the normal C++ boolean array uses a byte for each entry, so with 2 GB of RAM, I expect to be able to get to somewhere on the order of n = 2 000 000 000. Why is the practical memory limit so much smaller?
And why does using <vector>, which encodes the booleans as bits instead of bytes, yield more than an eightfold increase in the computable limit?
Here is a working example of my code, with n set to a small value.
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int main() {
// Count and sum of primes below target
const int target = 100000;
// Code I want to use:
bool is_idx_prime[target];
for (unsigned int i = 0; i < target; i++) {
// initialize by assuming prime
is_idx_prime[i] = true;
}
// But doesn't work for target larger than ~1200000
// Have to use this instead
// vector <bool> is_idx_prime(target, true);
for (unsigned int i = 2; i < sqrt(target); i++) {
// All multiples of i * i are nonprime
// If i itself is nonprime, no need to check
if (is_idx_prime[i]) {
for (int j = i; i * j < target; j++) {
is_idx_prime[i * j] = 0;
}
}
}
// 0 and 1 are nonprime by definition
is_idx_prime[0] = 0; is_idx_prime[1] = 0;
unsigned long long int total = 0;
unsigned int count = 0;
for (int i = 0; i < target; i++) {
// cout << "\n" << i << ": " << is_idx_prime[i];
if (is_idx_prime[i]) {
total += i;
count++;
}
}
cout << "\nCount: " << count;
cout << "\nTotal: " << total;
return 0;
}
outputs
Count: 9592
Total: 454396537
C:\Users\[...].exe (process 1004) exited with code 0.
Press any key to close this window . . .
Or, changing n = 1 200 000 yields
C:\Users\[...].exe (process 3144) exited with code -1073741571.
Press any key to close this window . . .
I am using the Microsoft Visual Studio interpreter on Windows with the default settings.
Turning the comment into a full answer:
Your operating system reserves a special section in the memory to represent the call stack of your program. Each function call pushes a new stack frame onto the stack. If the function returns, the stack frame is removed from the stack. The stack frame includes the memory for the parameters to your function and the local variables of the function. The remaining memory is referred to as the heap. On the heap, arbitrary memory allocations can be made, whereas the structure of the stack is governed by the control flow of your program. A limited amount of memory is reserved for the stack, when it gets full (e.g. due to too many nested function calls or due to too large local objects), you get a stack overflow. For this reason, large objects should be allocated on the heap.
General references on stack/heap: Link, Link
To allocate memory on the heap in C++, you can:
Use vector<bool> is_idx_prime(target);, which internally does a heap allocation and deallocates the memory for you when the vector goes out of scope. This is the most convenient way.
Use a smart pointer to manage the allocation: auto is_idx_prime = std::make_unique<bool[]>(target); This will also automatically deallocate the memory when the array goes out of scope.
Allocate the memory manually. I am mentioning this only for educational purposes. As mentioned by Paul in the comments, doing a manual memory allocation is generally not advisable, because you have to manually deallocate the memory again. If you have a large program with many memory allocations, inevitably you will forget to free some allocation, creating a memory leak. When you have a long-running program, such as a system service, creating repeated memory leaks will eventually fill up the entire memory (and speaking from personal experience, this absolutely does happen in practice). But in theory, if you would want to make a manual memory allocation, you would use bool *is_idx_prime = new bool[target]; and then later deallocate again with delete [] is_idx_prime.

Can you allocate memory for an array already on the heap

int main(){
int * x = new int[3];
for(int i = 0; i < 5; ++i){
x = new int[i];
x[i] = i;
cout << i << endl;
}
}
So say I have an integer array allocated on the heap, with capacity of 3 integers, as seen in x.
Now say I have this for loop where I want to change the values of x into whatever i is.
Now when I run this code by it self it does run, and 0,1,2,3,4 prints like I want.
What I'm wondering is, when I do new int[i] when i is 0, 1, 2, since x[0], x[1], x[2] is already allocated on the heap, am I make three new address in the heap?
Thanks!
int main(){
int * x = new int[3];
for(int i = 0; i < 5; ++i){
x = new int[i];
x[i] = i;
cout << i << endl;
}
}
Running it
-> An array of size 3 is created on the heap
-> An array of size 0 is created on the heap
-> The 0 index of array size 0 is equal to 0
-> Print 0
-> An array of size 1 is created on the heap
-> The 1 index of array size 1 is equal to 1
-> Print 1
.
.
.
-> An array of size 4 is created on the heap
-> The 4 index of array size 4 is equal to 4
-> Print 4
I'm not sure if this is your intention, but as the rest of the comments said, there are memory leaks and undefined behavior.
I think what you're trying to implement is instead
#include <iostream>
#include <vector>
int main()
{
std::vector<int> g1; //initialises a vector called g1
for (int i = 1; i <= 5; i++) {
// Adds i to the vector, expands the vector if
// there is not enough space
g1.push_back(i);
// Prints out i
std::cout<<i<<std::endl;
}
Every time you new something, you are requesting memory and system is allocating a memory block(it may fail, that's another case itself) and giving you a pointer to the initial address of that memory, please remember this when you new something. So here initially you new an array of 3 ints, then in the loop you again new 5 times which returns 5 new memory addresses(which is 5 different memory blocks). So you have 6 new addresses(memory blocks of different sizes) to deal with. It's definitely not the thing you want. So you should use the 1st allocation without any more new in the loop, in that case you should know the bounds of array beforehand. So to make that automatic you can use vector which can grow when you push elements into it.
please refer to this for vector.
a sidenote: when you new something you should take care of that memory yourself, so new is generally not inspired, please look at smart pointers to make your code safe.
Can you allocate memory for an array already on the heap?
Answer: Yes (but not how you are doing it...)
Whenever you have memory already allocated, in order to expand or reduce the allocation size making up a given block of memory, you must (1) allocate a new block of memory of the desired size, and (2) copy the existing block to the newly allocated block (up to the size of the newly allocated block), before (3) freeing the original block. In essence since there is no equivalent to realloc in C++, you simply have to do it yourself.
In your example, beginning with an allocation size of 3-int, you can enter your for loop and create a temporary block to hold 1-int (one more than the loop index) and copy the number of existing bytes in x that will fit in your new tmp block to tmp. You can then delete[] x; and assign the beginning address of the new temporary block of memory to x (e.g. x = tmp;)
A short example continuing from your post could be:
#include <iostream>
#include <cstring>
int main (void) {
int nelem = 3, /* var to track no. of elements allocated */
*x = new int[nelem]; /* initial allocation of 3 int - for fun */
for (int i = 0; i < 5; i++) {
nelem = i + 1; /* update nelem */
/* create temporary block to hold nelem int */
int *tmp = new int[nelem]; /* allocate tmp for new x */
memcpy (tmp, x, i * sizeof *tmp); /* copy i elements to tmp */
delete[] x; /* free x */
x = tmp; /* assign tmp to x */
x[i] = i; /* assign x[i] */
for (int j = 0; j < nelem; j++) /* output all */
std::cout << " " << x[j];
std::cout << '\n';
}
delete[] x; /* free x */
}
(note: on the first iteration zero bytes are copied from x -- which is fine. You can include an if (i) before the memcpy if you like)
Example Use/Output
$ ./bin/allocrealloc
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/allocrealloc
==6202== Memcheck, a memory error detector
==6202== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6202== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6202== Command: ./bin/allocrealloc
==6202==
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
==6202==
==6202== HEAP SUMMARY:
==6202== in use at exit: 0 bytes in 0 blocks
==6202== total heap usage: 7 allocs, 7 frees, 72,776 bytes allocated
==6202==
==6202== All heap blocks were freed -- no leaks are possible
==6202==
==6202== For counts of detected and suppressed errors, rerun with: -v
==6202== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
I'll just throw your code back at you with some comments that hopefully clear things up a bit.
int main()
{
// Allocate memory for three integers on the heap.
int * x = new int[3];
for(int i = 0; i < 5; ++i)
{
// Allocate memory for i (0-4) integers on the heap.
// This will overwrite the x variable allocated earlier.
// What happens when i is zero?
x = new int[i];
// Set the recently allocated array at x[i] to its index.
x[i] = i;
// Print out current index of 0-4.
cout << i << endl;
}
}

Segmentation fault occurs way after index leaves array boundary in C++ [duplicate]

This question already has an answer here:
will Index Out Of Array Bounds throw exception or error before core in C++?
(1 answer)
Closed 5 years ago.
I have this code:
#include <cstdio>
int foo[100];
int main()
{
for(int i=0;i<10000;i++)
foo[i]=10000;
}
Debugging with GDB gives a surprising result:
[New Thread 23684.0x59b4]
[New Thread 23684.0x5c0c]
[New Thread 23684.0x541c]
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401564 in main () at C:\Users\DARREN\Documents\Visual Studio
2017\Projects\Untitled1.cpp:9
warning: Source file is more recent than executable.
9 }
(gdb) print i
$1 = 4080
(gdb)
Now, I know the statement foo[i]=10000 caused the error, but I declared foo to be only of size 100. Why would the value of i be so big before the error occurs?
Any explanation is appreciated.
After you made an update to your question you posted this:
int foo[100];
int main()
{
for(int i=0;i<10000;i++)
foo[i]=10000;
}
And you are asking about segmentation fault.
Here you have an array with a size of 100 and you have a loop that ranges [0,9999] and within the for loop you are indexing the array with the for loops incremental variable i. When you step through the for loop for each iteration of i and you get to:
foo[i] = 10000;
when i <= 99 everything is okay.
What do you suppose happens when i >= 100?
When you use raw arrays there is no bounds checking; and this is something that you and the user will have to be responsible for. If you want automatic bounds checking done for you to prevent this out of bounds memory segmentation fault you should use any of the standard containers such as std::vector<T>, std::list<T>, std::set<T> etc. depending on your needs. If you need to use array index notation then std::vector<T> is the way to go. Or any other vector from any other library such as boost.
EDIT
For you to fix this problem you would have to either increase the size of the array from 100 to 10,000 or you would have to decrease your loop's condition from i<10000 to i<100 to accommodate for proper array indexing. Do not forget that C++ arrays have their starting index at 0 so you would have a basic array and loop as such:
int var[10]; // Uninitialized
for ( int i = 0; i < 10; ++i ) {
var[i] = 0; // Initialize all array indexes to 0
}
Notice that the condition in the for loop is i < 10 which is less than the actual size of the array when it is declared and not i <= 10 less than or equal to for this would also generate a segmentation fault or out of bounds error.

Why can array cells exceed array length [duplicate]

This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 7 years ago.
While debugging I found an error with an int array of 0. In a test document I messed around with array with more cell input than their length.
int array[0];
for(int i = 0; i < 10; i++)
array[i] = i;
for(int i = 0; i < 10; i++)
cout << array[i];
After I compiled and ran the program I got
0123456789
Then I received the message "test.exe has stopped working". I expected both of these, but what I am confused about is why the compiler lets me create an array of 0, and why the program doesn't crash until the very end of the program. I expected the program to crash once I exceeded the array length.
Can someone explain?
The compiler should have at least warned you about a zero size array - if it didn't .. consider changing compiler.
Remember that an array is just a bit of memory just like any other. In your example the array is probably stored on the stack and so writing off the end of it may not cause much of a problem until your function exits. At that point you may find you have written some text over the return address and you get an exception. Writing off the end of arrays are a common cause of bugs in C/C++ - just be thankful you got an error with this one and it didn't just overwrite some other unrelated data.

C array with float data crashing in Objective C class (EXC_BAD_ACCESS)

I am doing some audio processing and therefore mixing some C and Objective C. I have set up a class that handles my OpenAL interface and my audio processing. I have changed the class suffix to
.mm
...as described in the Core Audio book among many examples online.
I have a C style function declared in the .h file and implemented in the .mm file:
static void granularizeWithData(float *inBuffer, unsigned long int total) {
// create grains of audio data from a buffer read in using ExtAudioFileRead() method.
// total value is: 235377
float tmpArr[total];
// now I try to zero pad a new buffer:
for (int j = 1; j <= 100; j++) {
tmpArr[j] = 0;
// CRASH on first iteration EXC_BAD_ACCESS (code=1, address= ...blahblah)
}
}
Strange??? Yes I am totally out of ideas as to why THAT doesn't work but the FOLLOWING works:
float tmpArr[235377];
for (int j = 1; j <= 100; j++) {
tmpArr[j] = 0;
// This works and index 0 - 99 are filled with zeros
}
Does anyone have any clue as to why I can't declare an array of size 'total' which has an int value? My project uses ARC, but I don't see why this would cause a problem. When I print the value of 'total' when debugging, it is in fact the correct value. If anyone has any ideas, please help, it is driving me nuts!
Problem is that that array gets allocated on the stack and not on the heap. Stack size is limited so you can't allocate an array of 235377*sizeof(float) bytes on it, it's too large. Use the heap instead:
float *tmpArray = NULL;
tmpArray = (float *) calloc(total, sizeof(float)); // allocate it
// test that you actually got the memory you asked for
if (tmpArray)
{
// use it
free(tmpArray); // release it
}
Mind that you are always responsible of freeing memory which is allocated on the heap or you will generate a leak.
In your second example, since size is known a priori, the compiler reserves that space somewhere in the static space of the program thus allowing it to work. But in your first example it must do it on the fly, which causes the error. But in any case before being sure that your second example works you should try accessing all the elements of the array and not just the first 100.