寻找最优服务器的C++代码本地正常,大学服务器报段错误求助
我帮你分析下代码里导致段错误的问题,本地运行正常但服务器报错,大概率是内存越界破坏了堆结构,咱们一步步来:
任务背景
要在计算机网络中找出最优服务器节点:该节点到其他所有计算机的最短路径(跳数)的最大值是所有节点中最小的(也就是图的中心节点问题)。
输入输出规则
输入规则
- 第一行是计算机数量
- 后续每行是相连的计算机编号
- 最后一行固定为
0 0
示例输入:
5 5 4 1 2 4 3 1 4 0 0
输出规则
- 第一行是所有计算机收到消息的最小最长跳数(最优节点的最大跳数)
- 第二行是所有符合条件的服务器节点编号
示例输出:
2 1 4
错误现象
本地运行正常,但提交到大学测试服务器后,5个公开测试用例仅2个通过,其余3个触发段错误(signal 11),错误信息如下:
Caught fatal signal 11 stderr *** Error in `solution': corrupted size vs. prev_size: 0x0000000001a36940 ***
======= Backtrace: =========
[0x4bb811] [0x4c47bb] [0x4c7d87] [0x42688e] [0x429f47] [0x42aa4d] [0x400817] [0x49a0b6] [0x49a2aa] [0x401039]
======= Memory map: ========
00400000-005a3000 r-xp 00000000 fd:01 776099 /box/solution
007a2000-007ab000 rw-p 001a2000 fd:01 776099 /box/solution
007ab000-007b0000 rw-p 00000000 00:00 0
01a1f000-01a42000 rw-p 00000000 00:00 0 [heap]
2b1ae7340000-2b1ae7349000 rw-p 00000000 00:00 0
7fffd3bb6000-7fffd3bd7000 rw-p 00000000 00:00 0 [stack]
7fffd3bfb000-7fffd3bfe000 r--p 00000000 00:00 0 [vvar]
7fffd3bfe000-7fffd3c00000 r-xp 00000000 00:00 0 [vdso]
ffffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
你的实现代码
#include <fstream> using namespace std; int BreathFirstSearch(int** matrix, int size, int row){//function to walk around matrix and find every path from vertex to vertex int pathLen=0; int q[size+1], dis[size+1], queue_input = 0, queue_output = 0, look_at; bool stop = false; for(int i=1;i<=size+1;i++){ q[i]=0;//queue for element I need to look at dis[i]=-1; //to now if I have looked at it and to count how many jumps there are between row vertex and every other vertex } dis[row] = 0;//the row from matrix can go to itself with 0 jumps q[queue_input]=row; while(q[queue_output]!=0){ look_at=q[queue_output]; queue_output++; if(!stop){ for(int col=1; col<=size; col++){//walking through every matrix collon if(matrix[look_at][col]==1 && dis[col]==-1){//if matrix collon has 1 to show that there is string between it and the row element. also check if it have already been ir queue queue_input++; q[queue_input]=col;//add collon to queue dis[col]=dis[look_at]+1;//add +1 to path from row to collon element } } } int s=0; for(int i=1; i<=size; i++){ for(int k=1; k<=size; k++){ if(q[k]==i){ s++;//count how many elements row has break; } } } if(s==size) stop=true; //if row has as much elements as matrix size, then I know that there wont be more and can stop } int maxDis = 0; for (int i = 1; i <= size; i++){ if (dis[i] > maxDis){ maxDis = dis[i]; } } return maxDis;//return only farthest distance } int main(){ ifstream fin ("serveris.in"); ofstream fout ("serveris.out"); if (fin.is_open()){ int size, x, y; fin >> size; //read size of matrix from file int** matrix = new int*[size]; for(int i = 1; i <= size; ++i){ matrix[i] = new int[size]; } int *result = new int[size]; for(int i=1; i<=size; i++){//fill matrix with zeros for(int k=1; k<=size; k++){ matrix[i][k]=0; } } while(fin.good()){ fin >> x >> y; if(x!=0){//fill 1 in their places matrix[x][y]=1; matrix[y][x]=1; } } for(int row=1; row<=size; row++){//go through every row of matrix result[row]=BreathFirstSearch(matrix, size, row);//in result array I put in only farthest path } int min = result[1]; for(int i=1; i<=size; i++){//find shortest path between vertex if(result[i]<min)min=result[i]; } fout<<min<<endl; for(int i=1; i<=size; i++){//find in witch row/s this path was if(result[i]==min)fout<< i<<' '; } for(int i=1; i<=size; i++) delete[] matrix[i]; delete[] matrix; delete[] result; } fin.close(); fout.close(); }
问题排查与修复方案
段错误(Signal 11)几乎都是内存访问越界导致的,咱们逐个找问题:
1. 二维数组matrix的内存越界
你在main里分配matrix的代码:
int** matrix = new int*[size]; for(int i = 1; i <= size; ++i){ matrix[i] = new int[size]; }
new int*[size]创建的指针数组下标范围是0~size-1,但你循环从i=1到i=size,会访问matrix[size]——这超出了数组边界,直接破坏堆内存结构,后续delete时就会触发corrupted size错误。
修复:分配size+1个元素,让下标1~size都可用:
int** matrix = new int*[size+1]; for(int i = 1; i <= size; ++i){ matrix[i] = new int[size+1]; // 列也分配size+1个元素 }
2. result数组的越界访问
main里result的分配是int *result = new int[size];,下标范围0~size-1,但你后续用result[row](row从1到size),访问了result[size],同样越界。
修复:分配size+1个元素:
int *result = new int[size+1];
3. BFS函数里的队列与循环越界
- 初始化队列时,你写了
for(int i=1;i<=size+1;i++),但q数组长度是size+1,下标范围0~size,访问q[size+1]会越界,改成i<=size。 - 队列结束条件用
while(q[queue_output]!=0)很不安全,如果节点编号有0(虽然题目里是1开始),或者队列指针超出范围,都会出错。应该用队列头尾指针判断:while(queue_output <= queue_input)。 - 那个
stop变量的逻辑完全多余,BFS遍历完所有可达节点后队列自然为空,删掉那部分双重循环统计的代码,既提高效率又避免错误。
4. 文件读取逻辑问题
用while(fin.good())读取会导致多读一次循环,因为读取0 0后fin.good()还是true,直到下一次读取失败才会退出。改成直接判断读取结果,读到0 0就退出:
while(fin >> x >> y) { if(x == 0 && y == 0) break; matrix[x][y] = 1; matrix[y][x] = 1; }
修复后的完整代码
#include <fstream> using namespace std; int BreathFirstSearch(int** matrix, int size, int row) { int dis[size+1]; int q[size+1], queue_input = 0, queue_output = 0, look_at; for(int i = 1; i <= size; ++i) { dis[i] = -1; q[i] = 0; } dis[row] = 0; q[++queue_input] = row; // 调整队列初始化,避免下标0的问题 while(queue_output < queue_input) { // 用头尾指针判断队列是否为空 look_at = q[++queue_output]; for(int col = 1; col <= size; ++col) { if(matrix[look_at][col] == 1 && dis[col] == -1) { q[++queue_input] = col; dis[col] = dis[look_at] + 1; } } } int maxDis = 0; for(int i = 1; i <= size; ++i) { if(dis[i] > maxDis) { maxDis = dis[i]; } } return maxDis; } int main() { ifstream fin("serveris.in"); ofstream fout("serveris.out"); if(fin.is_open()) { int size, x, y; fin >> size; // 分配size+1个元素,下标1~size可用 int** matrix = new int*[size+1]; for(int i = 1; i <= size; ++i) { matrix[i] = new int[size+1]; // 初始化当前行所有元素为0 for(int k = 1; k <= size; ++k) { matrix[i][k] = 0; } } int* result = new int[size+1]; while(fin >> x >> y) { if(x == 0 && y == 0) break; matrix[x][y] = 1; matrix[y][x] = 1; } for(int row = 1; row <= size; ++row) { result[row] = BreathFirstSearch(matrix, size, row); } int min = result[1]; for(int i = 1; i <= size; ++i) { if(result[i] < min) { min = result[i]; } } fout << min << endl; for(int i = 1; i <= size; ++i) { if(result[i] == min) { fout << i << ' '; } } // 释放内存 for(int i = 1; i <= size; ++i) { delete[] matrix[i]; } delete[] matrix; delete[] result; } fin.close(); fout.close(); return 0; }
内容的提问来源于stack exchange,提问作者Arnita Ziemele

