Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么新的int[n]在int数组[n]无效时有效?_C++_Arrays - Fatal编程技术网

C++ 为什么新的int[n]在int数组[n]无效时有效?

C++ 为什么新的int[n]在int数组[n]无效时有效?,c++,arrays,C++,Arrays,对于以下代码: foo(int n){ int array[n]; } 我理解这是无效的语法,它是无效的,因为C++标准要求在编译时设置数组大小(虽然有些编译器支持以下语法)。 但是,我也理解以下语法是有效的: bar(int n){ int *array = new int[n]; } 我不明白为什么允许这样做,这与创建一个在运行时确定大小的数组不一样吗?这样做是一种很好的做法,或者如果我需要这样做,我应该使用向量吗?int-array[n]在编译时在调用堆栈上分配一个固定

对于以下代码:

foo(int n){
    int array[n];
}

我理解这是无效的语法,它是无效的,因为C++标准要求在编译时设置数组大小(虽然有些编译器支持以下语法)。 但是,我也理解以下语法是有效的:

bar(int n){
    int *array = new int[n];
}

我不明白为什么允许这样做,这与创建一个在运行时确定大小的数组不一样吗?这样做是一种很好的做法,或者如果我需要这样做,我应该使用向量吗?

int-array[n]
在编译时在调用堆栈上分配一个固定长度的数组,因此需要在编译时知道
n
(除非使用特定于编译器的扩展来允许在运行时进行分配,但数组仍在堆栈上)


int*array=new int[n]
在运行时在堆上分配动态长度数组,因此编译时不需要知道
n

在第一种情况下,静态分配内存空间来保存整数。这是在编译程序时完成的,因此存储量是不灵活的

在后一种情况下,您动态分配一个内存空间来保存整数。这是在程序运行时完成的,因此所需的存储量是灵活的


第二个调用实际上是一个函数,它与操作系统对话,以便在内存中找到要使用的位置。在第一种情况下不会发生相同的过程。

这是因为前者在堆栈上分配,后者在堆上分配

当您在堆栈上分配某些内容时,了解对象的大小对于正确构建它是至关重要的。C99允许在运行时指定大小,这会在构建和拆除上述堆栈时带来一些复杂情况,因为您无法在编译时计算其大小。必须按顺序发出机器代码在程序执行过程中执行所述计算,这可能是这个特性不包含在C++标准中的主要原因。 相反,堆没有固定的结构,顾名思义。任何大小的块都可以不按特定顺序分配,只要它们不重叠,并且您有足够的(虚拟)内存。在这种情况下,在编译时知道大小并不重要

另外,请记住,堆栈的大小是有限的,主要是为了在无限递归消耗所有可用内存之前检测它们。通常,该限制固定在1MB左右,并且很少达到该限制。除非您分配大对象,这些对象应该放在堆中

至于您应该使用什么,可能是一个
std::vector
。但它实际上取决于您正在尝试做什么

还请注意,C++11有一个
std::array
类,其大小必须在编译时已知。C++14本应引入
std::dynarray
,但它被推迟了,因为在编译时未知大小的堆栈分配方面还有很多工作要做


出于性能原因,通常按顺序分配块,但这不是必需的


²正如所指出的,知道编译时的大小不是一项困难的要求,但它使事情变得更简单。

您可以在上静态分配内存,也可以在上动态分配内存

在第一种情况下,您的函数包含一个可能具有可变长度的数组声明,但这是不可能的,因为原始数组在编译时必须具有固定的大小,因为它们是在堆栈上分配的。因此,必须将其大小指定为常量,例如
5
。您可以使用类似的方法:

foo(){
    int array[5]; // raw array with fixed size 5
}
使用指针可以为要指向的内存指定可变大小,因为此内存将在堆上动态分配。在第二种情况下,您使用参数
n
指定要分配的内存空间

最后,我们可以说指针不是数组:使用指针分配的内存在堆上分配,而为原始数组分配的内存在堆栈上分配

有一些很好的替代原始数组的方法,例如标准容器,它基本上是一个长度大小可变的容器


确保您能理解动态内存分配和静态内存分配之间的差异,堆栈上分配的内存和堆上分配的内存。

< P>这是因为C++语言没有C99中引入的C特性,称为“可变长度数组”(VLA)。 C++在采用这种C特性方面比较落后,因为它的库中的
std::vector
类型满足了大多数需求

此外,2011年的标准C倒退,使VLA的一个可选功能

简而言之,VLA允许您使用运行时值来确定在自动存储中分配的本地阵列的大小:

int func(int variable)
{
   long array[variable]; // VLA feature

   // loop over array

   for (size_t i = 0; i < sizeof array / sizeof array[0]; i++) {
     // the above sizeof is also a VLA feature: it yields the dynamic
     // size of the array, and so is not a compile-time constant,
     // unlike other uses of sizeof!
   } 
}

与VLA不同的是,此对象将一直存在,直到使用
delete[]
显式销毁为止,并且可以从周围的范围返回。

您的问题的唯一有效答案是,,因为标准如此规定

<> P>与C99相比,C++从不费心指定可变长度数组(VLAS),所以得到可变大小数组的唯一方法是使用动态分配,使用<代码> MalOC/,<代码>新< /C>或其他内存管理器。 < P>在C++的公平性下,运行时大小的栈分配会使堆栈展开变得复杂,这也使得使用该特征的函数异常处理变得更麻烦。 无论如何,即使您的编译器提供C99特性作为扩展,也最好始终严格控制堆栈的使用:
没有办法从破坏堆栈限制中恢复,错误情况只是没有定义
int *p = new int[variable];
unique_ptr<T[]> array{new T[n]};
int array[n]; //valid iff n is compile-time constant, space known at compile-time
int array[n]; //Cannot have a static array with a runtime value in C++
int * array = new int[n]; //This works because it happens at run-time, 
                          // not at compile-time! Different semantics, similar syntax.
new int[n]
int array[n];
typedef int variable_array[n];