何时在C中使用可变长度数组,但何时使用动态分配?

何时在C中使用可变长度数组,但何时使用动态分配?,c,arrays,malloc,free,c99,C,Arrays,Malloc,Free,C99,我在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);

我在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+免费

      • 一些实用建议:

        • VLA实际上位于空间有限的堆栈上,而
          malloc()
          及其朋友在堆上分配,这可能允许更大的分配。此外,您对该过程有更多的控制,因为
          malloc()
          如果失败,可能会返回
          NULL
          。换句话说,你必须小心VLA,不要在runtine中浪费时间
        • 并非所有编译器都支持VLA,例如Visual Studio。此外,作为可选功能,当定义了
          \uuu STDC\u NO\u VLA\uu
          宏时,允许不支持它们
        根据我的经验(数字程序,如用试除法求素数、Miller-Rabin等),我不会说VLA比
        malloc()
        快。当然,
        malloc()
        调用有一些开销,但似乎更重要的是数据访问效率


        下面是使用GNU/Linux x86-64和GCC编译器进行的一些快速而肮脏的比较。请注意,结果可能因平台而异,甚至可能因编译器版本而异。您可以使用一些基本的数据访问
        malloc()

        prime-trial-gen.c
        : 然后是第二个程序,它使用生成的“素数字典”:

        prime-trial-test.c
        : 编译和运行(VLA版本):


        正如你所说,π(10**7)
        实际上是
        664579
        。请注意,两个执行时间几乎相同。

        VLAs的一个优点是可以将可变尺寸的数组传递给函数,这在处理(大小相同的)矩阵时非常方便,例如:

        int n = 4;
        int m = 5;
        int matrix[n][m];
        // …code to initialize matrix…
        another_func(n, m, matrix);
        // No call to free()
        
        其中:

        void another_func(int n, int m, int matrix[n][m])
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    // …use matrix just like normal…
                    sum += matrix[i][j];
                }
            }
            // …do something with sum…
        }
        
        以及:

        void另一个函数2(int n,int m,int*矩阵)
        {
        整数和=0;
        对于(int i=0;i
        指针向量
        int n=4;
        int m=5;
        int**matrix=malloc(sizeof(*matrix)*n);
        对于(int i=0;i
        以及:

        void另一个函数3(int n,int m,int**matrix)
        {
        整数和=0;
        对于(int i=0;i
        此表单可优化为两种分配:

        int n = 4;
        int m = 5;
        int **matrix = malloc(sizeof(*matrix) * n);
        int *values = malloc(sizeof(*values) * n * m);
        for (int i = 0; i < n; i++)
            matrix[i] = &values[i * m];
        // …code to initialize matrix…
        another_func2(n, m, matrix);
        free(values);
        free(matrix);
        
        int n=4;
        int m=5;
        int**matrix=malloc(sizeof(*matrix)*n);
        int*值=malloc(sizeof(*值)*n*m);
        对于(int i=0;i
        优势弗拉 当您使用VLA时,需要做的簿记工作更少。但是如果您需要处理大小荒谬的数组,
        malloc()
        仍然会得分。如果您小心的话,您可以将VLA与
        malloc()
        等一起使用-例如,请参见。

        malloc()
        一起使用,code与VLA不同,它知道OOM。
        $ 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
        
        $ 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
        
        int n = 4;
        int m = 5;
        int matrix[n][m];
        // …code to initialize matrix…
        another_func(n, m, matrix);
        // No call to free()
        
        void another_func(int n, int m, int matrix[n][m])
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    // …use matrix just like normal…
                    sum += matrix[i][j];
                }
            }
            // …do something with sum…
        }
        
        int n = 4;
        int m = 5;
        int *matrix = malloc(sizeof(*matrix) * n * m);
        // …code to initialize matrix…
        another_func2(n, m, matrix);
        free(matrix);
        
        void another_func2(int n, int m, int *matrix)
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    // …do manual subscripting…
                    sum += matrix[i * m + j];
                }
            }
            // …do something with sum…
        }
        
        int n = 4;
        int m = 5;
        int **matrix = malloc(sizeof(*matrix) * n);
        for (int i = 0; i < n; i++)
            matrix[i] = malloc(sizeof(matrix[i] * m);
        // …code to initialize matrix…
        another_func2(n, m, matrix);
        for (int i = 0; i < n; i++)
            free(matrix[i]);
        free(matrix);
        
        void another_func3(int n, int m, int **matrix)
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    // …use matrix 'just' like normal…
                    // …but there is an extra pointer indirection hidden in this notation…
                    sum += matrix[i][j];
                }
            }
            // …do something with sum…
        }
        
        int n = 4;
        int m = 5;
        int **matrix = malloc(sizeof(*matrix) * n);
        int *values = malloc(sizeof(*values) * n * m);
        for (int i = 0; i < n; i++)
            matrix[i] = &values[i * m];
        // …code to initialize matrix…
        another_func2(n, m, matrix);
        free(values);
        free(matrix);