【问题标题】:Creating a variable-sized array without malloc创建没有 malloc 的可变大小数组
【发布时间】:2021-01-23 03:13:03
【问题描述】:

我正在用 C 语言编写一个程序,我想读取一个数组长度,并创建一个该大小的数组。但是,C 不支持可变长度数组,所以我想知道如何做到这一点。我不想更改我的编译器设置。

我正在考虑以某种方式使用预处理器指令来发挥我的优势,但我无法这样做。几乎,我有一个包含我想要的大小的整数变量,我想用 0 声明数组。另外,我不想使用 malloc/其他动态数组方法。

这可能看起来很基本,但我一直在努力做到这一点。如果重要,我将通过 I/O 接收数组大小。

【问题讨论】:

  • 抱歉,我忘了指定 - 我想在没有 malloc 的情况下执行此操作
  • 没有 malloc 就无法做到。要么定义大小编译时间,要么分配内存运行时。
  • 我通过 I/O 接收整数。这有关系吗?
  • 否 - 如果您直到运行时才知道大小,malloc 或其同类之一是您唯一的动态分配方式。
  • 顺便说一句:C 确实支持 VLA(只是 C++ 不支持)...

标签: c


【解决方案1】:

有几种可能的解决方案,但没有一个能满足您的所有要求。

致电malloc 是显而易见的解决方案;这就是它的用途。你说你不想使用malloc,但你没有解释原因。

C 确实支持变长数组——或多或少。 VLA 在 C90 中不存在,在 C99 中引入,在 C11 中成为可选。所以如果你想要可移植的代码,你不能假设它们是受支持的。如果是,您可以执行以下操作:

int size;
// get value of size from input
int vla[size];

有一些限制。如果没有足够的内存(堆栈大小可能比堆大小更受限制),则行为未定义。另一方面,对于普通的固定大小数组也是如此,VLA 可以让你分配更少量的内存,而不是假设一个固定的上限。 VLA 仅存在于块范围内,因此当控制离开封闭块时(通常是函数返回时),对象将不复存在。

您可以定义一个数组(可能在文件范围内,在任何函数定义之外),您知道该数组对于您的数据来说足够大。您必须指定一些上限。例如,您可以定义int arr[10000];,然后拒绝任何大于 10,000 的输入。然后,您可以将该数组的初始子集用于您的数据。

你说你想创建一个“可变大小的数组”,但你“不想使用 malloc/其他动态数组方法”。听起来你想创建一个动态数组,但你不想创建一个动态数组。这就像说你想拧螺丝,但你不想用螺丝刀。

【讨论】:

    【解决方案2】:

    请问:你为什么对 malloc() 过敏?

    我问的原因是,许多为 C 定义安全配置文件的尝试表明 malloc 是万恶之源。在这种情况下:

    int *arr;
    arr = mmap(0, sizeof *arr * N, PROT_READ|PROT_WRITE, MAP_PRIVATE, -1, 0);
    

    【讨论】:

      【解决方案3】:

      你可以做的是读取数组长度,然后生成一个程序的源代码:

      fprintf(outfile, "int main(void) { static int arr[%d]; ...}\n", size);
      

      然后在生成的程序上执行编译器(例如,使用system 函数),并运行生成的可执行文件。

      【讨论】:

      • 您假设目标系统上有一个可用的编译器。
      【解决方案4】:

      任何支持可变长度数组的语言都使用下面的动态内存分配机制来实现该功能。 “C”没有支持真正可变长度数组的语法糖,但它提供了模仿一个所需的所有机制。

      mallocreallocfree 和其他可以很容易地用于处理任何大小和类型元素的数组的动态分配和释放。您可以在内存中分配数据并使用指针返回对调用函数的引用或传递给其他函数。 (另一方面,'C' VLA 的用途有限,如果在堆栈上分配,则无法返回给调用者)。

      因此,您最好的选择(除非您从事嵌入式软件开发)是开始使用“c”动态内存分配。

      【讨论】:

        【解决方案5】:

        但是,C 不支持变长数组,

        错了。这是完全有效的 C 代码:

        #include <stdio.h>
        
        int main(void)
        {
            int size;
            scanf("%d", &size);
            int arr[size];
        }
        

        它被称为 VLA(可变长度数组),自 1999 年以来一直是 C 的一部分。但是,它在 C11 中是可选的,但像 clang 和 gcc 这样的大型编译器永远不会删除它们。至少在可预见的未来不会。

        【讨论】:

        • 它可能在幕后调用 malloc。您无法知道它确实存在、不存在并且没有检测故障的机制。在所有合理的情况下,它不是 C。
        • 不幸的是(1)它是一个必须后退的部分,成为可选的,(2)代码基本上分配了与输入所说的一样多的堆栈,如果这也没有任何方法检测到问题很多。所以“完全有效”有点牵强。
        • @mevets:不太可能使用malloc。生命周期在最里面的封闭块的末尾结束。 VLA 显然打算在堆栈上分配。一个实现可以使用malloc 来分配VLA,但它必须生成额外的代码来在正确的时间调用free,而不管块是如何退出的(gotolongjmp 等)。顺便说一句,VLA 是在 C99 中引入的,在 C11 中是可选的。
        • 一点也不假。 C 的作者非常确定语言本身没有“惊喜”——没有搜索、分配或任何类似的东西。没有任何责任的语言委员会做出了一个糟糕的选择,即引入了一种对语言的性质或意图毫无意义的设施。此外,它们使未来的人能够继续错误决策的传统,直至并包括原子的愚蠢定义。杂散;不。他们不称职,应该被剥夺。
        • @mevets: void func(void) { char big_array[1000000]; /* ... */ } -- 有一个 C 结构会导致您的程序出错,您无法拦截、恢复或避免它。是的,这听起来像 C。
        猜你喜欢
        • 2019-06-28
        • 2013-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-21
        • 2011-09-30
        • 1970-01-01
        相关资源
        最近更新 更多