There are really two separate issues. The first is keeping the elements of the array in proper order so that there are no "holes" after removing an element. The second is actually resizing the array itself.
Arrays in C are allocated as a fixed number of contiguous elements. There is no way to actually remove the memory used by an individual element in the array, but the elements can be shifted to fill the hole made by removing an element. For example:
void remove_element(array_type *array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++) array[i] = array[i + 1];
}
Statically allocated arrays can not be resized. Dynamically allocated arrays can be resized with realloc(). This will potentially move the entire array to another location in memory, so all pointers to the array or to its elements will have to be updated. For example:
remove_element(array, index, array_length); /* First shift the elements, then reallocate */
array_type *tmp = realloc(array, (array_length - 1) * sizeof(array_type) );
if (tmp == NULL && array_length > 1) {
/* No memory available */
exit(EXIT_FAILURE);
}
array_length = array_length - 1;
array = tmp;
realloc() will return a NULL pointer if the requested size is 0, or if there is an error. Otherwise, it returns a pointer to the reallocated array. The temporary pointer is used to detect errors when calling realloc() because instead of exiting, it is also possible to just leave the original array as it was. When realloc() fails to reallocate an array, it does not alter the original array.
Note that both of these operations will be fairly slow if the array is large or if a lot of elements are removed. There are other data structures like linked lists and hashes that can be used if efficient insertion and deletion is a priority.
Answer from Ben on Stack OverflowThere are really two separate issues. The first is keeping the elements of the array in proper order so that there are no "holes" after removing an element. The second is actually resizing the array itself.
Arrays in C are allocated as a fixed number of contiguous elements. There is no way to actually remove the memory used by an individual element in the array, but the elements can be shifted to fill the hole made by removing an element. For example:
void remove_element(array_type *array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++) array[i] = array[i + 1];
}
Statically allocated arrays can not be resized. Dynamically allocated arrays can be resized with realloc(). This will potentially move the entire array to another location in memory, so all pointers to the array or to its elements will have to be updated. For example:
remove_element(array, index, array_length); /* First shift the elements, then reallocate */
array_type *tmp = realloc(array, (array_length - 1) * sizeof(array_type) );
if (tmp == NULL && array_length > 1) {
/* No memory available */
exit(EXIT_FAILURE);
}
array_length = array_length - 1;
array = tmp;
realloc() will return a NULL pointer if the requested size is 0, or if there is an error. Otherwise, it returns a pointer to the reallocated array. The temporary pointer is used to detect errors when calling realloc() because instead of exiting, it is also possible to just leave the original array as it was. When realloc() fails to reallocate an array, it does not alter the original array.
Note that both of these operations will be fairly slow if the array is large or if a lot of elements are removed. There are other data structures like linked lists and hashes that can be used if efficient insertion and deletion is a priority.
What solution you need depends on whether you want your array to retain its order, or not.
Generally, you never only have the array pointer, you also have a variable holding its current logical size, as well as a variable holding its allocated size. I'm also assuming that the removeIndex is within the bounds of the array. With that given, the removal is simple:
Order irrelevant
array[removeIndex] = array[--logicalSize];
That's it. You simply copy the last array element over the element that is to be removed, decrementing the logicalSize of the array in the process.
If removeIndex == logicalSize-1, i.e. the last element is to be removed, this degrades into a self-assignment of that last element, but that is not a problem.
Retaining order
memmove(array + removeIndex, array + removeIndex + 1, (--logicalSize - removeIndex)*sizeof(*array));
A bit more complex, because now we need to call memmove() to perform the shifting of elements, but still a one-liner. Again, this also updates the logicalSize of the array in the process.
Videos
Can't seem to find a way on how to do it....
for example if I have an array
a = {1,2,3}
and I want to delete a[1] so the result would be
a = {1,3 }
How can this be done ?
What do you mean by "remove"? How are the arrays allocated?
If you have an array created by a declaration such as:
struct foo my_foos[123];
there is nothing you can do to change the fact that my_foos is 123 elements long. You can of course select to ignore some of them by having a separate size_t foo_count variable that you maintain.
Arrays in C are not generally dynamic (unlike lists/arrays in many more high-level languages). You can implement a dynamic array using malloc(), which is not too hard but it's unclear if that's what you've done.
If you're open for using external files, have a look at utarray:
It's a collection of macros stored in one header that allow what you're searching for. No need to link an additional library, just #include the file and you have what you need.
You'd have to implement a custom UT_icd providing functions to init, copy and free the elements stored in the array.
Belaying potential alignment issues, you don't need a loop. I believe this is all you need to shift the right-most desired elements 'back' one 'slot':
unsigned char *dst = (unsigned char*)array->array + indice * array->elem;
memmove(dst, dst + array->elem, array->elem * (array->len - indice - 1));
There are lot of things that go wrong in your implementation.
For example, the way you use your name char pointer can lead to it pointing to deallocated memory. The following code :
void foo(Array *array) {
char name[] = "abc";
char type[] = "int";
init_array(type, name, array);
}
int main(int args, char **argv) {
Array array;
foo(&array);
puts(array.name);
}
leads to undefined behavior, because array.name and array.dtype point to chunks of memory which have been popped from the stack.
One can also mention that you only manage very few cases. What happens if the user input "short" as dtype ?
For your specific problem, memmove is your friend :
void* slot = array->array + array->elem * indice;
memcpy(array->array + array->len * array->elem, slot, array->elem);
--vector->len;
memmove(slot, (const void *) slot + array->elem, (array->len - indice) * array->elem);
Use a List, Queue or Stack instead..
List<String>
Queue<String>
Stack<String>
Queue<T> (first in, first out) or Stack<T> (last in, first out) are what you're after.
Arrays in .NET are fixed length - you can't remove an element from them or indeed add elements to them. You can do this with a List<T> but Queue<T> and Stack<T> are more appropriate when you want queue/stack semantics.