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 ;
}
}
CodePudding user response:
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:
C evaluates the highest precedent operators first. In this case,
<
evaluates before&&
.if ((0 < i < zeilen) && (0 < j < spalten)) {
But if there are multiple operators at the same level of precedence, they evaluate left-to-right.
if (((0 < i) < zeilen) && ((0 < j) < spalten)) {
If
i
orj
are not0
, 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.
CodePudding user response:
The code contains many errors. Some of them have already been mentioned above. In general, this fragment is quite large. I doubt anyone would want to review such a large piece of code. What to do? Some of the errors can be easily found by compiler warnings / static code analyzer. Upload the code to Compiler Explorer and check it using the PVS-Studio tool. I give you some code errors’ examples here. But I suppose there are others of a higher-level type.
char **body;
....
execution(zeilen,spalten,body);
....
free_speicherplatz(zeilen,body);
In fact, the body
pointer is uninitialized. The free_speicherplatz
function is supposed to free previously unallocated memory, but works with garbage (uninitialized memory) as a result. Here is the right way:
char **body;
execution(zeilen,spalten,&body);
....
void execution(char zeilen, char spalten, char*** body){
*body = malloc(zeilen * sizeof(char *));
By the way, let’s look at the execution
function, that is below in this fragment. It contains the check that allows you to know whether memory is allocated. This is fine. However, along with issuing a message from the check, it’s better to terminate the program.
Next, look at the following code fragment:
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;
}
}
Only one branch returns a value. In other cases, the undefined behavior will occur.
The following expression makes no sense:
if(alive_neighbor_cell != 2 || alive_neighbor_cell != 3)
The variable is always not equal to 2 or 3. The condition is always met.