How do I use realloc
and malloc
to declare a global variable 2-dimensional integer array say int array[][]
then reallocate it once numbers for x
and y
are given so it is int array[x][y]
?

- 254,901
- 44
- 429
- 631

- 1,051
- 2
- 11
- 31
-
Why would you want to pay time to allocate memory initially if you're just going to reallocate it later? – merlin2011 Apr 29 '15 at 00:51
-
I am just trying to give it global scope. – Evan Bloemer Apr 29 '15 at 00:54
-
2I'd declare it as a an `int**` in that case. – merlin2011 Apr 29 '15 at 00:56
-
How do I make sure that it has the parameters of `x` and `y`? – Evan Bloemer Apr 29 '15 at 00:57
-
1See [this question](http://stackoverflow.com/questions/13677566/malloc-a-2d-array-in-c). – merlin2011 Apr 29 '15 at 00:58
-
I've edited your question to use "2-dimensional" rather than "double", since `double` is a floating-point type. – Keith Thompson Apr 29 '15 at 03:30
3 Answers
There are several points to consider when simulating a 2D array or matrix in C. First understanding what you are actually allocating. To simulate a 2D array that you access simply by array[m][n]
, what you are doing is first allocating an array of m
pointers to pointer to int. This provides m
int*
(or rows) which you have available to allocate n
int (columns).
So simply put, you allocate m pointers to int*
rows and n int
columns.
Now before we look at the code, there is a practical choice to make on whether you use malloc
to allocate the memory (columns specifically) or whether you use calloc
. Why? Before you can even attempt to access an element of you array, you must initialize that element to hold some value. Otherwise, any attempt to read from that element, is an attempt to read from an uninitialized value which is undefined behavior and can send your program spinning off into the land of no return..
Why calloc
instead of malloc
. Not only does calloc
allocate space for you, it also initializes/sets the memory at that location to 0/NULL
(0
in the case of a numeric type, NULL
in the case of a pointer -- both are effectively 0
) This prevents the inadvertent read from an uninitialized element because all elements are initialized to 0
to begin with. Now you are free to set up a loop and set every value to 0
(or whatever) that way, but often this is overlooked by new C programmers. So calloc
can help protect you against yourself. Let's look at an allocation function:
/* 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;
}
The allocation function is straight forward. It accepts m
and n
as arguments (type size_t
-- indexes cannot be negative), and returns a fully allocated, fully initialized set of m
pointers to arrays of n
int
. Let's look at its use to allocate my_array
as a 4x5
matrix of int
:
int **my_array = mtrx_calloc (4, 5);
Throughout the remainder of your code, you can access any element by my_array[0-3][0-4]
(indexes are zero based, just like the rest of indexing in C)
What about realloc
? When you are talking about fixed size arrays, the only time you need to reallocate memory is if you need to resize the array. (Now granted you could just create a new array and copy old/new) However, since reallocating memory is an important concept in C, lets write a function to reallocate the number of rows for our matrix.
Let's say you now find you need my_array
as an 8x5
matrix instead of a 4x5
matrix. In that case you would need to realloc
the number of pointers to int*
to allow the addition of 4
more rows. You would also need to allocated space to hold the new values for rows 5-8
(indexes 4-7
).
You also need to keep track to the number of rows that you have allocated, so if we send a pointer to the current number of rows, we can update the value at that address and have the value available back in our calling function (main()
in this case). The only thing we would need to preserve in main
before we make the call to reallocate is the old value for m
(to allow filling the new space with values, etc.) Our reallocation of rows could look like the following:
/* 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;
}
Now it is important to notice, that we do not directly assign the newly reallocated value to our array variable, but instead to a tmp
variable. Why? If the reallocation fails, realloc
frees the newly allocated space returns NULL
, which would cause a complete loss of our data if we had assigned the return of realloc
to our array. By using a tmp
array instead, you have the flexibility to handle a failure as required. A sample call to reallocate 4 additional rows would look like:
my_array = realloc_rows (my_array, &m, n, m + 4);
That's much longer an overview of a 2D matrix/array than I initially intended, but there are a lot of considerations that go into even a simple set of functions to handle dynamically allocating and reallocating a simulated 2D array. With that, we will leave you with an example to look at. The example will create a 3x4 2D array by default, but you can also specify the size as arguments to the program. For example:
./programname 4 5
Will create an initial 4x5 2D array, instead of the default. To show the use of realloc, whatever size is initially allocated will be resized to add 4 rows and fill the new rows with miscellaneous values. Both the original size and the reallocated size arrays are printed to stdout
. Let me know if you have questions:
/*
gcc -Wall -Wextra -o progname progname.c
*/
#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 4x5 matrix and reallocate to 8x5
$ ./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)

- 81,885
- 6
- 58
- 85
C doesn't have 2D arrays. It has arrays of arrays, and arrays of pointers, each of which can be used similarly to a 2D array. Unfortunately, realloc()
doesn't know about either one. You can realloc() an array of pointers, and then the new pointers will be null and have to be allocated themselves, and all the existing rows are still the old size and will have to be realloced. You can also realloc an array of arrays, but only if the minor dimension is the same, that is, if you originally allocated a 10x10 array, you can reallocate it to 20x10, but not 10x20 (or else existing values will be moved to weird places).

- 12,927
- 3
- 29
- 55
-
1C does have 2-dimensional and multidimensional arrays. They're described, using those terms, in section 6.5.2.1 of [the C standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf). They just happen to be exactly the same thing as arrays of arrays. – Keith Thompson Apr 29 '15 at 03:32
-
The spec mentions "strings" too, but they're nothing like what anyone who's used higher-level languages would recognize as such, – Lee Daniel Crocker Apr 29 '15 at 03:37
-
@KeithThompson C uses the term "multidimensional array" to mean an array of arrays, however that is at odds with use of the same term in most other programming contents. In many languages a 2-D array can have an element selected directly, without first selecting a sub-array. – M.M Apr 29 '15 at 04:30
-
1@MattMcNabb: The question is tagged "c". I suggest that using (and if necessary explaining) the terminology used by C is the best way to avoid confusion. – Keith Thompson Apr 29 '15 at 04:33
-
@KeithThompson With all due respect, and appreciating your motive of terminology -- the cited standard location (the only one in the main text) contains in an example: "`int x[3][5];` Here x is a 3 × 5 array of ints; **more precisely,** x is an array of three element objects". In other words, the standard itself acknowledges that "multidimensional array" is a somewhat imprecise concept for what's really happening in C. Because it's often not obvious to beginners and relevant to the question Lee did good pointing that out. "Hey, we developed a 30GHz CPU [cough -- well, 10 core, each 3 GHz] – Peter - Reinstate Monica May 06 '15 at 16:09
-
@PeterSchneider: Sure, describing `x` as an array of arrays is in a sense more precise than calling it a multidimensional array. But the phrase "multidimensional array" is still a perfectly correct and unambiguous description. I don't suggest saying `x` is a 2D array and leaving it at that. I suggest saying it's a 2D array *and describing what that term means in C*. The statement in this answer that "C doesn't have 2D arrays" is quite simply incorrect. – Keith Thompson May 06 '15 at 17:21
Since you are not trying to resize the matrix, but initialize with dynamic dimensions, you can do it by calling malloc() when you know your x and y:
int **global_array;
void main() {
// ...
if (allocateMatrixDynamically(3, 5) == 0) {
// We can now set a value
global_array[0][0] = 11;
}
//...
}
// This functions returns zero if allocation was succesful, and !=0 otherwise
int allocateMatrixDynamically(int rows, int cols) {
int idxRow, idxCol;
int RCod = -1;
// Allocate the memory as requested
if (rows > 0 && cols > 0) {
global_array = (int**) malloc(rows * sizeof(int*));
if (!global_array) {
return -1;
}
for (idxRow=0; idxRow< rows; ++idxRow) {
global_array[idxRow] =(int*) malloc(cols * sizeof(int));
if (!global_array[idxRow]) {
return -1;
}
}
}
return 0;
}

- 1,426
- 12
- 21