我通常用其他语言(R,Python和Java)编写代码,但最近开始使用C++。我一直在 hackerrank.com 解决问题,特别是我遇到了这个问题: https://www.hackerrank.com/challenges/variable-sized-arrays
在这个问题之前,我从来没有遇到过Segmentation Fault
错误。我已经修改了代码,发现错误仅在我尝试从arr
变量打印时才会发生。
我想知道是否有人可以帮助我解决这个问题,并可能提供有关确切错误的详细解释?
代码如下,但问题可能出在int arr[100000][100000] = {-1};
和printf("%dn", arr[iHat][jHat]);
上,因为我可以同时printf
iHat
和jHat
,但我无法使用它们来访问arr
数组中的整数。
#include <iostream>
using namespace std;
int main(){
int n, q;
/*
*scan in:
*n array entries
*q quaries
*/
int arr[100000][100000] = {-1}; //initialize an array, larger than 10^5
scanf("%d %dn", &n, &q); //n is size of array, q is # of quaries
for (int i = 0; i < n; ++i){ //loop through lines of input to populate array
int c, y = 0; //initialize to zero at the start of each line
while((c = getchar()) != 'n'){ //readline
if(c != ' '){ //pass spaces
arr[i][y] = c; //place integer into array
++y;
}
}
}
for (int i = 0; i < q; ++i){
int iHat, jHat = 0;
scanf("%d %dn", &iHat, &jHat); //scan for coordinates
printf("%dn", arr[iHat][jHat]); //Segmentation fault occurs here, why?
}
return 0;
}
更新
这个问题的重点是内存管理,特别是指针的使用。不会导致分段错误的有效解决方案如下:
#include <iostream>
using namespace std;
int main(){
int n, q;
/*
*scan in:
*n array entries
*q quaries
* format: %d %d
*/
scanf("%d %dn", &n, &q);//n is size of array of arrays, q is # of quaries
int **arr = new int *[n]; //int** arr is a pointer of pointers of size n
for (int i = 0; i < n; ++i){//loop through lines of input to populate array
int k; //Always initialize variables in the narrowest scope possible!
scanf("%d", &k);//grab k, the number of ints in the line
arr[i] = new int[k];//create a 2nd dimension at entry i of size k
for (int j = 0; j < k; ++j){
scanf("%d", &arr[i][j]);//populate array
}
}
for (int i = 0; i < q; ++i){
int iHat, jHat = 0;
scanf("%d %dn", &iHat, &jHat); //scan for query coordinates
printf("%dn", arr[iHat][jHat]); //print results of query
}
return 0;
}
C++使您可以控制要分配内存的位置。在您的情况下,您发现您在堆栈上分配了一个超过堆栈大小的整数数组。在某些时候,您访问位于堆栈边界之外的这些元素之一以及程序,这会导致称为分段错误的访问冲突。
既然你提到你是C++的新手,那么了解这 3 个记忆领域以及如何将每个领域用于你的情况会有所帮助:
堆栈内存 - 临时变量无需显式请求即可自动使用的空间。如果超过堆栈大小,您将看到未定义的行为。
int main() {
int arr[100000][100000];
}
堆内存 - 每当使用运算符"new"显式请求时动态分配空间的空间。如果请求的内存大小超过可用大小,则会引发"std::bad_alloc"异常。
int main() {
int **arr = new int *[100000];
for (std::size_t i = 0; i < 100000; ++i) {
arr[i] = new int[100000];
}
}
静态内存 - 在主运行之前为静态对象分配的空间。如果数组维度太大,您将收到编译器错误。
int arr[100000][100000];
int main() {
...
}
那是 40 GB!
即使您在机器中有那么多 RAM,它肯定不会分配为堆栈空间。
如果您确实有那么多内存,则可以在main
之前将arr
移动到全局区域。这样它就不会在堆栈上。
如果您没有40 + GB可用,则可能需要重新考虑解决方案。也许在较小的部分进行计算?
这里有一些想法
1) 您正在尝试分配 100,000 x 100,000 字节,等于堆栈上的 10,000,000,000 字节 (~10GB)。 在 32 位 Linux 上,默认堆栈大小约为 8MB。 即使堆栈大小更大,也不会是 10GB。
2)您正在处理的练习的名称是"可变大小数组"您输入的行,int arr[100000][100000]
是一个固定大小的数组。 您应该使用关键字new
来动态创建数组。
3) 分段错误的原因是因为您的 print 语句试图访问堆栈大小允许的虚拟内存空间之外的内存。
[建议]
1)尝试做一些练习,使用new
和delete
分配和清理动态内存。 同样在C++分配和删除数组的方式与单个数据结构不同。
干杯
你想这样做吗?
#include <iostream>
using namespace std;
int main(){
int n, q;
const int length = 100;
int arr[length][length] = { -1 };
cout << "Enter length of 2d array" << endl;
cin>>n>>q;
cout << "Fill the array" << endl;
for (int i = 0; i < n; ++i) {
for(int y=0;y<q;y++){
int f;
cin >> f;
arr[i][y]=f;
}
}
int iHat;
int jHat;
cout << "Enter coordinates" << endl;
cin>>iHat>>jHat;
cout<<arr[iHat][jHat];
return 0;
}
P.S i 减小了阵列大小,因为 100000 x 100000 这是很多千兆字节,它说数组太大了