【问题标题】:Dynamically allocating array with the [] operator instead of using malloc?使用 [] 运算符而不是使用 malloc 动态分配数组?
【发布时间】:2021-07-11 12:25:09
【问题描述】:

我确信这已被问过一百万次,但我找不到解释它的答案。有人告诉我永远不要这样做,但我真的不明白为什么。为什么这样的事情不能算作动态分配内存,为什么这么糟糕?

int a;
scanf("%d",&a);
int arr[a];

【问题讨论】:

  • 这不是 [] 运算符,它被称为变长数组

标签: c dynamic-memory-allocation


【解决方案1】:

这不是动态分配,而是一个可变长度数组

这样一个数组的生命周期是它的封闭范围,就像一个固定大小的数组,所以你不需要担心释放。这些数组通常驻留在堆栈上,因此堆栈的大小确实限制了 VLA(或任何数组)的大小。

如果您发现 VLA 对堆栈来说太大,您可以随时回退到使用 malloc

【讨论】:

  • 感谢您的回答,所以这不一定是坏事,只是大多数时候不是很有用?
  • @spiroulis 如果数组不是很大,即 1MB 或更大的大小,这很有用。
【解决方案2】:

使用 [] 运算符而不是使用 malloc 动态分配数组?

这里的[] 用于定义一个数组[]这里,不是运营商。

int arr[a];

有人告诉我永远不要这样做,但我还没有真正理解为什么。

这句话适用于 C(和生活)中的许多事情,在您了解如何使用之前不要使用它。

为什么这样的事情不能算作动态分配内存

它是动态分配内存分配,但通常使用不同的内存池并且具有与通过malloc()不同的生命周期。

...为什么它那么糟糕?

int arr[a]; 是一个变长数组 (VLA),存在以下问题:

  • 并非总是可用。 VLA 在 C99 中支持,并且在以后的版本中经常(但并非总是)支持。研究__STDC_NO_VLA__.

  • 对于int a,代码在a <= 0 时是未定义行为(UB)。

  • a 太大时,没有标准机制来检测内存不足。

VLA 更好地用于受控的较小尺寸的情况。

【讨论】:

  • 对“不同内存池”的小解释:malloc在堆上分配新内存,int arr[a]把数组放到栈上(你的局部变量在哪里)。
【解决方案3】:

首先,让我告诉你,这叫做变长数组,它是一个可选功能。最好不要依赖此功能(或编译器支持)。

另一方面,分配器函数(malloc()free() 和系列)符合标准,任何符合标准的编译器/库都将支持这些函数。

也就是说,other answers 中提到了区别,主要区别在于范围和可移植性。

【讨论】:

  • 感谢您的回答,所以在某些编译器中甚至无法编译?
  • @spiroulis 是的,一些编译器可能不支持 VLA。不完全确定,但 IIRC,Microsoft 编译器不支持 VLA。
  • 许多符合标准的独立编译器支持 VLA 但不支持 malloc,这也是独立实现的可选功能......所以我们应该避免大多数标准 C lib 吗?
  • @Lundin 这取决于您的目标环境。如果您不需要它们,请不要使用它们。我们包含标准头文件,而我们可以手动添加所需的函数原型。
【解决方案4】:

为什么这样的事情不能算作动态分配内存

对象的大小是在运行时确定的,不足以进行动态分配。动态分配需要直接或间接使用专门执行动态内存分配的函数之一,malloccallocrealloc 是主要示例。你的例子...

int arr[a];

... 不这样做,因此对象不是动态分配的。你arr是一个或多或少的普通局部变量,具有变长数组类型。

从语义上讲,动态分配的对象具有“已分配”的存储持续时间,这意味着它们存在并保留其最后存储的值,直到显式解除分配。您的 arr 具有“自动”存储持续时间,这意味着当其最内层包含块的执行终止时,它不再存在。

为什么这么糟糕?

意见不一。 VLA 在 C99 中是必需的功能,但在 C11 中支持是可选的。如果您在代码中使用 VLA,那么您会限制其可移植性。 C++ 不支持它们(或者至少不支持——我知道它们现在也开始使用 C++,而且也许它们已经出现了),这对某些人来说可能是个问题。

然而,引用的主要风险是 VLA 的常规和自然实现是在堆栈上分配它们,而堆栈大小通常比堆空间更有限。在像您这样的幼稚示例中,很容易创建堆栈溢出,这可能取决于用户输入,因此既难以测试又存在潜在的安全风险。

确实不时在我的代码中使用 VLA,但通常以不受上述堆栈破坏风险影响的方式使用。我通常对“永远不要这样做”的告诫持怀疑态度,但实际上我永远不会编写您为生产应用程序提供的确切代码。

【讨论】:

    【解决方案5】:

    这是一个可变长度数组的例子。它的生命周期与任何其他 auto 变量(包括定长数组)相同,因此一旦退出其封闭范围,它的内存就会被释放。

    与固定长度数组不同,VLA 不能在文件范围(任何函数之外)或使用 static 关键字声明,也不能使用初始化程序声明。由于它们通常是如何管理的,它们不能任意大。尽管有名称,但一旦定义它们就无法调整大小 - 可变长度的“变量”仅意味着它们的大小在每次定义时都可以不同。

    VLA 有用但有限。当您需要一些在函数本地的临时工作存储并且不需要太大(不超过 1 兆字节左右)时,它们非常有用。

    它们仅在 C99 中引入,在 C11 中成为可选,因此对它们的支持可能有点参差不齐。

    【讨论】:

      猜你喜欢
      • 2015-08-08
      • 2017-05-29
      • 2013-11-20
      • 1970-01-01
      • 1970-01-01
      • 2015-04-11
      • 2020-08-04
      • 1970-01-01
      • 2018-07-13
      相关资源
      最近更新 更多