为什么我们将单维或多维数组的大小声明为常量值?
Why do we declare the size of a single or a multi-dimensional array as a constant value?
自从开始编程竞赛,我发现人们总是习惯于从输入规范的最大值中取一个常量最大值来初始化单维数组或二维数组。
但我一直想知道,当您可以根据输入初始化数组时,为什么人们会这样做。
例如,假设一个问题在接收数组(或向量)大小的输入时具有零到十的五次方的输入规范。
人们为什么这样做:
表示法:整数n
表示输入,a
表示数组:
#include<bits/stdc++.h>
using namespace std;
const int MXN = 1e5;
int a[MXN], n;
int main() {
cin >> n;
for(int i = 0; i<n; i++)
cin >> a[i];
}
而不是这个:
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
int a[n];
for(int i = 0; i<n; i++)
cin >> a[i];
}
或者这是最好的方法(这是我通常做的):
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int>a(n);
for(int i = 0; i<n; i++)
cin >> a[i];
//for(auto &i:a) cin >> i;
}
这样做有什么好处吗?谢谢。
标准要求数组长度是一个在编译时可计算的值,以便编译器能够在堆栈上分配足够的 space。
在您的例子中,您试图将数组长度设置为编译时未知的值。是的,编译器应该知道它似乎很明显,但这里并非如此。编译器无法对非常量变量的内容做出任何假设。
这是我们应该使用常量来声明数组大小的突出原因之一,这样编译器就会知道在创建数组时应该在堆栈上分配多少内存。
对于动态分配,我们可以使用data_type variable = new data_type[len]
格式或vector<>
格式。请注意,C99 支持 VLA(关于您尝试声明数组的方式,如 arr[n]
)。
举个例子,假设如果你告诉编译器
int vla = 100;
int a[vla];
如果不进行大量非常复杂的分析来追踪 vla
的值发生变化的每个最后位置,编译器将无法考虑您在运行时实际需要多少内存.
这3种方法各有优缺点。选择取决于目标。
第一种方法:静态存储时长数组
- 数组在程序执行期间持续存在,
- 内存分配在程序启动时执行(可能由 os),并且非常便宜
- 它不提供值语义。 (不能轻易复制、移动或分配)。
这种方法在小项目中可能对执行速度有好处,但不可扩展。
方法二:栈上分配数组
- 数组生命周期从它的定义开始到块作用域退出结束
- 内存分配是在程序执行期间执行的,并且仅由非常便宜的汇编指令组成。
- 它不提供值语义。 (不能轻易复制、移动或分配)。
- 它是标准语言的编译器扩展。
这种方法对于临时缓冲区来说是一个不错的选择,但同样不可扩展,已知它是堆栈溢出的原因。
第三种方法:动态分配数组,std::vector
- 数组生命周期在需要时开始和结束,
- 内存分配在程序执行过程中进行,相对昂贵
- 它确实提供了值语义。 (可以轻松复制、移动或分配)。
这应该是默认选择。
自从开始编程竞赛,我发现人们总是习惯于从输入规范的最大值中取一个常量最大值来初始化单维数组或二维数组。
但我一直想知道,当您可以根据输入初始化数组时,为什么人们会这样做。
例如,假设一个问题在接收数组(或向量)大小的输入时具有零到十的五次方的输入规范。
人们为什么这样做:
表示法:整数n
表示输入,a
表示数组:
#include<bits/stdc++.h>
using namespace std;
const int MXN = 1e5;
int a[MXN], n;
int main() {
cin >> n;
for(int i = 0; i<n; i++)
cin >> a[i];
}
而不是这个:
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
int a[n];
for(int i = 0; i<n; i++)
cin >> a[i];
}
或者这是最好的方法(这是我通常做的):
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int>a(n);
for(int i = 0; i<n; i++)
cin >> a[i];
//for(auto &i:a) cin >> i;
}
这样做有什么好处吗?谢谢。
标准要求数组长度是一个在编译时可计算的值,以便编译器能够在堆栈上分配足够的 space。
在您的例子中,您试图将数组长度设置为编译时未知的值。是的,编译器应该知道它似乎很明显,但这里并非如此。编译器无法对非常量变量的内容做出任何假设。
这是我们应该使用常量来声明数组大小的突出原因之一,这样编译器就会知道在创建数组时应该在堆栈上分配多少内存。
对于动态分配,我们可以使用data_type variable = new data_type[len]
格式或vector<>
格式。请注意,C99 支持 VLA(关于您尝试声明数组的方式,如 arr[n]
)。
举个例子,假设如果你告诉编译器
int vla = 100;
int a[vla];
如果不进行大量非常复杂的分析来追踪 vla
的值发生变化的每个最后位置,编译器将无法考虑您在运行时实际需要多少内存.
这3种方法各有优缺点。选择取决于目标。
第一种方法:静态存储时长数组
- 数组在程序执行期间持续存在,
- 内存分配在程序启动时执行(可能由 os),并且非常便宜
- 它不提供值语义。 (不能轻易复制、移动或分配)。
这种方法在小项目中可能对执行速度有好处,但不可扩展。
方法二:栈上分配数组
- 数组生命周期从它的定义开始到块作用域退出结束
- 内存分配是在程序执行期间执行的,并且仅由非常便宜的汇编指令组成。
- 它不提供值语义。 (不能轻易复制、移动或分配)。
- 它是标准语言的编译器扩展。
这种方法对于临时缓冲区来说是一个不错的选择,但同样不可扩展,已知它是堆栈溢出的原因。
第三种方法:动态分配数组,std::vector
- 数组生命周期在需要时开始和结束,
- 内存分配在程序执行过程中进行,相对昂贵
- 它确实提供了值语义。 (可以轻松复制、移动或分配)。
这应该是默认选择。