多维数组赋值行错误:奇数阶幻方生成程序故障排查
奇数阶幻方C程序赋值错误排查与修复
我正在编写一个生成奇数阶幻方的C程序,规则如下:
- 将1放在第0行的中间位置
- 后续数字放在上一行的右一列(越界则循环)
- 若目标位置已有数字,则放在当前数字的正下方
但执行else分支时,值被赋到了错误的行:修改else分支打印row值显示为1,却持续赋值到第2行,甚至出现覆盖之前数值的情况。
原代码
// Print an nxn magic square #include <stdio.h> int main(void) { int n; printf("This program creates a magic square of a specified size.\n"); printf("The size must be an odd number between 1 and 99.\n"); printf("Enter size of the square: "); scanf("%d", &n); int square[n] [n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { square[i] [j] = 0; } } square[0] [n / 2] = 1; int row = 0, column = n/2; for (int i = 2; i < n * n + 1; i++) { if (square[row == 0 ? n - 1 : row - 1] [(column + 1) % n] == 0) { square[row == 0 ? row = n - 1 : --row] [(++column) % n] = i; } else { square[++row] [column] = i; } for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { printf("%2d ", square[j] [k]); } printf("\n"); } printf("\n"); } return 0; }
修改后的else分支代码(用于调试)
} else { square[printf("row: %d ", row), row] [column] = i; }
输出示例(n=5时)
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 3 0 0 0 2 0 0 0 1 0 0 0 5 0 0 0 4 0 0 0 0 0 0 0 0 3 0 0 0 2 0 row: 1 0 0 1 0 0 0 5 0 0 0 4 6 0 0 0 0 0 0 0 3 0 0 0 2 0 row: 1 0 0 1 0 0 0 5 0 0 0 4 7 0 0 0 0 0 0 0 3 0 0 0 2 0 . . .
问题分析
- 下标内赋值导致逻辑混淆:原代码将row的修改(
row = n-1或--row)直接写在数组下标中,虽然能修改row,但逻辑不直观,容易引发后续错误。 - else分支未正确更新row:调试用的else分支仅打印row并赋值,但未更新row的值,导致下一次循环时row仍为旧值,重复进入else分支并覆盖同一位置的数值。
- 原else分支的前缀自增误解:原else分支使用
++row,会先将row自增再赋值,这符合“正下方”的规则(当前数字在row,正下方是row+1),但调试时打印的是自增前的row值,导致误以为赋值位置错误。
修复方案
将候选位置的计算与row、column的更新逻辑分离,避免在数组下标内进行赋值操作,让代码逻辑更清晰:
// Print an nxn magic square #include <stdio.h> int main(void) { int n; printf("This program creates a magic square of a specified size.\n"); printf("The size must be an odd number between 1 and 99.\n"); printf("Enter size of the square: "); scanf("%d", &n); int square[n][n]; // 初始化数组为0 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { square[i][j] = 0; } } // 放置初始值1 int row = 0, column = n / 2; square[row][column] = 1; // 填充剩余数字 for (int i = 2; i <= n * n; i++) { int next_row, next_col; // 计算右上候选位置 next_row = row - 1; if (next_row < 0) { next_row = n - 1; } next_col = column + 1; if (next_col >= n) { next_col = 0; } if (square[next_row][next_col] == 0) { // 候选位置为空,更新到该位置 row = next_row; column = next_col; } else { // 候选位置被占,放到当前位置的正下方 row = row + 1; // 处理越界(Siamese方法中实际不会触发,但保留以增强鲁棒性) if (row >= n) { row = 0; } } // 赋值当前数字 square[row][column] = i; // 打印当前状态(可选,用于调试) for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { printf("%2d ", square[j][k]); } printf("\n"); } printf("\n"); } return 0; }
修复说明
- 单独计算右上候选位置,逻辑清晰易懂,避免了原代码中嵌套三元运算符的混乱。
- 明确更新row和column的值,确保每一步的位置都正确同步。
- else分支中更新row为当前位置的正下方,符合幻方规则,同时处理了可能的越界情况。
内容的提问来源于stack exchange,提问作者raidenfox
相关产品推荐
相关产品推荐

