I see several problems in the published code, each of which can cause problems:
returns a new array
Your function accepts an int* array , but then you try to swap it with your temp variable at the end before returning a new array. This will not work, as you are simply replacing the local copy of int* array , which will disappear after returning from the function.
You need to pass the pointer to the array as int** , which will allow you to set the actual pointer to the array in the function, or I would suggest just returning the int * value for your function and returning a new array.
Also, as mentioned in this answer , you really don't need to redistribute when you remove an element from the array, as the original array is large enough to hold everything.
size and offset calculations
You use sizeof(int*) to calculate the size of an array element. This may work for some types, but, for example, for the array short sizeof(short*) does not work. You do not need the size of the pointer to the array, you want the size of the elements, which for your example should be sizeof(int) , although this may not cause problems in this case.
Calculating the length for offsets in arrays looks fine, but you forget to multiply the number of elements by the element size for the memcpy size parameter. e.g. memcpy(temp, array, (indexToRemove - 1) * sizeof(int)); .
The second memcpy call uses temp plus the offset as the source array, but it should be array plus the offset.
The second memcpy call uses sizeOfArray - indexToRemove for the number of elements to copy, but you should only copy the SizeOfArray - indexToRemove - 1 (or (sizeOfArray - indexToRemove - 1) * sizeof(int) bytes tags
Wherever you calculate offsets in temp arrays and arrays, you do not need to multiply sizeof (int), since pointer arithmetic already takes into account the size of the elements. (I missed this first, thanks: this answer .)
view the wrong item
You print test[16] (the 17th element) for testing, but you delete the 16th element, which will be test[15] .
corner cabinets
Also (thanks to this answer ) you should handle cases where indexToRemove == 0 and indexToRemove == (sizeOfArray - 1) , where you can do all the deletion in one memcpy.
In addition, you need to worry about the case when sizeOfArray == 1 . In this case, it is possible either to select a size 0 block of size or return zero. In my updated code, I chose to allocate a block of size 0, just to split the array with 0 elements compared to an unallocated array.
The return of an array of size 0 also means that the code does not require additional changes, since the conditions that must be met before each memcpy to handle the first two cases mentioned will prevent memcpy from being executed.
And just note that there is no error handling in the code, so there are implicit assumptions that indexToRemove is within the bounds, that the array not null and that the array has the size passed as sizeOfArray .
updated code example
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 - 1) * 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]); remove_element(test, howMany, 16); --howMany; printf("%d\n", test[16]); return 0; }
a few words about memory management / abstract data types
Finally, something to consider: there may be problems using malloc to return memory to a user, which should be a free d user, and with free memory, that a malloc user Ed. In general, it is less likely that memory management will be confusing and difficult to process if you design your code modules in such a way that the memory allocation is processed within a single block of logical code.
For example, you can create a module of an abstract data type that would allow you to create an integer array using a structure containing a pointer and a length, and then all manipulations with this data go through functions that take the structure as the first parameter.This also allows you, with the exception of of this module, avoid the need to perform calculations such as elemNumber * sizeof(elemType) . Something like that:
struct MyIntArray { int* ArrHead; int ElementSize;
etc..
It basically implements some C ++ -like functions in C, and this IMO is a very good idea, especially if you are starting from scratch and want to create something more than a simple application. I know some C developers who really don't like this idiom, but it worked well for me.
The good thing about this way of implementing things is that anything in your code that uses a function to remove an element will never touch the pointer directly. This would allow several 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 redistributed after the element was deleted, all variables pointing to your abstract array would be automatically updated.
In general, memory management can be very confusing, and this is one of the strategies that can make it less. Just a thought.