This question already has answers here:
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 6 years ago.
Hi i get a weird segmentation fault from this code:
int main(void){
int array1[10000000];
int n = sizeof(array1);
printf("%d \n", n );
return 0;
}
However if i change
int array1[10000000];
to
int array1[1000000]; ( one less zero)
The program works and prints 4000000
I'm running it on Fedora 21(64bits)
Is this because there is a maximum size for array in C? Thank you in advance
int array1[10000000];
is too large for your stack and you overflow your stack whereas
int array1[1000000];
is large, but does not overflow your stack as the array fits in it.
Note that the size of the stack can vary on different systems and can be set to a particular size.
Methods to solve it:
Make the array static.
Make the array global.
Allocate memory on the heap using malloc from stdlib.h:
int *array1;
array1 = malloc(10000000 * sizeof(int));
if(array1 == NULL) /* If `malloc` failed to allocate memory */
{
fputs("Oops! `malloc` failed to allocate memory!\n", stderr);
exit(-1); /* Exit the program with a return value of `-1` ; Requires `stdlib.h` */
}
/* Use the array and after use, free it using */
free(array1);
An additional method to solve it is to increase stack size with setrlimit. Standard size is 8 MB, at least on my Linux.
#include <stdio.h>
#include <errno.h>
#include <sys/resource.h>
static int setstacksize(rlim_t stacksize)
{
struct rlimit rl;
int res;
if ((res = getrlimit(RLIMIT_STACK, &rl)) != 0) {
fprintf(stderr, "getrlimit result = %d, errno = %d\n", res, errno);
return res;
}
if (rl.rlim_cur >= stacksize) return res;
rl.rlim_cur = stacksize;
if ((res = setrlimit(RLIMIT_STACK, &rl)) != 0) {
fprintf(stderr, "setrlimit result = %d, errno = %d\n", res, errno);
}
return res;
}
static int func(void){
int array1[10000000];
int n = sizeof array1;
printf("%d\n", n);
return 0;
}
int main(void){
setstacksize(48 * 1024 * 1024);
func();
return 0;
}
Related
I have a fortran code that I am trying to get to work for my research purposes. The fortran code passes an integer variable and an integer size into a C program that will allocate memory. The code consists of a pointer "iarrays" that point to "arrays(1)". I get a segmentation fault with the following message:
Segmentation Fault
The following is the fortran Code:
subroutine initmem
c-----initial memory setup
pointer ( iarrays , arrays(1) )
c-----allocate pointer memory for blocks and set blocks index pointers
lpoint(0,1) = 0
c-----first call to lpoinst computes storage requirements
call lpoinst
c-----Returns kplast = 1138280 which is the No. of bytes for pointered arrays. I have verified lpoinst works correctly
nwdinc = kplast - lpoint(0,1)
Array lpoint after lpoinst function
c-----nbytaddr = 1
call getmem (lpoint(0,1), (nwdinc*nbytaddr))
c-----Note:getmem is a fortran file only used to check if memory is allocated. I have not included the code in this post.
c-----getmem.F calls C program memalloc(lpoint(0,1), (nwdinc*nbytaddr))
c-----memalloc.c code attached below
c-----value of lpoint(0,1) = -1431465968
c-----second call to lpoinst sets pointers with updated lpoint(0,1).
call lpoinst
Array lpoint after lpoint(0,1) was updated
iarrays = lpoint(0,1)
isize = nwdinc / addrinc
do 100 i=1,isize
arrays(i) = zero
100 continue
return
end
Here is the C program memalloc.c:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#ifdef _CRAY
int MEMALLOC (nextptr, size)
#else
#ifdef POST_UNDERSCORE
int memalloc_ (nextptr, size)
#else
int memalloc (nextptr, size)
#endif
#endif
int *size;
int *nextptr;
{
void *ptr;
printf("Size Address:%d Size Value: %d \n", size, *size);
printf("nextptr Address:%d nextptr Value: %d \n", nextptr, *nextptr);
printf("ptr before hexa: %p ptr before int: %d \n", (void *) ptr, (int *) ptr );
if (*nextptr == NULL) {
if ((ptr = (void *) malloc (*size)) == NULL) {
return(-1);
}
}
else {
if ((ptr = (void *) realloc (*nextptr, *size)) == NULL) {
return(-1);
}
}
printf("ptr after hexa: %p ptr after int: %d \n", (void *) ptr, (int *) ptr );
*nextptr = (int) ptr;
printf("nextptr Address:%d nextptr Value: %d \n", nextptr, *nextptr);
return (0);
}
Print statements in memalloc.c
The pointer iarrays is set to a negative value. Can the value of that pointer be negative? Why is not able to access the memory for arrays(i)? Can someone help me get through this segmentation fault?
Thank you!
I want to allocate some memory to one of the members of a dynamic structure, dynamically. But I don't know what do I do and also, i don't know how to use them after allocating.
This is my code work :
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
struct Sample_Structure {
float *Number_ptr; // This is the pointer to allocate some memory, dynamically.
int Num1;
int Num2;
} *struct_ptr;
struct_ptr = (struct Sample_Structure*) malloc (sizeof (struct Sample_Structure));
if (!struct_ptr)
{
printf("An error occurred while allocating memory.\n");
exit(1);
}
// I don't know what do I write here to allocate some memory to the pointer, "Number_ptr" in the structure
printf("Enter your number 1 and 2 : ");
scanf("%d%d", &struct_ptr->Num1, &struct_ptr->Num2);
system("cls");
printf("Your numbers are %d and %d\n", Struct_ptr->Num1, Struct_ptr->Num2);
return 0;
}
I wrote some comments for you to know where did I want to allocate some memory to the pointer of the structure, "Sample_Structure". Generally, can we do that? If yes, how?
you can allocate memory the for it , the same way you allocated for *struct_ptr
like this
struct_ptr->Number_ptr = (float *) malloc(sizeof(float));.
and when you want to scan data for it you shouldn't use & for it:
scanf("%d%d%f", &struct_ptr->Num1, &struct_ptr->Num2, struct_ptr->Number_ptr);
and in printf you should use * for it:
printf("Your numbers are %d and %d\nand %f\n", struct_ptr->Num1, struct_ptr->Num2, *struct_ptr->Number_ptr);
also you should this capital S to lowercase letter in this printf:
printf("Your numbers are %d and %d\n", struct_ptr->Num1, struct_ptr->Num2);
also note that you don't need to cast for malloc and it's not good to that , unless you're using c++ compiler.
int main()
{
struct Sample_Structure {
float* Number_ptr;
int Num1;
int Num2;
} *struct_ptr;
struct_ptr = (struct Sample_Structure *)malloc(sizeof(struct Sample_Structure));
if (!struct_ptr)
{
printf("An error occurred while allocating memory.\n");
exit(1);
}
struct_ptr->Number_ptr = (float *) malloc(sizeof(float));
printf("Enter your number 1 and 2 : ");
scanf("%d%d%f", &struct_ptr->Num1, &struct_ptr->Num2, struct_ptr->Number_ptr);
system("cls");
printf("Your numbers are %d and %d\nand %f\n", struct_ptr->Num1, struct_ptr->Num2, *struct_ptr->Number_ptr);
return 0;
}
For example, you want to allocate memory for 10 floats for Number_ptr:
struct_ptr->Number_ptr = malloc( sizeof(float) * 10 );
Correction:
Change this line
printf("Your numbers are %d and %d\n", Struct_ptr->Num1, Struct_ptr->Num2);
^ ^
to
printf("Your numbers are %d and %d\n", struct_ptr->Num1, struct_ptr->Num2);
And, you're leaking memory. You need to deallocate memory using free() after use. Make sure for every allocation e.g. malloc(), there is corresponding deallocation e.g. free().
Also, validate if the memory is allocated or not.
Here's a small example for your reference (live):
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define MAX 10
typedef struct S
{
int* ilist;
} S;
int main()
{
S s;
s.ilist = malloc( MAX * sizeof(*s.ilist) ); // allocation
if ( s.ilist == NULL )
{
printf("Unable to allocate memory!\n");
return -1;
}
// An assertion may also be used like this (Header: <assert.h>):
// assert( s.ilist != NULL );
for ( int i = 0; i < MAX; ++i )
{
s.ilist[i] = i + 1; // store elements
}
for ( int i = 0; i < MAX; ++i )
{
printf("%d ", s.ilist[i]); // read elements
}
free( s.ilist ); // deallocation
return 0;
}
Output:
1 2 3 4 5 6 7 8 9 10
I'm trying to reallocate memory for an pointers vector, originally the vector is:
Album* albuns
Where Album is a struct;
I created a function passing the adress of type albuns and the total number of albuns as arguments:
void AddAlbum (int* n_albuns, Album** albuns);
I wanted to reallocate memory for albuns so it could receive another pointer to album, so i did:
int aux = (*n_albuns) + 1;
albuns = (Album**) realloc (albuns,(sizeof(Album*) * aux));
albuns[*n_albuns] = (Album*) malloc (sizeof(Album));
(*n_albuns)++;
but the function returns me a SegFault in this line:
albuns[*n_albuns] = (Album*) malloc (sizeof(Album));
Any ideias? I'm relatively new to memory allocation
There are several issues with the question code. See impeded comments.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Question code should include a model of the structure. */
typedef struct Album_s
{
int a;
char b;
int *c;
char *d;
struct Album_s *e;
} Album;
/* Question indicates: void AddAlbum (int* n_albuns, Album** albuns);
** However, in order to change the size of the array, the address of the
** array must be supplied. Hence, the change from **albuns to ***albuns.
*/
int AddAlbum(int *n_albuns, Album ***albums)
{
int rCode = EXIT_SUCCESS;
void *newMem = NULL;
/* Attempt to increase the size of the array by one (pointer) element.
** The question code casts (Album**) the value returned by realloc(),
** which is not necessary. It is also important to verify that the call
** to realloc() actually succeeded. The realloc code below is fairly
** customary in order to check for this.
*/
newMem = realloc(*albums, sizeof(Album *) * (*n_albuns + 1));
if(!newMem)
{
rCode=errno;
goto CLEANUP;
}
*albums = newMem;
/* Again, the question code casts (Album*) the value returned by malloc(),
** which is not necessary. Being that the albums parameter is a pointer
** to a pointer to a pointer, the following assignment is correct. Again,
** it is important to verify that the call to malloc() actually succeeded.
*/
(*albums)[*n_albuns] = malloc(sizeof(Album));
if(!(*albums)[*n_albuns])
{
rCode=errno;
goto CLEANUP;
}
(*n_albuns)++;
CLEANUP:
return(rCode);
}
/* Example of how AddAlbum() might be called. */
int main(void)
{
int rCode = EXIT_SUCCESS;
Album **albunArray = NULL;
int albunCnt = 0;
int desiredCnt = 10;
while(albunCnt < desiredCnt)
{
rCode=AddAlbum(&albunCnt, &albunArray);
if(rCode)
{
fprintf(stderr, "AddAlbum() failed. errno: %d \"%s\"\n", rCode, strerror(rCode));
goto CLEANUP;
}
printf("Array element %d of %d added.\n", albunCnt, desiredCnt);
}
CLEANUP:
return(rCode);
}
I'm having an issue using two different recursive sum methods, where at some point both fail and return a segmentation fault error. The first, sum_a only fails on high values, passed 260000, which i do not know why, and the second sum_b always fails. Any help would be appreciated.
Thanks
The execution is done as follows : ./sum a x
Where x is the number of recursions wanted for the SUM(1:x) and a is either a or b
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned count=0;
void signal_segv_handler(int sig) {
char s[50];
sprintf(s, "Segmentation fault! count=%u\n", count);
write(2, s, strlen(s));
_exit(1);
}
unsigned long long *sum_b(unsigned long long x) {
unsigned long long *s;
count++;
if (x>0)
*s = *sum_b(x - 1) + x;
else
*s = 0;
return s;
}
unsigned long long sum_a(unsigned long long x) {
count++;
if (x>0)
return sum_a(x - 1) + x;
else
return 0;
}
int main(int argc, char** argv) {
unsigned long long x;
unsigned long long *sum_result;
char result[100];
static char stack[SIGSTKSZ];
stack_t ss = {
.ss_size = SIGSTKSZ,
.ss_sp = stack,
};
struct sigaction sa = {
.sa_handler = signal_segv_handler,
.sa_flags = SA_ONSTACK
};
sigaltstack(&ss, 0);
sigfillset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, 0);
if (argc < 3) {
printf("Please specify the sum function to use (a or b) and the target number of integers to sum.\n");
return -1;
}
x = atoi(argv[2]);
if (strcmp(argv[1], "a") == 0)
sprintf(result, "sum_a = %llu for x=%llu, count=%u \n", sum_a(x), x, count);
else if (strcmp(argv[1], "b") == 0) {
sum_result = sum_b(x);
sprintf(result, "sum_b = %llu for x=%llu, count=%u \n", sum_result, x, count);
free(sum_result);
}
else {
printf("error: function must be a or b\n");
return -1;
}
write(1, result, strlen(result));
return 0;
}
unsigned long long *sum_b(unsigned long long x) {
unsigned long long *s; <------
count++;
if (x>0)
*s = *sum_b(x - 1) + x;
else
*s = 0;
return s;
}
You are using an uninitialized pointer without any mem allocation to store the sum results.
Both sum_a and sum_b cause stack overflow when their iterations consume more memory than available in the stack. Seems like the stack size for your program is 8192KB(you may check it in the console with ulimit -s), one sum_a iteration consumes 32 bytes, and sum_b needs 48 bytes(because of more variables than in sum_a - unsigned long long *s;, and probably 16 byte stack aligning I'm not sure), so they owerflow the stack on ~260k and ~170k iteration respectively.
But sum_b has another point of segfault, here *s = *sum_b(x - 1) + x; and here *s = 0;
this is assigning to an uninitialized pointer (wild pointer, which points to a random memory address). It happens if no stack overflow took place of course(in that case assignment operation in this lines is never reached).
Some remarks not relevant to the question:
You allocate alt stack on the main stack, if which is overflown, your handler is in a bad stance, it still may work in some situations, but you should change static char stack[SIGSTKSZ]; to malloc function.
You should avoid using not signal-safe functions in the signal handler, the list of functions you may find in the signal-safety man.
This line is probably not necessary, you may remove it sigfillset(&sa.sa_mask);
Another segfault: free(sum_result); You should always balance a malloc with a call to free.
I am trying to make a simple example of a array that increases with its input. The input is a series of numbers and the end of this series is a zero. What I thought of was to increase my array every time a new number is read, but for some reason this does not seem to work since I get an error:
Realloc(): invalid pointer
This is my current code:
#include <stdio.h>
#include <stdlib.h>
int *resizeIntArray(int *series, int newSize) {
int *newSeries = realloc(series, newSize * sizeof(int));
if (newSeries == NULL) {
printf("Error: Memory allocation failed");
exit(-1);
}
return newSeries;
}
int main(int argc, char *argv[]) {
int number;
scanf("%d", &number);
int *numbers;
int size = 0;
while (number != 0) {
numbers = resizeIntArray(numbers, size + 1);
printf("%d ", number);
scanf("%d", &number);
size++;
}
}
You are passing an uninitialised variable to your function, in turn passed to realloc, which needs either a pointer to previously allocated memory, or NULL.
So initialise that variable:
int *numbers = NULL;
There are multiple issues in your code:
you do not initialize numbers to NULL, so realloc() invokes undefined behavior the first time it is called. This is causing the problem you observe.
you do not check the return value of scanf(), causing a potential endless loop and undefined behavior if the input stream does not contain a 0 number.
you do not store the number in the reallocated array...
you do not free the array (minor).
you do not return 0 at the end of main() (minor).
Here a simpler and safer version:
#include <stdio.h>
#include <stdlib.h>
int *resizeIntArray(int *series, int newSize) {
int *newSeries = realloc(series, newSize * sizeof(int));
if (newSeries == NULL) {
printf("Error: Memory allocation failed");
exit(-1);
}
return newSeries;
}
int main(int argc, char *argv[]) {
int number;
int *numbers = NULL;
int i, size = 0;
/* reading the numbers */
while (scanf("%d", &number) == 1 && number != 0) {
numbers = resizeIntArray(numbers, size + 1);
numbers[size++] = number;
}
/* printing the numbers */
for (i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
free(numbers);
return 0;
}
You can try an approach like this. This includes:
Memory checking, with appropriate error messages.
use of malloc() and realloc() to allocate and reallocate memory.
Allocates sufficient space when needed on run-time.
Appropriately checks return value of scanf().
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define EXIT 0
void exit_if_null(void *ptr, const char *msg);
int
main(int argc, char const *argv[]) {
int *numbers = NULL;
int number, num_size = 1, count = 0, i;
/* initial allocation of memory */
numbers = malloc(num_size * sizeof(*numbers));
/* small error checking, to be safe */
exit_if_null(numbers, "Initial Allocation");
/* Reading in numbers */
printf("Enter numbers(0 to end): ");
while (scanf("%d", &number) == 1 && number != EXIT) {
/* valid number found, but is there space? */
if (num_size == count) {
num_size *= 2;
/* resize run-time array */
numbers = realloc(numbers, num_size * sizeof(*numbers));
exit_if_null(numbers, "Reallocation");
}
numbers[count++] = number;
}
/* print out numbers */
printf("Your numbers stored in array:\n");
for (i = 0; i < count; i++) {
printf("%d ", numbers[i]);
}
/* free allocated memory, very important */
free(numbers);
return 0;
}
/* helper function for error checking */
void
exit_if_null(void *ptr, const char *msg) {
if (!ptr) {
printf("Unexpected null pointer: %s\n", msg);
exit(EXIT_FAILURE);
}
}
First you should first allocate some memory before reallocate it. So your code will change as:
#include <stdio.h>
#include <stdlib.h>
int *resizeIntArray(int *series, int newSize){
int *newSeries = realloc(series,newSize*sizeof(int));
if(newSeries == NULL){
printf("Error: Memory allocation failed");
exit(-1);
}
return newSeries;
}
int main(int argc, char* argv[]) {
int number;
scanf("%d",&number);
int *numbers=malloc(sizeof(int));///CHANGED
int size = 1;///CHANGED
while(number != 0){
numbers = resizeIntArray(numbers,size +1);
printf("%d ",number);
scanf("%d",&number);
size++;
}
}
But white you are doing is quite not efficent. A realloc() function hides a free() a malloc() and the worst one: memcpy(). So if you realloc() at each new item, you are going to have a bad time... O(n^2) exactly.
the best way to do it is to allocate a buffer of memory:
struct vector
{
int *numbers;
size_t size;
size_t i;
}
#define DEFAULTBUF 100
int main()
{
struct vector v;
v.numbers=malloc(sizeof(int)*DEFAULTBUF);
v.size=DEFAULTBUF;
v.i=0;
scanf("%d",&number);
while(number != 0 && v.numbers){
if (v.i->=v.size)
{ v.size+=v.size
v.numbers=realloc(v.numbers,sizeof(int)*v.size);
///i leave to you the error handling
}
v.i++;
printf("%d ",number);
scanf("%d",&number);
}
}
The correct use of realloc() malloc() and similar is very important. And also the increasing ratio of the resize. For the datastructure I ever double it. For text I proceed linearly