我正在学习动态内存分配,我了解到一个动态数组(类似于 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++。但也许我可以帮你解答 你 寻找的。
那么在这种情况下,动态数组的优势是什么呢?
语法 int a[n]
被称为VLA(可变长度阵列)。这些在C++中是非法的,但在C中是允许的。 所以我们把重点放在VLA的技术差异上,或者说是缺点上。
我们先把明显的事情说清楚。C89及以前没有VLA,因此动态分配是分配可变长度内存的唯一方式。
还有一点,静态数组甚至VLA都是在栈上分配的(虽然这是 实施定义,但更多的时候会在堆上)。) 而动态数组是在堆上分配的。关于栈和堆的更多信息,请阅读 这个
现在,在C++中禁止VLAs是有很好的理由的。VLAs可能会导致各种未定义的行为,因此应该是 始终 除非你清楚地知道自己在做什么,否则应避免使用。而 "你确切地知道你在做什么",我的意思是你知道那个VLA的大小参数不会溢出堆栈。
假设 VLAs 是 在C++中是允许的,你的代码中的这行----------。
cin>>n;
int a[n];
如果用户进入大量的 n
比堆栈大小还多?那就是保证堆栈溢出了。注意到问题了吗?与堆相比,栈是非常小的。这一点在下面的文章中也有解释 此处 并 此处
还有 这个 是应该不惜一切代价避免使用VLAs的主要原因。虽然VLAs实际上比上述的繁荣多了。事实上,我总是随身携带一份与 VLAs 相关的 UBs 清单,那里只是 是 那么多问题。
所以回到我的观点
[VLAs]应: 始终 除非你知道自己在做什么,否则就不要去做。
老实说,你应该 从来没有 使用VLAs,你真的不能,因为那甚至不是标准的C++。但堆分配往往比堆分配快。虽然不是因为人们认为明显的原因。阅读 这个. 所以有时候,如果你用的是C(而不是C++),只有当你使用VLA时才是安全的。知道 最大尺寸 n
在 int a[n]
会 不 溢出 和 VLA 的声明在您当前声明的范围的顶部。的创建者 alloca
(在c99之前,这曾经是使用VLA的唯一方式)似乎同意。
摘自 此处-
你可以使用 alloca() 的形式。
pointer_variable = alloca(expression)。
中的表达式语句。最外层的函数块.
哦,只是想回答你的编辑。
谢谢你的回答. 有网友回答说,通过输入a[n]来声明数组是不允许的。但是,为什么我的程序在输入下面的代码时运行正常呢?
这是因为你的编译器允许这样做。但是请记住,标准不允许。所以这类事情会让人产生 "在我的机器上能用!"的好感。
然而,与其这样做,为什么我们不能像这样声明一个静态数组。
因为语言规则是这样规定的 在C++中,所有变量的大小必须在编译时知道。
请注意,如果你这样声明一个数组(如果在编译时知道大小),数组就会有自动存储,而不是静态存储。
那么在这种情况下,动态数组的优势是什么呢?
优点是动态数组的大小不需要在编译时知道。
此外,自动存储的数量通常是非常有限的,而动态存储则不然。用自动存储创建大数组有很大几率造成堆栈溢出。
int a[n];
这一行声明了一个可变长度的数组,但这不是C++的一部分。 有些编译器把它作为扩展来实现,但这时它实际上不是C++的一部分。 它应该是特定编译器的C++方言。
所以,这甚至不是一个选择(如果你希望你的代码是可移植的)。
标准的建议是使用 std::vector<int>
而不是管理自己的内存,所以我建议你这样做。 当然,通过练习来帮助你了解如何进行正确的内存管理是没有错的)。