C语言二维数组元素下落异常:1向左偏移后下落问题排查
二维数组元素垂直下落异常的问题修复
在C语言中定义了20×20的二维数组,期望将值为1的元素垂直下落至数组底部,但运行代码后元素会先向左偏移再向下移动。预期逻辑是将当前位置设为0,下方位置设为1,重复此操作实现直落效果,核心逻辑在fallDown()函数中。
原代码
#include<stdio.h> #include<stdlib.h> #include<conio.h> #ifdef __unix__ # include <unistd.h> #elif defined _WIN32 # include <windows.h> #define sleep(x) Sleep(1000 * (x)) #endif int sizeX = 20; int sizeY = 20; int grid[20][20] = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; int fallDown(int grid[sizeX][sizeY], int x, int y){ grid[x][y]=0; grid[x][y+1]=1; } int main(void){ int neighbour_count[sizeX][sizeY]; int x,y,iterations; for(iterations=0;iterations<500;iterations++){ system("cls"); //Clear screen for(x=0;x<sizeX;x++){ printf("\n"); for(y=0;y<sizeY;y++){ if(grid[x][y]==1){ printf("@"); } else{ printf(" "); } } } for(y=0;y<sizeY;y++){ for(x=0;x<sizeX;x++){ if(grid[x][y] == 1){ fallDown(grid, x, y); } } } printf("\n"); sleep(1); } }
问题原因
- 坐标逻辑错误:根据打印逻辑,
x代表行(每轮x循环输出一行),y代表列。垂直下落应该是行号增加(向下移动一行),但原代码中fallDown()函数修改的是y+1(列号增加,即向右移动),这是偏移的根本原因。 - 遍历顺序错误:主函数中从
x=0到x=sizeX-1遍历行,当处理完(x,y)的元素后,将(x,y+1)设为1,后续循环会处理到这个新设置的1,导致同一轮内元素被多次移动,出现向左偏移的异常。 - 无边界判断:当元素处于最后一行时,
x+1会超出数组范围,引发越界访问。
修复方案
- 修正
fallDown()函数的坐标逻辑,改为修改行号x+1,并添加边界判断,确保元素不会越界。 - 调整遍历顺序:从下往上遍历行(
x从sizeX-2到0),同一列内先处理下方的元素,避免同一轮循环中重复处理刚下落的元素。 - 修正遍历循环的顺序,确保每一轮只处理一次当前位置的元素。
修复后的代码
#include<stdio.h> #include<stdlib.h> #include<conio.h> #ifdef __unix__ # include <unistd.h> #elif defined _WIN32 # include <windows.h> #define sleep(x) Sleep(1000 * (x)) #endif int sizeX = 20; int sizeY = 20; int grid[20][20] = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; // 修正下落逻辑,添加边界判断 void fallDown(int grid[sizeX][sizeY], int x, int y){ // 确保不是最后一行,才能下落 if(x < sizeX - 1){ grid[x][y] = 0; grid[x + 1][y] = 1; } } int main(void){ int x,y,iterations; for(iterations=0;iterations<500;iterations++){ system("cls"); // 清屏 for(x=0;x<sizeX;x++){ printf("\n"); for(y=0;y<sizeY;y++){ if(grid[x][y]==1){ printf("@"); } else{ printf(" "); } } } // 从下往上遍历行,避免同一轮重复处理 for(y=0;y<sizeY;y++){ for(x=sizeX - 2;x >= 0;x--){ if(grid[x][y] == 1){ fallDown(grid, x, y); } } } printf("\n"); sleep(1); } return 0; }
关键修改点
- 将
fallDown()的返回类型改为void(原代码无返回值,不符合语法),并修改坐标为x+1,添加x < sizeX -1的边界判断。 - 遍历行时从
sizeX-2(倒数第二行)开始向上遍历到0,这样处理当前元素时,下方的位置还未被本轮循环修改,不会出现重复移动的问题。
内容的提问来源于stack exchange,提问作者Saw
相关产品推荐
相关产品推荐

