Reputation: 3191
Suppose I have two structures one of which extends the other one (as below). What's the correct procedure for dealing with memory when creating an extended structure from an existing structure? Should malloc be called again for the new structure? Would this be doubling up memory allocation where it shouldn't be?
typedef struct Grid {
int rows;
int cols;
int * grid;
} Grid;
typedef struct SuperGrid {
Grid;
char * property;
int id;
} SuperGrid;
static Grid * new_grid(int rows, int cols) {
Grid * grid = (Grid *)(malloc(sizeof(Grid)));
grid->rows= rows;
grid->cols= cols;
grid->grid = (int *)(calloc(rows*cols, sizeof(int)));
}
static SuperGrid * new_super_grid(int rows, int cols) {
/* What needs to happen here? */
return (SuperGrid *)new_grid(rows, cols);
}
Upvotes: 0
Views: 79
Reputation: 144800
Your structure extension mechanism is similar to a primitive C++ class derivation system. To achieve your goal, you need to separate structure allocation and initialization:
typedef struct Grid {
int rows;
int cols;
int *grid;
} Grid;
typedef struct SuperGrid {
Grid;
char *property;
int id;
} SuperGrid;
static Grid *init_grid(Grid *grid, int rows, int cols) {
if (grid) {
grid->rows = rows;
grid->cols = cols;
grid->grid = (int *)calloc(rows * cols, sizeof(int));
}
return grid;
}
static Grid *new_grid(int rows, int cols) {
return init_grid((Grid *)malloc(sizeof(Grid)), rows, cols);
}
static SuperGrid *init_super_grid(SuperGrid *sg, int rows, int cols,
const char *property, int id) {
if (sg) {
init_grid((Grid *)sg, rows, cols);
sg->property = strdup(property);
sg->id = id;
}
return sg;
}
static SuperGrid *new_super_grid(SuperGrid *sg, int rows, int cols,
const char *property, int id) {
return init_super_grid((SuperGrid *)malloc(sizeof(SuperGrid)),
rows, cols, property, id);
}
The allocators may fail and will return NULL
in case of memory allocation failure. You may want them to fail in more explicit ways such as exiting the program with an error message via abort
. Similarly, the delete_xxx
functions should gracefully ignore NULL
pointers as free
does and the C++ delete
operator.
For consistency, you will also separate the delete_grid
and finalize_grid
functions in order to call the finalize_grid
from finalize_super_grid
. It is not strictly necessary for this simple example, but may prove handy if you instantiate Grid
structures that are not allocated (with static or automatic storage or embedded in more complex superstructures).
This poor man's C++ class system will quickly show its limitations. You may consider using C++ directly.
Upvotes: 3