Deleting dynamically allocated array members in C - c

Lets say I have an array of structs and I want to delete an entry that has a struct with an entry matching some criteria.
This array is dynamically allocated with malloc, I keep the element count in a separate variable.
How do I go about deleting the entry?
I'm thinking of
for (i = pos; i < arr_len; i++) {
arr[i] = arr[i+1];
}
arr_len--;
But this leaves the same amount of memory for the array while I actually need less and an orphan (sort of) last entry.
Is issuing a realloc in such situation an accepted practice? Would realloc do memcpy in this case? (shortening the allocated memory by one block).

realloc is ok ... but keep reading :)
realloc will not move parts of the memory; it may move the whole block. So you need to copy the data before changing the allocated size.
To move the data, memmove (not memcpy) is a good option: it works for memory areas that belong to the same object. Pay attention to not go over your array limits, though; like you do in your code.
for (i = pos; i < arr_len; i++) {
arr[i] = arr[i+1];
}
The arr[i] = arr[i + 1]; will try to access one past the allowed size. You need
for (i = pos + 1; i < arr_len; i++) {
arr[i - 1] = arr[i];
}
There is somewhat of an overhead when calling realloc. If your structs are not large and/or they live only for a short while, consider keeping both an element count and allocated count and only realloc to enlarge (when (element_count + 1) > (allocated_count)).
If the struct is large, also consider a different data structure (linked list perhaps).

Calling realloc to shrink the allocated memory would not necessarily be a bad idea.
However, you might have to reconsider the data structure you are using. It looks like a linked list would make it much easier to manage memory and make the delete operation much faster since it doesn't require shifting elements.

Using realloc would be appropriate here. It wouldn't do a memcpy -- that's only necessary when the realloc size is larger and there's no room to expand.

Related

How do you free a 2D malloc'd array in C?

I'm creating a 2D Array in C; am I freeing it correctly?
// create
int n = 3;
int (*X)[n] = malloc(sizeof(int[n][n]));
// set to 0
for(int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
X[i][j] = 0;
}
}
// is this all I need?
free(X);
You must call free once for each malloc. Your code has one malloc and one free (with the same address) so it is correct.
For every malloc(), there must be a matching free(). So if you call malloc() in a loop, there must be a similar loop later on that calls free() just as many times. Your code has one malloc() and one corresponding free(), so yes, you have freed everything you need to.
The most common way I've seen to allocate a two-dimensional array is to do something like:
int **arr = malloc(sizeof (int *) * num_rows);
for (i = 0; i < num_rows; ++i)
arr[i] = malloc(sizeof (int) * num_cols);
/*
* Using `sizeof *arr` and `sizeof **arr`
* respectively would have been more safe,
* but for the purpose of this example, I think
* using `int *` and `int` is simpler to
* understand.
*/
then later to free:
for (i = 0; i < num_rows; ++i)
free(arr[i]);
free(arr);
This makes the outer dimension hold num_row pointers to pointers to int (each of the num_row pointers points to the starting address of the 'column'). So each element in the outer dimension points to a row, and in each row there are num_cols elements in the inner dimension (the 'columns'), which is just a group of num_cols integers. Does this make sense to you? So you have to allocate num_rows integer pointers, and each one of these points to the first 'column' of that row--for each row you have to allocate space for num_cols integers, so you can see the loop will make a total of num_rows * num cols integers, and they way they are allocated allows you to use array indexing notation (two-dimensional in this case--each element in the outer dimension points to the start of a 'row', which contains a pointer to the start of a 'column', hence the double pointer) to access the elements. I know this is probably confusing, that is why I tried to describe it so many different times/ways, but please just ask any questions, especially about what you don't understand in particular, and I will be more than happy to work with you in helping understand it.
I'm not saying you have to create your 2-D array this way; your way works fine too, I just wanted to show you this way since you are likely to run into it since it's very common.
Also, look into Valgrind. You can use that tool to see if you have forgotten any free()s / have an unmatched malloc(), and lets you know if there is any allocated memory unreachable/leaked (maybe the pointer was changed before the call to free() so the call doesn't properly free the memory and you get a leak).
RastaJedi - another couple of things to note:
After a call to free(), it's a good idea to set the free'd variable to NULL, which helps prevent use after free.
Also, if you malloc in one block of code, then free in some called function, and then return from that function, sometimes C forgets about the final free (in your example, free(arr) ), and you should set the variable to NULL upon return.
I came here, and verified that the malloc and free calls that I wrote in the code I'm working on are indeed exactly as your "common" way, but kept running into a Seg Fault, because I was using malloc from in main, free-ing from a helper function which received the double-indirect head of the array. Having that all wrapped in a while-loop for user interaction, a second pass around was checking the array head for NULL-ness, but not seeing it as NULL, despite explicitly setting to NULL inside the helper function. Crawling thru the code with a debugger is how I identified the behavior, and why I came looking.
After being free'd, the memory is available, and variously (and randomly) reassigned; when the function with the free() calls returns, the memory that was allocated has been released, however it seems that the calling code still holds a pointer to that place in memory. There then exists a possible race-condition; by the time the calling code regains control, there's no guarantee as regards the location pointed to by the variable used for the array head, and therefore it's a very good idea to set the variable to NULL after the function returns.
Although you can use malloc'd pointers for pass-by-reference behavior, after a call to free() inside some function, the by-reference behavior breaks (because the thing being referenced is what has been free'd).
So, thank you for your answer, which confirmed that I was looking at the wrong part of my problem - just figured maybe someone else may stumble here, and possibly have the same issue I did.

Do I need to realloc after memmove when remove an element from dynamic array?

I'm working on a ArrayList implementation in C. ArrayList stores pointers (void*), that means ArrayList is a dynamic array of pointers. Here how I remove an element from ArrayList:
typedef struct
{
void* ptr; // pointer of array (beginning)
int length; // pointer count
}ArrayList;
void ArrayList_Remove(ArrayList *list, int index)
{
memmove(
list->ptr + (sizeof(void*) * index),
list->ptr + (sizeof(void*) * (index + 1)),
(list->length - index) * sizeof(void*)
);
list->length--;
// Do I need to realloc list->ptr to free space?
// list->ptr = realloc(list->ptr, list->length * sizeof(void*));
}
As I commented in code, do I need to realloc list->ptr or memmove will do it?
First thing: memmove is not involved in memory allocation at all. It just does what it should, move (potentially overlapping) parts of the memory.
In your example it is not absolutely necessary to realloc the array. It mainly depends if so much elements are removed that there would be a relevant amount of free space for reusage. If you feel that this is indeed relevant, your realloc-statement below looks correct. But keep in mind, that the unallocated space might not be usable at all if just a few elements are deleted per array due to heap fragmentation issues.
memmove() will not free any memory.
You could use realloc(), or maybe just leave the extra space there in case you need to add/insert an item. That would need an extra member in your struct to keep track of the allocated size.
Also, if you plan to dynamically add or insert items, you might want to grow your buffer in larger chunks to prevent having to call realloc() each time. Normally this is done in powers of two up to a certain size (for example 16 - 32 - 64 -- 1024). After that, expand the buffer with a fixed size each time.

A suitable replacement for *****double

I have this big data structure which is a list of lists of lists of lists of lists of doubles. Clearly it's extremely inefficient to handle. Around 70% of time spent to run my application is used to write zeros in the doubles at the end of the lists. I need a faster replacement which satisfies two constraints:
1)All the memory must be allocated continuously (that is, a huge chunk of memory)
2)I must access this chunk using the usual A[][][][][] syntax
As for now, I thought of using a *double to hold the entire chunk and reuse my list of lists of... to store pointers to the appropriate areas in the chunk.
Any better ideas?
One example of how to achieve this with a 2D array, I'm to lazy to do the 5D case, is
double **a;
a = malloc (n * sizeof(*double));
a[0] = malloc (n * m * sizeof(double));
for (int i = 1; i < n; ++i)
a[i] = a[0][i*n];
This way you can decide if you wish to index it with a[0][i*n], or a[i][j]. The memory is contiguous, and you get away with only two allocations. Of course, this also requires a free n*m*sizeof(double) block in memory, but since you demand the memory to be allocated continuously I expect this to be satisfied. This also means that you will have to delete it correctly with:
free(a[0]);
free(a);
so I would make a create5Darray (n,m,k,l,t) and a delete5Darray function to make this easier.

Fastest way possible to allocate an array of strings

I have a function which takes an array of strings (buffer) and needs to increase its size.
So I invoke a realloc
temp = (char**) realloc (buffer, newSize * (sizeof(char*)));
if (temp == NULL)
return false;
else
buffer = temp;
And thus far everything is fine. Now for every new cell I must invoke a malloc with the correct size. Notice that newSize is always even and that odd strings have a different length than even ones.
for (i = oldSize; i < newSize; i++){
support = (char*) malloc (LENGTH1 * sizeof(char));
if (support == NULL){
marker = i;
failedMalloc = true;
break;
}
else
buffer[i] = support;
i++;
support = (char*) malloc (LENGTH2 * sizeof(char));
if (support == NULL){
marker = i;
failedMalloc = true;
break;
}
else
buffer[i] = support;
}
The fact is that since I work with huge data sooner or later I'll finish memory and the realloc or one of the mallocs will fail. The problem is that if it's one of the mallocs the one that fails there is the risk that I'll have to invoke millions of free to clear up some memory. This takes a lot of time. Is there any way to speedup this process or even better avoid it?
if (failedMalloc){
for (i = oldRows; i < marker; i++)
free(buffer[i]);
temp = (char**) realloc (buffer, oldRows * (sizeof(char*)));
}
PS: Yes I know that pointer arithmetic is faster than array indexing. I will implement it when I find a way to solve this problem, for the moment I prefer using array indexing because I find it less error prone. But the final version will use pointer arithmetic
Instead of allocating each string individually, allocate them in blocks. You could for example malloc 128*(LENGTH1+LENGTH2) and have room for 256 consecutive strings. Whenever your index crosses a block boundary, malloc another big block and use modulo arithmetic to get an offset into it for the start of the string.
P.S. sizeof(char) is guaranteed to be 1.
Allocate larger blocks of memory. The less malloc calls, the better. The fastest will be to precalculate the required size and allocate only once.
Also, using pointer arithmetic will not produce any visible difference here.
You could write your own allocation and deallocation routines, and use them instead of malloc/free for the strings. If your routines malloc one or more big buffers and portion out little bits of it, then you can free the whole lot in one go just by calling free on each big buffer.
The general idea works especially well in the case where all allocations are the same size, in which case it's called a "pool allocator". In this case, for each array or strings you could have one associated pool for the LENGTH1 allocations, and another for the LENGTH2.
I say, "write your own", but no doubt there are simple open-source pool allocators out there for the taking.
One way to avoid waste memory is to malloc larger memory each time, when you need to malloc,
malloc fixed size(align to 2^n), e.g.
int m_size = 1;
// when need malloc
while (m_size < require_size) m_size * 2;
malloc(m_size);

How can I free all allocated memory at once?

Here is what I am working with:
char* qdat[][NUMTBLCOLS];
char** tdat[];
char* ptr_web_data;
// Loop thru each table row of the query result set
for(row_index = 0; row_index < number_rows; row_index++)
{
// Loop thru each column of the query result set and extract the data
for(col_index = 0; col_index < number_cols; col_index++)
{
ptr_web_data = (char*) malloc((strlen(Data) + 1) * sizeof(char));
memcpy (ptr_web_data, column_text, strlen(column_text) + 1);
qdat[row_index][web_data_index] = ptr_web_data;
}
}
tdat[row_index] = qdat[col_index];
After the data is used, the memory allocated is released one at a time using free().
for(row_index = 0; row_index < number_rows; row_index++)
{
// Loop thru all columns used
for(col_index = 0; col_index < SARWEBTBLCOLS; col_index++)
{
// Free memory block pointed to by results set array
free(tdat[row_index][col_index]);
}
}
Is there a way to release all the allocated memory at once, for this array?
Thank You.
Not with the standard malloc() allocator - you need to investigate the use of memory pools. These work by allocating a big block of memory up-front, allocating from it and freeing back to it as you request via their own allocation functions, and then freeing the whole lot with a special "deallocate all" function.
I must say I've always found these things a bit ugly - it really isn't that hard to write code that doesn't leak. The only reason I can see for using them is to mitigate heap fragmentation, if that is a real problem for you.
No there is not. Memory which is separately allocated must be separately freed.
The only way you could free it as once is if you allocated it at once is a giant block. You would then have to do a bit of pointer math to assign every row the correct index into the array but it's not terribly difficult. This approach does have a few downsides though
Extra pointer math
Requires one giant contiguous block of memory vs. N smaller blocks of memory. Can be an issue in low memory or high fragmentation environments.
Extra work for no real stated gain.
If you want to release it all at once, you have to allocate it all at once.
A simple manual solution, if you know the total size you'll need in advance, is to allocate it all in once chunk and index into it as appropriate. If you don't know the size in advance you can use realloc to grow the memory, so long as you only access it indexed from the initial pointer, and don't store additional pointers anywhere.
That being said, direct allocation and deallocation is a simple solution, and harder to get wrong than the alternatives. Unless the loop to deallocate is causing you real difficulties, I would stick with what you have.

Resources