tags:

views:

168

answers:

6

Possible Duplicate:
C programming, why does this large array declaration produce a segmentation fault?

This is my first time here so sorry if I break some rules or if this has been answered before. I recently made a C program in which I had a matrix of

char buff[NR][1024*1024];

I needed NR = 128. So the program would alocate 128MB. This was in main(). I tried it on a few systems with enough memory with no error on compile. At runtime I recieved segmentation fault on all systems. It worked for NR = 7, but not 8. I moved that code outside of main making it global. It didn't crash anymore even for 128. Does anyone know why this happened? The compiler was GCC

+15  A: 

The problem is you are overflowing the stack which is typically just a few MB in size (the exact size depends on the system and your compiler options). You could allocate the memory on the heap instead using malloc.

Mark Byers
if he's using C, he should probably use malloc.
SB
OP could tell the compiler to use a bigger stack as well (http://stackoverflow.com/questions/156510/increase-stack-size-on-windows-gcc) .. but essentially you are right :)
akira
@SB: Yep, sorry! Fixed now. @akira: I wouldn't recommend increasing the stack size to 128MB.
Mark Byers
Moving the piece of code in and out is not the solution. Problem may be somewhere else. Paste entire source here incase you want exact solution.
Praveen S
Placing the variable outside `main` and making it global as bluntkhan did works just fine too. Are there any C "best practices", so to speak, that discourage that?
JAB
Stack default is 8 megs on Linux and can easily be changed with `ulimit.`. 1 meg seems extremely small... Of course there are no guarantees.
R..
@JAB, yes, global variables are **VERY BAD**. I would say the #1 best practices rule is never to use global variables for anything. (Global const tables are fine of course.) If you need an object that's too big to reliably allocate on the stack, use `malloc`!
R..
@R..: You're right. The code failing between NR = 7 and NR = 8 suggest that the stack size for his system is 8MB.
Mark Byers
Thanks for the prompt response.Don't know why I thought that main() wasn't put in the stack.I didn't use malloc because I knew how much I needed.It was just a curiosity. Thanks
bluntkhan
Or even in static memory by adding `static` storage class qualifier.
atzz
@Mark Byers: neither would i.
akira
@atzz: +1 for a great comment. No need to bother with malloc() since this is in main(). Static is a nice solution to not making the variable global but keeping it off of the stack.
tomlogic
A: 

The segmentation fault probably had another reason. Use a debugger such as gdb to determine where exactly the segmentation fault happened.

Sjoerd
-1: No, the program almost definitely crashed because of that line. That code is pretty much always going to result in crashes, usually with a stack overflow error or segmentation fault, depending on the compiler.
Brian
It was just beacuse of that line. When I commented it out it would run normally.
bluntkhan
If you commented it out and it ran normally, what exact effect did this have?
DeadMG
I don't understand exactly what you're asking. I removed the line from the code and the program didn't cause a segmentation fault.
bluntkhan
+5  A: 

When you put it in main() it allocates the 128MB on the stack, and the stack is usually limited, with the limit varying from system to system. Some might allow you only 8MB, others as much as you can take -- your limit seems to be 8MB, which is standard for most Linux platforms. If this is a POSIX-like environment, you could try controlling the limit with ulimit -s.

When you take the declaration out of main() and make it static it will end up in the BSS segment (unless you initialize it), and be constrained only by heap space on most systems (which is usually very large and/or unlimited). See http://en.wikipedia.org/wiki/Data_segment

However, if you want it locally and ad hoc, consider allocating the NR megabytes yourself:

#define MB (1024*1024)
char *bufp = malloc(NR*MB)
char *buf[NR];
int i;

for (i = 0; i < NR; i++)
  buf[i] = bufp + i*MB;

You could also allocate each MB chunk separately, but I did it this way in case you want the whole area to be contiguous in memory. Remember to free(bufp) when you're done if you're writing a library of if your program will move on to do something else.

integer
+1 for qualifying the remark about `free()` with "if you're writing a library of if your program will move on to do something else."
R..
@R..: easy to please. :-)
integer
A: 

Or you can increase stack allocation size for your programm. For example in VS 2008 go to Project Properties -> Linker -> and set Stack Commit Size.

southerton
I disagree with this idea (but I won't downvote you). The stack is not an appropriate location for huge amounts of data.
tomlogic
+1  A: 

Your array is allocated on stack. Stack has limited size (depends on os and linker settings). I think default stack size is approximately 1 megabyte for win32(msvc compiler), and 8 megabytes for linux(gcc). Anything larger than that will cause stack overflow, which will cause instant segfault.

Possible solutions:

  1. Increase stack size in linker settings.
  2. Allocate memory dynamically (using malloc).
  3. Make array global.
  4. Make array static.

Making variable global/static will cause (on compilers I've seen, at least) it to be allocated outside of stack - either in data or code segment, which will not affect stack size.

SigTerm
A: 

You can use malloc, you can often also declare it outside of main using file scope. If you need it in another c file look into using extern. This method is not recommended unless you have a really good reason to have a file scoped variable (note c does not really have "global" variables, just file scope ones that you can access with extern). Google is your friend on these techniques as well :) . You can also usually find the setting for maximum stack size that goes along with your compiler/OS. Look for "set stack size ". Again not recommended, learn to use malloc :) .