【问题标题】:How to create variable length array on heap? [duplicate]如何在堆上创建可变长度数组? [复制]
【发布时间】:2017-04-12 16:00:16
【问题描述】:

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

int matrix[rows][cols];

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

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

【问题讨论】:

  • @user3528438 我在特别地询问可变长度数组数据类型。此外,5D,真的吗?
  • 适用于 5D 的内容可以简化为适用于 2D。你试过calloc(sizeof(int[rows][cols]), 1)吗?你买了什么尺寸的?实际上,更相关的是打印rowscolssizeof 表达式的值。它能给你你所需要的吗?问题是“我将结果分配给什么”?
  • @TomášZato 5D?是的,认真的!为什么不呢?
  • @user3528438 我误读了另一篇文章,我认为尺寸是常量(它们是大写的)。
  • 这个问题有多种重复。我刚刚看到一个在过去 6 小时内今天被问到的问题。我标记到那个特定的,因为 1)我使用 VLA 方法回答了它; 2) 5D 是一个独特的关键字,便于查找。然而,VLA 方法有两个版本:1)使用指向 N-D 数组的指针; 2) 使用指向 (N-1)-D 数组的指针并保持顶部维度为指针。前者的优点是将所有维度的大小记录为指针的类型,后者的优点是与常规 N-D 数组的语法相同,而不是 (N+1)-D

标签: c dynamic-memory-allocation calloc variable-length-array


【解决方案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 &amp;&amp; j &amp;&amp; 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

【讨论】:

  • 您可以使用int (*matrix)[rows][cols] = malloc(sizeof *matrix); 更简单地创建matrix,然后在调用set_matrix()print_matrix() 时使用*matrix 而不是matrix
【解决方案2】:

您可以创建一个指向 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(因为表达式 *arr 指的是VLA),而arr在评估 sizeof *arr 时是无效指针。

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

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

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

但是,如果我没有指出这个问题,并为您提供我知道不会导致 UB 的东西,那我就失职了。

【讨论】:

    猜你喜欢
    • 2017-06-02
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多