Memory Allocation for a 2D Array in C - c

I am given the following structures to create my code with:
struct Mtrx {
unsigned double h;
struct MtrxRows** mtrxrows;
}
struct MtrxRows {
unsigned double w;
double* row;
}
I am trying to create a method called mtrxCreate that takes in parameters height and width and this is what I have below:
Mtrx* mtrxCreate(unsigned double height, unsigned double width){
Mtrx* mtrx_ptr = malloc(sizeof(double)*height);
int i;
mtrx_ptr->mtrxrows = malloc(sizeof(double)*height);
for(i = 0; i < height; ++i){
mtrx_ptr->mtrxrows[i]->row = malloc(sizeof(double) * width);
mtrx_ptr->mtrxrows[i]->w = width;
}
mtrx_ptr->h = height;
return mtrx_ptr;
}
The GCC compiler is telling me that I have a segmentation fault so I believe I did not allocate the memory correctly. I am not sure what memory I am still needing to allocating and if I allocated the current amount to the parts of the matrix above, any help is appreciated!

You aren't allocating the right amount of memory for certain things. First of all, the Mtrx structure itself:
Mtrx* mtrx_ptr = malloc(sizeof(double)*height);
Should be:
Mtrx* mtrx_ptr = malloc(sizeof(struct Mtrx));
Next, I'm not sure why your mtrxrows field is a double pointer. I think it should be a single pointer, a one-dimensional array of rows (where each row has some number of elements in it, as well). If you change it to a single pointer, you would allocate the rows as such:
mtrx_ptr->mtrxrows = malloc(sizeof(struct MtrxRows)*height);
Edit: Sorry I keep noticing things in this sample, so I've tweaked the answer a bit.

Wow. I don't exactly know where to start with cleaning that up, so I'm going to try to start from scratch.
From your code, it seems like you want all rows and all columns to be the same size - that is, no two rows will have different sizes. If this is wrong, let me know, but it's much harder to do.
Now then, first let's define a struct to hold the number of rows, the number of columns, and the array data itself.
struct Matrix {
size_t width;
size_t height;
double **data;
};
There are different ways to do store the data, but we can look at those later.
size_t is an unsigned integer (not floating point - there are no unsigned floating point types) type defined in stddef.h (among other places) to be large enough to store any valid object size or array index. Since we need to store array sizes, it's exactly what we need to store the height and width of our matrix.
double **data is a pointer to a pointer to a double, which is (in this case) a complex way to say a two-dimensional array of doubles that we allocate at runtime with malloc.
Let's begin defining a function. All these lines of code go together, but I'm splitting them up to make sure you understand all the different parts.
struct Matrix *make_Matrix(size_t width, size_t height, double fill)
Notice that you have to say struct Matrix, not just Matrix. If you want to drop the struct you'd have to use a typedef, but it's not that important IMHO. The fill parameter will allow the user to specify a default value for all the elements of the matrix.
{
struct Matrix *m = malloc(sizeof(struct Matrix));
if(m == NULL) return NULL;
This line allocates enough memory to store a struct Matrix. If it couldn't allocate any memory, we return NULL.
m->height = height;
m->width = width;
m->data = malloc(sizeof(double *) * height);
if(m->data == NULL)
{
free(m);
return NULL;
}
All that should make sense. Since m->data is a double **, it points to double *s, so we have to allocate a number of double *-sized objects to store in it. If we want it to be our array height, we allocate height number of double *s, that is, sizeof(double *) * height. Remember: if your pointer is a T *, you need to allocate T-sized objects.
If the allocation fails, we can't just return NULL - that would leak memory! We have to free our previously allocated but incomplete matrix before we return NULL.
for(size_t i = 0; i < height; i++)
{
m->data[i] = malloc(sizeof(double) * width);
if(m->data[i] == NULL)
{
for(size_t j = 0; j < i; j++) free(m->data[j]);
free(m->data);
free(m);
return 0;
}
Now we're looping over every column and allocating a row. Notice we allocate sizeof(double) * width space - since m->data[i] is a double * (we've dereferenced the double ** once), we have to allocate doubles to store in that pointer.
The code to handle malloc failure is quite tricky: we have to loop back over every previously added row and free it, then free(m->data), then free(m), then return NULL. You have to free everything in reverse order, because if you free m first then you don't have access to all of ms data (and you have to free all of that or else you leak memory).
for(size_t j = 0; j < width; j++) m->data[i][j] = fill;
This loops through all the elements of the row and fills them with the fill value. Not too bad compared to the above.
}
return m;
}
Once all that is done, we just return the m object. Users can now access m->data[1][2] and get the item in column 2, row 3. But before we're finished, since it took so much effort to create, this object will take a little effort to clean up when we're done. Let's make a cleanup function:
void free_Matrix(struct Matrix *m)
{
for(size_t i = 0; i < height; i++) free(m->data[i]);
free(m->data);
free(m);
}
This is doing (basically) what we had to do in case of allocation failure in the (let's go ahead and call it a) constructor, so if you get all that this should be cake.
It should be noted that this is not necessarily the best way to implement a matrix. If you require users to call a get(matrix, i, j) function for array access instead of directly indexing the data via matrix->data[i][j], you can condense the (complex) double ** allocation into a flat array, and manually perform the indexing via multiplication in your access functions. If you have C99 (or are willing to jump through some hoops for C89 support) you can even make the flat matrix data a part of your struct Matrix object allocation with a flexible array member, thus allowing you to deallocate your object with a single call to free. But if you understand how the above works, you should be well on your way to implementing either of those solutions.

As noted by #Chris Lutz, it's easier to start from scratch. As you can see from the other answers, you should normally use an integer type (e.g. size_t) to specify array lengths, and you should allocate not only the pointers, but also the structures where they are stored. And one more thing: you should always check the result of allocation (if malloc returned NULL). Always.
An idea: store 2D array in a 1D array
What I'd like to add: often it is much better to store entire matrix as a contiguous block of elements, and do just one array allocation. So the matrix structure becomes something like this:
#include <stdlib.h>
#include <stdio.h>
/* allocate a single contiguous block of elements */
typedef struct c_matrix_t {
size_t w;
size_t h;
double *elems; /* contiguos block, row-major order */
} c_matrix;
The benefits are:
you have to allocate memory only once (generally, a slow and unpredictable operation)
it's easier to handle allocation errors (you do not need to free all previously allocated rows if the last row is not allocated, you have only one pointer to check)
you get a contuguous memory block, which may help writing some matrix algorithms effectively
Probably, it is also faster (but this should be tested first).
The drawbacks:
you cannot use m[i][j] notation, and have to use special access functions (see get and set below).
Get/set elements
Here they are, the function to manipulate such a matrix:
/* get an element pointer by row and column numbers */
double* getp(c_matrix *m, size_t const row, size_t const col) {
return (m->elems + m->w*row + col);
}
/* access elements by row and column numbers */
double get(c_matrix *m, size_t const row, size_t const col) {
return *getp(m, row, col);
}
/* set elements by row and column numbers */
void set(c_matrix *m, size_t const row, size_t const col, double const val) {
*getp(m, row, col) = val;
}
Memory allocation
Now see how you can allocate it, please note how much simpler this allocation method is:
/* allocate a matrix filled with zeros */
c_matrix *alloc_c_matrix(size_t const w, size_t const h) {
double *pelems = NULL;
c_matrix *pm = malloc(sizeof(c_matrix));
if (pm) {
pm->w = w;
pm->h = h;
pelems = calloc(w*h, sizeof(double));
if (!pelems) {
free(pm); pm = NULL;
return NULL;
}
pm->elems = pelems;
return pm;
}
return NULL;
}
We allocate a matrix structure first (pm), and if this allocation is successful, we allocate an array of elements (pelem). As the last allocation may also fail, we have to rollback all the allocation we already made to this point. Fortunately, with this approach there is only one of them (pm).
Finally, we have to write a function to free the matrix.
/* free matrix memory */
void free_c_matrix(c_matrix *m) {
if (m) {
free(m->elems) ; m->elems = NULL;
free(m); m = NULL;
}
}
As the original free (3) doesn't take any action when it receives a NULL pointer, so neither our free_c_matrix.
Test
Now we can test the matrix:
int main(int argc, char *argv[]) {
c_matrix *m;
int i, j;
m = alloc_c_matrix(10,10);
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
set(m, i, j, i*10+j);
}
}
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
printf("%4.1f\t", get(m, i, j));
}
printf("\n");
}
free_c_matrix(m);
return 0;
}
It works. We can even run it through Valgrind memory checker and see, that it seems to be OK. No memory leaks.

Related

How to initiliaze a dynamic 2D array inside a struct in c?

I want to use a struct to contain some data and passing them between different functions in my program,this struct has to contain a dynamic 2D array (i need a matrix) the dimensions change depending on program arguments.
So this is my struct :
struct mystruct {
int **my2darray;
}
I have a function that read numbers from a file and has to assign each of them to a cell of the struct array.
I tried doing this :
FILE *fp = fopen(filename, "r");
int rows;
int columns;
struct mystruct *result = malloc(sizeof(struct mystruct));
result->my2darray = malloc(sizeof(int)*rows);
int tmp[rows][columns];
for(int i = 0;i<rows;i++) {
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &tmp[i][j]);
}
result->my2darray[i]=malloc(sizeof(int)*columns);
memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
}
But this is giving me a strange result : all the rows are correctly stored except for the first.
(I'm sure that the problem is not in the scanning of file).
While if i change the fourth line of code in this :
result->my2darray = malloc(sizeof(int)*(rows+1));
it works fine.
Now my question is why this happens?
Here's an answer using some "new" features of the language: flexible array members and pointers to VLA.
First of all, please check Correctly allocating multi-dimensional arrays. You'll want a 2D array, not some look-up table.
To allocate such a true 2D array, you can utilize flexible array members:
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
It will be allocated as a true array, although "mangled" into a single dimension:
size_t x = 2;
size_t y = 3;
array2d_t* arr2d = malloc( sizeof *arr2d + sizeof(int[x][y]) );
Because the problem with flexible array members is that they can neither be VLA nor 2-dimensional. And although casting it to another integer array type is safe (in regards of aliasing and alignment), the syntax is quite evil:
int(*ptr)[y] = (int(*)[y]) arr2d->flex; // bleh!
It would be possible hide all this evil syntax behind a macro:
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
Read as: if arr2d is a of type array2d_t* then access that pointer to get the flex member, then cast it to an array pointer of appropriate type.
Full example:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
int main (void)
{
size_t x = 2;
size_t y = 3;
array2d_t* arr = malloc( sizeof *arr + sizeof(int[x][y]) );
arr->x = x;
arr->y = y;
for(size_t i=0; i<arr->x; i++)
{
for(size_t j=0; j<arr->y; j++)
{
get_array(arr)[i][j] = i+j;
printf("%d ", get_array(arr)[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
Advantages over pointer-to-pointer:
An actual 2D array that can be allocated/freed with a single function call, and can be passed to functions like memcpy.
For example if you have two array2d_t* pointing at allocated memory, you can copy all the contents with a single memcpy call, without needing to access individual members.
No extra clutter in the struct, just the array.
No cache misses upon array access due to the memory being segmented all over the heap.
The code above never sets rows and columns, so the code has undefined behavior from reading those values.
Assuming you set those values properly, this isn't allocating the proper amount of memory:
result->my2darray = malloc(sizeof(int)*rows);
You're actually allocating space for an array of int instead of an array of int *. If the latter is larger (and it most likely is) then you haven't allocated enough space for the array and you again invoke undefined behavior by writing past the end of allocated memory.
You can allocate the proper amount of space like this:
result->my2darray = malloc(sizeof(int *)*rows);
Or even better, as this doesn't depend on the actual type:
result->my2darray = malloc(sizeof(*result->my2darray)*rows);
Also, there's no need to create a temporary array to read values into. Just read them directly into my2darray:
for(int i = 0;i<rows;i++) {
result->my2darray[i]=malloc(sizeof(int)*columns);
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &result->my2darray[i][j]);
}
}
In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.
When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)
int main(void)
{
struct mystruct result = {0};
result.my2darray = Create2D(5, 20);
if(result.my2darray)
{
// use result.my2darray
result.my2darray[0][3] = 20;// for simple example, but more likely in a read loop
// then free result.my2darray
free2D(result.my2darray, 5);
}
return 0;
}
Using the following two functions:
int ** Create2D(int c, int r)
{
int **arr;
int y;
arr = calloc(c, sizeof(int *)); //create c pointers (columns)
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
}
return arr;
}
void free2D(int **arr, int c)
{
int i;
if(!arr) return;
for(i=0;i<c;i++)
{
if(arr[i])
{
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.
int some_array[5][20] = {0};//init all elements to zero
Is what is commonly referred to in C an int array, also allowing access to each element via indexing. In actuality (Even though commonly referred to as an array.) it is not an array. The location of elements in this variable are stored in one contiguous location in memory.
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0... (~ 82 more)
But C maintains the locations such that they are all indexable as an 2D array.

C , regarding pointers (or pointers to pointers?), **, and malloc

As said in title, I have a question regarding using * twice, like in the main function of the following code. it DOES run, but I don't understand why using ** is right here. What i want is an array of SPPoints , sized n, where parr is the base adress. Why is ** right and * wrong in this case? thanks.
SPPoint code:
struct sp_point_t
{
double* data;
int dim;
int index;
};
SPPoint* spPointCreate(double* data, int dim, int index)
{
if (data == NULL || dim <= 0 || index < 0)
{
return NULL;
}
SPPoint* point = malloc(sizeof(*point));
if (point == NULL)
{
return NULL;
}
point->data = (double*)malloc(dim * sizeof(*data));
for (int i = 0; i < dim; i++)
{
point->data[i] = data[i];
}
point->dim = dim;
point->index = index;
return point;
}
And this is the main function:
int main()
{
int n, d, k;
scanf("%d %d %d", &n, &d, &k);
double* darr = malloc(d * sizeof(double));
if (darr == NULL)
{
return 0;
}
SPPoint** parr = malloc(n * sizeof(SPPoint*));
if (parr == NULL)
{
return 0;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < d; j++)
{
scanf(" %lf", &darr[j]);
}
parr[i] = spPointCreate(darr, d, i);
}
}
When using a dynamically-allocated array, it's usually "handled" by having a pointer to the first element of the array, and also having some method of knowing the length, such as explicitly storing the length, or having an end sentinel.
So for a dynamically allocated array of SPPoint * as you have in your code, a pointer to the first one of those has type SPPoint * *
Your existing code creates an array of SPPoint *, i.e. an array of pointers. Each of those pointers points to one dynamically-allocated instance of SPPoint, i.e. you have separate allocations for each entry.
This is viable but you indicate that you instead wanted an array of SPPoint, in which case a pointer to the first element has type SPPoint *.
In order to have such an array, it is a single memory allocation. So you will need to redesign your spPointCreate function. Currently that allocates memory for and initializes only a single SPPoint. Instead you want to separate the allocation from the initialization, since you only need one allocation but you need multiple initializations. Your program logic will read something like:
Allocate one block of memory big enough for n SPPoints
Initialize each SPPoint inside the allocated space
If you have tried this but got stuck then post a new question showing your code and explaining where you got stuck.
An array can behave similarly to a pointer. For instance, int a [] is very similar to int* a. Each function in SPPoint returns a pointer to a SPPoint struct. An array of pointers to SPPoint can be written as a pointer to a pointer to SPPoint. With the malloc command, you are designating a certain amount of memory (enough to hold n pointers to SPPoint) for storage of pointers to SPPoint structs.
Not all pointers are arrays, however. SPPoint** parr is acting as an array holding pointers to single structs of type SPPoint.
Arrays can behave differently from pointers, especially when used for strings.
The reason why it is advantageous to use pointers to SPPoint (as you are now) is that you can view or modify a single element without having to copy the entire struct.

Array of pointers issue

i'm having some troubles when passing data from one pointer to an element of an array of pointers of an struct.
typedef struct {
float* data;
int size;
} vector;
//This function creates the vector
vector* doVector(int n, float* data){
vector * vec = (vector *) malloc(sizeof(vector));
vec->size = n;
vec->data = data;
return vec;
}
void delVector(vector* v){
free(v->data);
free(v);
}
void prVector(vector* v)
{
printf("[");
for(unsigned int i = 0; i<v->size; i++){
if(i!=v->size-1)
printf("%f,", v->data[i]);
else
printf("%f]\n", v->data[i]);
}
}
void fillVectors(float* data,int size){
vector * vectors = (vector*) malloc(size * sizeof(vector));
for(unsigned int i = 0; i < size; i++){
vectors[i] = *doVector(size,data);//This gives trouble
prVector(&vectors[i]);
}
//More stuff will be added here to work with the vectors.
for(unsigned int i = 0; i < size; i++)
delVector(&vectors[i]);//Memory leak here obv
free(vectors);// I also need to free the array
}
int main()
{
//Here recieving data from file and calling fillVectors
//Also allocating memory for data (which is send to fillvectors)
//Avoided to post because it's irrelevant and big
}
So the main idea is to create vectors with the struct,Data and size is read from file and stored into float array called data and int size. Then we call the function fillVector, which will call the doVector function and create the vector itself.
Then I want to assign the value of each vector to a position of the pointer array,(there are 3 mallocs, data and single vector, which is made in doVector, and the array of vectors made in fillVectors).
Problem comes when freeing this pointers, keep getting memory leaks.
Has something to do with the malloc of the array of vectors and the vector malloc from doVector.
ps: fillVector function is only called once
thanks.
Simple rule: in C if want to process smth in function send pointer. So if want to delete vector by pointer then pass pointer to pointer
void delVector(vector** v){
free((*v)->data);
free(*v);
*v = NULL;
}
Function already returns pointer so no need to use asterisk sign.
vectors[i] = *doVector(size,data);
Second: you want array of vectors? so use array of pointers to vectors
vector **vectors = (vector**) malloc(size * sizeof(vector*));
for (unsigned int i = 0; i < size; i++){
vectors[i] = doVector(size, data);//This gives trouble
prVector(vectors[i]);//no need to use ampersand, it is already pointer
}
And main: you need deep copy of float data inside vector. Now all vectors keep pointer to same array, given as argument. And beside that, you delete this data
free(v->data);
But this pointer was copied, but not owned.
vector* doVector(size_t n, float* data){
size_t i;
vector * vec = (vector *) malloc(sizeof(vector));
vec->size = n;
vec->data = (float*)malloc(sizeof(float) * n);
for (i = 0; i < n; i++) {
vec->data[i] = data[i];
}
//or just
//memcpy(vec->data, data, n*sizeof(float));
return vec;
}
More questions...
I will focus on your line with the comment //This gives trouble
With function doVector you use malloc to create a vector instance somewhere in memory. Then, when dereferencing the result by doing *doVector(size, data), you take the created vector and try to assign it to vectors[i]. This copies the memory block of newly created vector into the location vectors[i], but you don't keep the pointer to the result of doVector.
Afterwards, you free the memory of vectors element by element in the for loop and later you try to free the same space again using free(vectors) after the for loop. However, the memory allocated inside doVector is never freed, because you don't have the pointers to created vectors.
I would stick to Ivan Ivanov's answer for making it correct. I just wanted to point out why it doesn't work.
You should be initializing all pointers created and not IMMEDIATELY allocated to NULL or 0 or (void*)0. Then a call to free will clean up any allocated data.
Whenever allocating the actual data type make sure that you set the internal ptr to NULL before you allocate it as well.
C
vector* newVector;
newVector = (void*)0; //or 0, NULL
... //Code here
newVector = malloc(sizeof(vector));
newVector->data = (void*)0;
... //More code
if(!newVector){
free(newVector);
newVector = (void*)0;
}
Notes
If you must do dynamic memory allocation, do it in a format where you manage pointers with a static value.
As Chris mentions below, deleting a null ptr is already handled by delete and free, but I like to include the if statements to remind myself to set the pointer to NULL when its absolutely necessary.
Thanks again Chris :D

Why does my 2D array cause a bus error in C?

I'm attempting to create a simple 2D array in C but apparently running into some memory trouble. My setup is simple enough and I can't tell what's wrong. I admit that my understanding of pointers is insufficient, but I still think this should be working. Can anyone see the flaw here?
typedef unsigned int DATUM;
DATUM **series_of_data;
void initialize_data()
{
*series_of_data = (DATUM *) malloc(1024 * sizeof(DATUM));
}
This causes my program to crash with a bus error when I run it.
series_of_data is actually not allocated.
You have various way to allocates a 2D array, either using the array of rows model whcih has bad cache coherency and thus has usually bad performances or to use the Iliffe vector adviced in Numerical recipes in C that consists in allocating one huge h*w memory block and a side pointer array which contains the beginning of your rows (or columns) :
DATUM** alloc_array( int h, int w )
{
int i;
DATUM** m = (DATUM**)malloc(h*sizeof(DATUM*));
m[0] = (DATUM*)malloc(h*w*sizeof(DATUM));
for(i=1;i<h;i++) m[i] = m[i-1]+w;
return m;
}
void release_array(DATUM** m)
{
free( m[0] );
free( m);
}
int main()
{
int r,c;
DATUM** tab;
int width = 5;
int height = 3;
tab = alloc_array(height, width); /* column first */
for(r = 0;r<height;++r)
for(c = 0;c<width;++c)
tab[r][c] = (1+r+c);
for(r = 0;r<height;++r)
{
for(c = 0;c<width;++c)
{
printf("%d\t",tab[r][c]);
}
puts("");
}
release_array(tab);
}
Data are nicely packed in memory, so cache are happy and you keep the [][] access pattern.
As a matter of speed this is in +/-3% speed of the classical DATUM* + polynomial access method.
series_of_data is an invalid pointer - you don't assign it to anything. When you try to assign to its memory location (*series_of_data = ...), it's putting stuff in a random place, which is likely to not do what you want. You have to point series_of_data somewhere useful, e.g.
series_of_data = (DATUM **)malloc(16 * sizeof(DATUM *))
for an array with 16 slots for DATUM * pointers in it.
You haven't allocated the series_of_data pointer before you assign to *series_of_data.
For example, if series_of_data is intended to be an array then you would need to write something like this:
series_of_data = malloc(n*sizeof(DATUM*));
where n is the length of the series_of_data array.
Only after you have done this can you assign to *series_of_data.

int matrix with pointers in C - memory allocation confusion

I'm having some issues with producing an int matrix without creating memory leaks. I want to be able to make a given (global) matrix into any size dynamically via read_matrix(). But then i want to be able to free the memory later on. So in my main method the second printf should result in a bus error since it should not have any memory allocated to it. How would i go about creating this?
int** first_matrix;
int** second_matrix;
int** result_matrix;
int** read_matrix(int size_x, int size_y)
{
int** matrix;
matrix = calloc(size_x, sizeof(int*));
for(int i = 0;i<size_x;i++) {
matrix[i] = calloc(size_y, sizeof(int));
}
for(int i = 0;i<size_x;i++) {
for(int j = 0;j<size_y;j++) {
matrix[i][j] = i*10+j;
}
}
return matrix;
}
int main(int stackc, char** stack)
{
first_matrix = read_matrix(10,10);
printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
free(*first_matrix);
free(first_matrix);
printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
}
Just because the memory has been free'd doesn't mean you can't access it! Of course, it's a very bad idea to access it after it's been free'd, but that's why it works in your example.
Note that free( *first_matrix ) only free's first_matrix[0], not the other arrays. You probably want some kind of marker to signify the last array (unless you will always know when you free the outer array how many inner arrays you allocated). Something like:
int** read_matrix(int size_x, int size_y)
{
int** matrix;
matrix = calloc(size_x, 1+sizeof(int*)); // alloc one extra ptr
for(int i = 0;i<size_x;i++) {
matrix[i] = calloc(size_y, sizeof(int));
}
matrix[size_x] = NULL; // set the extra ptr to NULL
for(int i = 0;i<size_x;i++) {
for(int j = 0;j<size_y;j++) {
matrix[i][j] = i*10+j;
}
}
return matrix;
}
Then when you're freeing them:
// keep looping until you find the NULL one
for( int i=0; first_matrix[i] != NULL; i++ ) {
free( first_matrix[i] );
}
free( first_matrix );
You need to free each row individually:
void free_matrix(int **matrix, int size_x)
{
for(int i = 0; i < size_x; i++)
free(matrix[i]);
free(matrix);
}
Freeing the memory doesn't make it go away, it just means that another allocation might grab that same chunk of memory. Whatever you put in it will still be there until something else overwrites it.
Also, you're not freeing everything you allocated. You're only freeing the array of pointers and the first row. But even if you free everything correctly, you would still have the same effect.
If you want to create a "bus error" you need to point to memory that doesn't belong to your process. Why do you want to do that anyway?
You only freed the first row (or column) of first_matrix. Write another function like this:
void free_matrix(int **matrix, int rows)
{
int i;
for(i=0; i<rows; i++)
{
free(matrix[i]);
}
free(matrix);
}
You might want to make the matrix into a struct to store it's row and column count.
I recommend using valgrind to track down unfree'd memory, as opposed to trying to make a bus error occur. It rocks for lots of other stuff as well.
Sam
You're getting memory leaks because you're freeing the first row of the matrix and the list of rows, but none of the 1 to nth rows. You need to call free in a loop.
There are a couple of alternatives, however:
- Allocate sizeof(int*)rows + rowscols*sizeof(int) bytes and use the first bytes for the row pointers. That way, you only have a single chunk of memory to free (and it's easier on the allocator, too)
- Use a struct that contains the number of rows. Then you can avoid the row list altogether (saving memory). The only downside is that you have to use a function, a macro, or some messy notation to address the matrix.
If you go with the second option, you can use a struct like this in any C99 compiler, and again only have to allocate a single block of memory (of size numints*sizeof(int)+sizeof(int)):
struct matrix {
int rows;
int data[0];
}
The concept you are missing here, is that for every calloc, there must be a free.
and that free must be applied to the pointer passed back from calloc.
I recommend you create a function (named delete_matrix)
that uses a loop to free all of the pointers that you allocate in here
for(int i = 0;i < size_x;i++) {
matrix[i] = calloc(size_y, sizeof(int));
}
then, once that is done, free the pointer allocated by this.
matrix = calloc(size_x, sizeof(int*));
The way you are doing it now,
free(*first_matrix);
free(first_matrix);
won't do what you want it to do.

Resources