1

Say I initialize an array of 5 integer elements like this:

int *Q = malloc(sizeof(int) * 5);

for (int i = 0; i < 5; i++) {
    Q[i] = i;
}

The array looks like: {0, 1, 2, 3, 4}. Now if I shift everything along by 1 position:

Q++;

The array looks like: {1, 2, 3, 4, #}, where # is some garbage value.

Is there a way to free the final element so it's not stored in the array?

I tried this:

free(Q[4]);

But I know this won't work because free() can only operate of the whole chunk of memory allocated for Q.

Is there a better way to shift everything along? The resulting array should look like: {1, 2, 3, 4}.

Would it be a good idea to realloc() Q after every shift?

  • Yes, if you do `Q++`, than adjust `size--`. You have a chunk of memory, and you control how you access it. – StoryTeller - Unslander Monica May 25 '16 at 12:36
  • 6
    After `Q++`, `Q[4]` doesn't contain "garbage". Accessing it is **undefined**. – EOF May 25 '16 at 12:40
  • 2
    You can use [realloc](http://www.tutorialspoint.com/c_standard_library/c_function_realloc.htm). – LPs May 25 '16 at 12:40
  • If it's only one element it's questionable if it worth the work, it's quite likely that you won't release any memory in reality by doing so. – skyking May 25 '16 at 12:44
  • 4
    You should probably provide more context. This sounds like an XY-problem (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), what are you **really** trying to do? – skyking May 25 '16 at 12:52
  • This sounds like the wrong solution indeed. It sounds very much like you should be using a linked list. Arrays and realloc will be terribly inefficient. – Lundin May 25 '16 at 14:28

5 Answers5

5

realloc() can change the size of an allocated chunk of memory, which will do the job for you. Note that this cannot be used to "free" arbitrary elements of an array, but only one(s) on the end.

How good an idea it is to do this depends on a number of factors, none of which you have provided.

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
2

When you do Q++ the array has not changed, it still contains the five values 0,1,2,3,4 it is just that Q is pointing to the second element in the array.

If you want to change the size of allocated memory then do as Scott said and realloc the block - but it is a costly way of handling heap memory.

If you just want to keep track of the number of elements in the array let Q remain pointing on the first element and have a size variable indicating how many integers there are.

Alternatively use another data structure to hold your integers e.g. a linked list of integers, then you can add and remove integers easier.

AndersK
  • 35,813
  • 6
  • 60
  • 86
1

Taliking about last elements of array you can surely use realloc

BTW take note that when you say

The array looks like: {1, 2, 3, 4, #}, where # is some garbage value.

You are wrong and you are invoking undefined behavior as well explained by this SO answer.

So the loop that left shift value have not to do Q[4] = Q[5];

Community
  • 1
  • 1
LPs
  • 16,045
  • 8
  • 30
  • 61
1

To shift around elements inside an array one can use memmove().

#include <stdio.h>
#include <string.h>

int main(void)
{
  int d_init[] = {0, 1, 2, 3, 4};

  size_t s = sizeof d_init/sizeof *d_init;
  int d[s];

  /* Fill d */
  memcpy(d, d_init, s * sizeof *d);

  for (size_t i = 0; i < s; ++i)
    printf("%d ", d[i]);
  puts("\n");

  /* shift one to the left */
  memmove(d, d + 1, (s - 1) * sizeof *d);

  for (size_t i = 0; i < s; ++i)
    printf("%d ", d[i]);
  puts("\n");


  /* shift two to the right */
  memmove(d + 2, d, (s - 2) * sizeof *d);  

  for (size_t i = 0; i < s; ++i)
    printf("%d ", d[i]);
  puts("\n");
}

The snippet above would print:

0 1 2 3 4
1 2 3 4 4
1 2 1 2 3
alk
  • 69,737
  • 10
  • 105
  • 255
0

If you're doing a Q++ you've not shifted the elements of the array, your array is simply pointing to the second element (index 1). Thus, Q[4] is reading something that doesn't belong to the array: C is permissive enough to let you do that (in most cases), but it is a mistake.

To shift elements you should either do

for (int i=0; i<4; i++)
    Q[i] = Q[i+1];

or (smarter)

memmove(Q, Q+1, 4*sizeof(int));

but indeed, to have an array of size 4 you'll have to realloc.

BUT if you need to do that, maybe an array is not the data structure you should use: a linked list seems to be a better choice.