For arrays and matrices I recommend
Code:
#include <stdlib.h>
#include <errno.h>
#define MATRIXDATA int
struct matrix {
long rows;
long cols;
size_t rowstep;
size_t colstep;
MATRIXDATA data[];
};
struct matrix *free_matrix(struct matrix *const m)
{
if (m && m->rows > 0L && m->cols > 0L) {
m->rows = 0L;
m->cols = 0L;
m->rowstep = 0;
m->colstep = 0;
}
return NULL;
}
struct matrix *new_matrix(const long rows, const long cols)
{
const size_t cells = (size_t)rows * (size_t)cols;
const size_t bytes = cells * sizeof (MATRIXDATA);
const size_t total = bytes + sizeof (struct matrix);
struct matrix *m;
/* Invalid number of rows or cols? */
if (rows < 1L || cols < 1L) {
errno = EINVAL;
return NULL;
}
/* Too many cells? Relies on C99 casting rules to detect overflow/wrapping. */
if (total < bytes || (long)(bytes / (size_t)rows) != (long)(cols * sizeof (MATRIXDATA))) {
errno = ENOMEM;
return NULL;
}
m = malloc(total);
if (!m) {
errno = ENOMEM;
return NULL;
}
m->rows = rows;
m->cols = cols;
m->rowstep = (size_t)cols;
m->colstep = 1;
return m;
}
#define CELL(matrix, row, col) ((m)->data[ (row)*(m)->rowstep + (col)*(m)->colstep ])
static inline MATRIXDATA matrix_get(const struct matrix *const m, const long row, const long col)
{
if (!m || row < 0L || col < 0L || row >= m->rows || col >= m->cols)
return (MATRIXDATA)0;
else
return m->data[ row * m->rowstep + col * m->colstep ];
}
static inline MATRIXDATA matrix_set(struct matrix *const m, const long row, const long col, const MATRIXDATA value)
{
if (!m || row < 0L || col < 0L || row >= m->rows || col >= m->cols)
return (MATRIXDATA)0;
else
return m->data[ row * m->rowstep + col * m->colstep ] = value;
}
This is basic dynamic memory management. You can #define MATRIXTYPE to whatever numeric type or pointer you want, too.
You create a new matrix or table using
Code:
struct matrix *thing;
thing = new_matrix(rows, columns);
if (!thing) {
fprintf(stderr, "Could not create a new thing!\n");
exit(1);
}
After you no longer use it, you free it,
Code:
thing = free_matrix(thing);
(If you do not, then it will stay in memory until the program exits.) Most people use free_matrix(thing);, but I recommend the above format because it also sets thing to NULL. If you accidentally use it after freeing it -- use-after-free is a very common error --, you'll always crash (via a segment violation), instead of it sometimes working and sometimes not. Bugs are better fixed than hidden.
To set the value of a matrix element, you can use
Code:
matrix_set(thing, row, column, new_value);
or
CELL(thing, row, column) = new_value;
To get the value of a matrix element (which will be semi-random when created), you can use
Code:
value = matrix_get(thing, row, column);
or
value = CELL(thing, row, column);
The difference is that CELL is a preprocessor macro which does not do any checks, whereas matrix_get() and matrix_set() safely return zero if you try to access outside the matrix (without any buffer overruns or such happening).