life

Conway's Game of Life (ncurses)
git clone https://github.com/michaelneuper/life.git
README | Files | Log | Refs

commit c80091d4748c63f34b4320d8fcd395a85ab7fba2
parent ece9d3159b43d57b23b7415799dd7965b36421c3
Author: Michael Neuper <michael@michaelneuper.com>
Date:   Tue, 11 Nov 2025 08:41:52 +0200

remove goto's and fix memory leak

Diffstat:
Mlife.c | 73++++++++++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 40 insertions(+), 33 deletions(-)

diff --git a/life.c b/life.c @@ -54,12 +54,12 @@ void randomize_grid(Grid *grid); /* --- main routine --------------------------------------------------------- */ -int main(int argc, char *argv[]) { +int main(void) { init_screen(); game_loop(); cleanup(); - return 0; + return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ @@ -72,7 +72,13 @@ void game_loop() { Grid *cur = init_grid(rows, cols); Grid *next = init_grid(rows, cols); - if (!(cur && next)) goto err; + if (!(cur && next)) { + cleanup(); + if (cur) free_grid(cur); + if (next) free_grid(next); + fprintf(stderr, "Something terrible has happened.\n"); + exit(1); + } struct timespec ts; ts.tv_sec = 0; @@ -107,14 +113,6 @@ void game_loop() { free_grid(cur); free_grid(next); - return; - -err: - cleanup(); - if (cur) free_grid(cur); - if (next) free_grid(next); - fprintf(stderr, "Something terrible has happened.\n"); - exit(1); } void tick(const Grid *cur, Grid *next) { @@ -180,12 +178,26 @@ Grid *init_grid(size_t rows, size_t cols) { State **cells = malloc(rows * sizeof(State *)); Grid *grid = malloc(sizeof(Grid)); - if (!(grid && cells)) goto err; + if (!(grid && cells)) { + if (cells) free(cells); + if (grid) free(grid); + + return NULL; + } for (size_t i = 0; i < rows; i++) { cells[i] = malloc(cols * sizeof(State)); - if (!cells[i]) goto err; // FIXME memory leak + if (!cells[i]) { + for (size_t j = 0; j < i; j++) + free(cells[i]); + free(cells); + free(grid); + + return NULL; + } + + // initialize all cells to DEAD for (size_t j = 0; j < cols; j++) { cells[i][j] = DEAD; } @@ -196,12 +208,6 @@ Grid *init_grid(size_t rows, size_t cols) { grid->cols = cols; return grid; - -err: - if (cells) free(cells); - if (grid) free(grid); - - return NULL; } void free_grid(Grid *grid) { @@ -216,6 +222,7 @@ void free_grid(Grid *grid) { void print_grid(const Grid *grid) { for (size_t i = 0; i < grid->rows; i++) { for (size_t j = 0; j < grid->cols; j++) { + // print ' ' for dead cells to avoid having to clear the screen print_char(i, j, grid->cells[i][j] ? '#' : ' ', 0); } } @@ -224,6 +231,8 @@ void print_grid(const Grid *grid) { } void set_grid(Grid *grid) { + bool paused = true; + struct { size_t row, col; } curs = {grid->rows / 2, grid->cols / 2}; @@ -231,32 +240,32 @@ void set_grid(Grid *grid) { init_pair(CURS_COL, COLOR_BLUE, COLOR_BLACK); print_char(curs.row, curs.col, '*', CURS_COL); - while (true) { + while (paused) { int key = getch(); switch (key) { case KEY_UP: case 'k': case 'w': - curs.row -= 1; + curs.row--; break; case KEY_LEFT: case 'h': case 'a': - curs.col -= 1; + curs.col--; break; case KEY_DOWN: case 'j': case 's': - curs.row += 1; + curs.row++; break; case KEY_RIGHT: case 'l': case 'd': - curs.col += 1; + curs.col++; break; case 't': @@ -267,19 +276,22 @@ void set_grid(Grid *grid) { randomize_grid(grid); break; + case 'q': + free_grid(grid); + cleanup(); + exit(0); + case '\n': case '\r': case ' ': case 'e': - return; - - case 'q': - goto quit; + paused = false; default: continue; } + // wrap cursor around screen curs.row = (curs.row + grid->rows) % grid->rows; curs.col = (curs.col + grid->cols) % grid->cols; @@ -287,11 +299,6 @@ void set_grid(Grid *grid) { print_grid(grid); print_char(curs.row, curs.col, '*', CURS_COL); } - -quit: - free_grid(grid); - cleanup(); - exit(0); } void randomize_grid(Grid *grid) {