简体   繁体   中英

C malloc segmentation fault using a 1-dimensional array

I use malloc to create an array in C. But I got the segmentation fault when I tried to assign random values to the array in 2 loops.

There is no segmentation fault when I assign values to this array in 1 loop. The array size is large. Please see the code I attached. Anyone can give me a hint what is going on here. I am pretty new to C. Thanks a lot in advance.

int n=50000;
float *x = malloc(n*n*sizeof(float));

// there is segmentation fault:
int i, j;
for (i=0; i<n; i++){
   for (j=0; j<n; j++){
       x[i*n+j] = random() / (float)RAND_MAX;
    }
}
// there is no segmentation fault:
int ii;
for (ii=0; ii<n*n; ii++){
        x[ii] = random() / (float)RAND_MAX;
}

int overflow.

50000 * 50000 --> 2,500,000,000 --> more than INT_MAX --> undefined behavior (UB).

First, let us make certain a calculation for the size of this allocation is possible

assert(SIZE__MAX/n/n/sizeof(float) >= 1);

Then with verified wide enough size_t , use size_t math to do the multiplication and use size_t math for array index calculation. Rather than int*int*size_t , do size_t*int*int .

// float *x = malloc(n*n*sizeof(float));

// Uses at least `size_t` math by leading the multiplication with that type.
float *x = malloc(sizeof(float) * n*n);
// or better
float *x = malloc(sizeof *x * n*n); 

for (i=0; i<n; i++){
  for (j=0; j<n; j++){
    x[(size_t)n*i + j] = random() / (float)RAND_MAX;
  }
}

2nd loop did not not "fail" as n*n is not the large value as expected, but likely the same UB value in the allocation.

First off, you're invoking undefined behavior due to signed integer overflow. Assuming an int is 32-bit, the value of 50000*50000 is outsize the range of an int , causing the overflow.

You can fix this by putting sizeof(float) first in the expression. The result of sizeof is a size_t which is unsigned and at least as large as an int . Then when each n is multiplied, it is first converted to size_t thus avoiding overflow.

float *x = malloc(sizeof(float)*n*n);

However, even if you fix this you're asking for too much memory.

Assuming sizeof(float) is 4 bytes, n*n*sizeof(float) is about 10GB of memory. If you check the return value of malloc , you'll probably see that it returns NULL.

You'll need to make your array much smaller. Try n=1000 instead, which will only use about 4MB.

I believe the issue is related to integer overflow:

50,000 * 50,000 = 2.5 Billion

2^31 ~ 2.1 Billion

Thus, you are invoking undefined behavior when calculating the array index. As to why it works for one but not the other, that's just the way it is. Undefined behavior means the compiler (and computer) can do whatever it wants including doing what you expect and crashing the program.

To fix, change the types of i, j, n, and ii to long long from int. That should solve the overflow issue and the segmentation fault.

Edit:

You should also check that malloc returns a valid pointer before you perform operations on the pointer. If malloc fails, you will receive a null pointer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM