Left Shift an Array

I have a list that I want to shift the data inside from right to left, which means I also need to move the first value to the end of the list.

For example

recv[4]={4,30,60,2} and I want to change that into recv[4]={30,60,2,4}

The code that I am using doesn't work and it's here.

int beginning=recv[0];
    memcpy(recv, &recv[1], sizeof(recv) - sizeof(int));
    recv[3]=beginning;

Does anyone know how to fix that?? :o

temp = recv[3] ;
recv[3]=recv[2] ;
recv[2]=recv[1] ;
recv[1]=recv[0] ;
recv[0]=temp ;

Hi, 6v6gt:

The thing is. That array I just made up is something for instance. I got a list contains 69 values and more. I can't do it one by one like this.

But still thank you~

I can't do it one by one like this.

Have you heard of for loops ?

Exactly. You can surely see a pattern there ?

recv[ x ] = recv[ x -1] ;

Look at the "for" statement. start at the highest index and work backwards. Be careful at the ends.

Interestingly, your original code with memcpy doesn't look too bad, assuming memcpy works nicely with overlapping memory spaces in all implementations of c/c++. Is this a school exercise ?

UKHeliBob:
Have you heard of for loops?

In this case, I don't think for loop will work maybe you will notice that if you use a for loop to do left shit for an array you will see the latter data will be covered by the previous one if you try.

Not if you do it right

6v6gt:
Exactly. You can surely see a pattern there?

recv[ x ] = recv[ x -1] ;

Look at the "for" statement. start at the highest index and work backwards. Be careful at the ends.

Interestingly, your original code with memcpy doesn't look too bad, assuming memcpy works nicely with overlapping memory spaces in all implementations of c/c++. Is this a school exercise ?

Yes, similarly. For a left shift of the array I can do this:

for(int i=3;i>0;i--){
recv*=recv[i-1];*
}
but for a right shift of the array I can't do this:
for(int i=0;i<3;i++){
recv*=recv[i+1];*
}
somehow i printed out the array the latter data get covered by the previous one.

Zumii:
Yes, similarly. For a left shift of the array I can do this:

for(int i=3;i>0;i--){

recv[i]=recv[i-1];
}

but for a right shift of the array I can't do this:

for(int i=0;i<3;i++){
recv[i]=recv[i+1];
}



somehow i printed out the array the latter data get covered by the previous one.

// doesn't this work ?
// moves array 1 element <<

int temp = recv[ 0 ] ;
for(int i=0;i<3;i++){
recv[i]=recv[i+1];
}
recv[3] = temp ;

Are you interchanging left and right when you talk about a direction shift ?
You can, incidentally, use memmove (but NOT memcpy) for overlapping memory spaces.

Don't shift the array (massive waste of memory bandwidth/processing cycles), shift where the start and end are supposed to be.

AWOL:
Don't shift the array (massive waste of memory bandwidth/processing cycles), shift where the start and end are supposed to be.

The google search term is "circular array".

PaulS:
The google search term is "circular array".

Here is crude implementation using the OP's example:

  int recv[4] = {4, 30, 60, 2} ;
  int arrLen =  sizeof( recv) / sizeof( recv[0] ) ;

  int shift = -1 ;  // positive is shift left ; negative is shift right e.g. -1 = shift right 1 ; +2 = shift left 2 ;

  // print array with shift
  for ( byte i = 0 ; i < arrLen ; i++ ) {
    Serial.println( recv[ ( arrLen + shift + i ) % arrLen ]  ) ;   // % can be expensive ; force positive return
  }

Make the array size 2N and you can get rid of the modulo operator and just use an 'and' mask to keep the lower N bits of the index. Use unsigned (uint8_t, uint16_t) for all indexing operations so the value properly wraps around when you subtract from zero and apply the mask.

memcpy is not guaranteed to work when the source and destination memory addresses overlap. From this reference page:

If the objects overlap, the behavior is undefined.

Undefined means that the function could do anything, which might or might not be what you want and you can't count on it.

memmove is OK for overlapped memory space.

  int recv[4] = {4, 30, 60, 2} ;
  int beginning = recv[0];
  memmove(recv, &recv[1], sizeof(recv) - sizeof(int));
  recv[3] = beginning;
  for ( byte i = 0 ; i < sizeof(recv) / sizeof(int)  ; i++ ) {
    Serial.println( recv[ i ]  ) ;
  }
1 Like

But, the issue seems moot. It's stupid to shift the whole array around if you can accomplish the same thing by changing a variable that indexes into the array.

It's stupid to shift the whole array around if you can accomplish the same thing by changing a variable that indexes into the array.

I would rephrase that as it's not necessary to shift the whole array around if you can accomplish the same thing by changing a variable that indexes into the array. But bear in mind that this is at the expense of extra processing in the program.

gfvalvo:
But, the issue seems moot. It's stupid to shift the whole array around if you can accomplish the same thing by changing a variable that indexes into the array.

Indeed but you also suggested this

gfvalvo:
Make the array size 2N and you can get rid of the modulo operator . . .

Rounding up an array to the next power of 2 could be very extravagant, especially if your array was say 1025 bytes. A small MCU may not tolerate it.

“if you use a for loop to do left shit for an array ”

Naughty.

UKHeliBob:
But bear in mind that this is at the expense of extra processing in the program.

I wouldn’t call it an “expense” as the “extra processing” would likely require fewer processor cycles than shuffling around the whole array.

6v6gt:
Rounding up an array to the next power of 2 could be very extravagant, especially if your array was say 1025 bytes. A small MCU may not tolerate it.

I'm going to go out on a limb and say that manipulating an index is still more efficient even if your array is arbitrary size and you must use the modulo operator (or an ‘if’ statement).

The 2^N technique is simply an additional optimization that may or may not be applicable.