当使用长long数据类型时,malloc()失败

时间:2018-03-11 09:58:17

标签: c malloc

下面的代码打印出[m,n]之间的所有素数。 当我使用unsigned int时,malloc在我的64位系统上正常工作直到10^9

  #include <stdio.h>
  #include <string.h>
  #include <stdbool.h>
  #include <stdlib.h>
  #include <time.h>

  #define true 1 
  #define false 0

  void SieveOfEratosthenes(unsigned int m ,unsigned int n) {
      bool *prime;
      prime = (bool*)malloc(m - n + 2);
      if (!prime) {
          printf("FAIL\n");
          return;
      }
      memset(prime, true, (m - n + 2));
      unsigned int i = 2;
      for (i = 2; i * i <= n; i++) {
          if (prime[i] == true) {
              for (unsigned int j = i * 2; j <= n; j += i)
                  prime[j] = false;
          }
      }
      for (i = m; i <= n; i++)
          if (prime[i] && i != 1)
              printf("%u  \n", i);
  }

  int main() {
      clock_t begin,end;
      unsigned int m, n;
      scanf("%u %u", &m, &n);
      begin = clock();
      SieveOfEratosthenes(m, n);
      end = clock();
      double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
      printf("\nTime Taken : %lf secs\n", time_spent);
      return 0;
  }

但是当我从unsigned int更改为unsigned long long时,对于更大的值,malloc对每个值都会失败,即使对于小值也是如此。为什么这不起作用?

  #include <stdio.h>
  #include <string.h>
  #include <stdbool.h>
  #include <stdlib.h>
  #include <time.h>

  #define true 1 
  #define false 0

  void SieveOfEratosthenes(unsigned long long m, unsigned long long n) {
      bool *prime;
      prime = (bool*)malloc(m - n + 2);
      if (!prime) {
          printf("FAIL\n");
          return;
      }
      memset(prime, true, (m - n + 2));
      unsigned long long i = 2;
      for (i = 2; i * i <= n; i++) {
          if (prime[i] == true) {
              for (unsigned long long j = i * 2; j <= n; j += i)
                  prime[j] = false;
          }
      }
      for (i = m; i <= n; i++)
          if (prime[i] && i != 1)
              printf("%llu  \n", i);
  }

  int main() {
      clock_t begin,end;
      unsigned long long m, n;
      scanf("%llu %llu", &m, &n);
      begin = clock();
      SieveOfEratosthenes(m,n);
      end = clock();
      double time_spent=(double)(end - begin) / CLOCKS_PER_SEC;
      printf("\nTime Taken : %lf secs\n", time_spent);
      return 0;
  }                                                                                                                                                                                                                

1 个答案:

答案 0 :(得分:3)

您的代码因此而具有未定义的行为:

      unsigned int m, n;
      scanf("%llu %llu", &m, &n);

此外,您没有分配适当的内存量:

      prime = (bool*)malloc(m - n + 2);

如果m小于n + 2,则大小变得很大。它只适用于unsigned int,因为您可以在系统上分配4GB或16GB的内存。

事实上,根据您的算法,您必须分配n + 1元素,因为您在筛子期间使用从2开始的数字索引此数组。

此外,对于此数组,您应该使用unsigned char而不是bool,因为类型bool可能大于1个字节。

以下是修改后的版本:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

void SieveOfEratosthenes(unsigned long long m, unsigned long long n) {
    unsigned char *prime = malloc(n + 1);
    if (!prime) {
        printf("FAIL\n");
        return;
    }
    memset(prime, 1, n + 1);
    unsigned long long i, j;
    for (i = 2; i * i <= n; i++) {
        if (prime[i]) {
            for (j = i * 2; j <= n; j += i)
                prime[j] = 0;
        }
    }
    for (i = m; i <= n; i++) {
        if (prime[i] && i != 1)
            printf("%llu\n", i);
    }
}

int main() {
    clock_t begin, end;
    unsigned long long int m, n;
    if (scanf("%llu %llu", &m, &n) == 2) {
        begin = clock();
        SieveOfEratosthenes(m, n);
        end = clock();
        double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
        printf("\nTime Taken : %f secs\n", time_spent);
    }
    return 0;
}

可以对主要候选者和筛子切片使用单独的数组,对于非常大的数量的切片是必要的。尝试为大小为ceil(sqrt(n + 1))的主要候选者分配一个数组并对其进行筛分,而不是为切片分配一个数组,并使用正确的偏移和初始值对其进行筛分,使用第一个的素数阵列。

这是一个天真的实现:

void SieveOfEratosthenes(unsigned long long m, unsigned long long n) {
    unsigned int maxp = (unsigned int)(ceil(sqrt(n)) + 1);
    unsigned char *composite = calloc(maxp, 1);
    unsigned char *slice = calloc(n - m + 1, 1);
    if (!composite || !slice) {
        free(composite);
        free(slice);
        printf("FAIL\n");
        return;
    }
    /* compute the primes */
    unsigned int p, q;
    for (p = 2; p * p < maxp; p++) {
        if (!composite[p]) {
            for (q = p * 2; q < maxp; q += p)
                composite[p] = 1;
        }
    }
    /* sieve the slice */
    unsigned long long i;
    if (m == 0)
        slice[0] = 1;
    if (m <= 1 && n >= 1)
        slice[1 - m] = 1;
    for (p = 2; p < maxp; p++) {
        if (!composite[p]) {
            i = 2 * p;
            if (i < m) {
                i = m - m % p;
                if (i < m)
                    i += p;
            }
            while (i <= n) {
                slice[i - m] = 1;
                i += p;
            }
        }
    }
    for (i = m; i <= n; i++) {
        if (!slice[i - m])
            printf("%llu\n", i);
    }
    free(composite);
    free(slice);
}