cmemorymallocconways-game-of-life

Errorcode EXC_BAD_ACCESS (code=1, address=0xffffffffffffff)


I have to build the "Game of Life" by J.H. Conway. The game follows strict rules I wanted to implement in my code. Now I am getting an Errorcode anytime I want to debug. For those who doesn't know the game. Please look it up. It would take some time to explain :)

I was trying to implement the rules for "Game of Life". I started working with dynamic 2D-Arrays. I think I messed something up with my memory allocation, but I can't help myself.

// Game of Life

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

#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
#pragma warning (disable: 4996)

int dau_eingabe(int min, int max);
char** zufallsstart(char zeilen, char spalten, float prozent);
void execution(char zeilen, char spalten, char** body);
void print_body(char zeilen, char spalten, char ** body);
void free_speicherplatz(char zeilen, char ** body);

int main(){
    int choice = 0;
    char zeilen = 0;
    char spalten = 0;
    float prozent;
    char ** body;

    srand( time( NULL ) );

    printf("\n");
    printf("\t\t*** Game of Life ***\n\n");
    printf("Zufallsgenerator: 1\n");
    printf("Datei: 2\n");
    printf("\n");
    printf("Startzustand auswählen:\n");
    choice = dau_eingabe(1,2);
    printf("\n");

    // 1. Menü für Startzustand über eine Datei
    if(choice == 2){
        printf("Datei");
    }

    // 2. Menü für Startzustand: Zufall und Datei
    switch(choice){
        case 1:
            // Start durch Zufallsgenerator

                printf("\nGeben Sie die Anzahl an Zeilen an (1 - 255):");
                zeilen = dau_eingabe(1,255);
                printf("\nGeben Sie die Anzahl an Spalten an (1 - 255:");
                spalten = dau_eingabe(1,255);
                printf("\nGeben Sie an, mit wie viel Prozent das Spielfeld mit lebenden Zellen zu füllen ist (0 - 100):");
                prozent = dau_eingabe(0,100);
                

                zufallsstart(zeilen,spalten,prozent);
                break;            
    }

    printf("\nWählen Sie aus die Form der Abarbeitung aus:");
    printf("\n\n1. schrittweise Abarbeitung\n2. animierte Abarbeitung");
    printf("\nEingabe >> ");
    choice = dau_eingabe(1,2);
    switch(choice){
        case 1:
        printf("\n\t\t***Schrittweise Abarbeitung***");
        case 2:
        printf("\n\t\t***Animierte Abarbeitung***\n");
        execution(zeilen,spalten,body);
    }

    free_speicherplatz(zeilen,body);
    return 0;
}

int dau_eingabe(int min, int max){
    int choice;

    if(scanf(" %d",&choice) == 0){
        printf("Die Eingabe ist falsch. Beachten Sie den Eingabebereich!\n");
        choice = dau_eingabe(min,max);
    }

    if(choice < min || choice > max){
        printf("Die Eingabe ist falsch. Beachten Sie den Eingabebereich!\n");
        choice = dau_eingabe(min,max);
        }

    if(choice >= min && choice <= max){
        return choice;
        } 
}

    // Funktion gibt body (Matrix der Zellen) zurück an main-Funktion und realisiert den Zufallsstart
    // d.h. die Funktion erstellt den Startzustand des Spiels
char** zufallsstart(char zeilen, char spalten, float prozent){

    char ** body;
    int maxcells_alive = (zeilen * spalten) * (prozent / 100);
    int maxcells_dead = ((zeilen) * (spalten)) - maxcells_alive;
    int cells_alive = 0;
    int cells_dead = 0;
    char currentstate = ' ';

   
    // Speicherplatz reservieren für die char-Zeiger
    body = malloc(zeilen * sizeof(char *));
    if(body == NULL){
        printf("\nFehler bei der Speichervergabe!\n");
    }

    // Speicherplatz reservieren für die einzelnen Spalten der jeweiligen Zeile i
    for(int i = 0; i < zeilen;i++){
        body[i] = malloc(spalten * sizeof(char *));
            if(body[i] == NULL){
            printf("\nFehler bei der Speichervergabe in Zeile %d!\n",i);
            }
    }

    // Zufallsstart
    for(int i = 0; i < zeilen; i++){
        for(int j = 0; j < spalten; j++){
            body[i][j]= ' ';
        }
    }
    
    for(int i = 0; i < zeilen; i++){
        for(int j = 0; j < spalten; j++){
            if( maxcells_alive > cells_alive ){
                if( rand() % 2 == 1){                
                    currentstate = '*';
                    body[i][j] = currentstate;
                    cells_alive++;
                } else if( maxcells_dead > cells_dead) {
                currentstate = ' ';
                body[i][j] = currentstate;
                cells_dead++;
            } else{
                currentstate = '*';
                body[i][j] = currentstate;
                cells_alive++;
            }
        }
    }if(body== NULL){printf("Zellen sind null");}
}
    printf("\n\nStartzustand:\n");
    print_body(zeilen,spalten,body);
                
    return body;
}


    // zeigt die Matrix der Zellen
void print_body(char zeilen, char spalten, char ** body){
    for(int i = 0; i < zeilen; i++){
            for(int j = 0; j < spalten; j++){
            printf(" %c",body[i][j]);                       
            }
        printf("\n");
    }
}

    // gibt den Speicherplatz wieder frei, nachdem das Programm durchgelaufen ist
void free_speicherplatz(char zeilen, char ** body){
    for(int i = 0; i < zeilen; i++){
    free(body[i]);
    }
    free(body);
}

void execution(char zeilen, char spalten, char** body){
    int repetition = 0;
    int dead_neighbor_cell = 0;
    int alive_neighbor_cell = 0;
    char single_cell = ' ';

    // Speicherplatz reservieren für die char-Zeiger
    body = malloc(zeilen * sizeof(char *));
    if(body == NULL){
        printf("\nFehler bei der Speichervergabe!\n");
    }

    // Speicherplatz reservieren für die einzelnen Spalten der jeweiligen Zeile i
    for(int i = 0; i < zeilen;i++){
        body[i] = malloc(spalten * sizeof(char *));
            if(body[i] == NULL){
            printf("\nFehler bei der Speichervergabe in Zeile %d!\n",i);
            }
    }

            while(repetition <= 10){
                for(int i = 0; i < zeilen; i++){
                    for(int j = 0; j < spalten; j++){                      
    // Spieldynamik
                        dead_neighbor_cell = 0;
                        alive_neighbor_cell = 0;
                        single_cell = body[i][j];

                        if( single_cell == '*'){
                            if( i == 0 && j == 0){
                                if( single_cell == body[i][j+1]){alive_neighbor_cell++;}
                                if( single_cell == body[i+1][j]){alive_neighbor_cell++;}
                                if( single_cell == body[i+1][j+1]){alive_neighbor_cell++;}
                            }
                            if( i == 0 && j == (spalten)-1){
                                if( single_cell == body[i][j-1]){alive_neighbor_cell++;}
                                if( single_cell == body[i+1][j]){alive_neighbor_cell++;}
                                if( single_cell == body[i+1][j-1]){alive_neighbor_cell++;}
                            }
                            if( i == (zeilen)-1 && j == 0){
                                if( single_cell == body[i-1][j]){alive_neighbor_cell++;}
                                if( single_cell == body[i][j+1]){alive_neighbor_cell++;}
                                if( single_cell == body[i-1][j+1]){alive_neighbor_cell++;}                               
                            }
                            if( i == (zeilen)-1 && j == (spalten)-1){
                                if( single_cell == body[i-1][j]){alive_neighbor_cell++;}
                                if( single_cell == body[i][j-1]){alive_neighbor_cell++;}
                                if( single_cell == body[i-1][j-1]){alive_neighbor_cell++;}                               
                            }
                            if( 0 < i < zeilen && 0 < j < spalten){
                                if(single_cell == body[i-1][j-1]){alive_neighbor_cell++;}
                                if(single_cell == body[i-1][j]){alive_neighbor_cell++;}
                                if(single_cell == body[i-1][j+1]){alive_neighbor_cell++;}
                                if(single_cell == body[i][j-1]){alive_neighbor_cell++;}
                                if(single_cell == body[i][j+1]){alive_neighbor_cell++;}
                                if(single_cell == body[i+1][j-1]){alive_neighbor_cell++;}
                                if(single_cell == body[i+1][j]){alive_neighbor_cell++;}
                                if(single_cell == body[i+1][j+1]){alive_neighbor_cell++;}
                            }
                        }
                        if( single_cell == ' '){
                            if( i == 0 && j == 0){
                                if( single_cell != body[i][j+1]){dead_neighbor_cell++;}
                                if( single_cell != body[i+1][j]){dead_neighbor_cell++;}
                                if( single_cell != body[i+1][j+1]){dead_neighbor_cell++;}
                            }
                            if( i == 0 && j == (spalten)-1){
                                if( single_cell != body[i][j-1]){dead_neighbor_cell++;}
                                if( single_cell != body[i+1][j]){dead_neighbor_cell++;}
                                if( single_cell != body[i+1][j-1]){dead_neighbor_cell++;}
                            }
                            if( i == (zeilen)-1 && j == 0){
                                if( single_cell != body[i-1][j]){dead_neighbor_cell++;}
                                if( single_cell != body[i][j+1]){dead_neighbor_cell++;}
                                if( single_cell != body[i-1][j+1]){dead_neighbor_cell++;}                               
                            }
                            if( i == (zeilen)-1 && j == (spalten)-1){
                                if( single_cell != body[i-1][j]){dead_neighbor_cell++;}
                                if( single_cell != body[i][j-1]){dead_neighbor_cell++;}
                                if( single_cell != body[i-1][j-1]){dead_neighbor_cell++;}                               
                            }
                            if( 0 < i < zeilen && 0 < j < spalten){
                                if(single_cell != body[i-1][j-1]){dead_neighbor_cell++;}
                                if(single_cell != body[i-1][j]){dead_neighbor_cell++;}
                                if(single_cell != body[i-1][j+1]){dead_neighbor_cell++;}
                                if(single_cell != body[i][j-1]){dead_neighbor_cell++;}
                                if(single_cell != body[i][j+1]){dead_neighbor_cell++;}
                                if(single_cell != body[i+1][j-1]){dead_neighbor_cell++;}
                                if(single_cell != body[i+1][j]){dead_neighbor_cell++;}
                                if(single_cell != body[i+1][j+1]){dead_neighbor_cell++;}
                            }
                        }
                        if(body[i][j] == '*'){
                        if(alive_neighbor_cell != 2 || alive_neighbor_cell != 3){body[i][j] = ' ';}
                        else if (alive_neighbor_cell == 2 || alive_neighbor_cell == 3){body[i][j] = '*';}
                        }else if (body[i][j] == ' ' && dead_neighbor_cell == 3){body[i][j] = '*';}
                        else{body[i][j]= ' ';}
                    }
                }repetition++;
            }
}




Solution

  • This line here

    if( 0 < i < zeilen && 0 < j < spalten){
    

    does not do what you think it does. You probably meant to write

    if (0 < i && i < zeilen - 1 && 0 < j && j < spalten - 1) {
    

    Let's see why this is, step by step:

    1. C evaluates the highest precedent operators first. In this case, < evaluates before &&.

      if ((0 < i < zeilen) && (0 < j < spalten)) {

    2. But if there are multiple operators at the same level of precedence, they evaluate left-to-right.

      if (((0 < i) < zeilen) && ((0 < j) < spalten)) {

    3. If i or j are not 0 , the expression does not work.

    Let's go step by step (say i is 3 and j is 10 for example):

    if (((0 < 3) < zeilen) && ((0 < 10) < spalten)) {
    

    then

    if (((1) < zeilen) && ((1) < spalten)) {
    

    then

    if ((1) && (1)) {
    

    In mathematics, it's common practice to write expressions like a < x < b, but the C language cannot evaluate the expression in this way.