Search code examples
carraysmemorymemmove

Circular shifting an array with `memmove`


Say I have an integer array like such

#define MAX 5
int bar [MAX] = {0};
int foo [MAX] = {3,1,0,0,0};

Now I'd like to shift this array so that all null entries are to the left, i.e. bar = {0,0,0,3,1}.

I thought I could do this by

  1. Finding the number of shifts I must perform
  2. Using memmove() to do the shift.

I solved 1. with the following loop

for (shift = MAX - 1; shift >= 0; --shift) {
    if (foo[shift]) break;
}

But I do not know how to use memmove() now to perform the shift, I attempted to do memmove(bar + shift, foo, MAX * sizeof(*foo)-1); but with no success.

Is memmove() the correct tool for the job? How can I circulate an integer array as described? What if this is happening inside a function where bar is a passed as a pointer?


Solution

    • The formula you used to calculate shift does not give you the number of positions by which to shift.

    • You're not moving the correct number of bytes (MAX * sizeof(*foo)-1 is in no way based on the number of trailing zeroes).


    #include <string.h>
    
    #define MAX 5
    int bar[MAX] = {0};
    int foo[MAX] = {3,1,0,0,0};
    
    int i;
    int shift = 0;
    for (i=MAX; i--; ) {
       if (foo[i]) {
          shift = MAX - (i + 1);
          break;
       }
    }
    
    memcpy(bar+shift, foo, (MAX-shift) * sizeof(*foo));
    memcpy(bar, foo+(MAX-shift), shift * sizeof(*foo));
    

    You can do it in-place since you know what values to "rotate in".

    memmove(foo+shift, foo, (MAX-shift) * sizeof(*foo));
    memset(foo, 0, shift * sizeof(*foo));
    

    memmove must be used instead of memcpy since the destination and source buffers may overlap.