Reputation: 1136
I am trying to dynamically resize a 2D matrix in C. The matrix is sparse in the sense that its rows are not necessarily equally long. For example:
{
{1, 2},
{1, 2, 3}
}
I built the piece of code below. It's a silly piece of code but it resembles the actual problem well. The project this will be used in is very big and sharing a 1000 line piece of code would make it unnecessarily harder for yous to help me. The example worked fine. Then I tested it in my project and it made the whole program go haywire. Then I noticed that even the example would sometimes work and sometimes not work. So, obviously, even though the code worked, something is not right.
#include <stdio.h>
#include <stdlib.h>
void initializeArray(int **matrix)
{
matrix = (int **)realloc(matrix, 2 * sizeof(int *));
for(int i = 0; i < 2; i++)
{
matrix[i] = (int *)realloc((matrix)[i], 2 * sizeof(int));
}
for(int i = 0; i < 2; i++)
{
(matrix)[i][0] = i + 1;
(matrix)[i][1] = i + 2;
}
}
int main(void)
{
int **matrix = (int **)malloc(sizeof(int *));
initializeArray(matrix);
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
printf("alive?\n");
}
I have been trying to figure this out for some time now. Any help with this will be much appreciated.
Upvotes: 0
Views: 241
Reputation: 153368
How to properly use realloc to dynamically size a 2D matrix?
Pass in the old pointer with old and new size info. Return new pointer.
To preserve data and well handle allocation errors is a bit of a challenge. Recall that either/both matrix dimension may independently increase/decrease. Untested code:
// Free allocations
static void *freeMatrix(int **matrix, size_t row) {
while (row > 0) {
free(matrix[--row]);
}
free(matrix);
return NULL;
}
This is trickier than first thought.
// On error, free data and return NULL
int **reallocMatrix(int **matrix, size_t old_r, size_t old_c, size_t new_r, size_t new_c) {
// free reduced rows
for (size_t r = new_r; r < old_r; r++) {
free(matrix[r]);
}
int **new_m = realloc(matrix, sizeof *matrix * new_r);
if (new_m == NULL) {
return freeMatrix(matrix, old_r); // Oops, out-of-memory, free old one
}
matrix = new_m;
// Re-allocate old rows
size_t min_r = (new_r < old_r) ? new_r : old_r;
for (size_t r = 0; r < min_r; r++) {
int *row = realloc(matrix[r], sizeof matrix[r][0] * new_c);
if (row == NULL) {
return freeMatrix(matrix, old_r);
}
matrix[r] = row;
if (old_c < new_c) {
memset(&matrix[r][old_c], 0, sizeof matrix[r][0] * (new_c - old_c)); // zero new data
}
}
// Allocate new rows
for (size_t r = old_r; r < new_r; r++) {
matrix[r] = calloc(new_c, sizeof matrix[r][0]); // allocate & zero new data
if (matrix[r] == NULL) {
return freeMatrix(matrix, r);
}
}
return matrix;
}
Sample usage
int main(void) {
size_t r = 0;
size_t c = 0;
int **matrix = NULL; // No need to allocate anything here
size_t new_r = 2;
size_t new_c = 3;
matrix = resizeMatrix(matrix, r, c, new_r, new_c);
if (matrix) {
r = new_r;
c = new_c;
for (size_t i = 0; i < r; i++) {
for (size_t j = 0; j < c; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
freeMatrix(matrix, r);
printf("Done\n");
}
Upvotes: 2
Reputation: 1136
I found the solution and I will try to explain it as clear as possible.
I just found out that I was using realloc
on an uninitialized array. However, one cannot resize something which has no size yet.
A dynamically allocated 2D matrix in C can be constructed by making a list of pointers, these pointers point to lists of integers, hence the double ** in int **matrix
.
**matrix
itself is resized in resizeArray
by specifying how many rows (2 in this case) are in the matrix: matrix = (int **)realloc(matrix, 2 * sizeof(int))
.
Notice I used the word rezized instead of initialized because this reallocation only works because matrix
already had a size from when it was initialized in the main(void)
function. However, the rows themselves have not (and couldn't have been) initialized by just specifying how many rows **matrix
contains.
So, instead of using realloc
to resize the rows of the matrix, use malloc
.
#include <stdio.h>
#include <stdlib.h>
void resizeArray(int ***matrix)
{
*matrix = (int **)realloc(*matrix, 2 * sizeof(int *));
for(int i = 0; i < 2; i++)
{
(*matrix)[i] = (int *)malloc(2 * sizeof(int));
}
for(int i = 0; i < 2; i++)
{
(*matrix)[i][0] = i + 1;
(*matrix)[i][1] = i + 2;
}
}
int main(void)
{
int **matrix = (int **)malloc(sizeof(int *));
resizeArray(&matrix);
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
printf("alive?\n");
}
Upvotes: 0