Array copy, Is there a way to do this with pointers and save SRAM?

I have some code which includes functionality whereby an array has another array copied in to it, which array gets copied in is dependent on various conditions. I then process (with reads and writes) the array to which the copying was done.

Please see my pseudocode, with requirements explained within its comments:

uint8_t AArray[10]={0};//sizes are fixed, and all guaranteed to be smaller than ArrayMaxSize
uint8_t BArray[38]={0};
uint8_t CArray[25]={0};

#define ArrayMaxSize 40

uint8_t CopiedArray[ArrayMaxSize]={0};

uint8_t VariableLength=0;
uint8_t CopyDone=0;

//initially various things are done to put data in to AArray, BArray, CArray...
//details not shown, but each array accessed place by place AArray[i]= and so on

//then copying is done
if(Condition){
  VariableLength=sizeof(AArray);
  memmove(CopiedArray,AArray,sizeof(CopiedArray)); //copying sizeof the destinition array ensures we can't overwrite an array end, copied places at >=VariableLength but also <ArrayMaxSize may hold junk data stolen from other things in memory, but this is copied only, "So what. We only do later processing on array places <VariableLength"
  CopyDone=1;
}else if(OtherCondition){
  VariableLength=sizeof(BArray);
  memmove(CopiedArray,BArray,sizeof(CopiedArray));
  CopyDone=1;
}else if(YetAnotherCondition){
  VariableLength=sizeof(CArray);
  memmove(CopiedArray,CArray,sizeof(CopiedArray));
  CopyDone=1;
}else{
  CopyDone=0;
}

//then yet later on we do

if(CopyDone){
    for(uint8_t i=0; i<VariableLength; i++){
        //read from CopiedArray[i] for certain i values
        //write to CopiedArray[i] for other i values
        //do stuff with the variables read out
        //guaranteed never to act on places where i is >= to the length of the array which was copied in to CopiedArray
    }
    //do some processing on CopiedArray as a whole after certain i values have been rewritten above
}

//after this point we no longer care what happens to CopiedArray as long as it doesn't memory leak
//and we don't care about preserving or not the changes made to some i places during the for loop
//we are ok with AArray, BArray and CArray at this point either being just as they were befoe the conditional copying was done
//or with AArray, BArray and CArray at this point being changed in those ith places where the for loop made edit to CopiedArray

Is there a way to do this with pointers and save on SRAM usage?

I am writing this for use on an ATTiny AVR chip, with some initial testing on an Atmega328p Uno, when it goes to the ATTiny i don't have much SRAM to work with.

If I could avoid the need for ArrayMaxSize (40 in the example, but could be other sizes, depending on how big the XArray arrays are, (and there might be DArray, EArray... in future versions)) and just have one or two bytes of pointer then that would be nice.

Is there a way to do this, or does one have to create a pointer array just as big as CopiedArray presently is?

Also I think usage of pointers rather than memmove/memcpy (I hear that memcpy is usually the right one to choose, but memmove is perfectly safe to use anywhere a memcpy might be used) would speed up the code's running from having as many clock cycles to copy the whole array used in the copying if loop, to having a pointer swap taking very few clock cycles regardless of array size?

Is there a way to make CopiedArray in to some sort of copy by reference to the entries in the actual arrays, and not have to make CopiedArray as big as ArrayMaxSize?

P.S. please ignore considerations of variable scope in this, local variables would only help me reduce global usage of SRAM, not peak usage, and the way my full code operates I can't forget about AArray, BArray, CArray... once CopiedArray is full, nor can i do vice-versa. All the arrays must be kept global, and it is peak SRAM usage I need to keep low, reducing global SRAM usage would just give a false sense of security.

Thanks

Sorry to have to ask this, but can you point me to a sample piece of code for using that method. Somehow I've always found pointers mysterious and whilst I've used them in a few places, passing stuff to/from functions, have only used example code where the pointers themselves are concerned. Pointers are one of those things I've only "learnt" in the fashion an AI might "learn" something I can see an example and reproduce it in a slightly different context, but don't truly know how they work underneath. I know C/C++ arrays are glorified pointers, but don't know how to put that fact in to practice.

The method you propose means that I only use a pointer's worth of bytes (2 I think on AVR usually) rather than the whole 40 bytes of CopiedArray (globally and at peak)?

Can I see an example of how elements in that pointer version of CopiedArray are individually addressed, as well as how the copying is done.
Thank you very much indeed.

Also, do I have to destroy the pointer later to prevent a memory leak?
And I assume that sizeof(the pointer) won't work any longer for anything array size related, but as I'm using the VariableLength variable to track array size that shouldn't affect me.

Basically, use CopiedArray as a pointer, not an actual array. I renamed it here

uint8_t AArray[10] = {0}; //sizes are fixed, and all guaranteed to be smaller than ArrayMaxSize
uint8_t BArray[38] = {0};
uint8_t CArray[25] = {0};

#define ArrayMaxSize 40

//uint8_t CopiedArray[ArrayMaxSize] = {0};
uint8_t *ProcessArray;  // points to either AArray, BArray, CArray
uint8_t VariableLength = 0;
uint8_t CopyDone = 0;

//initially various things are done to put data in to AArray, BArray, CArray...
//details not shown, but each array accessed place by place AArray[i]= and so on

//then copying is done
if (Condition) {
  VariableLength = sizeof(AArray) / sizeof(AArray[0]);
  //memmove(CopiedArray, AArray, sizeof(CopiedArray)); //copying sizeof the destinition array ensures we can't overwrite an array end, copied places at >=VariableLength but also <ArrayMaxSize may hold junk data stolen from other things in memory, but this is copied only, "So what. We only do later processing on array places <VariableLength"
  ProcessArray = AArray;
  CopyDone = 1;
} else if (OtherCondition) {
  VariableLength = sizeof(BArray) / sizeof(BArray[0]);
  //memmove(CopiedArray, BArray, sizeof(CopiedArray));
  ProcessArray = BArray;
  CopyDone = 1;
} else if (YetAnotherCondition) {
  VariableLength = sizeof(CArray) / sizeof(CArray[0]);
  //memmove(CopiedArray, CArray, sizeof(CopiedArray));
  ProcessArray = CArray;
  CopyDone = 1;
} else {
  CopyDone = 0;
}

//then yet later on we do

if (CopyDone) {
  for (uint8_t i = 0; i < VariableLength; i++) {
    //read from ProcessArray[i] for certain i values
    //write to ProcessArray[i] for other i values
    //do stuff with the variables read out
    //guaranteed never to act on places where i is >= to the length of the array which was copied in to CopiedArray
  }
  //do some processing on ProcessArray as a whole after certain i values have been rewritten above
}

//after this point we no longer care what happens to CopiedArray as long as it doesn't memory leak
//and we don't care about preserving or not the changes made to some i places during the for loop
//we are ok with AArray, BArray and CArray at this point either being just as they were befoe the conditional copying was done
//or with AArray, BArray and CArray at this point being changed in those ith places where the for loop made edit to CopiedArray
//NOTE: original rray AArray, BArray, or CArray will be altered

Thank you, I think that solves it for me.

Delta_G, thanks also. Yes in this use case I'm ok with the AArray, BArray... being changed when the copied one is changed.

Ok, so the principle works but smething rather strange is going on for me.

This setup has CopiedArray being accessed within an interrupt, and AArray, BArray... being filled up in the main loop. All are defined volatile. I have also tried switching between whether CopiedArray (when using the pointer version) is volatile or not.

The trouble is that when CopiedArray was another array, filled by a memmove, it ran very fast. But the pointer version of CopiedArray seems to tke a lot more clock cycles? The copying operation is much quicker now, the instructions in the conditionals section, but accessing CopiedArray[i] seems to be much slower (both for reads and writes) with the pointer as versus with the array?

Are pointers to arrays slower than arrays Surely they should not be? Or does being in an interrupt affect this somehow? Declaring the CopiedArray pointer only within the array, rather than globally, didn't make things any faster either.

I've done some further testing, there is a definite difference, but it ends up pretty minimal once one declares the pointer in the correct scope. Making CopiedArray volatile with global scope seems to be quickest, it doesn't seem to add more than a us or so per access to a pointer array element as vs an access to a normal array element.

Showing is not so easy, this is in use as a small part of a pretty big piece of code. But when I say there is a difference, whilst it initially looked a major difference (perhaps due to other changes I was making in other parts of the code at the same time), with detailed testing I found the difference was measureable but small, small enough not to be a problem for my use case.

Consider that when using CopiedArray, the pointer is a known value, so the compiler can do more of the math at compile time.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.