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

C语言ncurses贪吃蛇:静态数组正常,动态数组存坐标失效求助

问题排查与修复

核心问题1:动态数组未初始化关键元素

malloc分配的堆内存不会自动初始化,存储的是随机垃圾值。你的动态数组版本中,初始蛇头位置没有提前存入snakeTailXPositions和snakeTailYPositions的第0位,且当蛇吃到苹果后snakeTailSize立即自增,后续渲染蛇尾时会访问未赋值的数组索引(比如snakeTailSize=2时访问索引1),这些垃圾值会导致坐标异常。

而静态数组版本依赖栈内存的默认初始值(通常为0或未被覆盖的栈数据),刚好在屏幕可见范围内,因此未触发明显异常,但本质上也是不规范的写法。

修复方法:在动态数组分配完成后,立即将初始蛇头位置存入数组:

int* snakeTailXPositions = malloc(sizeof(int) * 1000);
int* snakeTailYPositions = malloc(sizeof(int) * 1000);
// 初始化初始蛇头位置到数组第0位
snakeTailXPositions[0] = x;
snakeTailYPositions[0] = y;

核心问题2:逻辑判断误用位运算符

苹果碰撞检测的条件中,你使用了位运算符&而非逻辑运算符&&:

if (x == apples.xCoordinates[i] & y == apples.yCoordinates[i])

位运算&会对两个条件的结果做二进制位运算,而非逻辑上的“与”判断,可能导致错误判定(比如x相等但y不相等时,位运算结果可能不为0,错误触发吃苹果逻辑)。

修复方法:替换为逻辑运算符&&:

if (x == apples.xCoordinates[i] && y == apples.yCoordinates[i])

修复后的完整动态数组代码

#include <ncurses.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define DELAY 100000
#define APPLECOUNT 10

void preventAppleOverlap(int* appleX, int* appleY, int xBound, int yBound);

struct applePositions {
    int xCoordinates[APPLECOUNT];
    int yCoordinates[APPLECOUNT];
};

int main(void) {
    int ch;
    int x = 1, y = 1;
    int maxY = 0, maxX = 0;
    char controls[4] = {'d', 'a', 's', 'w'};
    char controlsInverted[4] = {'a', 'd', 'w', 's'};
    int heading = 0;

    struct applePositions apples;

    int snakeTailSize = 1;
    int* snakeTailXPositions = malloc(sizeof(int) * 1000);
    int* snakeTailYPositions = malloc(sizeof(int) * 1000);
    // 初始化初始蛇头位置
    snakeTailXPositions[0] = x;
    snakeTailYPositions[0] = y;

    initscr();
    noecho();
    curs_set(FALSE);
    nodelay(stdscr, TRUE);
    getmaxyx(stdscr, maxY, maxX);

    // 生成苹果初始位置
    for (int i = 0; i < APPLECOUNT; i++) {
        apples.xCoordinates[i] = rand() % maxX;
        apples.yCoordinates[i] = rand() % maxY;
    }

    preventAppleOverlap(apples.xCoordinates, apples.yCoordinates, maxX, maxY);

    while (1) {
        ch = getch();

        clear();
        char* score = malloc(sizeof(char) * 100);
        sprintf(score, "%i", snakeTailSize - 1);
        // 渲染分数
        mvprintw(0, 0, score);
        // 渲染蛇头
        mvprintw(y, x, "#");
        // 渲染蛇身
        for (int i = 1; i < snakeTailSize; ++i) {
            mvprintw(snakeTailYPositions[i], snakeTailXPositions[i], "#");
        }

        // 渲染苹果并处理吃苹果逻辑
        for (int i = 0; i < APPLECOUNT; ++i) {
            // 修复位运算符为逻辑运算符
            if (x == apples.xCoordinates[i] && y == apples.yCoordinates[i]) {
                apples.xCoordinates[i] = -1;
                apples.yCoordinates[i] = -1;
                snakeTailSize++;
            }
            mvprintw(apples.yCoordinates[i], apples.xCoordinates[i], "@");
        }
        refresh();
        usleep(DELAY);
        // 输入处理
        int previousHeading = heading;

        for (int i = 0; i < 4; ++i) {
            if (controls[i] == ch) {
                heading = i;
            }
        }

        // 禁止180度掉头
        if (controls[heading] == controlsInverted[previousHeading]) {
            heading = previousHeading;
        } 
        switch (heading) {
            case 0:
                x += 1;
                break;
            case 1:
                x -= 1;
                break;
            case 2:
                y += 1;
                break;
            case 3:
                y -= 1;
                break;
            default:
                break;
        }

        // 蛇身移动逻辑
        int* snakeTailXPosTemp = malloc(sizeof(int) * snakeTailSize);
        int* snakeTailYPosTemp = malloc(sizeof(int) * snakeTailSize);
        for (int i = 0; i < snakeTailSize; ++i) {
            snakeTailXPosTemp[i] = snakeTailXPositions[i];
            snakeTailYPosTemp[i] = snakeTailYPositions[i];
        }
        snakeTailXPositions[0] = x;
        snakeTailYPositions[0] = y;

        for (int i = 0; i < snakeTailSize - 1; ++i) {
            snakeTailXPositions[i + 1] = snakeTailXPosTemp[i];
            snakeTailYPositions[i + 1] = snakeTailYPosTemp[i];
        }

        // 重生被吃掉的苹果
        for (int i = 0; i < APPLECOUNT; ++i) {
            if (apples.xCoordinates[i] == -1) {
                apples.xCoordinates[i] = rand() % maxX;
                apples.yCoordinates[i] = rand() % maxY;
            }
        }

        preventAppleOverlap(apples.xCoordinates, apples.yCoordinates, maxX, maxY);

        // 蛇身碰撞检测
        for (int i = 0; i < snakeTailSize; ++i) {
            for (int j = 0; j < snakeTailSize; ++j) {
                if (snakeTailXPositions[i] == snakeTailXPositions[j] && snakeTailYPositions[i] == snakeTailYPositions[j] && i != j) {
                    free(snakeTailXPositions);
                    free(snakeTailYPositions);
                    endwin();
                    return 0;   
                }
            }
        }
        // 边界碰撞检测
        if (x >= maxX || x < 0 || y >= maxY || y < 0) {
            free(snakeTailXPositions);
            free(snakeTailYPositions);
            endwin();
            return 0;
        }
        free(score);
        free(snakeTailXPosTemp);
        free(snakeTailYPosTemp);
        
    }
    endwin();
    return 0;
}


void preventAppleOverlap(int* appleX, int* appleY, int xBound, int yBound) {
    int cycleCount = 1;
    int noOverlap = 0;
    while (!noOverlap) {
        cycleCount++;
        noOverlap = 1;
        for (int i = 0; i < APPLECOUNT; ++i) {
            for (int j = 0; j < APPLECOUNT; ++j) {
                if (appleX[i] == appleX[j] &&  appleY[i] == appleY[j] && i != j) {
                    noOverlap = 0;
                    appleX[i] = rand() % xBound;
                    appleY[i] = rand() % yBound;
                }
            }
        }
        if (cycleCount == 2) {
            break;
        }
    }
}

额外优化建议

  • 添加malloc失败检查,避免空指针访问:
    if (!snakeTailXPositions || !snakeTailYPositions) {
        fprintf(stderr, "内存分配失败\n");
        exit(EXIT_FAILURE);
    }
    
  • 优化蛇身碰撞检测逻辑,只需检查蛇头与身体的碰撞,减少重复判断:
    // 仅检查蛇头是否与身体碰撞
    for (int i = 1; i < snakeTailSize; ++i) {
        if (snakeTailXPositions[0] == snakeTailXPositions[i] && snakeTailYPositions[0] == snakeTailYPositions[i]) {
            free(snakeTailXPositions);
            free(snakeTailYPositions);
            endwin();
            return 0;   
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:06:32