How to copy structures that involve pointers in C? - c

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

Related

How to delete an element at specific index in dynamic array in C language? [duplicate]

So, I have this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void remove_element(int* array, int sizeOfArray, int indexToRemove)
{
int* temp = malloc((sizeOfArray - 1) * sizeof(int*)); // allocate an array with a size 1 less than the current one
memcpy(temp, array, indexToRemove - 1); // copy everything BEFORE the index
memcpy(temp+(indexToRemove * sizeof(int*)), temp+((indexToRemove+1) * sizeof(int*)), sizeOfArray - indexToRemove); // copy everything AFTER the index
free (array);
array = temp;
}
int main()
{
int howMany = 20;
int* test = malloc(howMany * sizeof(int*));
for (int i = 0; i < howMany; ++i)
(test[i]) = i;
printf("%d\n", test[16]);
remove_element(test, howMany, 16);
--howMany;
printf("%d\n", test[16]);
return 0;
}
It's reasonably self-explanatory, remove_element removes a given element of a dynamic array.
As you can see, each element of test is initialised to an incrementing integer (that is, test[n] == n). However, the program outputs
16
16
.
Having removed an element of test, one would expect a call to to test[n] where n >= the removed element would result in what test[n+1] would have been before the removal. So I would expect the output
16
17
. What's going wrong?
EDIT: The problem has now been solved. Here's the fixed code (with crude debug printfs), should anyone else find it useful:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int remove_element(int** array, int sizeOfArray, int indexToRemove)
{
printf("Beginning processing. Array is currently: ");
for (int i = 0; i < sizeOfArray; ++i)
printf("%d ", (*array)[i]);
printf("\n");
int* temp = malloc((sizeOfArray - 1) * sizeof(int)); // allocate an array with a size 1 less than the current one
memmove(
temp,
*array,
(indexToRemove+1)*sizeof(int)); // copy everything BEFORE the index
memmove(
temp+indexToRemove,
(*array)+(indexToRemove+1),
(sizeOfArray - indexToRemove)*sizeof(int)); // copy everything AFTER the index
printf("Processing done. Array is currently: ");
for (int i = 0; i < sizeOfArray - 1; ++i)
printf("%d ", (temp)[i]);
printf("\n");
free (*array);
*array = temp;
return 0;
}
int main()
{
int howMany = 20;
int* test = malloc(howMany * sizeof(int*));
for (int i = 0; i < howMany; ++i)
(test[i]) = i;
printf("%d\n", test[16]);
remove_element(&test, howMany, 14);
--howMany;
printf("%d\n", test[16]);
return 0;
}
I see several issues in the posted code, each of which could cause problems:
returning the new array
Your function is taking an int* array but then you are trying to swap it with your temp variable at the end prior to returning the new array. This will not work, as you are simply replacing the local copy of int* array which will disappear after you return from the function.
You either need to pass your array pointer in as an int**, which would allow you to set the actual pointer to the array in the function, or, I would suggest just returning a value
of int* for your function, and returning the new array.
Also, as mentioned in this answer, you really don't even need to reallocate when deleting an element from the array, since the original array is big enough to hold everything.
size and offset calculations
You are using sizeof(int*) for calculating the array element size. This may work for some types, but, for instance, for a short array sizeof(short*) does not work. You don't want the size of the pointer to the array, you want the size of the elements, which for your example should be sizeof(int) although it may not cause problems in this case.
Your length calculation for the offsets into the arrays looks ok, but you're forgetting to multiply the number of elements by the element size for the size parameter of the memcpy. e.g. memcpy(temp, array, indexToRemove * sizeof(int));.
Your second call to memcpy is using temp plus the offset as the source array, but it should be array plus the offset.
Your second call to memcpy is using sizeOfArray - indexToRemove for the number of elements to copy, but you should only copy SizeOfArray - indexToRemove - 1 elements (or (sizeOfArray - indexToRemove - 1) * sizeof(int) bytes
Wherever you are calculating offsets into the temp and array arrays, you don't need to multiply by sizeof(int), since pointer arithmetic already takes into account the size of the elements. (I missed this at first, thanks to: this answer.)
looking at incorrect element
You are printing test[16] (the 17th element) for testing, but you are removing the 16th element, which would be test[15].
corner cases
Also (thanks to this answer) you should handle the cases where indexToRemove == 0 and indexToRemove == (sizeOfArray - 1), where you can do the entire removal in one memcpy.
Also, you need to worry about the case where sizeOfArray == 1. In that case perhaps either allocate a 0 size block of memory, or return null. In my updated code, I chose to allocate a 0-size block, just to differentiate between an array with 0 elements vs. an unallocated array.
Returning a 0-size array also means there are no additional changes necessary to the code, because the conditions before each memcpy to handle the first two cases mentioned will prevent either memcpy from taking place.
And just to mention, there's no error handling in the code, so there are implicit preconditions that indexToRemove is in bounds, that array is not null, and that array has the size passed as sizeOfArray.
example updated code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int* remove_element(int* array, int sizeOfArray, int indexToRemove)
{
int* temp = malloc((sizeOfArray - 1) * sizeof(int)); // allocate an array with a size 1 less than the current one
if (indexToRemove != 0)
memcpy(temp, array, indexToRemove * sizeof(int)); // copy everything BEFORE the index
if (indexToRemove != (sizeOfArray - 1))
memcpy(temp+indexToRemove, array+indexToRemove+1, (sizeOfArray - indexToRemove - 1) * sizeof(int)); // copy everything AFTER the index
free (array);
return temp;
}
int main()
{
int howMany = 20;
int* test = malloc(howMany * sizeof(int));
for (int i = 0; i < howMany; ++i)
test[i] = i;
printf("%d\n", test[16]);
test = remove_element(test, howMany, 16);
--howMany;
printf("%d\n", test[16]);
free(test);
return 0;
}
a few words on memory management/abstract data types
Finally, something to consider: there are possible issues both with using malloc to return memory to a user that is expected to be freed by the user, and with freeing memory that a user malloced. In general, it's less likely that memory management will be confusing and hard to handle if you design your code units such that memory allocation is handled within a single logical code unit.
For instance, you might create an abstract data type module that allowed you to create an integer array using a struct that holds a pointer and a length, and then all manipulation of that data goes through functions taking the structure as a first parameter. This also allows you, except within that module, to avoid having to do calculations like elemNumber * sizeof(elemType). Something like this:
struct MyIntArray
{
int* ArrHead;
int ElementSize;
// if you wanted support for resizing without reallocating you might also
// have your Create function take an initialBufferSize, and:
// int BufferSize;
};
void MyIntArray_Create(struct MyIntArray* This, int numElems /*, int initBuffSize */);
void MyIntArray_Destroy(struct MyIntArray* This);
bool MyIntArray_RemoveElement(struct MyIntArray* This, int index);
bool MyIntArray_InsertElement(string MyIntArray* THis, int index, int Value);
etc.
This is a basically implementing some C++-like functionality in C, and it's IMO a very good idea, especially if you are starting from scratch and you want to create anything more than a very simple application. I know of some C developers that really don't like this idiom, but it has worked well for me.
The nice thing about this way of implementing things is that anything in your code that was using the function to remove an element would not ever be touching the pointer directly. This would allow several different parts of your code to store a pointer to your abstract array structure, and when the pointer to the actual data of the array was reallocated after the element was removed, all variables pointing to your abstract array would be automatically updated.
In general, memory management can be very confusing, and this is one strategy that can make it less so. Just a thought.
You don't actually change the passed pointer. You're only changing your copy of array.
void remove_element(int* array, int sizeOfArray, int indexToRemove)
{
int* temp = malloc((sizeOfArray - 1) * sizeof(int*));
free (array); /* Destroys the array the caller gave you. */
array = temp; /* Temp is lost. This has **no effect** for the caller. */
}
So after the function the array still points to where it used to point BUT, you've also freed it, which adds insult to injury.
Try something like this:
void remove_element(int **array, int sizeOfArray, int indexToRemove)
^^
{
int *temp = malloc((sizeOfArray - 1) * sizeof(int*));
/* More stuff. */
free(*array);
*array = temp;
}
There is also a C FAQ: Change passed pointer.
#cnicutar is right (+1), but also, you write:
memcpy(temp+(indexToRemove * sizeof(int*)), temp+((indexToRemove+1) * sizeof(int*)), sizeOfArray - indexToRemove); // copy everything AFTER the index
while it should be:
memmove(temp+(indexToRemove), temp+(indexToRemove+1), sizeOfArray - indexToRemove); // copy everything AFTER the index
Since the multiplication by the size of int* is done by the compiler (that's pointer arithmetic)
Also, when moving overlaying memory areas, use memmove and not memcpy.
Further: the second argument to your second memcpy call should be based on array, not on temp, right? And shouldn't you be mallocing and copying based on sizeof int and not based on sizeof int*, since your arrays store integers and not pointers? And don't you need to multiply the number of bytes you're copying (the last argument to memcpy) by sizeof int as well?
Also, watch the case where indexToRemove == 0.
There are a few problems with that code :
(a) When allocating memory, you need to make sure to use the correct type with sizeof. For an array of int eg., you allocate a memory block with a size that is a multiple of sizeof(int). So :
int* test = malloc(howMany * sizeof(int*));
should be :
int* test = malloc(howMany * sizeof(int));
(b) You don't free the memory for the array at the end of main.
(c) memcpy takes the amount of bytes to copy as the third parameter. So, you need to again make sure to pass a multiple of sizeof(int). So :
memcpy(temp, array, cnt);
should be :
memcpy(temp, array, cnt * sizeof(int));
(d) when copying items from the old array to the new array, make sure to copy the correct data. For example, there are indexToRemove items before the item at index indexToRemove, not one less. Similarly, you'll need to make sure that you copy the correct amount of items after the item that needs to be removed.
(e) When incrementing a pointer, you don't need to multiply with sizeof(int) - that's done implicitly for you. So :
temp + (cnt * sizeof(int))
should really be :
temp + cnt
(f) In your remove_element function, you assign a value to the local variable array. Any changes to local variables are not visible outside of the function. So, after the call to remove_element ends, you won't see the change in main. One way to solve this, is to return the new pointer from the function, and assign it in main :
test = remove_element(test, howMany, 16);
All the other answers make good points about the various problems/bugs in the code.
But, why reallocate at all (not that the bugs are all related to reallocation)? The 'smaller' array will fit fine in the existing block of memory:
// Note: untested (not even compiled) code; it also doesn't do any
// checks for overflow, parameter validation, etc.
int remove_element(int* array, int sizeOfArray, int indexToRemove)
{
// assuming that sizeOfArray is the count of valid elements in the array
int elements_to_move = sizeOfArray - indexToRemove - 1;
memmove( &array[indexToRemove], &array[indexToRemove+1], elements_to_move * sizeof(array[0]));
// let the caller know how many elements remain in the array
// of course, they could figure this out themselves...
return sizeOfArray - 1;
}

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

How can I make a pool with pointers in C?

I'm making my library, and just when I thought understanding the pointers syntax, I just get confused, search on the web and get even more confused.
Basically I want to make a pool, here is what I actually want to do:
the following points must be respected :
when I add an object to the pool, the pointers of the current array to the objects are
added to a new array of pointers + 1 (to contain the new object).
the new array is pointed by "objects" of my foo structure.
the old array is free'ing.
when I call the cleanup function, all the object in the pool are
free'd
How should I define my structure ?
typedef struct {
int n;
(???)objects
} foo;
foo *the_pool;
here's the code to manage my pool :
void myc_pool_init ()
{
the_pool = (???)malloc(sizeof(???));
the_pool->n = 0;
the_pool->objects = NULL;
}
void myc_push_in_pool (void* object)
{
if (object != NULL) {
int i;
(???)new_pointers;
the_pool->n++;
new_pointers = (???)malloc(sizeof(???)*the_pool->n);
for (i = 0; i < the_pool->n - 1; ++i) {
new_pointers[i] = (the_pool->objects)[i]; // that doesn't work (as I'm not sure how to handle it)
}
new_array[i] = object;
free(the_pool->objects);
the_pool->objects = new_array; // that must be wrong
}
}
void myc_pool_cleanup ()
{
int i;
for (i = 0; i < the_pool->n; ++i)
free((the_pool->objects)[i]); // as in myc_push_in_pool, it doesn't work
free(the_pool->objects);
free(the_pool);
}
Note: the type of objects added to the pool are not known in advance, so i should handles all pointers as void
any feedback would be very welcomed.
A straight answer to your question would be: use void *. This type is very powerful as it allows you to put any kind of pointer in your pool. However, it's up to you to do the correct casts when retrieving a void * pointer from your pool.
Your struct would look like this
typedef struct {
int n;
(void **)objects
} foo;
foo *the_pool;
As in, an array of pointers.
Your malloc:
new_pointers = (void **)malloc(sizeof(void *)*the_pool->n);
There is an performance issue here. You could simply allocate an array of a fixed size, and only reallocate if the number of elements exceeds a predefined load factor (= number used/ max size)
Also, instead of allocating a new pointer each time you add something to your pool, you could just use realloc (http://www.cplusplus.com/reference/cstdlib/realloc/)
the_pool->objects = (void **)realloc(the_pool->objects, the_pool->n* sizeof(void*));
Realloc tries to increase the current allocated area, without the need to copy everything. Only if the function cannot increase the allocated area contiguously will it allocate a new area and copy everything.
Firstly, you already answered your "What should the type of foo.objects be?" question: void *objects;, malloc already returns void *. Your struct needs to store the size_t item_size;, too. n should probably also be a size_t.
typedef struct {
size_t item_count;
size_t item_size;
void *objects;
} foo;
foo *the_pool;
You could use a home-grown loop, but I'd consider memcpy to be a more convenient way to copy your old items to your new space, and the new item to it's new space.
Dereferencing a void * is a constraint violation, as is pointer arithmetic on a void *, so new_pointers will need to be a different type. You need a type that points to objects of the right size. You could use an array of the right number of unsigned char, like so:
// new_pointers is a pointer to array of the_pool->item_size unsigned chars.
unsigned char (*new_pointers)[the_pool->item_size] = malloc(the_pool->item_count * sizeof *new_pointers);
// copy the old items
memcpy(new_pointers, the_pool->objects, the_pool->item_count * sizeof *new_pointers);
// copy the new items
memcpy(new_pointers + the_pool->item_count, object, sizeof *new_pointers);
Remember, free() is only for pointers returned by malloc(), and there should be a one-to-one correspondence: Each malloc() should be free()d. Look how you malloc: new_pointers = malloc(sizeof(???)*the_pool->n); ... What makes you think you need a loop (in myc_pool_cleanup) to free each item, when you can free them all in one foul swoop?
You could use realloc, but you otherwise seem to be handling malloc/memcpy/free *in myc_push_in_pool* flawlessly. Lots of people tend to mess up when writing realloc code.

C using malloc and duplicating array

I am supposed to follow the following criteria:
Implement function answer4 (pointer parameter and n):
Prepare an array of student_record using malloc() of n items.
Duplicate the student record from the parameter to the array n
times.
Return the array.
And I came with the code below, but it's obviously not correct. What's the correct way to implement this?
student_record *answer4(student_record* p, unsigned int n)
{
int i;
student_record* q = malloc(sizeof(student_record)*n);
for(i = 0; i < n ; i++){
q[i] = p[i];
}
free(q);
return q;
};
p = malloc(sizeof(student_record)*n);
This is problematic: you're overwriting the p input argument, so you can't reference the data you were handed after that line.
Which means that your inner loop reads initialized data.
This:
return a;
is problematic too - it would return a pointer to a local variable, and that's not good - that pointer becomes invalid as soon as the function returns.
What you need is something like:
student_record* ret = malloc(...);
for (int i=...) {
// copy p[i] to ret[i]
}
return ret;
1) You reassigned p, the array you were suppose to copy, by calling malloc().
2) You can't return the address of a local stack variable (a). Change a to a pointer, malloc it to the size of p, and copy p into. Malloc'd memory is heap memory, and so you can return such an address.
a[] is a local automatic array. Once you return from the function, it is erased from memory, so the calling function can't use the array you returned.
What you probably wanted to do is to malloc a new array (ie, not p), into which you should assign the duplicates and return its values w/o freeing the malloced memory.
Try to use better names, it might help in avoiding the obvious mix-up errors you have in your code.
For instance, start the function with:
student_record * answer4(const student_record *template, size_t n)
{
...
}
It also makes the code clearer. Note that I added const to make it clearer that the first argument is input-only, and made the type of the second one size_t which is good when dealing with "counts" and sizes of things.
The code in this question is evolving quite quickly but at the time of this answer it contains these two lines:
free(q);
return q;
This is guaranteed to be wrong - after the call to free its argument points to invalid memory and anything could happen subsequently upon using the value of q. i.e. you're returning an invalid pointer. Since you're returning q, don't free it yet! It becomes a "caller-owned" variable and it becomes the caller's responsibility to free it.
student_record* answer4(student_record* p, unsigned int n)
{
uint8_t *data, *pos;
size_t size = sizeof(student_record);
data = malloc(size*n);
pos = data;
for(unsigned int i = 0; i < n ; i++, pos=&pos[size])
memcpy(pos,p,size);
return (student_record *)data;
};
You may do like this.
This compiles and, I think, does what you want:
student_record *answer4(const student_record *const p, const unsigned int n)
{
unsigned int i;
student_record *const a = malloc(sizeof(student_record)*n);
for(i = 0; i < n; ++i)
{
a[i] = p[i];
}
return a;
};
Several points:
The existing array is identified as p. You want to copy from it. You probably do not want to free it (to free it is probably the caller's job).
The new array is a. You want to copy to it. The function cannot free it, because the caller will need it. Therefore, the caller must take the responsibility to free it, once the caller has done with it.
The array has n elements, indexed 0 through n-1. The usual way to express the upper bound on the index thus is i < n.
The consts I have added are not required, but well-written code will probably include them.
Altought, there are previous GOOD answers to this question, I couldn't avoid added my own. Since I got pascal programming in Collegue, I am used to do this, in C related programming languages:
void* AnyFunction(int AnyParameter)
{
void* Result = NULL;
DoSomethingWith(Result);
return Result;
}
This, helps me to easy debug, and avoid bugs like the one mention by #ysap, related to pointers.
Something important to remember, is that the question mention to return a SINGLE pointer, this a common caveat, because a pointer, can be used to address a single item, or a consecutive array !!!
This question suggests to use an array as A CONCEPT, with pointers, NOT USING ARRAY SYNTAX.
// returns a single pointer to an array:
student_record* answer4(student_record* student, unsigned int n)
{
// empty result variable for this function:
student_record* Result = NULL;
// the result will allocate a conceptual array, even if it is a single pointer:
student_record* Result = malloc(sizeof(student_record)*n);
// a copy of the destination result, will move for each item
student_record* dest = Result;
int i;
for(i = 0; i < n ; i++){
// copy contents, not address:
*dest = *student;
// move to next item of "Result"
dest++;
}
// the data referenced by "Result", was changed using "dest"
return Result;
} // student_record* answer4(...)
Check that, there is not subscript operator here, because of addressing with pointers.
Please, don't start a pascal v.s. c flame war, this is just a suggestion.

Memory Allocation for a 2D Array in 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.

Resources