You have stumbled onto the challenge where you must simulate a 2d
array from a simple 1d
array. If you look at the function declaration you are given, you have GW *gw_build(...)
which tells you gw_build
will return an array
of struct GW
. Now ideally, you could make things easier by creating an array of pointers to struct GW
, but obviously part of the assignment is to have you work with a simple array of struct.
This simplifies the allocation, but complicates the indexing. Meaning, your declaration of gw_build
can simply be:
GW *gw_build(int nrows, int ncols, int pop, int rnd){
GW *list = calloc (nrows * ncols, sizeof *list);
if (!list) {
fprintf (stderr, "gw_build() error: virtual memory exhausted.\n");
return NULL;
}
return list;
}
But the challenge then comes in filling and referencing each, especially if you want a pseudo-2d representation. The assignment is really an exercise in understanding pointers as well as index manipulation. The best way to talk about this is by example. (note: below, I've included the declaration of gw_struct
in gw.h
, but if you can't do that, just put the declaration in each source file)
#ifndef _gw_header_
#define _gw_header_ 1
typedef struct gw_struct GW;
struct gw_struct {
int Alive;
int row;
int column;
int id;
};
extern GW *gw_build(int nrows, int ncols, int pop, int rnd);
#endif
The #ifdef _gw_header_
is just an example of controlling header file inclusion. It insures gw.h
is only included once. You can scrap it if you can't add to the header file.
The source file gw.c
simply needs to allocate nrows * ncols
structs, so it can be as simple as:
#include <stdio.h>
#include <stdlib.h>
#include "gw.h"
GW *gw_build(int nrows, int ncols, int pop, int rnd){
GW *list = calloc (nrows * ncols, sizeof *list);
if (!list) {
fprintf (stderr, "gw_build() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return list;
}
Both standard and not much to discuss. The real work comes in your source file containing main()
where you will fill and use the array returned by gw_build
.
#include <stdio.h>
#include "gw.h"
#define ROWS 10
#define COLS 10
int main (void) {
GW *world = gw_build (ROWS, COLS, 34, 1);
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
(world + i * ROWS + j)->Alive = (i*ROWS + j) % 3;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
printf (" world[%2d][%2d] : %d\n", i, j, (world + i*ROWS + j)->Alive);
return 0;
}
(for example purposes, I've just filled Alive
with values between 0-2
depending on the index value)
When you receive the allocated array back from gw_build
you must manage filling and use by offset
from the beginning of the array. You can simply use (0 < index < (nrows*ncols)
), but that will defeat using the pseudo 2D indexing. The trick is simply finding a way to calculate and reference each offset using 2D array syntax. If you note above, the offset of each struct is accessed by i * ROWS + j
. That allows the psuedo-2D reference of array[i][j]
where behind the scene i
represents i * nrows
and j
just the additional offset from that address.
You also have the choice of using the ->
operator to reference the cells as shown above, or you can write an equivalent form that uses the .
operator for struct member reference. The alternative is shown below:
#include <stdio.h>
#include "gw.h"
#define ROWS 10
#define COLS 10
int main (void) {
GW *world = gw_build (ROWS, COLS, 34, 1);
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
world[i * ROWS + j].Alive = (i * ROWS + j) % 3;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
printf (" world[%2d][%2d] : %d\n", i, j, world[i * ROWS + j].Alive);
return 0;
}
Look over both and let me know if you have questions. I've used two #define
statements to fix nrows
and ncols
for the example. Compiling and running the code, you will see the output:
$ ./bin/gwtest
world[ 0][ 0] : 0
world[ 0][ 1] : 1
world[ 0][ 2] : 2
world[ 0][ 3] : 0
world[ 0][ 4] : 1
world[ 0][ 5] : 2
world[ 0][ 6] : 0
world[ 0][ 7] : 1
world[ 0][ 8] : 2
world[ 0][ 9] : 0
world[ 1][ 0] : 1
world[ 1][ 1] : 2
world[ 1][ 2] : 0
world[ 1][ 3] : 1
world[ 1][ 4] : 2
world[ 1][ 5] : 0
world[ 1][ 6] : 1
world[ 1][ 7] : 2
world[ 1][ 8] : 0
world[ 1][ 9] : 1
world[ 2][ 0] : 2
...
world[ 8][ 8] : 1
world[ 8][ 9] : 2
world[ 9][ 0] : 0
world[ 9][ 1] : 1
world[ 9][ 2] : 2
world[ 9][ 3] : 0
world[ 9][ 4] : 1
world[ 9][ 5] : 2
world[ 9][ 6] : 0
world[ 9][ 7] : 1
world[ 9][ 8] : 2
world[ 9][ 9] : 0