如何在堆上创建可变长度数组?

How to create variable length array on heap?

我用C的变长数组实现了一个算法:

int matrix[rows][cols];

我设法测试了这对于荒谬的尺寸确实失败了。有没有办法在堆上而不是堆栈上分配这个矩阵?否则我将不得不将其重写为 int**...

类似calloc(sizeof(int[rows][cols]), 1)?请注意,这个问题特别关于可变长度数组。

看起来很简单。唯一棘手的一点是保存指向动态分配数组的指针的类型:

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

static void print_matrix(int r, int c, int matrix[r][c])
{
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
            printf(" %d", matrix[i][j]);
        putchar('\n');
    }
}

static void set_matrix(int r, int c, int matrix[r][c])
{
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
            matrix[i][j] = (i+1) * 100 + j + 1;
    }
}

int main(void)
{
    size_t rows = 9;
    size_t cols = 7;
    size_t size = sizeof(int[rows][cols]);
    printf("rows = %zu, cols = %zu, size = %zu\n", rows, cols, size);
    int (*matrix)[cols] = calloc(sizeof(int[rows][cols]), 1);
    if (matrix != 0)
    {
        set_matrix(rows, cols, matrix);
        print_matrix(rows, cols, matrix);
        free(matrix);
    }
    return 0;
}

此代码小心地使用 calloc() 将数组的所有元素归零,然后调用 set_matrix() 将它们设置为非零值。正如所写,malloc() 会比 calloc() 好,但是问题使用了 calloc() 并且不难让它也适用于此代码(例如,条件赋值在 set_matrix(),例如 if (i && j && i != j)).

示例输出:

rows = 9, cols = 7, size = 252
 101 102 103 104 105 106 107
 201 202 203 204 205 206 207
 301 302 303 304 305 306 307
 401 402 403 404 405 406 407
 501 502 503 504 505 506 507
 601 602 603 604 605 606 607
 701 702 703 704 705 706 707
 801 802 803 804 805 806 807
 901 902 903 904 905 906 907

您可以创建指向 VLA 的指针:

size_t rows, cols;
... // get values for rows and cols
T (*arr)[cols] = malloc( sizeof (T [cols]) * rows );
if ( arr )
{
  ...
  arr[i][j] = some_value; 
  ...
}

是否存在一些争论

T (*arr)[cols] = malloc( sizeof *arr * rows );

应该可以。标准的措辞方式,这种形式导致未定义的行为,因为 sizeof 必须在运行时评估 *arr (因为 expression *arr 引用到 VLA),并且 arr 在计算 sizeof *arr 时是无效指针。

但是,这取决于 "evaluate" 在特定上下文中的含义;没有理由必须 取消引用 arr 来确定它指向的数组的大小,就像固定长度数组一样:

T (*arr)[10] = malloc( sizeof *arr * rows ); 

我和其他一些人认为该标准在这方面措辞不佳,并且 sizeof *arr 应该有效,无论 arr 是否指向固定的 变长数组。这是我使用的成语,它对我没有失败...

但是,如果我不指出这个问题,并向您提供一些我知道不会导致 UB 的东西,那将是我的失职。