Jake Thomas
Jake Thomas

Reputation: 19

2 Dimensional Array not Printing Expected Answer

When I iterate through the 2D array elements to display each int, I get a string of digits. I have tried a number of different things to fix it but I figure it is something small I am overlooking which will bring it all together.

Anyway, in header.h we create

    typedef struct gol{
    int **board;
    size_t size;
}gol;

and in Main.c

void GOL_Opton1(){

    printf(" This is running Game Of Life on a default board\n");

    gol* mainGOL = (gol*)malloc(sizeof(gol));

    mainGOL = create_default_gol();
    print_gol(mainGOL);
}

gol* create_default_gol()
{
    gol* defaultGol = (gol*)malloc(sizeof(gol));

    int defaultArray[20][20];
    defaultGol->board = defaultArray;

    for (i = 0; i<20; i++){
        for (j = 0; j<20; j++){
           defaultGol->board[i,j] = 0;
     }
    }
    return defaultGol;
}

void print_gol(gol* g){
printf(" ------------------------------------------------\n");
for (i = 0; i<20; i++){
     for (j = 0; j<20; j++){
       printf("%d \t",g->board[i,j] );
     }printf("\n");
     }
}

Option 1, is called from a menu, then the board array in the gol is populated with a set of 0's for a starting point.

Upvotes: 0

Views: 74

Answers (3)

BLUEPIXY
BLUEPIXY

Reputation: 40145

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

typedef struct gol{
    int **board;
    size_t size;
}gol;


gol *create_gol(size_t size){
    size_t i, j;
    gol *aGol = (gol*)malloc(sizeof(gol));

    aGol->board = malloc(size * sizeof(int*));
    aGol->size = size;
    for (i = 0; i < size; i++){
        aGol->board[i] = malloc(size * sizeof(int));
        for (j = 0; j < size; j++){
           aGol->board[i][j] = 0;
        }
    }
    return aGol;
}

gol *create_default_gol(void){
    return create_gol(20);
}

void print_gol(gol *g){
    size_t i, j;
    printf("------------------------------------------------\n");
    for (i = 0; i < g->size; i++){
        for (j = 0; j < g->size; j++){
            printf("%d ", g->board[i][j] );
        }
        printf("\n");
    }
}

void GOL_Opton1(void){
    printf("This is running Game Of Life on a default board\n");

    gol *mainGOL = create_default_gol();
    print_gol(mainGOL);
}

int main(void){
    GOL_Opton1();
    //deallocate
    return 0;
}

Upvotes: 0

rslemos
rslemos

Reputation: 2731

The specific problem you're facing is in create_default_gol().

int defaultArray[20][20];
defaultGol->board = defaultArray;
[...]
return defaultGol;

defaultArray is alloc'ed in stack, then it's pointer escapes the function. The data you've written to defaultArray (or ->board for that matter) will be long gone by the time you access it.

You can correct this by alloc'ing your ->board on the heap, with mallocs: one for the entire board (malloc(20 * sizeof( int* ))), then 20 more for each row (malloc(20 * sizeof( int ))).

Upvotes: 1

ilbelkyr
ilbelkyr

Reputation: 435

There's a few things to improve there. First off, in your header, an easier way to deal with a two-dimensional array would be to store a pointer to the first array element as well as the size. (Your code assumes all boards are square. We'll go with that for now.)

typedef struct { /* No need to name the struct if you typedef it */
    int *board;  /* We point to the first int, then calculate offsets manually */
    size_t size;
} gol;

We can then calculate the position in the array manually. Let's assume we store the numbers in this order:

012
345
678

Now, let's assume we want the element in the 1st row, 2nd column - starting from zero, so really the middle row and last column - we know that there are three columns per row, so rows * columns_per_row + columns will be the element to look up.

void GOL_Opton1(){
    printf(" This is running Game Of Life on a default board\n");

create_default_gol() already calls malloc for you. If you assign mainGOL the return of a malloc first, you ask for that memory but never use it as you immediately store another address in mainGOL. That would result in a memory leak.

    gol* mainGOL = create_default_gol();

    print_gol(mainGOL);
}

To avoid "magic numbers", I'd use a #define. The default board size is easily adjustable this way, too.

#define DEFAULT_GOL_SIZE 20

gol* create_default_gol()
{
    gol* defaultGol = (gol*)malloc(sizeof(gol));

Declaring an array normally allocates it on the stack. However, you want create_default_gol to return a gol that can be used by outside functions, so you need to allocate it on the heap. This might result in all kinds of strange behaviour otherwise.

    defaultGol->board = malloc(sizeof(int) * DEFAULT_GOL_SIZE * DEFAULT_GOL_SIZE);
    defaultGol->size  = DEFAULT_GOL_SIZE; /* and store the size */

Here, the memset function is a common way of quickly setting the entire board to 0.

    /* memset avoids an ugly for loop here */
    memset(defaultGol->board, defaultGol->size * defaultGol->size, 0);

    return defaultGol;
}

void print_gol(gol* g){
    size_t row, col;
    printf(" ------------------------------------------------\n");

You'll want your print_gol function to be able to handle boards of a different size than 20, so generalize this to use the size member.

    for (row = 0; row < g->size; row++) {
        for (col = 0; col < g->size; col++) {

This is where the offsets discussed above come into play. Your original code had [i, j], which wouldn't do what you meant; with an ordinary two-dimensional array, you'd want [i][j], but in this case, we are doing the offset calculations manually to allow for arbitrary sizes.

            printf("%d \t", g->board[col + row*g->size] );
        }
        printf("\n");
    }
}

Upvotes: 4

Related Questions