How to initialize a array with determined values? - c

I'm trying to prepare a value list. Briefly:
int x = 5;
int y = 9;
int z = 43;
int myarray[80] = {x, y, z};
But as you know, it's a mistake. I have too many value and they have a special order. The array is like this at the moment:
int x = 5;
int y = 9;
int z = 43;
int myarray[80];
myarray[1] = x;
myarray[2] = y;
myarray[3] = z;
when I want to insert a value between y and z, I need to change all values order by plus 1 after z.

If you want to "insert" new elements into your array, you need to make space for it. That means you need to move the latter elements one step "up" in the array.
You can either do this moving by using a loop like
for (size_t i = 79; // Index of last element
i > 2; // The index of the element you want to insert *before*
++i)
{
myarray[i] = myarray[i - 1]; // Move previous element up one step
}
Then you can "insert" the new value at the wanted position
myarray[2] = new_value;
Instead of an explicit loop you could also use memmove:
// Move element 2 to become element 3, element 3 will become element 4, etc.
memmove(&myarray[3], &myarray[2], sizeof myarray - sizeof myarray[0] * 2);
myarray[2] = new_value;
[Note that the above memmove call is just written without testing, I could have gotten the size wrong]
No matter what you do, an explicit loop or calling memmove, you will lose the last element in the array (at index 79 for an 80-element array).
If you're going to do insertions like this a lot, or if you don't want to loose any elements, then an array is probably not the correct container type. A linked list would be a lot better.

In C you cant add or remove the element from the array. You need to write your own functions like this
void insert(void *arr, void *val, size_t pos, size_t arraySize, size_t elemSize)
{
char *startRef = (char *)arr + pos * elemSize;
memmove(startRef + elemSize, startRef, (arraySize - pos - 1) * elemSize);
memcpy(startRef, val, elemsize);
}

First of all, what do you mean by insert. If by insert the size of the array changes (from 80 to 81), then you
1) need to use dynamic memory allocated arrays: int* myarray = (int*)malloc(80 * sizeof(int));
2) before insert, you need to increase the size: myarray = (int*)realloc(myarray, 81*sizeof(int));
3) then move the content of the memory: start from 81 -- downwards
If you want to keep the size of your array to 80, then go to step 3.

If your max value is less than 80 you can use the index of array to store a flag 0/1 (present/not present)
unsigned char myarray[80];
memset(myarray,0,sizeof(myarray));
myarray[x]=1;
myarray[y]=1;
myarray[z]=1;
/* x,y,z... must be <80 */
So array is always sorted without moving array items.

This is correct syntax for array initialization with values:
var a = new int[] {x, y, z};

Related

How to delete an element at specific index in dynamic array in C language? [duplicate]

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;
}

Muti-dimensional Array

I have a trouble regarding to multi-dimensional array in C.
We have to make a multi-dimensional array in which in which the user has to input the size of the array. After that according to the size C has to create a multi-dimensional array. Remember, in the center there always has to be '1'.
At every side of one there should be '2'. on every side of '2' there should be '3', depends upon the size of array. Also shown in image.
can locate the mid point of an array but when i do this: int Array[size/2][size/2] it gives me error. and how i can adjust other 2,3 and and other numbers at the sides?
This is the code I have written for now:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
const size;
printf("Enter the size: ");
scanf("%d", &size);
int Grid[size][size];
Grid[size/2][size/2] = 1;
printf("%d", Grid[1][1]);
return 0;
}
Firstly, you shall not do such a thing in C :
int grid[size][size];
If you're interested in knowing why, look at C11's Initialization paragraph :
No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
Then, I'm not a fan of
const size;
Since the type is not explicit and your variable isn't const here. Even if you're using scanf, you do modify the value of size during the function.
But then, let's hit the problem ;)
I suggest you use a function to allocate your array. It will help clarifying your code :
int** create_array(int size)
{
int i;
int** array;
i = 0;
// You allocate the first dimension of your array
// (the one that will contain other arrays)
array = malloc(size * sizeof(int *));
if (array != NULL)
{
while (i < size)
{
// You allocate each 'sub-array' that will contain... ints !
array[i] = malloc(size * sizeof(int));
i += 1;
}
}
return (array);
}
Now this function returns a well-allocated array of the size you want. Don't forget to check if it's NULL in your calling function, and to free it (if it has been allocated).
To free the array, I'll let you write the function yourself, since it is very similar to the initialization. But still, be careful considering some sub-array might be NULL!
Then the initialization. The most simple way I can think of is iterating on your array and calculating the delta from the center.
int most_far;
////
/// Insert the loop stuff here...
//
if (x == size/2 && y == size/2)
array[x][y] = 1;
else
{
// You could use a ternary here but I don't know if you're familiar with them
// You're getting the position that is the most far from center...
if (abs(x - size/2) > abs(y - size/2))
most_far = abs(x - size/2);
else
most_far = abs(y - size/2);
// With this position, you calculate the 'distance' between the center and your position.
// This distance is your number ! :D
array[x][y] = most_far;
}
//
/// End of the loop, interations, etc...
////
Little tip : I suggest you do the population stuff in some function that returns a boolean. This boolean will be false if one sub-array has been found NULL during the population. And if it's the case, you probably don't want to read/display it !
Pfiouh, what a massive answer I wrote !
Hope it won't scare you (and that you'll find some help in it)
If your targeted element is in position a[2][2] then the condition will be some what like this.
Consider i to be row and j to be column.
if(a[i+1][j]==a[i+1][j+1]==a[i+1][j-1]==a[i][j+1]==a[i][j-1]==a[i-1][j]==a[i-1][j+1]==a[i-1][j-1])
flag=1; \\any process you want
and you can only assign constant to an array while declaring it. You can't assign a value like
int array[size/2][size/2];
There are two ways of doing this you might consider:
Filling entries in a growing square. (i.e., filling all the 1s, then the 2s, then the 3s, ...)
Figuring out a "formula" or procedure for each row.
Looking at the first method:
void fillSquare(int **arr, int n, int size)
{
fillSquareTopSide(arr, n, size);
fillSquareLeftSide(arr, n, size);
fillSquareRightSide(arr, n, size);
fillSquareBottomSide(arr, n, size);
}
where n is the current number (1, 2, or 3) and size is 3. And then a possible implementation of fillSquareTopSide:
void fillSquareTopSide(int **arr, int n, int size)
{
for(int i = size - n; i < size + n; i++)
arr[size - n][i] = n;
}

C pointing 2d array at another 2d array

int newBoard[9][9];
int dirtyBoard[9][9];
/*add stuff to every element of dirtyBoard*/
...
newBoard = &dirtyBoard;
I am trying to make my newBoard be an exact copy of cleanBoard. Since performance is a concern I wanted to see if I could bypass creating a loop to copy each element 1 at a time in favor of changing my pointer address or something. Is this possible?
Use memcpy.
memcpy( newBoard , dirtyBoard , sizeof( newBoard )) ;
Don't forget that both arrays must be of the same size, or at least the array you are copying into must be larger.
assert( sizeof( newBoard ) == sizeof( dirtyBoard ) ) ;
If you want to merely point to dirtyBoard use a pointer.
int (*p)[9] = dirtyBoard ;
Now p behaves almost exactly as dirtyBoard.
use memcpy
memcpy(newBoard,dirtyBoard, sizeof(newBoard));
Use memcpy:
memcpy(newBoard, dirtyBoard, sizeof(newBoard);
This will copy sizeof(newBoard) bytes starting at dirtyBoard into newBoard. newBoard must be the same size or bigger than dirtyBoard for this to not cause a buffer overflow.
Arrays don't point. You can't "re-point" an array of ints any more than you can "re-point" a single int.
The name of a variable is only ever associated with the storage allocated to that variable; you can't move a variable around in memory, or repurpose the variable's name to a different variable.
However , pointers point. You can make a pointer that points at an array (or a subset of an array), and then change it to point to a different array.
In your case the syntax would be:
int (*newBoard)[9] = &dirtyBoard[0];
This makes newBoard point at a 1-D array of 9 ints . So then you can use the syntax newBoard[i][j] to access the cells.
As you have probably found, you cannot do:
newBoard = &dirtyBoard;
The syntax above however will work like this:
int newBoard[9][9];
int* dirtyBoard;
int i, j;
for(i = 0; i < 9; ++i)
for(j = 0; j < 9; ++i)
newBoard[i][j] = i*j;
dirtyBoard = newBoard;
However, then you are not copying, you are effectively making an alias. If you update a value in the pointer you will also update the underlying array and vice versa.
If you want to edit the array via the pointer you can do this sort of thing:
#define cols 9
#define rows 9
...
int n;
int newBoard[rows][cols];
int* dirtyBoard;
int i, j;
int row = 3;
int col = 5;
dirtyBoard[row * cols + col] = 3; /* to flip from 1 dimensional ptr -> [][] form */
With C++ you don't need to use define's you can use:
const int rows = 9; // and use as array dimensions.
Since newBoard and dirtyBoard are both statically declared arrays, you can't just point newBoard to the address of dirtyBoard.
If you intend for both to be static arrays, you'll need to copy the data in each element:
for(i=0;i<9;i++)
for(j=0;j<9;j++)
newBoard[i][j] = dirtyBoard[i][j];
Edit: As others have mentioned, memcpy() is the way to go, and more efficient.
You could define newBoard as an array of pointer to int, like this:
int (*newBoard)[9];
then you can just do:
newBoard = dirtyBoard;
But, difference here, is that newBoard and dirtyBoard point to the same memory. If you declare two distinct static arrays, you'll end up with two discrete copies of the data.

Concatenating 2 arrays without memcpy

Suppose I ve
int *a,*b;
a= malloc(5*sizeof(int));
b= malloc(5*sizeof(int));
and subsequently assign values.
Let a - 1, 2, 3, 4, 5
b - 6, 7, 8, 9, 10
Is there a method to concatenate both these malloced arrays without using further malloc,realloc or memcpy? There shud not be a malloc of 10 locations!
I must be able to get a[8]=9 after executing, without the overhead of moving the arrays.
The language is C
a= malloc(5*sizeof(int));
You only allocated 5 ints to a, so no, you can't do it without some form or memory allocation (malloc / realloc), since a[8] would be illegal to begin with.
I must be able to get a[8]=9 after executing, without the overhead of
moving the arrays
Since since you are working with contiguous memory regions (which you are calling arrays) you will always have some overhead when moving elements around. If you don't need to access elements by their indexes just use linked lists.
If you don't need strict array indexing, you could make a pseudo-linked-list (I know there's a name for this data type but I can't remember it right now):
struct listish {
int *arr
size_t size;
struct listish *next;
};
The "indexing" function would look like this:
int *index(struct listish *list, size_t i)
{
if(list == NULL) return NULL; // index out of bounds
if(i < list->size) return list->arr + i; // return a pointer to the element
else return index(list->next, i - list->size); // not in this array - go to next node
}
The idea is to combine the in-place reordering of a linked list with the contiguous space of an array. In this case, index(list, 4) would return &a[4], and index(list, 5) would return &b[0], simulating continuous indexing without reallocating and moving your entire array - all you need to do is allocate a few small struct listish objects and set them up properly, a task I leave to you.
What you ask can't be done.
You have, maybe, another option.
Just allocate space for 10 values, and make b point to the correct element
int *a = malloc(10 * sizeof *a);
/* error checking missing */
int *b = a + 5;
a[0] = 1; a[1] = 2; a[2] = 3; a[3] = 4; a[4] = 5;
b[0] = 6; b[1] = 7; b[2] = 8; b[3] = 9; b[4] = 10;
printf("a[8] is %d\n", a[8]);

Removing elements from dynamic arrays

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;
}

Resources