我在C99中找到了有关可变长度数组的信息,但看起来它的行为几乎与malloc + free相同。

我发现的实际差异:

  • 太大的数组处理:
    unsigned size = 4000000000;
    int* ptr = malloc(size); // ptr is 0, program doesn't crash
    int array[size]; // segmentation fault, program crashes
    
  • 内存泄漏:仅在动态数组分配中可能:
    int* ptr = malloc(size);
    ...
    if(...)
        return;
    ...
    free(ptr);
    
  • 对象的生命周期以及从函数返回的可能性:动态分配的数组将一直存在,直到释放内存为止,并且可以从分配了内存的函数中返回。
  • 调整大小:仅在使用指向已分配内存的指针时才可以调整大小。

  • 我的问题是:
  • 还有什么区别(我对实用建议感兴趣)?
  • 程序员使用可变长度数组的两种方式还会遇到什么问题?
  • 什么时候选择VLA,但是何时进行动态数组分配?
  • 什么是更快的:VLA或malloc + free?
  • 最佳答案

    一些实用建议:

    实际上,

  • VLA位于受空间限制的堆栈上,而malloc()及其 friend 则在堆上分配,这很可能会允许更大的分配。此外,您对该进程有更多控制权,因为malloc()如果失败,可能会返回NULL。换句话说,您必须小心使用VLA,不要在runtine中炸毁堆栈。
  • 并非所有编译器都支持VLA,例如视觉工作室。此外,C11 marked them是可选功能,并且在定义__STDC_NO_VLA__宏时不支持它们。

  • 根据我的经验(诸如使用试验除法,Miller-Rabin等查找质数的数字程序),我不会说VLA比malloc()快得多。当然,调用malloc()会有一些开销,但是似乎更重要的是数据访问效率。

    这是一些使用GNU/Linux x86-64和GCC编译器的快速比较。请注意,结果可能因平台,另一个甚至编译器的版本而异。您可以将数据访问malloc()与VLA基准测试作为一些基本的(尽管非常完善)。
    prime-trial-gen.c:
    #include <assert.h>
    #include <stdbool.h>
    #include <stdio.h>
    
    bool isprime(int n);
    
    int main(void)
    {
        FILE *fp = fopen("primes.txt", "w");
        assert(fp);
    
        fprintf(fp, "%d\n", 2);
        for (int i = 3; i < 10000; i += 2)
            if (isprime(i))
                fprintf(fp, "%d\n", i);
        fclose(fp);
        return 0;
    }
    
    bool isprime(int n)
    {
        if (n % 2 == 0)
            return false;
        for (int i = 3; i * i <= n; i += 2)
            if (n % i == 0)
                return false;
        return true;
    }
    

    编译并运行:
    $ gcc -std=c99 -pedantic -Wall -W prime-trial-gen.c
    $ ./a.out
    

    这是第二个程序,它使用生成的“素数字典”:
    prime-trial-test.c:
    #include <assert.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    bool isprime(int n, int pre_prime[], int num_pre_primes);
    int get_num_lines(FILE *fp);
    
    int main(void)
    {
        FILE *fp = fopen("primes.txt", "r");
        assert(fp);
    
        int num_lines = get_num_lines(fp);
        rewind(fp);
    
    #if WANT_VLA
        int pre_prime[num_lines];
    #else
        int *pre_prime = malloc(num_lines * sizeof *pre_prime);
        assert(pre_prime);
    #endif
    
        for (int i = 0; i < num_lines; i++)
            assert(fscanf(fp, "%d", pre_prime + i));
        fclose(fp);
    
        /* NOTE: primes.txt holds primes <= 10 000 (10**4), thus we are safe upto 10**8 */
        int num_primes = 1; // 2
        for (int i = 3; i < 10 * 1000 * 1000; i += 2)
            if (isprime(i, pre_prime, num_lines))
                ++num_primes;
        printf("pi(10 000 000) = %d\n", num_primes);
    
    #if !WANT_VLA
        free(pre_prime);
    #endif
        return 0;
    }
    
    bool isprime(int n, int pre_prime[], int num_pre_primes)
    {
        for (int i = 0; i < num_pre_primes && pre_prime[i] * pre_prime[i] <= n; ++i)
            if (n % pre_prime[i] == 0)
                return false;
        return true;
    }
    
    int get_num_lines(FILE *fp)
    {
        int ch, c = 0;
    
        while ((ch = fgetc(fp)) != EOF)
            if (ch == '\n')
                ++c;
        return c;
    }
    

    编译并运行(malloc版本):
    $ gcc -O2 -std=c99 -pedantic -Wall -W prime-trial-test.c
    $ time ./a.out
    pi(10 000 000) = 664579
    
    real    0m1.930s
    user    0m1.903s
    sys 0m0.013s
    

    编译并运行(VLA版本):
    $ gcc -DWANT_VLA=1 -O2 -std=c99 -pedantic -Wall -W prime-trial-test.c
    ime ./a.out
    pi(10 000 000) = 664579
    
    real    0m1.929s
    user    0m1.907s
    sys 0m0.007s
    

    如您所愿check π(10**7)确实是664,579。请注意,两个执行时间几乎相同。

    关于c - 什么时候在C中使用可变长度数组,但是何时进行动态分配?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27337168/

    10-10 00:07