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

C语言记忆游戏程序在序列长度增至5位时出现运行时错误

Simple Simon记忆游戏数组值异常问题解决

问题描述

编写的Simple Simon记忆游戏初始3位序列运行正常,但当序列长度增至5位时,对比用户输入数组guessedNumArr与目标数组numToGuess时,numToGuess[0]的值会被莫名修改,导致玩家直接失败。游戏规则为:电脑短时间显示数字序列,玩家记忆后输入相同序列,连续3次成功则序列长度增加,目标是尽可能延续游戏。

核心错误分析

  1. 变长数组(VLA)的误用:
    代码中numToGuess[difficulty]和guessedNumArr[difficulty]是变长数组,在main函数开头声明时difficulty的值为5,后续difficulty增加后,数组实际长度仍为5,当访问索引超过4的元素时,会发生栈内存越界,破坏相邻变量(包括numToGuess[0])的值。

  2. scanf格式符不匹配导致栈溢出:
    处理用户输入Y/N时使用scanf("%s", &Y_N),但Y_N是单个char类型,%s会读取字符串并写入终止符\0,这会超出Y_N的内存空间,覆盖栈中其他变量(如numToGuess的元素)。

  3. 随机数种子重复初始化:
    srand(time(NULL))放在循环内部,每次循环都会重置随机数种子。由于time(NULL)返回秒级时间,短时间内多次循环会导致生成相同的随机序列,同时也可能影响程序执行时序,间接引发内存问题。

修复方案

  • 改用动态内存分配:使用malloc和realloc根据当前difficulty动态调整数组大小,避免越界。
  • 修正scanf格式符:对单个字符输入使用%c,并通过getchar()处理输入缓冲区的换行符,避免残留字符干扰后续输入。
  • 初始化随机数种子一次:将srand(time(NULL))移到main函数开头,仅初始化一次。
  • 移除goto语句:用循环结构替代goto,提升代码可读性和可维护性。

完整修正代码

#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <stdlib.h>
#include <ctype.h>

int main() {
    bool play = true;
    time_t now;
    int try_count = 1, anotherGame;
    int difficulty = 3;  // 初始难度改为3,符合游戏描述
    int *numToGuess = malloc(difficulty * sizeof(int));
    int *guessedNumArr = malloc(difficulty * sizeof(int));
    int count = 0, guessedNum, singleScore = 0, totalScore = 0;

    if (!numToGuess || !guessedNumArr) {
        printf("内存分配失败\n");
        return 1;
    }

    // 仅初始化一次随机数种子
    srand(time(NULL));

    puts("\nSimple Simon is a memory-test game. In this game, the\n"
         "computer displays a sequence of digits on the screen for a short period of time.\n"
         "You then have to memorize them, and when the digits disappear from the screen,\n"
         "you must enter exactly the same sequence of digits. "
         "Each time you succeed 3 times in a row, the process repeats with a longer sequence of digits for you to try.\n"
         "The objective is to continue the process for as long as possible\n"
         "Press enter to play");
    // 处理换行符
    getchar();

    do {
        int consecutive_success = 0;
        while (consecutive_success < 3) {
            const unsigned int DELAY = 2;

            // 生成目标序列
            for (int i = 0; i < difficulty; i++) {
                numToGuess[i] = rand() % 10;
                printf("%d   ", numToGuess[i]);
            }

            // 延迟后清空屏幕(用换行替代,实际可根据系统调用清屏命令)
            now = clock();
            while (clock() - now < DELAY * CLOCKS_PER_SEC);
            puts("\n\n");

            // 获取玩家输入
            puts("Try to enter the same exact sequence of numbers, remember to put a space in between the numbers:\n");
            for (int k = 0; k < difficulty; k++) {
                scanf("%d", &guessedNum);
                guessedNumArr[k] = guessedNum;
            }
            // 清除输入缓冲区的换行符
            while (getchar() != '\n');

            // 对比输入与目标序列
            count = 0;
            for (int j = 0; j < difficulty; j++) {
                printf("%d --- %d\n", guessedNumArr[j], numToGuess[j]);
                if (guessedNumArr[j] == numToGuess[j]) {
                    count++;
                }
            }
            try_count++;

            if (count == difficulty) {
                consecutive_success++;
                totalScore++;
                printf("正确!已连续成功%d次\n", consecutive_success);
            } else {
                char Y_N;
                printf("抱歉,你输了。总得分:%d。是否再玩一次?Y/N\n", totalScore);
                while (true) {
                    scanf(" %c", &Y_N);  // 空格跳过空白字符
                    Y_N = tolower(Y_N);
                    if (Y_N == 'y') {
                        try_count = 0;
                        totalScore = 0;
                        consecutive_success = 0;
                        difficulty = 3;
                        // 重新分配初始难度的内存
                        numToGuess = realloc(numToGuess, difficulty * sizeof(int));
                        guessedNumArr = realloc(guessedNumArr, difficulty * sizeof(int));
                        if (!numToGuess || !guessedNumArr) {
                            printf("内存分配失败\n");
                            return 1;
                        }
                        break;
                    } else if (Y_N == 'n') {
                        printf("游戏结束\n");
                        play = false;
                        break;
                    } else {
                        printf("请输入Y或N\n");
                    }
                }
                if (!play) break;
            }
        }

        if (!play) break;

        // 连续成功3次,询问是否继续
        int gotItwrong = 0;
        char yOrN;
        while (true) {
            if (gotItwrong == 0) {
                puts("已连续成功3次,输入Y继续(序列长度+1),输入N结束游戏\n");
            }
            scanf(" %c", &yOrN);
            yOrN = tolower(yOrN);
            if (yOrN == 'y') {
                difficulty++;
                // 重新分配内存
                numToGuess = realloc(numToGuess, difficulty * sizeof(int));
                guessedNumArr = realloc(guessedNumArr, difficulty * sizeof(int));
                if (!numToGuess || !guessedNumArr) {
                    printf("内存分配失败\n");
                    return 1;
                }
                consecutive_success = 0;
                break;
            } else if (yOrN == 'n') {
                printf("游戏结束,总得分:%d\n", totalScore);
                play = false;
                break;
            } else {
                printf("请输入Y或N\n");
                gotItwrong++;
            }
        }

    } while (play == true);

    // 释放动态分配的内存
    free(numToGuess);
    free(guessedNumArr);

    return 0;
}

内容的提问来源于stack exchange,提问作者Giacomo D.G.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:20:52