动态分配数组和静态数组的区别
Posted
技术标签:
【中文标题】动态分配数组和静态数组的区别【英文标题】:Difference between dynamically allocated arrays and static arrays 【发布时间】:2020-09-18 06:50:01 【问题描述】:我正在了解动态内存分配,并且我了解到动态数组(当您不知道用户需要多少个元素/声明用户需要的大小的数组时使用像 int *p = new int[n] \\ where n is the user input describing the number of elements
这样的数组)想要。但是,与其那样做,我们为什么不能像这样声明一个静态数组:
int n;
cout << "Enter the size : " <<endl;
cin>>n;
int a[n];
那么在这种情况下动态数组有什么优势呢?我不理解这个概念。
编辑:感谢您的回答。一些用户回应说不允许通过键入 a[n] 来声明数组。但是,为什么我输入以下代码时我的程序运行良好:
int main()
int n;
cout << "Enter the size : " <<endl;
cin>>n;
int a[n];
cout << "Enter your numbers : " <<endl;
for (int i=0;i<=n;i++)
cin>>a[i];
for (int i=0;i<=n;i++)
cout<<a[i]<<endl;
【问题讨论】:
int a[n];
-- 这不是有效的 C++。
【参考方案1】:
但是,我们为什么不能像这样声明一个静态数组,而不是这样做:
因为语言规则是这样说的。在 C++ 中,所有变量的大小必须在编译时就知道。
请注意,如果您声明这样的数组(如果在编译时已知大小),则该数组将具有自动存储,而不是静态存储。
那么在这种情况下动态数组有什么好处呢?
优点是动态数组的大小不需要在编译时知道。
此外,自动存储的数量通常非常有限,而动态存储则不然。使用自动存储创建大型数组很有可能导致堆栈溢出。
【讨论】:
但是当我编写以下代码时,程序运行良好。为什么会这样?int main() int n; cout >n;整数 [n]; cout >a[i]; for (int i=0;i @Anon123 该程序格式错误。当一个格式错误的程序编译时,通常要么 1. 编译器实现语言扩展,要么 2. 编译器损坏。在这种情况下,它是 1。如果编译器没有发出诊断消息,那么它不符合 C++ 标准。 有时运行良好的程序不是合法的 C++。再举一个例子,从for (int i=0;i<=n;i++)
上面的代码看这个应该是for (int i=0;i<n;i++)
。工作正常绝对不能保证正确。【参考方案2】:
现在,人们已经声明int a[n]
不是有效的c++。但也许我可以为您提供您正在寻找的答案。
那么在这种情况下动态数组有什么好处呢?
语法int a[n]
称为VLA(可变长度数组)。这些在 C++ 中是非法的,但在 C 中是允许的。所以让我们关注技术差异,或者说 VLA 的缺点。
让我们先把显而易见的事情弄清楚。 C89 及之前没有 VLA,因此动态分配是分配可变长度内存的唯一方法。
还有一件事,静态数组甚至 VLA 都分配在堆栈上(虽然这是implementation defined,但通常它会在堆栈上)。而动态数组是在堆上分配的。有关堆栈和堆的更多信息,请阅读this
现在,C++ 中禁止 VLA 是有充分理由的。 VLA 可能会导致各种未定义的行为,应该始终避免,除非您确切知道自己在做什么。 “你确切地知道你在做什么”,我的意思是你知道那个 VLA 的 size 参数不会溢出堆栈。
假设 C++ 中允许使用 VLA,您的代码中的这一行-
cin>>n;
int a[n];
如果用户输入大量的n
,远远超过堆栈大小怎么办?这是有保证的堆栈溢出。注意到问题了吗?与堆相比,堆栈非常小。这也解释了here 和here
而 这 是不惜一切代价避免使用 VLA 的主要原因。尽管 VLA 实际上比前面提到的更繁荣。事实上,我总是随身携带与 VLA 相关的 UB 列表,只是 有那么多问题。
回到我的观点
应该始终避免使用 [VLA],除非您确切知道自己在做什么
老实说,你应该永远使用 VLA,你真的不能,因为那甚至不是标准的 C++。但是堆栈分配通常比堆分配快。虽然不是出于人们可能认为显而易见的原因。阅读this。所以有时,如果您使用 C(不是 C++),唯一安全使用 VLA 的时间是当您知道int a[n]
中n
的最大大小不 溢出堆栈并且 VLA 的声明位于您当前声明它的范围的顶部。 alloca
(在 c99 之前是使用 VLA 的唯一方法)的创建者似乎同意。
摘自here-
你可以使用 alloca() 的形式:
pointer_variable = alloca(表达式);
作为函数最外层块中的表达式语句。
哦,只是为了回答您的编辑:
感谢您的回答。一些用户回应说不允许通过键入 a[n] 来声明数组。但是,为什么当我输入以下代码时我的程序运行良好:
这是因为您的编译器允许这样做。但请记住,标准没有。所以这些东西可以产生好的“它在我的机器上工作!”
【讨论】:
感谢您的精彩解释!【参考方案3】:int a[n];
这一行声明了一个可变长度数组,但这不是 C++ 的一部分。一些编译器将其实现为扩展,但此时它实际上并不是 C++。这将是特定编译器的 C++ 方言。
因此,这甚至不是一个选项(如果您希望您的代码可移植)。
标准建议是使用std::vector<int>
而不是管理自己的内存,所以我建议这样做。 (当然,练习帮助你理解如何进行正确的内存管理并没有错。)
【讨论】:
以上是关于动态分配数组和静态数组的区别的主要内容,如果未能解决你的问题,请参考以下文章