C malloc 分割错误使用一维数组



我用malloc在C语言中创建一个数组。但是当我尝试在 2 个循环中为数组分配随机值时,我遇到了分割错误。

当我在 1 个循环中为这个数组赋值时,没有分段错误。数组大小很大。请参阅我附加的代码。任何人都可以给我一个提示,这里发生了什么。我对C很陌生,提前非常感谢。

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溢出。

50000 * 50000 --> 2,500,000,000 --> 超过 INT_MAX 个 -->未定义行为 (UB(。

首先,让我们确定可以计算此分配的大小

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

然后,在验证足够宽的size_t的情况下,使用size_t数学进行乘法,并使用size_t数学进行数组索引计算。 与其int*int*size_t,不如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;
  }
}

第二个循环并没有"失败",因为n*n不是预期的大值,而是分配中的相同 UB 值。

首先,由于有符号整数溢出,您正在调用未定义的行为。 假设int是 32 位,则 50000*50000 的值大于int的范围,从而导致溢出。

您可以通过在表达式中将sizeof(float)放在首位来解决此问题。 sizeof的结果是一个无符号且至少与int一样大的size_t。 然后,当每个n相乘时,首先将其转换为size_t从而避免溢出。

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

但是,即使您修复了此问题,您也会要求太多内存。

假设sizeof(float)是 4 个字节,n*n*sizeof(float)大约是 10GB 的内存。 如果检查 malloc 的返回值,您可能会看到它返回 NULL。

您需要使阵列更小。 尝试改用n=1000,这将仅使用大约 4MB。

我相信

这个问题与整数溢出有关:

5万

*5万=25亿

2^31 ~ 21亿

因此,您在计算数组索引时调用未定义的行为。至于为什么它适用于一个而不是另一个,这就是它的方式。未定义的行为意味着编译器(和计算机(可以做任何它想做的事情,包括做你期望的事情和使程序崩溃。

要修复,请将 i、j、n 和 ii 的类型从 int 更改为 long long。这应该可以解决溢出问题和分段错误。

编辑:

在对指针执行操作之前,还应检查 malloc 是否返回有效的指针。如果 malloc 失败,您将收到一个空指针。

相关内容

  • 没有找到相关文章

最新更新