向我的小游戏添加功能时出现奇怪的错误(0xC0000005)

时间:2015-05-29 17:48:14

标签: c memory-management memory-leaks heap-memory

大家好,

我前段时间决定将我自己的扫雷车版本作为一些练习编写,我就这样做了。游戏运行完美,但在决定添加“选择难度”选项后,窗口冻结,我收到一条错误消息,说该程序没有响应。还会显示 0xC0000005 行。我尝试了很多很多东西:将代码从 main()转移到单独的函数(现在全部在int playGame()中),在堆中分配更多内存,甚至创建一个单独的.c文件来存储一些代码,但没有任何工作。几个星期后我回到了代码中,但我仍然不知道为什么会发生这种情况。 谁能帮我这个?我希望我的代码不难阅读。我添加了一些解释什么是什么的评论。我还是C的新手。

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include "difLvl.c"

    int displayFiled(char **field); //prints out the map of the field
    int combine(char answer, int answer1); //combines user input and field       numeration
    int Randomizer(int **mineArray); //generates random mine map
    int difficulty();
    int playGame();

    int main(){

        int playGame();

        playGame();

        system("PAUSE");

    return 0;
}

int Randomizer(int **mineArray){

    int difficulty();
    int i, j;
    srand(time(NULL));
    int mines;
    int placeMine;
    int totalMines;
    //int difLvl=2;
    int difLvl=difficulty();

    for(i=0, totalMines=0; i<10; i++){
        for(j=0, mines=0; j<10 && mines<difLvl; j++){
            placeMine= rand() % 2;
            mineArray[i][j] = placeMine;
            if(placeMine==1){
                ++mines;
            };
        };
        totalMines+=mines;
    };

    return totalMines;
}

int displayFiled(char **field){

    int i, j;

    printf("    A B C D E F G H I J\n");
    printf("   --------------------\n");
    for (i=0; i<10; i++){
            if (i==9){
                printf("%d |", i+1);
            }else{
                printf("%d  |", i+1);
            };
        for (j=0; j<10; j++){
            printf("%c ", field[i][j]);
            if (j==9){
                printf("\n");
                };
        };
    };
    printf("\n");

    return 0;
}

int playGame(){

    int displayFiled(char **field);
    int combine(char answer, int answer1);
    int Randomizer(int ** mineArray);
    char Y_char; //column as character (a, b, c etc.)
    int X; //row 
    int Y; //Y_char converted to a number 
    int **mineArray; //stores the map of mines
    char **fieldDisplay; //prints out the map of the field
    int i, j; //counters
    int life=1;
    int movePl=0; //no dying on the first move
    int globalMines; //number of mines placed
    int openedFields=0; //counts the number of fields opened
    //int difLvl;
    //int difficulty();

    //difLvl= difficulty();

    /*disabled the trhee lines above while I was trying some solutions*/
    /*int difficulty() is now called from int Randomizer()*/

    system("cls");

    /*Allocates memory to mineArray*/
    mineArray= (int*)calloc(10, sizeof(int));
    for(i = 0; i < 10; i++){
        mineArray[i] = calloc(10, sizeof(int));
    };


    /*Allocates memory to fieldDisplay*/
    fieldDisplay= (int*)calloc(10, sizeof(int));
    for(i = 0; i < 10; i++){
        fieldDisplay[i] = calloc(10, sizeof(int));
    };

    /*default look of fields with ?*/
    for (i=0; i<10; i++){
        for (j=0; j<10; j++){
            fieldDisplay[i][j]='?';
        };
    };

    globalMines= Randomizer(mineArray);

    while(life==1 && openedFields<(100-globalMines)){

        /*for checking purposes only*/
        /*for (i=0; i<10; i++){
            for (j=0; j<10; j++){
                printf("%d ", mineArray[i][j]);
            if (j==9){
                printf("\n");
                };
            };
        };*/

        //printf("\nDifficulty level %d\n", difLvl);
        printf("Total number of mines is %d\n\n", globalMines);
        printf("\tMove nr. %d\n\n", movePl+1);
        displayFiled(fieldDisplay);

        printf("Which field do You want to activate?\nType first the letter, space and then the number (A 1, B 10 etc.)\n");
        scanf("%c %d", &Y_char, &X);
        if (Y_char >= 'A' && Y_char <= 'Z'){
            Y = Y_char - 'A';
        }else if(Y_char >= 'a' && Y_char <= 'z'){
            Y = Y_char - 'a';
        };

        /*checks if a field is a mine*/
        /*X-1 because the player chooses from 1 to 10*/
        if (mineArray[X-1][Y]==0 && fieldDisplay[X-1][Y]=='?'){
            movePl++;
            fieldDisplay[X-1][Y]='0';
            openedFields=openedFields+1;

OPEN :      if (((X-2)<10) && ((X-2)>=0)){
                if (mineArray[X-2][Y]==0 && fieldDisplay[X-2][Y]=='?'){
                    fieldDisplay[X-2][Y]='0';
                    openedFields=openedFields+1;
                };
            };

            if ((X<10) && (X>=0)){
                if (mineArray[X][Y]==0 && fieldDisplay[X][Y]=='?'){
                    fieldDisplay[X][Y]='0';
                    openedFields=openedFields+1;
                };
            };

            if (((Y+1)<10) && ((Y+1)>=0)){
                if (mineArray[X-1][Y+1]==0 && fieldDisplay[X-1][Y+1]=='?'){
                    fieldDisplay[X-1][Y+1]='0';
                    openedFields=openedFields+1;
                };
            };

            if (((Y-1)<10) && ((Y-1)>=0)){
                if (mineArray[X-1][Y-1]==0 && fieldDisplay[X-1][Y-1]=='?'){
                    fieldDisplay[X-1][Y-1]='0';
                    openedFields=openedFields+1;
                };
            };

            system("cls"); //clears console screen
        }else if (mineArray[X-1][Y]==0 && fieldDisplay[X-1][Y]=='0'){
            system("cls");
            printf("You can't choose an already opened field!\n\n");
        }else if(mineArray[X-1][Y]==1 && movePl==0){
        /*only activates on the first turn if players hits mine*/
            movePl++;
            mineArray[X-1][Y]= 0;
            fieldDisplay[X-1][Y]='0';
            globalMines=globalMines-1;
            goto OPEN;
            system("cls");
        }else{
            system("cls");
            printf("YOU DIED ! YOU DIED ! YOU DIED !\n\n");
            printf("Moves successfully made: %d\n\n", movePl-1);
            fieldDisplay[X-1][Y]='1';
            displayFiled(fieldDisplay);
            --life;
        };
    };

    if(openedFields==(100-globalMines)){
        printf("Congratulations! You won the game!\n\n");
        displayFiled(fieldDisplay);
    };

    for(i = 0; i < 10; i++){
        free(mineArray[i]);
    };
    free(mineArray);

    for(i = 0; i < 10; i++){
        free(fieldDisplay[i]);
    };
    free(fieldDisplay);



    return 0;

}

difLvl.c文件:

#include <stdio.h>
#include <stdlib.h>

int difficulty(){

    int difLvl;

    while(1){
        printf("Please choose a difficulty level:\n");
        printf("Easy-1\nNormal-2\nNightmare-3\n");
        printf("Your answer: ");
        scanf(" %d", &difLvl);
        if(difLvl>=1 && difLvl<=3){
            break;
        }else{
            system("cls");
            continue;
        };
    };
    system("cls");
    return difLvl;
}

我创建了它,因为我认为可能 main()中有太多代码,这可能就是为什么难度选项无法正常工作。

EDIT 在提示用户输入难度级别后,将创建地雷图,但在选择字段后,程序会崩溃。

解决 scanf(“%c%d”,&amp; Y_char,&amp; X); 变成 scanf(“%c%d”,&amp; Y_char,&amp; X);

1 个答案:

答案 0 :(得分:3)

首先,您没有正确分配二维字段。 “外部”字段必须包含int *,而不仅仅是int

mineArray = calloc(10, sizeof(*mineArray));
for (i = 0; i < 10; i++) {
    mineArray[i] = calloc(10, sizeof(*mineArray[i]));
}

分段错误的另一个潜在来源是Y可能最终未初始化,因此具有垃圾值。原因是scanf

scanf("%c %d", &Y_char, &X);

大多数scanf格式会在转化前跳过空格,但%c则不会。当您希望阅读一封信时,很有可能将新行字符作为%c的字符读取。因为新行字符是空白字符,您可以通过在%c之前放置空格来进行热修复?格式:

scanf(" %c %d", &Y_char, &X);

(我说热修复,因为它不是一个好的解决方案。scanf不会特别处理换行符;它们只是空格。更好的解决方案可能是首先读取一行fgets,然后使用sscanf进行扫描。至少可以将每一行视为frash输入。(您的输入确实应该确保忽略错误的输入。)

最后,包含*.c文件很奇怪。如果你想在各种文件上传播ypur项目,这基本上是一个好主意,你应该为每个*.c编写一个头文件,它有文件的接口。将头文件包含在其他*.c个文件中;将*.c文件分别编译为对象,然后链接它们。此过程通常由Makefile或项目控制。