How to insert an element into an array on malloc? - c

say we are going to insert an element into an array on malloc. I know where and how to insert, but I'm having trouble shuffling every succeeding element down by 1. What would be the technical approach for this? Thanks
| x x x x x x x x x x x | original array
| x x x x x 0 x x x x x x | new array
Suppose the "memmove" function is not available to us...

Yes, if you need to do this without memmove, you can do it with a simple loop. Note that you might also need to use realloc first, to expand the size of the allocated array so that it can fit the new element.
The trick to this is having the loop move each element one forward, starting from the last one. A moment's reflection should tell you why this is necessary.

The basic principle is the same whether the array is dynamically allocated, statically allocated or automatically allocated. The main difference is that if there is insufficient room in a dynamically allocated array, you can reallocate it with more space (subject to some system-imposed limits. Assuming there is enough space in the array, you could use memmove() to copy the section of the array after target location up one space, and then set the target location to the inserted value. Or you could write a loop to do the job.
int *dynarr = malloc(24 * sizeof(*dynarr));
int idx = 0;
dynarr[idx++] = 0;
dynarr[idx++] = 23;
dynarr[idx++] = 34;
dynarr[idx++] = 9;
dynarr[idx++] = 15;
Now insert at position n = 2:
memmove(&dynarr[n+1], &dynarr[n], (idx - n) * sizeof(int));
dynarr[n] = 19;
idx++;
That's a bulk move, an assignment, and increment the counter because there's one more element in the array.
Since the question was edited to disallow memmove(), here is a solution with simple array indexing, assuming that the same initialization sequence is used:
int i;
int n = 2;
for (i = idx; i > n; i--)
{
dynarr[i] = dynarr[i-1];
}
dynarr[n] = 19;
idx++;
Complete example code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static void print_array(int *a, int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("a[%d] = %d\n", i, a[i]);
}
}
int main()
{
{
int *dynarr = malloc(24 * sizeof(*dynarr));
int idx = 0;
dynarr[idx++] = 0;
dynarr[idx++] = 23;
dynarr[idx++] = 34;
dynarr[idx++] = 9;
dynarr[idx++] = 15;
printf("Before insert\n");
print_array(dynarr, idx);
int n = 2;
memmove(&dynarr[n+1], &dynarr[n], (idx - n) * sizeof(int));
dynarr[n] = 19;
idx++;
printf("After insert\n");
print_array(dynarr, idx);
free(dynarr);
}
{
int *dynarr = malloc(24 * sizeof(*dynarr));
int idx = 0;
dynarr[idx++] = 0;
dynarr[idx++] = 23;
dynarr[idx++] = 34;
dynarr[idx++] = 9;
dynarr[idx++] = 15;
printf("Before insert\n");
print_array(dynarr, idx);
int n = 2;
int i;
for (i = idx; i > n; i--)
{
dynarr[i] = dynarr[i-1];
}
dynarr[n] = 19;
idx++;
printf("After insert\n");
print_array(dynarr, idx);
free(dynarr);
}
return(0);
}

As Don suggested, memmove() will allow moving part of this array, in order to make room for the new element.
Depending on the size of the elements in the array, you may also consider storing only pointers, in the array, allowing easier/faster re-shuffling of the array, at the cost of a extra indirection when accessing individual elements. (and also at the cost of having to manage individual element-sized memory blocks). Deciding on this type of approach depends on the amount of reorganization of the array elements, as well as their size.
Alert: in view of the added "picture" in the question, memmove(), or indeed any operation, may be impossible, if the memory move implies writing past the size of memory originally allocated!
If this is really what is desired, the idea of an array of pointers may be more appropriate as this allows allocating an over-sized memory block initially (for the array proper) and to allocate (or dispose of) individual elements as needed.
Edit: "We're not allowed to use memmove()" indicates some form of homework. (BTW do tag it as such !!!)
To better help you we need to understand the particular premise of the question. Here's what appears to be the situtation:
1) we readily have an array, containing say N elements.
2) the array on the heap, i.e. it was allocated using malloc() (or related
functions)
3) the effective size of the malloc-ated block of memory is bigger than that of
the array.
Is #3 true ?
4) Depending on #3 we need to either allocate a new memory block (a bigger one)
and copy the array. We expect this copy would be done in 3 steps
- copy the elements that precede the new element
- copy the new element
- copy the elements that are after the new element
or... (if we have enough room), we'd require two steps
- "shift" the elements that are supposed to be after the new element
This can be done one element at a time, if we wish to avoid memcopy
- copy the new element.

Related

Array size redefinition

So basically according to definition of array we cannot change array size. But if I am adding element to a same array by shifting other elements to the right of array, so the array size is going to increase.
How this is possible?
#include<stdio.h>
int main() {
int n, j, k, item;
printf("Enter size of array:\n");
scanf("%d", &n);
printf("Enter element to insert and position of element:\n");
scanf("%d,%d", &item, &k);
int a[n];
for (j = 0; j < n; j++) {
printf("Enter a[%d] element:\n", j);
scanf("%d", &a[j]);
}
j = n - 1;
while (j >= k - 1) {
a[j + 1] = a[j];
j = j - 1;
}
a[k - 1] = item;
for (j = 0; j <= n; j++) {
printf("%d\n", a[j]);
}
}
Shifting the contents of the array to the right will not resize the array. If the array was not already large enough to hold the result of the shift, then you have overrun the array object, and have induced undefined behavior.
There is no way to dynamically increase the size of a variable with static or auto duration (e.g., global or local variables), and this includes arrays. If your compiler supports variable length arrays (VLAs), changing the value of the expression controlling the dimension of the array does not affect the array's size.
int main (void) {
int n = 3;
int v[n];
printf("%zu\n", sizeof(v));
++n;
printf("%zu\n", sizeof(v));
}
The program above will print the same value twice.
I am not entirely sure what you're asking, but for any readers interested in knowing how to dynamically change the size of an array in C: if an array is declared in stack memory, its size cannot change. However, a block of memory intended to be used as an array is declared on the heap (i.e. with malloc or calloc), can be reallocated with a different size if necessary:
int *data = malloc(10 * sizeof(int)), *data2 = NULL;
int i;
if(data == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
for (i = 0; i < 10; i++)
{
data[i] = i;
}
data2 = realloc(data, 11 * sizeof(int));
if(data2 == NULL)
{
free(data);
perror("realloc");
exit(EXIT_FAILURE);
}
else
{
data = data2;
}
data[10] = 10;
for (i = 0; i < 11; i++)
printf("%d ", data[i]);
free(data);
data = NULL;
Shifting elements in an array down one element will not change its size.
If you declare an array as
T a[N]; // assume N is a constant expression
then a can only ever hold N elements of type T - no more, no less. You cannot add extra elements to the array, nor can you remove elements from the array.
However...
C does not force any bounds checking on array subscripting, so it's possible that you can read or write past the end of the array such as
a[N + 2] = x;
The behavior on doing so is undefined - your program may work as expected, or it may crash immediately, or you may corrupt other objects in the program. The runtime environment will (most likely) not throw an IndexOutOfBounds-type exception.
There is a thing called a variable-length array that was added in C99, where the array size is not a constant expression:
size_t size = some_value();
T a[size];
Variable length arrays are only variable length in the sense that their size isn't determined until runtime - however, once defined, their size is fixed throughout their lifetime, and like regular arrays, they cannot grow as new items are added.
If you dynamically allocate a chunk of memory using
T *a = malloc( sizeof *a * some_size );
then you can grow or shrink that chunk of memory using realloc:
T *tmp = realloc( a, sizeof *a * (some_size * 2) );
if ( tmp )
{
a = tmp;
some_size *= 2;
}
.... array we cannot change .. But if I (do something special) ... the array size is going to increase.
How this is possible?
Undefined behavior
Arrays cannot change size once defined.
Code attempts to assign a[j + 1] with j = n-1 and that is a[n]. This is outside array a[] and so undefined behavior. Rest of code is irrelevant for at that point anything is possible, code crash, error report, even apparent successful array expansion, etc.
int a[n];
...
j = n - 1;
while (j >= k - 1) {
a[j + 1] = a[j]; // To attempt access to `a[n]` is UB

Removing elements of an array

I am new to c and was wondering if there are any built in operations to remove a specified element from an array.
for example if I wanted to remove the even elements in an array
for(.....) //goes through the array one by one
if(nums[i] / 2 = 0)
nums[i].remove;
What could I put instead of .remove to remove the number.
on a separate note if anybody knows a good documentation website for other c array operations would you be able to link it?
No, elements cannot be removed from an array.
An array has a certain size from the moment you create it and that size cannot be changed.
You would need to loop through your array starting at the item you want to remove and then copy each successive array item into the one before it. e.g. Shift the array items to the left.
Once you have done that, you can use realloc() to trim the last array item off of the allocated memory. You'll of course need to do the math to determine the size of each array item and pass realloc() the original size of the array minus the one that you are going to "trim off".
Other options would bememmove and memcopy, but then you get into all kinds of extra temp buffers.
An example of "manually" shifting array items:
int* items = NULL;
int arraySize = 10;
int itemToRemove = 5;
items = (int*)malloc(sizeof(int) * arraySize);
//Initialize the array with some dummy values.
for (int i = 0; i < arraySize; i++)
{
items[i] = (i * 100);
}
//Print out the contents of the array - before we remove an item.
printf("Before removing item:\n");
for (int i = 0; i < arraySize; i++)
{
printf("items[%d]: %d\n", i, items[i]);
}
//Shift each array item left, starting at the item specified by "itemToRemove".
for (int i = itemToRemove; i < arraySize; i++)
{
items[i] = items[i + 1];
}
arraySize--; //Be sure to keep track of the new array size.
//Reallocate the array, this will trim the size of the allocated block of memory.
items = (int*)realloc(items, sizeof(int) * arraySize);
//Print out the contents of the array - after we remove an item.
//** NOTICE: The array now only contains 9 items and the 5th one contains the data previously held in the 6th, etc.
printf("After removing item:\n");
for (int i = 0; i < arraySize; i++)
{
printf("items[%d]: %d\n", i, items[i]);
}
//Be sure to cleanup when done. :)
free(items);

malloc() and free() an array in c

I have been using Java and quite new to C. I tried to create a function that generates a random pixel array with malloc. I free the memory in another function after using that random array. I think my concept is just fine, but I wonder if I write the codes properly and it really frees the heap memory. It'd be great if you can look at the codes and see if it works.
pixel* randomPalette(int colors){
int i, x;
pixel * randomArr = (pixel *)malloc(sizeof(pixel)* colors);
srand(time(NULL)); //generate a random seed
for (i = 0; i < colors; i++){
x = rand() % 256;
randomArr[i].r = x; randomArr[i].g = x; randomArr[i].b = x;
}
return randomArr;
}
void QuantizeA(pixel* Im, int width, int height){
//create a random palette of 8 RGB colors;
const int num = 8;
pixel* Arr = randomPalette(num);
//find the min distance between pixel and palette color
int x, y, z;
int min = 195075; // max distance is 255^2 + 255^2 + 255^2
int pos = 0;
for (x = 0; x < height; x++){
for (y = 0; y < width; y++){
//compare distance of the pixel to each palette color
for (z = 0; z < num; z++) {
if (distance(Im[pos], Arr[z]) < min){
Im[pos].r = Arr[pos].r;
Im[pos].g = Arr[pos].g;
Im[pos].b = Arr[pos].b;
}
}
pos++; //go to next piexl
}
}
glutPostRedisplay();
free(Arr);
}
From the memory allocation-deallocation part, your code is fine (I did not check your logic). However, two things to notice here,
Check for the success of malloc() before using the returned value.
You need to call srand(time(NULL)); only once at the start of your program, possibly in main().
As a suggestion, you can always make use of the memcheck tool from valgrind to check for the memory leakage related issues, if you suspect any.
Also, please see this discussion on why not to cast the return value of malloc() and family in C..
When you assign the new minimum distance:
Im[pos].r = Arr[pos].r;
you use the wrong index. It should be:
Im[pos].r = Arr[z].r;
As a side note: You cannot compare two structs with the comparison operators, not even for equality, but C allows you to assign one struct to another, which effectively copies the contents. So you don't need to copy all components, you can just say:
Im[pos] = Arr[z];

Building an array where each element depends on the previous

I'm building a set of arrays where each element depends on the previous element, and I'm having a hard time coming up with an elegant solution for setting the initial value. The code looks something like this:
int A[1024];
int B[1024];
/* ... more arrays... */
int i;
for (i = 0; i < 1024; i++) {
/* do some work */
A[i] = A[i-1] + some_value();
B[i] = B[i-1] + some_other_value();
/* ... and so on... */
}
But of course this is an invalid memory access when i is 0. I know that the initial values of all arrays should be 0.
There are several ways to solve this problem. I could put a giant if statement in the loop to check if i is 0. Seems clunky since it will only evaluate to true once. I could keep a temporary variable, initialized to 0, for each array, called prev_val_of_A, etc, that holds the value of the last iteration. I'd have to update it to the current value at the end of every iteration. This seems a little silly since, most of the time, the value I want is sitting right there in the array's previous element. I could fiddle with the meaning of the array, and adopt the convention that the second element in the array contains the value for the first iteration of the loop; that is, allocate for A[1025], initialize A[0], then in the loop, do
A[i+1] = A[i] + some_value();
This seems confusing and might invite errors on further use of A.
I'm looking for clean, elegant suggestions to solve this issue.
The easiest way to solve this is to initialise A[0], B[0] etc and then start the loop from i = 1. i.e.
int A[1024];
int B[1024];
/* ... more arrays... */
int i;
A[0] = stuff();
B[0] = other_stuff();
/* etc */
for (i = 1; i < 1024; i++) {
/* do some work */
A[i] = A[i-1] + some_value();
B[i] = B[i-1] + some_other_value();
/* ... and so on... */
}
EDIT: And this is reasonably elegent, as it mirrors the mathematics: sequences are often defined by f(0) = x, f(n) = <stuff with f(n-1)> if n > 0)
What about the following:
int AX[1024+1];
int BX[1024+1];
int *A = AX+1, *B = BX+1;
AX[0] = 0;
BX[0] = 0;
/* ... more arrays... */
int i;
for (i = 0; i < 1024; i++) {
/* do some work */
A[i] = A[i-1] + some_value();
B[i] = B[i-1] + some_other_value();
/* ... and so on... */
}
Conceptually, your array is defined as an initial value and a reccurence relation. So just initialize your first element outside the loop, and then compute the next values with a loop. I don't see why it will not be pretty.

problems with data entry and malloc in C

I'm new to C and I'm having a small problem with my code:
int i, n;
int *arr;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
exit(1);
else {
arr = (int*) malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
} //end if
} //end while
What I'm trying to do is to make an array of n size and I want to stop reading when I get a '0' for example if I enter:
3
2
2
5
2
6
7
0
I want an array of size 3 with values 2, 2, 5, an array of 2 with values 6 and 7 and exit because of the 0
* Sorry, I left out an important part I think... In my code a call a calc() where I send arr, right after scanf("%d",&arr[i]) and then i'll return the value and then if the next values e.g. 2 isn't 0 I'll read, create a new array, send arr, print result on console and again if the next value is 0 then it will exit. *
Could you guys tell me where I'm wrong?
You are almost there!
You are creating the new arrays in arr, but this is a single pointer so can only refer to one block of memory. When you call malloc the new memory is stored in arr but the old memory is lost. You are 'leaking memory' because the machine has the old memory reserved but you don't have a variable storing it's address so you have no way to find it again.
If you only need to store the last list you should free the old memory (in arr) before malloc'ing the new space. If you need to store all the arrays you will need an array of pointers in arr.
edit:
You need to call free to 'free' the previously allocated memory before you allocate the new memory. At the first set of data you don't have any existing 'malloc' but it's always safe to free a NULL pointer, so simply set the pointer to NULL at the start.
Hint: It's always a good idea to set all the variables to some safe initial value when you define them.
int *arr=NULL; // Mark this as pointing to no memory
....
free(arr); // first time it does nothing, afterwards it deletes the previous reserved memory
arr = (int*) malloc(sizeof(int) * n); // as before this reserves some memory
The problems which are visible in your code are:
1. Checking uninitialized integer n in while. To fix this either initialize n to non zero or use a do{ ... } while() instead of while().
2. You need to validate the value of n which is read through scanf. malloc takes size_t type as the parameter which is unsigned int. But n being an integer can accept negative values, thus if a negative value is entered it will be passed as unsigned int to malloc, this may lead to undesired results (Also for loop will be executed incorrect number of times). You may also consider changing the type of n from integer to unsigned int type or change the exit condition to if( n < 1 ).
3. There is memory leak in your program. Memory allocated through malloc is not freed through free.
4. Do not assume that malloc will always succeed. Please check for the success of malloc through a NULL check i.e.
if (NULL == arr)
{
//error handling
}
5. exit with non zero value generally indicates abnormal termination. You can use break or return. break might be a better idea as it generally gets difficult to test a function as the exit points in the function increase (though this may not be true in your case, but it is FYI)
6. Optionally, you can check the return value of scanf to make sure that a valid input was entered.
Help this helps!
You're not initializing n so you may or may not enter your while loop. Starting n at -1 would be a reasonable thing to do:
int i, n = -1;
And you should cast the return value of malloc, that can hide problems.
You're also leaking memory because you're not calling free on that you get back from malloc and you're losing track of what you read in every time you assign a new value to arr. Brian Roach and Martin Becket have mentioned these things though.
Presumably you want to be able to access these arrays later.
As it is, you're losing your pointer to the previous array when you malloc the next one (and of course, causing a memory leak if it were a larger application).
You need to allocate a chuck of int * (a set of int pointers) then store each int pointer there.
The trick is ... if you don't know how many arrays you're going to need, you need your code to be dynamic (for example; allocate some amount of space, then allocate more if you run out).
Another option is that you could limit the number of series the user can input and tell them they're done when they reach it.
Here's some help if you wanted to go the latter route:
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5); /* max of 5 arrays */
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
HOWEVER ... now you don't know how long each array is. Which is a problem. You'd need to keep track of that, or use a dynamic structure such as a linked list. In the example below, we add the length as the first element of each array:
int main()
{
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5);
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * (n + 1)); /* one more than we need */
arr[0] = n; /* store the array length in the first element */
for(i = 1; i <= n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
int j;
for (i = 0; i < arrayCount; i++)
{
int length = myArrayOfArrays[i][0]; /* retrieve the length */
for (j = 1; j <= length; j++)
printf("%d ", myArrayOfArrays[i][j]);
printf("\n");
}
}
Dynamic allocation using arrays / raw memory means you need to keep track of stuff. The better approach really is using a linked list for your data. In this case, you could have a linked list of nodes, each of which contained a link list of integers.

Resources