Carry variables to a function via an array, to change the variable values.

A little problem I could do with some advice on.

I have managed to get the RFID call to alter for me a set of values in paramStore[16] that is built from a collection of variables I wish to change.

With me so far?

The returned values inside paramStore are nicely altered by the call readRFID(paramStore, 16) to the function void readRFID(uint8_t theList[], uint8_t n)

What I cannot seem to manage is to get the newly returned array to change the actual variables as I’d hoped, and I’m struggling.

The paramStore is being used as a pointer - got that. But the references inside paramStore don’t function as I hope, with no alteration happening to the actual variables referenced.

My call to the function using an array may not be the way to do it, and any advice on an elegant way to do what I require would be appreciated.

/*
 * Here are the variables to have changed by the call to RFID
 */
uint8_t  varOne[] = {240, 120, 80, 40, 20};
uint8_t varOneIndex = 1;         // Number from 0 to 4 indentifying which  is used 
uint8_t varTwo = 10;
uint8_t varThree = 4;                
uint8_t varFour = 2;                 
uint8_t varFive = 2;                  
//uint8_t varSix;                   
//uint8_t varSeven = 30;
// uint8_t varEight = 10;          
//uint8_t varNine = 5;


/*
 * Here is the array I send and get back from the call to the RFID function
 * altered as required - success so far.
 */
uint8_t paramStore[16] = {&varOneIndex, &varTwo, &varThree, &varFour, &varFive/*, varSix, varSeven, varEight, varNine, etc */};  

void loop(){

readRFID(paramStore, 16);

}

void readRFID(uint8_t theList[], uint8_t n) {

//some code

for (uint8_t i = 0; i < 16; i++){
              if (i + (16*(currentblock-4)) <= 16) {
                theList[i + (16*(currentblock-4))] = data[i];   // build the paramStore[] sent in the call
              }
            }
// some code

}
uint8_t paramStore[16] = {&varOneIndex, &varTwo, &varThree, &varFour, &varFive/*, varSix, varSeven, varEight, varNine, etc */};

You wanted this to be an array of pointers?

uint8_t* paramStore[16] = {&varOneIndex, &varTwo, &varThree, &varFour, &varFive/*, varSix, varSeven, varEight, varNine, etc */};

*! ::slight_smile:

Aargh!

I was under the misapprehension that an array was a pointer, so didn't see that.

The array name is a pointer to the first element of the array. But the things in the array aren't pointers unless it is an array of pointers. So now paramStore is a pointer to a pointer to a uint8_t.

Maybe time to read up on structs.

struct PARAM
{
  uint8_t varOne;
  char varTwo[12];
  float varThree;
};

void readRFID(struct PARAM *list)
{
  list->varOne = 1;
  strcpy(list->varTwo, "two");
  list->varThree = 3.14;
}

void setup()
{
struct PARAM paramStore;

  paramStore.varOne = 99;
  ...
  ...

  readRFID(&paramStore);
  Serial.println(paramStore.varOne);
  ...
  ...
}

Just to give you a bit of an idea.

I'm missing something here. If all of the data are uint8_t types: 1) why the use of an array of pointers rather than just using the array to store the values, and 2) I don't see how a struct helps here. Also, where are currentblock and data[] defined?

econjack:
I'm missing something here. If all of the data are uint8_t types: 1) why the use of an array of pointers rather than just using the array to store the values, and 2) I don't see how a struct helps here. Also, where are currentblock and data[] defined?

Thanks econjack,
I think you may be right about the fact that the array of vars are all uint8_t, and I may have been barking loudly at the moon...
currentblock and data[] are defined in the function, which for brevity's sake I did not fully include.

The idea I was pursuing is as follows:

Sketch has two main options for the user for altering those variables 1) via menu, old school and clunky and 2) via RFID card, with the data blocks containing the pre-set options. This is why I have a block of (call them Master) variables, which will be altered by the user using the menu system, and why I separated out the array of those variables for the RFID function to alter, returning the altered values to be applied to the Masters just as the Menu would.
I wrote the code for the menu system first, with the RFID being a bolt-on.

The RFID read gives me a data dump which I can easily plonk into the variable paramStore - so off I headed.

But, I see what you are getting at; use the paramStore array for the Master variables too, and no complications arise.

Delta_G:
The array name is a pointer to the first element of the array. But the things in the array aren't pointers unless it is an array of pointers. So now paramStore is a pointer to a pointer to a uint8_t.

Perfectly clear now the smoke has cleared, thanks.
Interestingly, however, when I attempt to compile now I get an error which is puzzling me:

call of overloaded 'print(uint8_t*&)' is ambiguous

  Serial.print(i);
    Serial.print(":");
    Serial.print(paramStore[i]);  //*******highlighted line********
    Serial.print(" ");
  }

sterretje:
Maybe time to read up on structs.

struct PARAM

{
 uint8_t varOne;
 char varTwo[12];
 float varThree;
};

void readRFID(struct PARAM *list)
{
 list->varOne = 1;
 strcpy(list->varTwo, "two");
 list->varThree = 3.14;
}

void setup()
{
struct PARAM paramStore;

paramStore.varOne = 99;
 ...
 ...

readRFID(&paramStore);
 Serial.println(paramStore.varOne);
 ...
 ...
}



Just to give you a bit of an idea.

You may well be right - I need to do a lot of reading-up!

And I see where you are going there.

When I saw this block of code with no cast in it:

for (uint8_t i = 0; i < 16; i++){
              if (i + (16*(currentblock-4)) <= 16) {
                theList[i + (16*(currentblock-4))] = data[i];   // build the paramStore[] sent in the call
              }
            }
// some code

}

I assumed that data[] and theList[] are the same data type. This suggests two changes: one to get rid of the “magic number” 16, and the second to simplify the code.

First, hard coding magic numbers should be avoided whenever possible. To get rid of the 16, use:

#define ELEMENTCOUNT(x)   (sizeof(x) / sizeof(x[0]))

// bunch of code down to the for loop...

for (uint8_t i = 0; i < ELEMENTCOUNT(paramStore); i++){

    // rest of loop code...

Now if you change the number of elements in paramStore, the for loop is automatically adjusted after the compile.

Next, since that loop simply copies data[] into paramStore[], why not replace the loop with:

     memcpy(paramStore, data, sizeof(paramStore));

I think this would simplify the code. I would also give the elements in the array symbolic names if they are used a lot, e.g.:

#define WHATEVER1MEANS   1   // This used to be var1Index
#define WHATEVER2MEANS   2   //                       var2
// and so on
// later in the code...

    importantValue = paramStore[WHATEVER2MEANS];

This also makes it easier to read if you use meaningful names.

When I saw this block of code with no cast in it:

for (uint8_t i = 0; i < 16; i++){

if (i + (16*(currentblock-4)) <= 16) {
                theList[i + (16*(currentblock-4))] = data[i];  // build the paramStore sent in the call
              }
            }
// some code

}




I assumed that data[] and theList[] are the same data type. This suggests two changes: one to get rid of the "magic number" 16, and the second to simplify the code.

First, hard coding magic numbers should be avoided whenever possible. To get rid of the 16, use:


#define ELEMENTCOUNT(x)  (sizeof(x) / sizeof(x[0]))

// bunch of code down to the for loop…

for (uint8_t i = 0; i < ELEMENTCOUNT(paramStore); i++){

// rest of loop code…




Now if you change the number of elements in paramStore, the for loop is automatically adjusted after the compile.

Cool. Now that’s way more elegant!

Next, since that loop simply copies data into paramStore, why not replace the loop with:

 memcpy(paramStore, data, sizeof(paramStore));

I think this would simplify the code.

Yes - I see.
However, the loop writes 16 bytes twice as the data comes in blocks of 16, making an array of 32, so the loop probably needs to stay in order to keep the test for the second 16.

  • Will this memcpy only work if all are of one type (like uint8_t )?

I would also give the elements in the array symbolic names if they are used a lot, e.g.:
This also makes it easier to read if you use meaningful names.

Of course :slight_smile: - I have that taken care of in my actual code - the example was just a simplified cut-down for ease of parsing.

Thank you for the inputs.

Will this memcpy only work if all are of one type (like uint8_t )?

memcpy() is as dumb as a bag of hammers and doesn't care what's in the memory blocks. What's in the two memory blocks will determine if the copy is meaningful. For example, if you have an array of structures, you can copy them even though the struct contains mixed data types. However, if you think about it, you're still copying similar data types.

OldManNoob:

  • Will this memcpy only work if all are of one type (like uint8_t )?

memcpy() copies bytes. Since all data structures are made up of one or more bytes, it will copy any of them -- if properly used. The prototype is conveniently defined with parameters of void *, so it will accept any pointer. See:
http://www.cplusplus.com/reference/cstring/memcpy/

Ok, I’m nearly there I think…

Based on this:

int val;
int *ptr;
ptr = &val;
*ptr = 10;

I’ve attempted to use indirection to alter the values in the array, but I’m not quite getting the result I need. The reason I’m using this method is that I’ll be passing the array into a function where the results from an RFID read will be applied.
Obviously I’m missing a trick, but I am close…

The code here is my attempt to do a debug on the code I’ll be using - that’s all.

Can anyone get me past the last mile here, as my desk won’t take much more of me banging my head on it :confused:

#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>   // The following files are included in the libraries Installed
#include <NfcAdapter.h>
#define ELEMENTCOUNT(x)   (sizeof(x) / sizeof(x[0]))

PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532_i2c);  // Indicates the Shield you are using

/*
 * Here are the variables to have changed by the call to RFID
 */
uint8_t startCounts[] = {24, 12, 8, 4, 2};
uint8_t startCountsIndex = 1;         // Number from 0 to 4 indentifying which of startCounts is used in this round, default 120 
uint8_t wakeUp = 10;
uint8_t maxExit = 4;                  // Total number of Ends for competition
uint8_t Details = 2;                  // Single (1) or Double detail (2)


/*
 * Here is the array I send and get back from the call to the RFID function
 * altered as required - success so far.
 */
uint8_t paramStore[4];
uint8_t *ptrStartCountsIndex;


void setup(void) {
  Serial.begin(115200);
  Serial.println("NFC TAG READER"); // Header used when using the serial monitor
  nfc.begin();
}

void loop(void) {

  ptrStartCountsIndex = &startCountsIndex;
   
  uint8_t *ptrParamStore;             // pointer to paramStore
  ptrParamStore = (int)&paramStore;    // set it
  
  paramStore[0] = {startCountsIndex };  //(edited - from *ptrStartCountsIndex)
  paramStore[1] = {wakeUp};
  paramStore[2] = {maxExit};
  paramStore[3] = {Details};


 
  Serial.print("paramStore: ");
  for (uint8_t i =0; i< ELEMENTCOUNT(paramStore); i++){
    uint8_t a = paramStore[i];
    Serial.print(a);
    Serial.print(",");
  }
  Serial.println();
  
  *ptrParamStore = 3;  //////////////////  Debug test 1: overwrite ptrParamStore[0]

  Serial.print("paramStore: ");
  for (uint8_t i =0; i< ELEMENTCOUNT(paramStore); i++){
    uint8_t a = paramStore[i];
    Serial.print(a);
    Serial.print(",");
  }
  Serial.println();
  Serial.print("startCountsIndex: ");
  Serial.println(startCountsIndex);   /////   Debug test 2:  is startCountsIndex changed?
  getRFID();

}

void getRFID(void){
  delay (10000);   // dummy content
  }

OldManNoob:
...but I'm not quite getting the result I need.

What is the result you need and what is the result you're currently getting?

gfvalvo:
What is the result you need and what is the result you're currently getting?

I am attempting to alter the variables in the code, and specifically startCountsIndex in this debug example. In the code I attempt to change it from 1 to 3. It stubbornly remains at 1.

I am managing to alter the value in the paramStore[4] which is the way I'll be sending the variables to the RFID function eventually. There will be at least 16 vars in paramStore when the code is implemented.
When I print the list of vars in paramStore before and after the I attempt to do the value change I get this:

Found chip PN532
Firmware ver. 1.6
paramStore: 1,10,4,2, (edited from 0 to 1 after edit in code above)
paramStore: 3,10,4,2,
startCountsIndex: 1

To be honest, I have no idea what you try to achieve; but it looks needlessly complicated. Based on your original question (carry variables over to a function) and your latest code, the below will simply update the 4 values of the paramStore variable.

#define ELEMENTCOUNT(x)   (sizeof(x) / sizeof(x[0]))


uint8_t paramStore[4];

void setup()
{
  Serial.begin(115200);
  
}

void loop() {

  Serial.print("paramStore: ");
  for (uint8_t i = 0; i < ELEMENTCOUNT(paramStore); i++) {
    uint8_t a = paramStore[i];
    Serial.print(a);
    Serial.print(",");
  }
  Serial.println();

  updateParamStore(paramStore);
  delay(5000);
}

void updateParamStore(uint8_t *ps)
{
  ps[0] = random(0, 256);
  ps[1] = random(0, 256);
  ps[2] = random(0, 256);
  ps[3] = random(0, 256);
}

Now the elements in the paramStore seem to have a certain meaning (the first element possibly being a count?).

You can use e.g. #defines to name the elements in the array

#define FIRST_ELEMENT 0
#define SECOND_ELEMENT 1

...
...

void setup()
{
  ...
  ...
}

void loop()
{
  ...
  ...
}

And next you can access the array elements by name, e.g.

void loop() {

  Serial.print("paramStore: ");
  for (uint8_t i = 0; i < ELEMENTCOUNT(paramStore); i++) {
    uint8_t a = paramStore[i];
    Serial.print(a);
    Serial.print(",");
  }
  Serial.println();
  Serial.print("FIRST_ELEMENT: "); Serial.println(paramStore[FIRST_ELEMENT]);
  Serial.print("SECOND_ELEMENT: "); Serial.println(paramStore[SECOND_ELEMENT]);

  updateParamStore(paramStore);
  delay(5000);
}

The output looks like

paramStore: 0,0,0,0,
FIRST_ELEMENT: 0
SECOND_ELEMENT: 0
paramStore: 167,241,217,42,
FIRST_ELEMENT: 167
SECOND_ELEMENT: 241
paramStore: 130,200,216,254,
FIRST_ELEMENT: 130
SECOND_ELEMENT: 200
paramStore: 67,77,152,85,
FIRST_ELEMENT: 67
SECOND_ELEMENT: 77
paramStore: 140,226,179,71,
FIRST_ELEMENT: 140
SECOND_ELEMENT: 226
paramStore: 23,17,152,84,
FIRST_ELEMENT: 23
SECOND_ELEMENT: 17
paramStore: 47,17,45,5,
FIRST_ELEMENT: 47
SECOND_ELEMENT: 17

Only thing you have to do is use sensible ‘names’ instead of FIRST_ELEMENT, SECOND_ELEMENT etc.

There's a lot broken here. If you really want to access / modify the actual variables (just not copies of them in the array) then you need an array of uint8_t *, not an array of uint8_t.

uint8_t startCountsIndex = 1;
uint8_t wakeUp = 10;
uint8_t maxExit = 4;
uint8_t Details = 2;

uint8_t *paramStore[] = {&startCountsIndex, &wakeUp, &maxExit, &Details};
const size_t pointerArraySize = sizeof(paramStore) / sizeof(uint8_t *);

void setup() {
  uint8_t index;
  Serial.begin(115200);
  delay(2000);
  Serial.println();

  // Print current values
  Serial.println(startCountsIndex);
  Serial.println(wakeUp);
  Serial.println(maxExit);
  Serial.println(Details);
  Serial.println();

  // Modify the values
  *paramStore[0] = 2;
  *paramStore[1] = 11;
  *paramStore[2] = 5;
  *paramStore[3] = 3;

  // Print the new values
  Serial.println(startCountsIndex);
  Serial.println(wakeUp);
  Serial.println(maxExit);
  Serial.println(Details);
}

void loop() {}

sterretje:
You can use e.g. #defines to name the elements in the array

or maybe, since this is C++, use references

int myArray[10] = {2,4,6,8,10,12, 14, 16, 18, 20};

int& FIRST_ELEMENT = myArray[0];
int& SECOND_ELEMENT = myArray[1];

void setup() 
{
  Serial.begin(115200);

  Serial.println(FIRST_ELEMENT);
  Serial.println(SECOND_ELEMENT);
}

void loop()
{ 

}

sterretje:
To be honest, I have no idea what you try to achieve; but it looks needlessly complicated. Based on your original question (carry variables over to a function) and your latest code, the below will simply update the 4 values of the paramStore variable.

Umm - Let me try to make myself clearer - sorry for any confusion.

I am writing a timer system which has setup parameters, represented in my example snippet by the variables listed for the sake of clarity, with their startup values, as:

uint8_t startCountsIndex = 1;
uint8_t wakeUp = 10;
uint8_t maxExit = 4;
uint8_t Details = 2;

startCounts is a list of various options indexed by startCountsIndex.

There will be many more vars to handle than these 4 in the final code.

In the program (working a dream, happily clicking away and doing all I need using these variables) if I wish to alter the setup I need to change the values of some or all of them.
Currently this is handled by a set of push-buttons and a menu.

What I wish to do is take these variables into a function which reads an RFID card containing a pre-defined set of these variable values - and for the function to apply the values present on the card to the variables passed in - bypassing the need for the user to have to deal with the menu/button settings.

To this end I have created an array named paramStore which is meant to hold pointers to all of the variables, get sent to the function getRFID() so that the values of the variables pointed to get changed by that function.

What my example code above is illustrating is my inability to get even one variable (in this case startCountsIndex ) to change - because I keep getting compiler errors when I get close - errors I have difficulty understanding and therefore great difficulty overcoming!

OldManNoob:
To this end I have created an array named paramStore which is meant to hold pointers to all of the variables, get sent to the function getRFID() so that the values of the variables pointed to get changed by that function.

The array in Reply #15 does exactly this. You can pass it to a function.

OldManNoob:
To this end I have created an array named paramStore which is meant to hold pointers to all of the variables, get sent to the function getRFID() so that the values of the variables pointed to get changed by that function.

What my example code above is illustrating is my inability to get even one variable (in this case startCountsIndex ) to change - because I keep getting compiler errors when I get close - errors I have difficulty understanding and therefore great difficulty overcoming!

it was mentioned way back that you ought to look at using a struct... this will allow you to do what you need without all the typing required using pointers.

Create the struct:

struct SetupParameters{
  uint8_t startCountsIndex;
  uint8_t wakeUp;
  uint8_t maxExit;
  uint8_t Details;
  int someArray[10];
};

then initialize it:

SetupParameters defaultSetup = {
  1, 10, 4, 2, {1, 2, 3, 4,5,6,7,8,9,10}
};

then use the dot operator to access elements:

defaultSetup.wakeUp = 99;