C语言KenKen游戏代码中全局变量board_size值莫名变更问题
问题排查与解决方案
核心问题分析
导致board_size莫名从5变为3、board数组异常的直接原因是缓冲区溢出:
- 全局变量
group_length仅声明为int group_length[MAXN],但游戏组数group_count最多可达MAXN*MAXN(每个单元格单独成组)。当group_count超过MAXN时,写入group_length[group_count]会覆盖相邻的全局变量(如board_size),破坏其值。
具体修复方案
1. 修正数组大小
将group_length的大小调整为与group_value、group_operator一致,确保能容纳所有组的长度信息:
// 原声明 // int group_length[MAXN] = {0}; // 修改后 int group_length[MAXN*MAXN] = {0};
2. 重构坐标解析逻辑
替换脆弱的手动索引递增方式,使用sscanf和指针迭代实现鲁棒的坐标解析,支持多位数坐标和任意空格:
// 替换原while(current_line[i]!='\0')循环 char *ptr = line; // 跳过值和运算符部分 while (*ptr != ' ' && *ptr != '\0') ptr++; int x, y; while (sscanf(ptr, " (%d,%d)", &x, &y) == 2) { group_size++; printf("(%d, %d) ", x, y); int bx = x - 1; int by = y - 1; board_group[bx][by] = group_count + 'a'; board[bx][by] = 0; group_points[group_count][group_size-1].x = x; group_points[group_count][group_size-1].y = y; // 移动指针到下一个坐标 while (*ptr != ')' && *ptr != '\0') ptr++; if (*ptr == ')') ptr++; }
3. 统一输入读取方式
避免混合使用fscanf和fgets导致的输入缓冲区残留问题,改用fgets读取整行后再解析:
// 读取棋盘尺寸 char line[MAX_IN]; if (!fgets(line, MAX_IN, fp)) { perror("Failed to read board size"); fclose(fp); exit(EXIT_FAILURE); } sscanf(line, "%d", &board_size); // 读取每组规则 while (fgets(line, MAX_IN, fp)) { // 跳过空行 if (line[0] == '\n' || line[0] == '\0') continue; int value; char op; if (sscanf(line, "%d%c", &value, &op) != 2) { fprintf(stderr, "Warning: Invalid line format - %s\n", line); continue; } // 后续解析逻辑... }
4. 添加错误检查
增加文件打开、读取的错误处理,避免程序崩溃:
FILE *fp = fopen(filename, "r"); if (!fp) { perror("Failed to open file"); exit(EXIT_FAILURE); }
完整修正后的代码片段
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXN 10 #define MAX_IN 256 struct point { int x; int y; }; struct point group_points[MAXN][MAXN] = {{}}; int board[MAXN][MAXN] = {{}}; char board_group[MAXN][MAXN] = {{}}; int group_value[MAXN*MAXN] = {0}; char group_operator[MAXN*MAXN] = {'\0'}; int group_length[MAXN*MAXN] = {0}; int board_size = 0; int group_count = 0; void readPuzzle(char *filename) { FILE *fp = fopen(filename, "r"); if (!fp) { perror("Failed to open file"); exit(EXIT_FAILURE); } printf("%s\n", filename); char line[MAX_IN]; // 读取棋盘尺寸 if (!fgets(line, MAX_IN, fp)) { perror("Failed to read board size"); fclose(fp); exit(EXIT_FAILURE); } sscanf(line, "%d", &board_size); printf("%d\n", board_size); int current_group = 0; while (fgets(line, MAX_IN, fp)) { if (line[0] == '\n' || line[0] == '\0') continue; int value; char op; if (sscanf(line, "%d%c", &value, &op) != 2) { fprintf(stderr, "Warning: Invalid line format - %s\n", line); continue; } printf("%d %c\n", value, op); group_value[current_group] = value; group_operator[current_group] = op; int group_size = 0; char *ptr = line; while (*ptr != ' ' && *ptr != '\0') ptr++; int x, y; while (sscanf(ptr, " (%d,%d)", &x, &y) == 2) { group_size++; printf("(%d, %d) ", x, y); int bx = x - 1; int by = y - 1; board_group[bx][by] = group_count + 'a'; board[bx][by] = 0; group_points[group_count][group_size-1].x = x; group_points[group_count][group_size-1].y = y; while (*ptr != ')' && *ptr != '\0') ptr++; if (*ptr == ')') ptr++; } group_length[group_count] = group_size; group_count++; current_group++; printf("\n\n%d\n\n", board_size); } fclose(fp); }
额外优化建议
- 避免全局变量:将游戏状态封装到结构体中,通过参数传递,减少意外副作用。
- 坐标合法性校验:确保解析的
x、y值在1~board_size范围内,防止数组越界访问。 - 测试多尺寸棋盘:验证代码对大于5x5的棋盘的兼容性,确保多位数坐标解析正常。
内容的提问来源于stack exchange,提问作者sophontosaphes
相关产品推荐
相关产品推荐

