Related
I try something like below but all the time I have a segmentation fault.
I don't really want to use (e.g.) #define N 1000 and then declare int buffer[N].
Just in case..I'm not allowed to use any headers except stdio.h as well as dynamic memory.
void input (int *buffer, int *length);
int main()
{
int length, *buffer = NULL, *numbers = NULL;
input(buffer, &length);
}
void input(int *buffer, int *length) {
scanf("%d", length);
if (*length < 0) {
error = 1;
return;
}
for (int i = 0; i < *length; i++) {
scanf("%d", *buffer[i]);
}
}
How to pass an array with unknown 1-d dimension into function
In C, arrays cannot exist until their size is known.
There are other approaches though.
In C, code cannot pass an array to a function. some_function(some_array) converts the array some_array to the address of the first element of the array: &some_array[0]. That is what the function receives, a pointer, not an array. The original size information of the array is not passed, thus also pass the length to the function.
Sample:
Read desired length.
{
int length = 0;
scanf("%d", &length);
Form a variable length array, length >= 1.
if (length <= 0) {
return NULL;
}
int buffer[length];
Now call a function, passing the length and the address of the first element of the array.
// Do stuff with length and buf, like read data
foo1(length, buffer);
// foo1() receives the length & address of the first element of the array as an int *
// Do more stuff with length and buf, like write data
foo2(length, buffer);
}
At the end of the block }, buffer no longer available.
In C, you can't create an array if you can't know its size at compile time (or at least not in certain implementations and standards), so doing something like buffer[length] won't work (again at least not in certain implementations/standards).
What you need to do to make sure this works everywhere is to use a pointer (as I see you're trying to use here). However, what you're doing wrong here that causes your segfault with the pointers is you assign them the value of NULL. This also won't work due to how when you assign a pointer an arbitrary value, there is no memory allocated for the pointer (This applies for everything other than addresses of "regular" variables using the & operator and assigning other pointers that are checked to be OK). Your pointers are just pointing to address 0 and can't be used for anything.
What you need to do here to fix the pointers is to use dynamic memory allocation, so you can have a truly variable-sized array. Specifically, you need to use a function like malloc or calloc to allocate memory for the pointers so they are usable. In your case, using calloc and reading its documentation, we see that it takes 2 parameters: The number of elements it should allocate memory for and the size of each element. We also know that it returns a pointer to the starting address of the allocated memory and that in case of failure (which can only happen if you're out of memory), it returns NULL. Using this, we understand that in your case the call to calloc would be like this:
int *buffer = (int *) calloc(length, sizeof(int));
The sizeof() function returns the size of a data type in bytes. Here you allocated enough memory for the pointer to hold length integers (since you'll use it as an array you need enough memory for all the integers, you're not just pointing to 1 integer but storing all of them), and calloc is also noted to initialize every allocated element to 0, so you have an array of integers that are all initialized to 0 (Also note that type casting has been used to make sure the allocated memory block is appropriate for use with an integer array, you can read more about type casting in this small article from Tutorialspoint if you'd like). Then, after this has been allocated, you can start reading your integers into the array. The complete code looks like this:
void input (int *buffer, int *length);
int main() {
// NOTE: I don't see the numbers pointer used here, maybe remove it?
int length, *buffer, *numbers;
input(buffer, &length);
}
void input(int *buffer, int *length) {
scanf("%d", length);
if (*length < 0) {
// Consider printing the exact error here
error = 1;
return;
}
buffer = (int *) calloc(length, sizeof(int));
if (buffer == NULL) {
printf("Couldn't allocate memory for buffer\n");
error = 1;
return;
}
// Accessing the elements of an array doesn't need * and in fact * here can (and probably will) cause terrible things
for (int i = 0; i < *length; i++) {
scanf("%d", buffer[i]);
}
}
Also don't forget to call free() on the pointer after you're done using it to avoid memory leaks (in your case that'd be after the call to input()).
Hope this helped, good luck!
You cannot use arrays because their memory size must be known to the compiler at compile time. Also you can't use Variable Length Arrays because they are allocated at the point of declaration and deallocated when the block scope containing the declaration exits.
The solution to your problem might be to use malloc
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;
}
If I'm trying to create a global array to hold an arbitrary number of integers in this case 2 ints. How is it possible that I can assign more numbers to it if I only allocate enough space for just two integers.
int *globalarray;
int main(int argc, char *argv[]) {
int size = 2;
globalarray = malloc(size * sizeof(globalarray[0]));
// How is it possible to initialize this array pass
// the two location that I allocated.
for (size_t i = 0; i < 10; i++) {
globalarray[i] = i;
}
for (size_t i = 0; i < 10; i++) {
printf("%d ", globalarray[i]);
}
printf("%s\n", "");
int arrayLength = sizeof(*globalarray)/sizeof(globalarray[0]);
printf("Array Length: %d\n", arrayLength);
}
When I run this it gives me
0 1 2 3 4 5 6 7 8 9
Array Length: 1
So I wanted to know if someone could clarify this for me.
(1) Am I creating the global array correctly?
(2) Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
And background info on why I want to know this is because I want to create a global array (shared array) so that threads can later access the array and change the values.
How is it possible to initialize this array pass the two location that I allocated.
Short answer: This is undefined behaviour and anything can happen, also the appearance that it worked.
Long answer: You can only initialize the memory you've allocated, it
doesn't matter that the variable is a global variable. C doesn't prevent you from
stepping out of bounds, but if you do, then you get undefined behaviour and anything can happen
(it can "work" but it also can crash immediately or it can crash later).
So if you know that you need 10 ints, then allocate memory for 10 int.
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
}
And if you later need more, let's say 15, then you can use realloc to increase
the memory allocation:
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
// do not contiue
}
....
// needs more space
int *tmp = realloc(globalarray, 15 * sizeof *globalarray);
if(tmp == NULL)
{
// error handling
// globalarray still points to the previously allocated
// memory
// do not continue
}
globalarray = tmp;
Am I creating the global array correctly?
Yes and no. It is syntactically correct, but semantically it is not, because you are
allocating space for only 2 ints, but it's clear from the next lines that
you need 10 ints.
Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
That's because
sizeof(*globalarray)/sizeof(globalarray[0]);
only works with arrays, not pointers. Note also that you are using it wrong in
two ways:
The correct formula is sizeof(globalarray) / sizeof(globalarray[0])
This only works for arrays, not pointers (see below)
We sometimes use the term array as a visual representation when we do stuff
like
int *arr = malloc(size * sizeof *arr)
but arr (and globalarray) are not arrays,
they are pointers. sizeof returns the amount in bytes that the
expression/variable needs. In your case *globalarray has type int and
globalarray[0] has also type int. So you are doing sizeof(int)/sizeof(int)
which is obviously 1.
Like I said, this only works for arrays, for example, this is correct
// not that arr here is not an array
int arr[] = { 1, 2, 3, 4 };
size_t len = sizeof arr / sizeof arr[0]; // returns 4
but this is incorrect:
int *ptr = malloc(4 * sizeof *ptr);
size_t len = sizeof ptr / sizeof ptr[0]; // this is wrong
because sizeof ptr does not returns the total amount of allocated
bytes, it returns the amount of bytes that a pointer needs to be stored in memory. When you are dealing with
pointers, you have to have a separate variable that holds the size.
C does not prevent you from writing outside allocated memory. When coding in C it is of the utmost importance that you manage your memory properly.
For your second question, this is how you would want to allocate your buffer:
globalarray = malloc(sizeof(int) * size);
And if you are on an older version of C than c11:
globalarray = (int*) malloc(sizeof(int) * size);
This question already has answers here:
Resizing an array with C
(3 answers)
Closed 5 years ago.
#define n 10
int a[n];
I wanted to declare an array globally and modify the size in other function
int main(){
int b;
printf("Enter the number of elements\n");
scanf("%d",&b);
#undef n
#define n b
for(int i = 0;i < n; i++)
scanf("%d",&a[i]);
display();
}
I modified the size in the main function
void display()
{
for(int i=0;i<n;i++)
printf("%d ",a[i]);
}
when i enter a size like 5 and enter the elements 1 2 3 4 5
the output shows 5 elements followed by 5 zeroes 1 2 3 4 5 0 0 0 0 0
how to remove the zeroes?
You can't. Once you declare an array you can't change it's size. As an alternative you can emulate this behavior perfectly using a pointer and then allocating dynamically memory and assigning the chunk address to this pointer. You can then realloc memory to incorporate this size change.
It will be something like:-
size_t sz = 10;
int *arr = malloc(sizeof *arr * sz); // sizeof(*arr)*sz (sizeof is operator)
if(!arr){
perror("malloc");
exit(1);
}
...
sz/=2; //correcting the size
int *p =realloc(arr,sizeof *arr * sz);
if(!p){
perror("realloc");
exit(1);
}
arr = p;
...
free(arr);
Also macro is not a runtime thing - it is expanded at compile time. And more over you want the array to be resized in run time not compile time. Otherwise you can set the array size to be that size from the very beginning when you wrote the code. That's why macro won't work here.
Note that arr here is not an array - it is a pointer pointing to an allocated memory (the starting address of the memory chunk that was created using malloc). Nothing else.
What you did was just changing a preprocessor constant. They are evaluated at compile time, so your redefinition is effectively pointless and takes no effect.
Not sure what you're trying to achieve here, since this array is not going to be reallocated. If you only want to limit the amount of entries you are iterating through, ditch your n and replace it with something like:
static const size_t n = 10;
static size_t num_entries = n;
Then instead of redefining n, you should just do
num_entries = b;
and later on use this to iterate through the array. However, do note that this does not reallocate the array so things are going to go terribly wrong if b is bigger than n!
If you want to reallocate the array, you're better off reading up about malloc, realloc and free. As well as some fundamental tutorials about C in the meantime, since basing on your misunderstanding of what preprocessor (#define'd variables) are, you most likely just started with C.
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;
}