森林火灾模拟程序修改行数后rows/colm出现超大随机数求助
森林火灾模拟程序行数修改后的数据异常排查
将测试配置从9行20列改为8行20列后,程序输出的rows和colm变为超大随机数,原配置运行正常。以下是相关代码、输入文件及异常输出:
相关代码
#include <stdio.h> void InfoInput(int *rows, int *colm, int *seed, int *fireProb){ FILE *file; char line[256]; file = fopen("Test.txt", "r"); if (file ==NULL){ printf("fatal error\n"); } fscanf(file, "%d",rows); fscanf(file, "%d",colm); fscanf(file, "%d",seed); fscanf(file, "%d",fireProb); } void treeInput(char forest[][102], int rows, int colm, int *totTrees){ FILE *file; char line[256]; file = fopen("Test.txt", "r"); if (file ==NULL){ printf("fatal error\n"); } char temp; int x=0, tempRow, tempColm; while(x<100){ fscanf(file, " %c", &temp); if(temp == 'Q'){ x=1; break; } else if(temp == 'A'){ for(int i = 0; i<rows; i++){ for(int j = 0; j<colm; j++){ forest[i][j] = 'T'; } } } else if (temp == 'T'||temp == 'E'||temp == 'F'){ fscanf(file, "%d", &tempRow); fscanf(file, "%d", &tempColm); if(temp == 'T'){ forest[tempRow-1][tempColm-1] = 'T'; } if(temp == 'F'){ forest[tempRow-1][tempColm-1] = 'F'; } else { forest[tempRow-1][tempColm-1] = '.'; } } } for(int i = 0; i<rows; i++){ for(int j = 0; j<colm; j++){ if (forest[i][j] == 'T'){ *totTrees += 1; } } } } void printInfo(char forest[][102], int rows, int colm, int seed, int fireProb, int totTrees){ printf("S. Madden 9/20\n\n"); printf("rows: %d\n", rows); printf("cols: %d\n", colm); printf("trees: %d\n",totTrees); printf("seed: %d\n", seed); printf("probability: %d%%\n\n",fireProb); } int main() { FILE *file; char line[256]; file = fopen("Test.txt", "r"); if (file ==NULL){ printf("fatal error\n"); } int rows, colm, seed, fireProb, Time=0; int totTrees = 0; InfoInput(&rows, &colm, &seed, &fireProb); //manualInput(&rows, &colm, &seed, &fireProb); char forest[rows][colm]; treeInput(forest, rows, colm, &totTrees); printInfo(forest, rows, colm, seed, fireProb, totTrees); return 0; }
输入文件Test.txt内容
8 20 28 75 A F 3 4 E 1 12 E 2 12 E 3 12 E 4 12 E 4 13 E 4 14 E 5 12 E 5 15 E 6 12 E 1 16 E 2 16 E 3 16 E 4 16 E 7 1 E 7 2 E 7 3 E 7 4 E 8 3 Q
异常输出
S. Madden 9/20 rows: 777278548 cols: 1414812756 trees: 141 seed: 28 probability: 75%
问题根源
- 栈内存越界破坏变量:
main中声明的char forest[rows][colm]是变长数组(VLA),存储在栈上。但treeInput函数的参数声明为char forest[][102],函数内部会按照102列的步长计算数组元素的内存地址。当实际传入的数组列数是20时,访问forest[i][j]会超出数组实际占用的内存范围,导致栈上的相邻变量被覆盖。 - 9行20列时,栈布局刚好没让越界写入覆盖到
rows和colm;改为8行后,栈上变量的相对位置变化,越界写入直接破坏了rows和colm的内存值,所以输出随机超大数。 - 额外问题:
treeInput中if(temp == 'T')后未加else就写if(temp == 'F'),存在逻辑漏洞,可能导致错误赋值。
修复方案
1. 统一数组维度声明
将treeInput的参数改为接受变长数组,匹配实际传入的数组维度,避免越界计算:
// 调整参数顺序,先传入rows和colm,再传入数组 void treeInput(int rows, int colm, char forest[rows][colm], int *totTrees)
2. 优化文件操作
避免重复打开文件,改为在main中打开一次,通过文件指针传递给函数,读完信息后重新定位指针:
// 修改InfoInput,接收已打开的文件指针 void InfoInput(FILE *file, int *rows, int *colm, int *seed, int *fireProb){ fscanf(file, "%d", rows); fscanf(file, "%d", colm); fscanf(file, "%d", seed); fscanf(file, "%d", fireProb); } // 在treeInput中重新定位到文件开头,跳过前四个整数 void treeInput(int rows, int colm, char forest[rows][colm], int *totTrees, FILE *file){ fseek(file, 0, SEEK_SET); int skip; for(int i=0; i<4; i++){ fscanf(file, "%d", &skip); } // 后续原有逻辑... }
3. 修复逻辑漏洞
将treeInput中的条件判断改为else if,避免重复判断:
if(temp == 'T'){ forest[tempRow-1][tempColm-1] = 'T'; } else if(temp == 'F'){ forest[tempRow-1][tempColm-1] = 'F'; } else { forest[tempRow-1][tempColm-1] = '.'; }
4. 添加错误处理
fopen失败时直接终止程序,避免后续非法操作:
#include <stdlib.h> // 引入exit函数 int main(){ FILE *file = fopen("Test.txt", "r"); if(file == NULL){ printf("fatal error\n"); exit(1); // 终止程序 } // 后续逻辑... fclose(file); // 关闭文件 return 0; }
内容的提问来源于stack exchange,提问作者Sarah Madden
相关产品推荐
相关产品推荐

