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
Related
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.
I have a vector type defined as follows:
typedef struct vector {
void **items;
unsigned int capacity;
unsigned int size;
} vector_st;
typedef vector_st *vector_t;
And I allocate and free it as follows:
vector_t vector_init(unsigned int capacity)
{
vector_t v = (vector_t)calloc(1, sizeof(vector_st));
v->capacity = capacity;
v->size = 0;
v->items = malloc(sizeof(void *) * v->capacity);
return v;
}
void vector_free(vector_t v)
{
if (v) {
free(v->items);
v->capacity = 0;
v->size = 0;
free(v);
v = NULL;
}
}
Now, the point is that I want to copy one vector to another one, meaning including all its content. So, I tried to define a function like this:
void vector_copy(vector_t to, vector_t from)
{
memcpy(to, from, sizeof(vector_st));
}
But, this does not seem to work quite right, as when I do something like this:
vector_t vec = vector_init(3);
vector_add(vec, 1);
vector_add(vec, 2);
vector_add(vec, 3);
unsigned int i;
for (i = 0; i < vec->size; i++) {
printf("%d\n", (int)vector_get(vec, i));
}
vector_t copied = vector_init(3);
vector_copy(copied, vec);
vector_free(vec);
for (i = 0; i < copied->size; i++) {
printf("%d\n", (int)vector_get(copied, i));
}
For the first vector it correctly prints 1 2 3 but for the second one it prints 0 2 3. So, basically I believe it just copies maybe the memory addresses and not the actual content, as when I free the first vector the first element is set to 0. Any ideas how to copy this structure in my case?
EDIT:
void vector_resize(vector_t v, unsigned int capacity)
{
void **items = realloc(v->items, sizeof(void *) * capacity);
if (items) {
v->items = items;
v->capacity = capacity;
}
}
void vector_add(vector_t v, void *item)
{
if (v->capacity == v->size) {
vector_resize(v, v->capacity * 2);
}
v->items[v->size++] = item;
}
Now, the point is that I want to copy one vector to another one, meaning including all its content.
What you seem to want to perform is called a "deep copy". That means copying not just the data, but any additional pointed-to data, recursively. You have judged correctly that memcpy() of the structure itself does not do this; the vector elements are pointed to by pointers in the structure, but they themselves are elsewhere, and therefore are not copied.
What's worse, you have a fundamental problem here with copying the pointed-to data: your copy function doesn't know how big the pointed-to elements are. Without such knowledge, it is impossible to copy them. Furthermore, if the elements themselves contain pointers, then to perform a true deep copy, you need information about which members those are, and how large are the objects to which they point. Etc.
Basically, then, it is impossible write a generic deep copy (in any language). Performing a deep copy requires information at every level about what you are copying. To give you a bit of a flavor, however, you could copy one level deeper if you could rely on the vector elements being of a consistent size that is known at call time. That might look something like this:
void vector_copy(vector_t to, vector_t from, size_t element_size) {
// NOTE: robust code would check for memory allocation failures. This code does not.
void **temp_items;
to->capacity = from->capacity;
to->size = from->size;
// evaluates to NULL if allocation fails:
temp_items = realloc(to->items, from->capacity * sizeof(*to->items));
to->items = temp_items;
for (int i = 0; i < from->size; i++) {
to->items[i] = malloc(element_size); // evaluates to NULL if allocation fails
memcpy(to->items[i], from->items[i], element_size);
}
}
You could avoid the need to pass the element size by instead making it a member of the vector structure.
Note that this assumes that vector to has been initialized, and that it is not necessary to free the pointers to the individual items, if any, that are currently in it (i.e. the vector does not own these, and is therefore not responsible for managing their memory).
void vector_copy(vector_t to, vector_t from)
{
memcpy(to, from, sizeof(vector_st));
}
This is wrong because the vector owns its items object. So you need to do four things in vector_copy:
1) Free the existing items objects in the destination vector so that it's not leaked.
2) Copy the capacity and size.
3) Allocate a brand new items for the destination vector to own.
4) Copy the source items into the newly-allocated destination items.
If you consider vector_copy to be an initialization function, skip step 1. But in that case, I'd strongly suggest changing the name to vector_init so that it's clear that it creates a new vector.
You're simply trying to access free()d memory. First you're calling free(v->items) in vector_free(), and then you're trying to print its contents as if nothing had happened!
When you copy a vector to another (no matter how) the new vector will hold a reference to old_vector->items, so you cannot just free() it -- C is not a garbage collected language and malloc doesn't reference-count the blocks it's managing.
So, basically I believe it just copies maybe the memory addresses and not the actual content
Yes, because at this line
memcpy(to, from, sizeof(vector_st));
you simply discards whatever memory was allocated for to, so memory held by copied becomes leaked; and after vector_free(vec) copied now holds a dangling reference to an already-freed memory.
To copy vector's contents into another, well, copy it:
memcpy(to->items, from->items, sizeof(void *) * from->size);
(Or less efficient
int i;
for(i = 0; i < from->size; ++i) to->items[i] = from->items[i];
)
Or, better, define a copy-constructor:
vector_t vector_copy(vector_t src);
// this functions allocates a fresh vector on heap;
// set its size and capacity to those of src;
// sets its items to a fresh array on heap of capacity elements;
// copies src's items into that array;
// and returns it
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.
I am trying to make a generic function in C that takes a 2D array of ANY type and copies it into a contiguous memory block. ( I need this function for Aggregate operations on MPI on my complex datatypes).
Imagine I have the following integer array
int n = 5;
int m = 6;
int** int_array = (int**) malloc(n* sizeof(int*));
for (int i = 0; i < n; i++ )
int_array[i] = (int *) malloc(m * sizeof(int) );
In this type of memory allocation one cannot, in principle, hope to access the , say i,j-th entry of int_array using the following pointer arithmetics
int value = (*lcc)[i*m+j];
Therefore I implemented a function that basically allocates a new memory block and neatly orders the entries of int_array so that the above indexing should work.
void linearize(char*** array, int n, int m,unsigned int size_bytes){
char* newarray = (char*)malloc(m*n*size_bytes);
//copy array!
for (int i = 0;i<n;i++)
for(int j = 0;j<m*size_bytes;j++)
{
newarray[i*m*size_bytes+j] = (*array)[i][j];
}
//swap pointers and free old memory!
for (int i = 0;i<n;i++)
{
char * temp = (*array)[i];
(*array)[i] = newarray + i*m*size_bytes ;
free(temp);
}
}
I wanted to make the above function to work with any kind of array type, hence I used char pointers to do operations byte by byte. I tested the function and so far it works, but I am not sure about memory deallocation.
Does free(temp) free the whole memory pointed to by int_array[i], that is the m*sizeof(int) bytes accessible from int_array[i] or only the first m bytes (since it thinks that our array is of type char rather than in) ? Or simply put, "Does the linearize function induce any memory leaks? "
Thank you in advance!
*EDIT*
As suggested by Nicolas Barbey, I ran a valgrind checks for memory leaks and it found none.
So to summarize the main points that I found difficult to understand about the behaviour of the program were:
in the function linearize does the following code induce memory leaks:
char * temp = (*array)[i];
(*array)[i] = newarray + i*m*size_bytes ;
free(temp);
NO!! somehow gnu compiler is smart enough to know how many bytes pointed to by "temp" to free. Originally I was afraid that if I array[i] is a pointer of type int , for example, that points to a memory location with say 5 ints = 5*4 bytes, the free(temp) is going to free only the first five bytes of that memory.
Another point to make is : how to free the already linearized array? that is if you have:
// first initialize the array.
int** array = (int**)malloc(5*sizeof(int*);
for(int i = 0; i< 5;i++)
array[i] = ( int* ) malloc(5*sizeof(int));
//now a call to linearize
linearize(&array,5,5,sizeof(int));
... do some work with array ....
// now time to free array
free(array[0]);
free(array);
//suffices to free all memory pointed to by array[i] and as well as the memory allocated
// for the pointers.
Thanks for the discussion and the suggestions.
You need to call free() exactly one call per malloc() inorder to be no memory leaks. Which means in your case int_array is passed to linearize function allocates a block of memory other than int_array allocation, therefore you need to loop over int_array[i] freeing each int* that you traverse followed by free'ing int_array itself. Also you need to free block created in linearize function too.
Here is a slightly slimmer version using actual two dimensional arrays:
void * linearize(void** array, int n, int m,unsigned int size_bytes){
char (*newarray)[m * size_bytes] = malloc(m*n*size_bytes);
//copy array!
int i;
for (i = 0;i<n;i++) {
memcpy(newarray[i], array[i], sizeof(*newarray));
free(array[i]);
}
free(array);
return newarray;
}
Use:
int (*newarray)[m] = linearize(array, n, m, sizeof(**int_array));
int value = newarray[i][j];
// or
value = newarray[0][i*m + j];
// or
value = ((int *)newarray)[i*m + j];
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.