0

In this rather lengthy program I get an error. I have tried to isolate the problem in a smaller program, but I've been unsuccessful, the problem disappears in the smaller program. So here we go:

This is a simple implementation of the game of life. It isn't complete yet. I have marked the row where the error occurs with a comment. It is in the populate_board() function, which is the second one from the bottom. Here is first of all the error message:

Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

It occurs when I try to access an element of the board array. I've had this error in the past when I haven't initialized the array and then indexed it. But here, I have clearly initialized the array in the read_init() function. You guys should also know that this error occurs the very first time the marked line is executed. I don't know what's going on here. Here is the code:

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

#define MAX_COORDINATE_SIZE 50
#define MAX_FILENAME_SIZE 20

struct coord{ //Holds coordinates to a cell
    int x;
    int y;
};

struct cell{
    int pop;    //Populated

};

struct coord *read_init(FILE *fp, int *i);

static int read_line(FILE *fp, char *line, int max_length);

struct coord read_coords(char *line);

struct cell **create_board(int x, int y);

void populate_board(struct coord *coords, struct cell **board, int *n);

struct cell new_cell(int x, int y, int pop);

struct cell **start_game(FILE *fp, int nrows, int ncols);

void print_board(struct cell **board, int nrows, int ncols);


int main(int argc, const char * argv[]) {
    if(argc != 2){
        fprintf(stderr, "Usage: %s [<seed-file>]\n<seed-file> can me up to %d characters long", argv[0], MAX_FILENAME_SIZE);
        exit(1);
    }
    FILE *fp = fopen(argv[1], "r");

    int nrows = 10;
    int ncols = 10;

    struct cell **board= start_game(fp, nrows, ncols);
    print_board(board, nrows, ncols);
    return 0;
}

struct coord *read_init(FILE *fp, int *n){ //Takes in filename and returns list of coordinates to be populated
    char raw_n[100];
    struct coord *coords;
    char *line;

    read_line(fp, raw_n, 100);

    *n = atoi(raw_n);//make an int out of raw_n

    coords = malloc(sizeof(struct coord)*(*n)); //Allocate memory for each coord

    for(int i = 0; i<(*n); i++){
        read_line(fp, line, MAX_COORDINATE_SIZE);
        coords[i] = read_coords(line); //Put coordinates in coords
    }

    return coords; // return coordinates
}

static int read_line ( FILE *fp, char *line, int max_length)
{
    int i;
    char ch;
    /* initialize index to string character */
    i = 0;
    /* read to end of line, filling in characters in string up to its
     maximum length, and ignoring the rest, if any */
    for(;;)
    {
        /* read next character */
        ch = fgetc(fp);
        /* check for end of file error */
        if ( ch == EOF )

            return -1;
        /* check for end of line */
        if ( ch == '\n' )
        {
            /* terminate string and return */
            line[i] = '\0';
            return 0;
        }
        /* fill character in string if it is not already full*/
        if ( i < max_length )
            line[i++] = ch;
    }
    /* the program should never reach here */
    return -1;
}

struct coord read_coords(char *line){ // Returns coordinates read from char *line
    int i = 0;
    struct coord c;
    char *x;
    char *y;
    x = malloc(sizeof(char)*MAX_COORDINATE_SIZE);
    y = malloc(sizeof(char)*MAX_COORDINATE_SIZE);

    do{
        x[i] = line[i];
        i++;
    }while(line[i] != ' ');
    i++;
    do{
        y[i-2] = line[i];
        i++;
    }while(line[i] != '\0');

    c.x = atoi(x);
    c.y = atoi(y);

    return c;
}

void init_board(int nrows, int ncols, struct cell **board){

    board = malloc(nrows * sizeof(*board) + nrows * ncols * sizeof(**board));

    //Now set the address of each row or whatever stackoverflow says
    struct cell * const firstrow = board + nrows;
    for(int i = 0; i < nrows; i++)
    {
        board[i] = firstrow + i * ncols;
    }

    for(int i = 0; i < nrows; i++){ //fill the entire board with pieces
        for(int j = 0; j < ncols; j++){
            board[j][i] = new_cell(i, j, 0);
        }
    }
}

struct cell new_cell(int x, int y, int pop){ //Return new populated or non-populated cell with specified coordinates
    struct cell c;
    c.pop = pop;
    return c;
}

struct cell **start_game(FILE *fp, int nrows, int ncols){ //x,y are no of rows/columns, fn is filename
    int n; // n is the number of populated rows in the seed
    struct coord *coords = read_init(fp, &n); // get the list of coords to populate board with
    struct cell **board;

    init_board(nrows, ncols, board); // Set up the board

    populate_board(coords, board, &n); //populate the cells specified in the seed

    return board;
}

void populate_board(struct coord *coords, struct cell **board, int *n){
    int x;
    int y;
    for(int i = 0; i < *n; i++){
        printf("%d", x = coords[i].x);
        printf("%d", y = coords[i].y);
        printf("%d", board[x][y].pop); // HERE IS THE ERROR
       // board[coords[i].x][coords[i].y].pop = 1; //populate the cell
    }
}

void print_board(struct cell **board, int nrows, int ncols){
    for(int i = 0; i<nrows; i++){
        for(int j = 0; j<ncols; j++){
            if(board[i][j].pop == 1){
                printf("X");
            }else{
                printf("O");
            }
        }
        printf("\n");
    }
    printf("\n");
}
Sahand
  • 7,980
  • 23
  • 69
  • 137
  • 1
    The basic problem is that `init_board` sets `board`, but that doesn't change the value of `board` in `start_game`. – Dietrich Epp Jul 17 '17 at 16:14
  • 1
    Or at least, that's one major problem. I stopped reading when I found that error. – Dietrich Epp Jul 17 '17 at 16:14
  • You mean board has to be initialised "higher up" in the program? – Sahand Jul 17 '17 at 16:16
  • I suggest reviewing how function parameters work. C is known as "pass by value", so if you set a parameter inside a function, you won't change the value of what was passed into the function. This is true of the vast majority of languages in common use today. – Dietrich Epp Jul 17 '17 at 16:18
  • You're right... That's why you need a pointer to a pointer to change the pointer itself in a function. But here I'm trying to chance a pointer to a pointer. Is making init accept a pointer to a pointer to a pointer (a `struct cell ***`) a reasonable solution? – Sahand Jul 17 '17 at 16:23
  • Let me put it this way... if you have a variable named `board`, then a function call `f(board)` won't change the value of `board` at all, no matter what type `board` is. It doesn't change because `board` is already a pointer, or already a pointer to a pointer. – Dietrich Epp Jul 17 '17 at 16:37

0 Answers0