I am currently writing a program to implement an arraylist (or dynamic array) in C. Hmm... I think I have 70 - 80% done with it, however, I found a serious problem with my c
As others have noted, the problem is in the arraylist_add()
function, which needs to dynamically allocate memory. This problem is actually perfectly suited for realloc()
, which will expand the dynamically allocated array (meaning you don't have to do the copying loop):
void arraylist_add(struct arraylist *list, value_type value) {
int size = arraylist_get_size(*list);
value_type *new_data;
new_data = realloc(list->data, (size + 1) * sizeof new_data[0]);
if (new_data)
{
new_data[size] = value;
arraylist_set_data_collection(list, new_data);
++list->size;
}
}
This will even work for the first allocation, since realloc()
works like malloc()
if you pass it a NULL
.
PS:
To make the implementation more efficient, you shouldn't expand the array by one entry each time - instead, keep track of the number of allocated blocks separately from the number of entries.
The root of your problem is here:
void arraylist_add(struct arraylist *list, value_type value) {
int size = arraylist_get_size(*list);
value_type new_data[size + 1];
...
arraylist_set_data_collection(list, new_data);
...
++list->size;
}
new_data
is declared on the stack. It's no longer safe to use that memory after the call returns. You need to allocate space for the data with malloc
, e.g.
In the arraylist_add
method you are storing the address of a local variable new_data
in to the list. This variable will destroyed as soon as the control comes out of the function. Hence you have invalid pointers which when derefrenced invoke undefined behavior. To fix this problem, you need to allocate memory for the string from heap using malloc
i.e. you need to do something like value_type* new_data = (value_type*)malloc( (size + 1) * sizeof(value_type));
. Also remember that you have to deallocate this memory yourself using free
.
At first glance: in arraylist_add you declare new_data as a local variable. When you pass that to arraylist_set_data_collection, it passes the pointer to this data. However, once arraylist_add returns to main, new_data is out of scope, and is therefore no longer valid.
Consider doing a deep copy and handling the memory manually with malloc and free.