调用数组上的函数会使程序退出

问题描述 投票:0回答:1

这里发生的事情是,我想要在控制台中安装一个生命游戏程序。 初始化“字段”的参数可以在 mainMenu() 中更改。 全部完成后,返回1,开始绘制。 当我们从绘图返回时,我们回到 mainMenu()。 这种情况在无限 while 循环中永远发生。 所有功能均在单独测试时有效。 有问题的是 border()、init() 等。 请帮助我,我错过了什么,我是 C 初学者,并且非常感谢这里的任何线索。

(fileIn() 无法正常工作,但这不是这里的问题。)

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <conio.h>

//structure for storing the state of each cell
typedef struct Cell{
    bool state, nState;
}Cell;

char path[50];
int rule;

Cell** setup(int width, int height){
    //create field
    int size = (width+2)*(height+2);
    Cell** field = malloc(size * sizeof(Cell));;
    
    if (field == NULL){
        printf("Malloc Error!");
        exit(-1);
    }
    return field;
}

void clrscr(){
    printf("\e[1;1H\e[2J");
}

void welcome(){
    clrscr();
    printf("This program was created by:\033[1;31m\n           U+0466.\033[1;m\n");
    sleep(2);
}

void display(Cell* c, int width, int height){
    clrscr();
    int size = (width+2)*(height+2);
    printf("\n");
    for (int i = 0; i <(width*2-32)/2; i++)
        printf(" ");
    printf("\033[1;31mThe Game of Life on a %dx%d grid.\033[1;m", width, height);

    //draw the field
    for (int i = 0; i < size; i++){
        if (i % (width+2) == 0)
            printf("\n");

        //skip border
        if (i < width+2){
            printf("X ");
            continue;}
        else if (i >= (size-(width+2))){
            printf("X ");
            continue;}
        else if ((i+1) % (width+2) == 0){
            printf("X ");
            continue;}
        else if ((i) % (width+2) == 0){
            printf("X ");
            continue;}
        
        (c[i].state)? printf("O ") : printf("  ");
    }
}

int fileIn(int* width, int *height){
    //get path from user
    printf("\033[1;31m");
    printf("Please enter file path: ");
    printf("\033[1;m");
    scanf("%s", path);
    
    //open file
    FILE *fptr = fopen(path, "r");
    if (fptr == NULL){
        return -1;
    }

    //find the dimenisons of the field
    char ch;
    int h = 0;
    int w = 0;
    int wmax = 0;

    for (ch = getc(fptr); ch != EOF; ch = getc(fptr)){
        //0 or 1
        if ((ch == 48)|(ch == 49)){
            w++;
        }
        //linebreak
        else if (ch == 10){
            if (w!=0)
                h++;
            if (w > wmax){
                wmax = w;
            }
            w = 0;
        }
    }
    if ((wmax > 0)|(height > 0)){
        *width = wmax;
        *height = h + 1;
    }
    return 0;
}

void fileOut(Cell* c, int width, int height){
    FILE *fptr = NULL;
    fptr = fopen("out.txt", "w+");

    //create a header
    for (int i = 1; i <= width; i++)
        fprintf(fptr, "-");
    fprintf(fptr, "\nThe Game of Life, by U+O466\n");
    for (int i = 1; i <= width; i++)
        fprintf(fptr, "-");

    //write file
    int size = (width+2)*(height+2);
    for (int i = 0; i < size; i++){
        //skip border
        if (i < width+2)
            continue;
        else if (i >= (size-(width+2)))
            continue;
        else if ((i+1) % (width+2) == 0)
            continue;
        else if ((i-3) % (width+2) == 0)
            continue;
        
        //write states
        else if (i % (width+2) == 0)
            fprintf(fptr, "\n");
        ((c+i)->state)? fprintf(fptr, "1"):fprintf(fptr, "0");
    }
    fclose(fptr);
}

void initFile(Cell* c, int w, int h){
    int size = (w+2)*(h+2);
    FILE* fptr = fopen(path, "r");

    char ch;

    //init to 0, than fill with data
    for (int i = 0; i < size; i++)
        (c+i)->state = 0;
    
    for (int j = 1; j < h+1; j++){
        for (int i = 1; i < w+1; i++){
            ch = getc(fptr);

            if (ch == 49){
                (c+j*(w+2)+i)->state = 1;
            }
            //linebreak - doesnt handle 'empty' rows properly
            else if ((ch == 10)){
                break;
            }
        }
    }
}

void initAuto(Cell* c, int width, int height){
    //populate first row with 0, set center as 1
    for (int i = 0; i < width+1; i++)
        (c+i)->state = 0;
    (width%2 == 0)? ((c+((width+1)/2))->state = 1) : ((c+(width/2))->state = 1);

    for (int j = 1; j < height+1; j++){
        for (int i = 1; i < width+1; i++){
            char pat = 0;
            //find out current pattern
            pat |= ((c+(j*(width+2))+i-1)->state << 2 );
            pat |= ((c+(j*(width+2))+i)->state << 1 );
            pat |= ((c+(j*(width+2))+i+1)->state);
            //set next rows state, based on the rule
            (c+((j+1)*(width+2))+i)->state = (rule >> pat) & 1;
        }
    }
}

void init(Cell* c, int w, int h, int mode){
    int size = (w+2)*(h+2);

    switch (mode){
        case 0:
        case 1:
            for (int i = 0; i < size; i++)
                (c+i)->state = mode;
            break;
        case 2:
            for (int i = 0; i < size; i++)
                (c+i)->state = rand()%2;
            break;
        case 3:
            initAuto(c, w, h);
            break;
        case 4:
            initFile(c, w, h);
            break;

    }
}

void border(Cell *c, int w, int h, int mode){
    w+=2;
    h+=2;
    for (int j = 0; j < h; j++){
        for (int i = 0; i < w; i++){
            if ((i==0) | (i == w-1) | (j==0) | (j == h-1)){
                switch (mode){
                    case 0: //dead
                    case 1: //alive
                        (c+(w*j)+i)->state = mode;
                        break;
                    case 2: //tiling - corners not handled 
                        if (i==0)
                            (c+(w*j))->state = (c+(w*j)+i-1)->state;
                        else if (i == w-1)
                            (c+(w*j)+i)->state = (c+(w*j)+1)->state;
                        if (j==0)
                            (c+i)->state = (c+(w*(h-2))+i)->state;
                        else if (j == h-1)
                            (c+(w*(h-1))+i)->state = (c+w+i)->state;                       
                        break;
                
                }
            (c+(w*j)+i)->nState =  (c+(w*j)+i)->state;
            }
        }
    }
}

void update(Cell* c, int w, int h){
    w = w + 2;
    h = h + 2;
    int size = w*h;

    for (int j = 1; j < h - 1; j++){
        for (int i = 1; i < w + 1; i++){
            //reset counter, then count neighbors
            int nbors = 0;
            nbors +=(c+(j-1)*w+(i-1))->state + //up-left
                    (c+(j-1)*w+(i))  ->state + //up
                    (c+(j-1)*w+(i+1))->state + //up-right
                    (c+(j)  *w+(i-1))->state + //left
                    (c+(j)  *w+(i+1))->state + //right
                    (c+(j+1)*w+(i-1))->state + //down-left
                    (c+(j+1)*w+(i))  ->state + //down
                    (c+(j+1)*w+(i+1))->state;  //down-right
            //decide next state based on current (rule: B3/S23)
            if ((c+(j*w)+i)->state)
                (c+(j*w)+i)->nState = (nbors == 3 || nbors == 2);
            else if (nbors == 3)
                (c+(j*w)+i)->nState = 1;
            else
                (c+(j*w)+i)->nState = 0;
        }
    }
    //update all cells
    for (int i = 0; i < size; i++)
        (c+i)->state = (c+i)->nState;
}

int menu(char* opts[], char msg[]){
    system("cls");
    printf("\033[1;31m");
    printf("%s\n", msg);
    printf("\033[1;m");
    //print options
    printf("(0) Return\n");
    int i = 0;
    while (opts[i] != NULL){
        printf("(%d) %s\n", i+1, opts[i]);
        i++;
    }
    //get answer
    
    printf("\033[1;31mPlease choose an option! (0-%d):\033[1;m ", i);
    int choice;
    scanf("%d", &choice);

    //if answer is not an option, try again
    if (choice > i){
        menu(opts, msg);
    }
    return choice-1;
}

int draw(Cell* c, int width, int height, int borderM){
    char ch;
    bool playing = false;
    
    while(1){
        display(c, width, height);
        printf("\033[1;31m\n0:     Return\nTab:   Continue\nSpace: Play\nEsc:   Exit\033[1;m ");
    
        ch = getch();
        if (ch == 27)
            return -1;

        else if(ch == 9){
            update(c, width, height);
            border(c, width, height, borderM);
            continue;
        }
        else if (ch == 48){
            return 0;
        }
        else if (ch == 32){
            playing = true;
            while (playing){
                display(c, width, height);
                update(c, width, height);
                border(c, width, height, borderM);
                printf("\033[1;31m\nPress [Space] to stop!\033[1;m ");
                sleep(1); 
                
                if (kbhit()) {
                    ch = getch();
                    if (ch == 32)
                        playing = false;
                }
            }  
        }
    }
    return 1;
}

int mainMenu(int* width, int* height, int* borderM, int* initM){
    //def menu options
    char* initOpts[] = {"Dead", "Alive", "Random", "Automaton", "File", NULL};
    char* borderOpts[] = {"Dead", "Alive", "Infinite", NULL};
    
    //print main menu
    clrscr();
    printf("\033[1;31mMage of File by U+0466\n\033[1;m");
    printf("(0) Exit\n");
    printf("(1) Size: %d x %d\n", *width, *height);
    if (*initM == 3) //automaton rule printing
        printf("(2) Starting state: %s (Rule %d)\n", initOpts[*initM], rule);
    else if (*initM == 4) //file path printing
        printf("(2) Starting state: %s\n", path);
    else
        printf("(2) Starting state: %s\n", initOpts[*initM]);
    printf("(3) Border mode: %s\n", borderOpts[*borderM]);
    printf("(4) Play\n");
    printf("\033[1;31mPlease choose an option! (0-4):\033[1;m ");

    //get answers
    int opt;
    scanf(" %d", &opt);
    int ans;

    //create submenus
    switch (opt){
        case 0: return -1;
        case 1: clrscr();
            printf("\033[1;31mEnter Width and Height:\033[1;m \n");
            scanf("%d %d", width, height);
            break;
        case 2:
            ans = menu(initOpts, "How do you want to populate the field?");
            if (ans == 3){
                clrscr();
                printf("\033[1;31mEnter rule for Cellular Automaton (0-255):\033[1;m ");
                scanf("%d", &rule);
                *initM = ans;
            }
            else if (ans == 4){
                clrscr();
                int tmp = fileIn(width, height);
                while (tmp == -1){
                    printf("\033[1;31mInvalid file, try again?\033[1;m (Y/N) ");
                    char ans;
                    scanf("%c", &ans);
                    if (ans == 89)
                        tmp = fileIn(width, height);
                    else if(ans == 78)
                        break;
                }
                if (tmp != -1)
                    *initM = 4;
                }
            else
                *initM = ans;
            break;
        case 3:
            ans = menu(borderOpts, "How do you want to set the border?");
            if (ans != -1)
                *borderM = ans;
            break;
        case 4:
            return 1;
    }
    return 0;
}

int main(){
    int width = 20, height = 30;
    int borderM = 1, initM = 2;

    Cell** field;
    field = NULL;
    int state = 0;
    
    //welcome();
    
    while (1){
        switch (state){
            case -1:
                free(field);
                printf("Good Bye!");
                return 0;
            case 0:
                state =  mainMenu(&width, &height, &borderM, &initM);
                if (state == 1){
                    free(field);
                    field =  setup(width, height);
                    init(*field, width, height, initM);
                    border(*field, width, height, borderM);
                }
                break;
            case 1:
                state = draw(*field, width, height, borderM);
                break;
        }
    }
    return 0;
}
arrays c function while-loop exit
1个回答
0
投票

在您的设置函数中,您可以在

malloc(size * sizeof(Cell))
类型上使用分配
Cell**
,如果您想创建 Cell 指针数组,则应该使用
sizeof(Cell*)
sizeof(*field)

© www.soinside.com 2019 - 2024. All rights reserved.