There are a few subtle points that can make dynamically creating 2D matricies more robust and less likely to provide a chance for inadvertent read from an uninitialized value (undefined behavior). The No. 1 improvement you can make is to allocate the column arrays with calloc
such that the memory for each cell is already initialized to zero - 0
at the time of allocation. This allows immediate iteration over the entire matrix without the potential for a read of an uninitialized value. Take a look at the following:
#include <stdio.h>
#include <stdlib.h>
int **mtrx_calloc (size_t m, size_t n); /* initialize elements to 0 */
int **realloc_rows (int **ap, size_t *m, size_t n, size_t newm); /* resize newm x n */
void mtrx_prn (size_t m, size_t n, int **matrix); /* print matrix with/pad */
void mtrx_free (size_t m, int **matrix); /* free memory allocated */
int main (int argc, char **argv)
{
/* set initial size from arguments given (default: 3 x 4) */
size_t m = argc > 2 ? (size_t)atoi (argv[1]) : 3;
size_t n = argc > 2 ? (size_t)atoi (argv[2]) : 4;
/* allocate the m x n matrix */
int **matrix = mtrx_calloc (m, n);
/* fill with misc values */
register size_t i = 0, j = 0;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
matrix [i][j] = (int)(i + j);
}
/* print matrix */
printf ("\nThe dynamically allocated %zux%zu matrix is:\n\n", m, n);
mtrx_prn (m, n, matrix);
/* reallocate matrix - add 4 rows */
printf ("\nReallocate matrix to %zux%zu:\n\n", m + 4, n);
size_t oldm = m;
matrix = realloc_rows (matrix, &m, n, m + 4);
/* fill new rows with misc values */
for (i = oldm; i < m; i++)
{
for (j = 0; j < n; j++)
matrix [i][j] = (int)(i + j);
}
mtrx_prn (m, n, matrix);
/* free memory alocated */
mtrx_free (m, matrix);
/* just to make it look pretty */
printf ("\n");
return 0;
}
/* allocate/initialize mxn matrix */
int **mtrx_calloc (size_t m, size_t n)
{
register size_t i;
int **array = calloc (m, sizeof *array);
if (!array) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
exit (EXIT_FAILURE);
}
for (i = 0; i < m; i++)
{
array[i] = calloc (n, sizeof **array);
if (!array[i]) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
exit (EXIT_FAILURE);
}
}
return array;
}
/* realloc an array of pointers to int* setting memory to 0. */
int **realloc_rows (int **ap, size_t *m, size_t n, size_t newm)
{
if (newm <= *m) return ap;
size_t i = 0;
int **tmp = realloc (ap, newm * sizeof *ap);
if (!tmp) {
fprintf (stderr, "%s() error: memory reallocation failure.\n", __func__);
// return NULL;
exit (EXIT_FAILURE);
}
ap = tmp;
for (i = *m; i < newm; i++)
{
ap[i] = calloc (n, sizeof **ap);
if (!ap[i]) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
exit (EXIT_FAILURE);
}
}
*m = newm;
return ap;
}
/* print a (m x n) matrix (check pad alloc) */
void mtrx_prn (size_t m, size_t n, int **matrix)
{
register size_t i, j;
for (i = 0; i < m; i++)
{
char *format = "[ %2d";
for (j = 0; j < n; j++)
{
printf (format, matrix [i][j]);
format = ", %2d";
}
puts(" ]");
}
}
void mtrx_free (size_t m, int **matrix)
{
register size_t i;
for (i = 0; i < m; i++)
{
free (matrix [i]);
}
free (matrix);
}
**Create 5x4 matrix and reallocate to **
$ ./bin/mtrx_dyn_int 4 5
The dynamically allocated 4x5 matrix is:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
Reallocate matrix to 8x5:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
[ 4, 5, 6, 7, 8 ]
[ 5, 6, 7, 8, 9 ]
[ 6, 7, 8, 9, 10 ]
[ 7, 8, 9, 10, 11 ]
Check Memory Errors/Leaks
$ valgrind ./bin/mtrx_dyn_int 4 5
==31604== Memcheck, a memory error detector
==31604== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==31604== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==31604== Command: ./bin/mtrx_dyn_int 4 5
==31604==
The dynamically allocated 4x5 matrix is:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
Reallocate matrix to 8x5:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
[ 4, 5, 6, 7, 8 ]
[ 5, 6, 7, 8, 9 ]
[ 6, 7, 8, 9, 10 ]
[ 7, 8, 9, 10, 11 ]
==31604==
==31604== HEAP SUMMARY:
==31604== in use at exit: 0 bytes in 0 blocks
==31604== total heap usage: 10 allocs, 10 frees, 256 bytes allocated
==31604==
==31604== All heap blocks were freed -- no leaks are possible
==31604==
==31604== For counts of detected and suppressed errors, rerun with: -v
==31604== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Matrix Allocated In Single Block - Stride Determines Dimensions
Here is another example that creates a single dimension array that is interpreted as a 2D array by setting a stride
defining the number of elements to be considered in each row/col. This approach provides an easier way to handle the underlying array data in a 1D array, but the logic to simulate a 2D array grows more complex to accommodate the underlying 1D array. You are free to remove the label
data from the struct that holds the size & stride
information, I found it convenient when working with multiple stride
settings. Here is the example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _STDINT_H
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
#endif
/** struct mdata defines matrix metadata for size, stride, label and lblsz.
*
* struct mdata defines metadata for handling array of numbers as 2d array.
*/
typedef struct mdata
{
int size;
int stride;
char *label;
size_t lblsz;
} mdata;
/* function prototypes */
void mtrx_prnmatrix (int *m, mdata *md);
void mtrx_prnrow (int *m, mdata *md, int v);
void mtrx_prncol (int *m, mdata *md, int v);
void mtrx_showmdata (mdata *md);
long mtrx_getval (int *m, mdata *md, int x, int y);
long mtrx_setval (int *m, mdata *md, int x, int y, int val);
int mtrx_setlable (mdata *md, char *s);
int mtrx_setstride (mdata *md, int stride);
void free_mtrxmd (mdata *md);
int main (int argc, char **argv) {
/* static for testing, you can allocate this single block */
int mtrx[] = { 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36 };
int sz = 36;
int stride = 6;
int vreq = 0;
mdata *m1d;
m1d = malloc (sizeof *m1d);
m1d-> size = sz;
m1d-> stride = stride;
m1d-> label = strdup ("m1d (6x6)");
m1d-> lblsz = strlen (m1d-> label);
if (argc < 2 ) {
fprintf (stderr, "Error: insufficient input, usage: %s int (vector [0-5])\n", argv[0]);
return 1;
}
/* show the metadata */
mtrx_showmdata (m1d);
/* set the vector request - use strtol for error check */
vreq = atoi (argv[1]);
/* print the full matrix */
mtrx_prnmatrix (mtrx, m1d);
printf ("\n");
/* print the requested column vector */
mtrx_prncol (mtrx, m1d, vreq);
/* print the requested row vector */
mtrx_prnrow (mtrx, m1d, vreq);
/* set a new stride for matrix (set new temp label) */
mtrx_setstride (m1d, 4);
mtrx_showmdata (m1d);
/* set a new label for matrix */
mtrx_setlable (m1d, "m1d (9x4)");
mtrx_showmdata (m1d);
/* print the full updated matrix */
mtrx_prnmatrix (mtrx, m1d);
printf ("\n");
/* set a new stride and label for matrix */
mtrx_setstride (m1d, 3);
mtrx_setlable (m1d, "m1d (12x3)");
mtrx_prnmatrix (mtrx, m1d);
printf ("\n");
/* set a new stride and label for matrix */
mtrx_setstride (m1d, 2);
mtrx_setlable (m1d, "m1d (18x2)");
mtrx_prnmatrix (mtrx, m1d);
printf ("\n");
/* mtrx_getval test */
mtrx_showmdata (m1d);
mtrx_setval (mtrx, m1d, 9, 1, 99);
int i = 0;
for (i = 0; i < (m1d-> size / m1d-> stride); i++) {
printf (" mtrx [%2d,%2d] : %2ld\n", i, 0, mtrx_getval (mtrx, m1d, i, 0));
printf (" mtrx [%2d,%2d] : %2ld\n", i, 1, mtrx_getval (mtrx, m1d, i, 1));
}
printf ("\n");
/* free data allocated to metadata */
free_mtrxmd (m1d);
return 0;
}
/** mtrx_prnmatrix (int *, int, mdata *) print matrix in row x column format.
*
* mtrx_prnmatrix print matrix in row x column format with metadata label.
*/
void mtrx_prnmatrix (int *m, mdata *md)
{
int i = 0;
if (!md) {
fprintf (stderr, "error: metadata structure not initialized\n");
}
printf ("Matrix: %s\n", md->label);
for (i = 0; i < md-> size; i++)
if (((i + 1) % md-> stride) == 0)
if (i == (md->size - 1))
printf (" %2d ]\n", m[i]);
else
printf (" %2d\n", m[i]);
else
if (i == 0)
printf ("[%2d", m[i]);
else
printf (" %2d", m[i]);
}
/** mtrx_prnrow (int *, mdata *, int) prints row vector.
*
* mtrx_prnrow prints matrix row vector based on metadata.
*/
void mtrx_prnrow (int *m, mdata *md, int v)
{
register int it = v;
if (!md) {
fprintf (stderr, "error: metadata structure not initialized\n");
}
if (v > md-> size/md-> stride - 1 || v < 0) {
fprintf (stderr, "error: invalid rvector (%d), valid: 0 < rvector < max (%d)\n",
v, md-> size/md-> stride);
return;
}
if (md-> label) printf ("Matrix: %s -- row vector: %d\n", md-> label, v);
for (it = v * md-> stride; it < (v * md-> stride) + md-> stride; it++)
printf (" %d", m[it]);
printf ("\n");
}
/** mtrx_prncol (int *, mdata *, int) prints column vector.
*
* mtrx_prncol prints matrix column vector based on metadata.
*/
void mtrx_prncol (int *m, mdata *md, int v)
{
register int it = v;
if (!md) {
fprintf (stderr, "error: metadata structure not initialized\n");
}
if (v > md-> size/md-> stride - 1 || v < 0) {
fprintf (stderr, "error: invalid vector (%d), valid: 0 < vector < max (%d)\n",
v, md-> size/md-> stride);
return;
}
if (md-> label) printf ("Matrix: %s -- column vector: %d\n", md-> label, v);
for (it = v; it < md-> size; it += md-> stride)
printf (" %d\n", m[it]);
}
/** mtrx_showmdata (mdata *) prints metadata struct.
*
* mtrx_showmdata prints label, size, stride and lblsz metadata.
*/
void mtrx_showmdata (mdata *md)
{
printf ("\n label : %s\n size : %d\n stride: %d\n lblsz : %zd\n\n",
md-> label, md-> size, md-> stride, md-> lblsz);
}
/** mtrx_getval (int *, mdata *, int, int, int) retrieves value at position x,y).
*
* mtrx_getval gets the value at the give position within the matrix based on x, y indexes.
*/
long mtrx_getval (int *m, mdata *md, int x, int y)
{
if (x * y > md-> size) {
fprintf (stderr, "%s() error: invalid index, (x * y) > size.\n", __func__);
return -1;
}
if (x > (md-> size / md-> stride - 1)) {
fprintf (stderr, "%s() warning: invalid metadata index, (x > %d).\n",
__func__, md-> size/md-> stride - 1);
}
if (y > (md-> stride - 1)) {
fprintf (stderr, "%s() warning: invalid metadata index, (y > %d).\n", __func__, md-> stride - 1);
}
return m[(x * md-> stride) + y];
}
/** mtrx_setval (int *, mdata *, int, int, int) sets value at position x,y).
*
* mtrx_setval set the value at the give position within the matrix based on x, y indexes.
*/
long mtrx_setval (int *m, mdata *md, int x, int y, int val)
{
if (x * y > md-> size) {
fprintf (stderr, "%s() error: invalid index, (x * y) > size.\n", __func__);
return -1;
}
if (x > (md-> size / md-> stride - 1)) {
fprintf (stderr, "%s() warning: invalid metadata index, (x > %d).\n",
__func__, md-> size/md-> stride - 1);
}
if (y > (md-> stride - 1)) {
fprintf (stderr, "%s() warning: invalid metadata index, (y > %d).\n", __func__, md-> stride - 1);
}
return m[(x * md-> stride) + y] = val;
}
/** mtrx_setlable (mdata *, char *) sets new label in metadata struct.
*
* mtrx_setlable sets new label metadata and updates lblsz.
*/
int mtrx_setlable (mdata *md, char *s)
{
if (!md) {
fprintf (stderr, "%s() error: metadata structure not initialized\n", __func__);
if (!(md = malloc (sizeof (md)))) {
fprintf (stderr, "%s() metadata structure allocation failed \n", __func__);
return 0;
}
}
if (!s) {
fprintf (stderr, "%s() error: string not initialized\n", __func__);
return 0;
}
md-> lblsz = strlen (s);
char *tmp = realloc (md-> label, md-> lblsz + 1);
if (!tmp) {
fprintf (stderr, "%s() error: metadata - label realloc failed.\n", __func__);
return 0;
}
strncpy (tmp, s, md-> lblsz + 1);
md-> label = tmp;
return 1;
}
/** mtrx_setstride (mdata *, int) sets new stride in metadata struct.
*
* mtrx_setstride validates and sets new stride metadata with temp label.
*/
int mtrx_setstride (mdata *md, int stride)
{
char newlabel[256];
int newrows = 0;
if (!md) {
fprintf (stderr, "%s() error: metadata structure not initialized\n", __func__);
md = malloc (sizeof (md));
if (!md)
fprintf (stderr, "%s() metadata structure allocated\n", __func__);
else {
fprintf (stderr, "%s() metadata structure allocation failed \n", __func__);
return 0;
}
}
if (stride < 1) {
fprintf (stderr, "%s() error: invalid (stride < 1) supplied.\n", __func__);
return 0;
}
if (md-> size % stride) {
fprintf (stderr, "%s() error: invalid stride (size %% stride != 0)\n", __func__);
return 0;
}
md-> stride = stride;
newrows = md-> size / stride;
sprintf (newlabel, "%s -> now (%dx%d)", md->label, newrows, stride);
mtrx_setlable (md, newlabel);
return 1;
}
void free_mtrxmd (mdata *md)
{
if (md-> label) free (md-> label);
if (md) free (md);
}
Output
$ /bin/mtrx_metadata_new 4
label : m1d (6x6)
size : 36
stride: 6
lblsz : 9
Matrix: m1d (6x6)
[ 1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36 ]
Matrix: m1d (6x6) -- column vector: 4
5
11
17
23
29
35
Matrix: m1d (6x6) -- row vector: 4
25 26 27 28 29 30
label : m1d (6x6) -> now (9x4)
size : 36
stride: 4
lblsz : 22
label : m1d (9x4)
size : 36
stride: 4
lblsz : 9
Matrix: m1d (9x4)
[ 1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
21 22 23 24
25 26 27 28
29 30 31 32
33 34 35 36 ]
Matrix: m1d (12x3)
[ 1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
25 26 27
28 29 30
31 32 33
34 35 36 ]
Matrix: m1d (18x2)
[ 1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20
21 22
23 24
25 26
27 28
29 30
31 32
33 34
35 36 ]
label : m1d (18x2)
size : 36
stride: 2
lblsz : 10
mtrx [ 0, 0] : 1
mtrx [ 0, 1] : 2
mtrx [ 1, 0] : 3
mtrx [ 1, 1] : 4
mtrx [ 2, 0] : 5
mtrx [ 2, 1] : 6
mtrx [ 3, 0] : 7
mtrx [ 3, 1] : 8
mtrx [ 4, 0] : 9
mtrx [ 4, 1] : 10
mtrx [ 5, 0] : 11
mtrx [ 5, 1] : 12
mtrx [ 6, 0] : 13
mtrx [ 6, 1] : 14
mtrx [ 7, 0] : 15
mtrx [ 7, 1] : 16
mtrx [ 8, 0] : 17
mtrx [ 8, 1] : 18
mtrx [ 9, 0] : 19
mtrx [ 9, 1] : 99
mtrx [10, 0] : 21
mtrx [10, 1] : 22
mtrx [11, 0] : 23
mtrx [11, 1] : 24
mtrx [12, 0] : 25
mtrx [12, 1] : 26
mtrx [13, 0] : 27
mtrx [13, 1] : 28
mtrx [14, 0] : 29
mtrx [14, 1] : 30
mtrx [15, 0] : 31
mtrx [15, 1] : 32
mtrx [16, 0] : 33
mtrx [16, 1] : 34
mtrx [17, 0] : 35
mtrx [17, 1] : 36