You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中2D沙粒模拟矩阵值异常消失问题排查

问题分析与修复方案

核心问题点

  • 边界检查逻辑完全错误:原代码中if(grid[y + 1][x] <= sizeY && grid[y][x + 1] <=sizeX)是拿网格中的值(0或1)和尺寸比较,而非判断坐标是否在合法范围内。
  • 越界访问内存:
    • drawScreen函数循环条件使用x <= sizeX和y <= sizeY,但网格索引范围是0到19(sizeX/Y=20),导致访问超出数组范围的内存,引发随机数据显示。
    • sand函数检查下方、左下、右下位置时未做边界校验,粒子处于边缘时会访问数组外内存,破坏其他数据。
  • 网格坐标遍历顺序错误:drawScreen函数把x和y的循环顺序搞反,导致画面显示的网格是转置状态。
  • 缺少画面刷新延迟:原代码没有绘制后延迟,画面刷新过快无法观察效果。

修复后的完整代码

#include <stdio.h>
#include <stdlib.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 alive = 1;
int dead = 0;

int grid[20][20] = {{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,1,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},
                    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};

void drawScreen() {
    system("cls"); // 清屏
    for (int y = 0; y < sizeY; y++) {
        for (int x = 0; x < sizeX; x++) {
            printf(grid[y][x] == alive ? "@" : " ");
        }
        printf("\n");
    }
}

void sand(int x, int y) {
    // 检查是否可以向下移动
    if (y + 1 < sizeY && grid[y + 1][x] == dead) {
        grid[y][x] = dead;
        grid[y + 1][x] = alive;
    }
    // 检查是否可以向左下移动(x不能小于0)
    else if (x - 1 >= 0 && y + 1 < sizeY && grid[y + 1][x - 1] == dead) {
        grid[y][x] = dead;
        grid[y + 1][x - 1] = alive;
    }
    // 检查是否可以向右下移动(x不能超过边界)
    else if (x + 1 < sizeX && y + 1 < sizeY && grid[y + 1][x + 1] == dead) {
        grid[y][x] = dead;
        grid[y + 1][x + 1] = alive;
    }
}

int main(void) {
    int x, y, iterations;

    for (iterations = 0; iterations < 1000; iterations++) {
        // 从下往上遍历,避免同一帧内重复处理同一个粒子
        for (y = sizeY - 2; y >= 0; y--) {
            for (x = 0; x < sizeX; x++) {
                if (grid[y][x] == alive) {
                    sand(x, y);
                }
            }
        }
        drawScreen();
        sleep(0.1); // 添加延迟,让画面可见
    }
    return 0;
}

关键修复说明

  1. 修正边界检查:sand函数中每次访问相邻位置前,先判断坐标是否在0 <= x < sizeX和0 <= y < sizeY范围内。
  2. 修复越界遍历:drawScreen循环条件改为y < sizeY和x < sizeX,确保只访问合法网格索引。
  3. 调整坐标顺序:drawScreen先循环行(y)再循环列(x),对应grid[y][x]的存储结构,显示正确画面。
  4. 优化遍历顺序:主循环y从sizeY-2开始(最底部粒子无法下移),避免无效判断。
  5. 添加刷新延迟:每次绘制后调用sleep(0.1),控制画面刷新速度,便于观察沙粒下落效果。
  6. 修正函数返回值:drawScreen和sand函数无需返回值,改为void类型,符合逻辑。

内容的提问来源于stack exchange,提问作者Saw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:33:24