Passing a structure array member to a function that in turn passes it to another function

As a "still learning Arduino and C++" exercise I built a multi-player Simon Says game. It all works now. At one point I thought I needed to pass player data structures to functions that in turn passed them to other functions. Each function modifying the data in the original structure member. I could not get that to work and solved the problem with simpler structures and some extra global variables.

But I want to understand how to deal with passing structure array members to cascading functions. So I wrote the demo code below which works and does exactly what I was trying to achieve.

Problem is I do not understand why it works. In the call to the first function I need to pass the Struct array member parameter using dereference (&) and have the function receive it with a pointer argument. But when the first function calls the second one the structure member parameter is passed referentially with no * or & but is still received as a pointer argument. I understand that "by reference" and pointer mean the same thing (eg passing arrays), but I am confused here as the first function call requires the dereference - and it is a member of an array!.

So obviously I have stuff to learn but I have not been able to find clear explanation of this in the stuff available on line. Can someone explain this for me?

Also, is this a clumsy way of doing what I need. Is there a simpler way. I tried creating a series of structure types (redPlayer, GreenPlayer, etc) and then making an array of them, but got completely out of my depth - couldn't get the original copy of the data updated.

Any help much appreciated.

/* 
 * routine to demo passing a member of a struct array down through
 * (two) cascading function calls. Summary:
 *
 *  struct sName {  };
 *  structArray sName sMember[] {
 *    
 *  pass array member from loop to first function
 *  with dereference "&"
 *  
 *      firstFunction(&structArray[n]);
 *      
 *  receive into first function as pointer "*"
 *  
 *      void firstFunction(structName *sMember)
 *      
 *  pass to second function plainly by reference only (is a pointer??)
 *  
 *      secondFunction(sMember);
 *      
 *  receive into second function with pointer 
 *      void secondFunction(sName *sMember)
 *  
 *  in both functions access structure data with "->" not "."
 *  
 *  Both functions update the structure directly and don't make copies.
 *  
 *  Code below works
 */

enum colour  {RED =  0, YELLOW = 1, GREEN = 2, BLUE = 3};

struct playerData              
{
  char pName[10];             //player's literal name
  byte offset;                //offset to player's button pins (colour)
  byte pattern [5];          //pattern of random LED flashes player must remember
};
                         
playerData player[] =        
{
  {"RED",    RED,    {1,1,1,1,1}},
  {"YELLOW", YELLOW, {1,1,1,1,1}}
}; 

void setup() 
{
Serial.begin(19200);
delay(200);
Serial.println();
}

void loop() 
{
Serial.println("In loop original data before call to firstFunction. ");
printPlayerData(0);
Serial.println();
firstFunction(&player[0], 0);  //Passes RED player data without call to 2nd function

Serial.println("In loop after first function data changed to ");
printPlayerData(0);

firstFunction(&player[0], 1);   //Passes RED player data and request to call to 2nd function

Serial.println();
Serial.println("In loop after second function data changed to ");
printPlayerData(0);

while (true) {;}
}

void firstFunction(playerData *player, bool call)
{
  if (!call)
  {
    player->offset = GREEN;   //2
    player->pattern[1] = BLUE;    //3
  }
  else
  {
    secondFunction(player);   //call to second function parameter is not pointer
  }
}

void secondFunction(playerData *player)
{
  player->offset = YELLOW;    //1
  for ( int i = 0; i < 5; i++)
  {
    player->pattern[i] = i;
  }
}

void printPlayerData(byte index)
{
  Serial.print("Player Name is ");
  Serial.println(player[index].pName);
  Serial.print("Player offset is ");
  Serial.println(player[index].offset);
  Serial.print("Player pattern is ");
  
  for ( int i = 0; i < 5; i++)
  {
   Serial.print( player[index].pattern[i]);
  }
  
  Serial.println();
}

Edit
Here is the output.


In loop original data before call to firstFunction. 
Player Name is RED
Player offset is 0
Player pattern is 11111

In loop after first function data changed to 
Player Name is RED
Player offset is 2
Player pattern is 13111

In loop after second function data changed to 
Player Name is RED
Player offset is 1
Player pattern is 01234

It is a pointer since this is how player’s type is defined in the function signature.

—-

Passing by reference is easier to read in C++, no need for ->
You would pass by pointer if you want to support passing a null pointer for example and your code then should check if the pointer is null before using ->

You are passing pointer in both cases, only in the first case you are extracting it from array, hence &array[index], I assume this is what got you confused. You just have to learn about arrays, there is no way around.

consider

#include <stdio.h>

struct Var {
    int var;
};

Var vars [] = {
    { 1 },
    { 2 },
    { 3 },
    { 4 },
};

// -----------------------------------------------------------------------------
void
func1 (
    Var &p )
{
    p.var = 88;
}

void
func2 (
    Var &p )
{
    p.var = 22;
    func1 (p);
}

// -----------------------------------------------------------------------------
int
main ()
{
    printf (" %d\n", vars[2].var);

    func2 (vars[2]);

    printf (" %d\n", vars[2].var);
    
    return 0;
}

output

 3
 88

I have to ask, why you insist on inventing different ways to confuse people with your weird formatting? It doesn’t make you look like an expert, just the opposite. If you going to share the code why not do it in conventional format? I swear to god next time I see more weirdness like this I’m adding you to never see again list :slight_smile:

this formatting was the required style at my last company, Qualcomm. the formatting with the return type, function and arguments on separate lines allowed comment describing each

I don’t believe you. Even if true, this is not Qualcomm JIRA

wow!

Someone should tell them that they don’t adhere to it in their GitHub

https://github.com/quic/sample-apps-for-Qualcomm-Robotics-RB5-platform/blob/master/Device-info/src/qrb5165_info.c

if you've worked at a large company, you know there are many cultures within it.

yes - indeed.
Sure - I could see such norms being required but you are not at Qualcomm here, I feel it's indeed confusing to post like this as it does not match the style you find in all the IDE examples nor the one used in most libraries

May be you should go all the way and add comments.
Also Shouldn't the closing parenthesis be on it's own line as well?

void              // the function does not return anything (useless comment to meet the requirements)
func1 (           // the function name is func1 (useless comment to meet the requirements)
  Var &p          // passing by reference the Var type element to work on (useless comment to meet the requirements)
)
{
  // here goes the code
}

:slight_smile:

really !?
this is starting to sound like the standards police. does this help the OP

a question was asked and i provided a practical explanation for the style

it was a fair question. I was curious about the Qualcomm style. it feels weird the last parameter would have the closing bracket before the comment.

just pure engineering curiosity - no evil intent.

would it need a comment?
does every argument need a comment?

I don't know, you tell me :slight_smile:
I though the idea of having 1 parameter per line was to be able to add a comment

so following this idea, I thought it would be visually weird to have

returnedType
func ( // <=== note the parenthesis is not with a parameter 
  type parm1,  // some comment possibly
  type parm2,  // some comment possibly
  type parm3)  // <== the parenthesis here looks/feels weird to me

this would look better to me

returnedType
func ( // <=== note the parenthesis is not with a parameter 
  type parm1,  // some comment possibly
  type parm2,  // some comment possibly
  type parm3   // some comment possibly
) // <== aligned with the function name

So I was just curious what the rule was

Thanks for the replies in the first few posts. I think I have understood something from them.
Putting aside the format wars, I will try to rewrite my code along the lines suggested. I'll be back if I get stuck, or to :heavy_check_mark: a post as solution.

Thanks gcjr for the outline code for the suggestion from J-M-L. Of course it works just fine in the little demo program I used in my post. What's more I do believe I understand why and how it works. I have checked gcjr post as "solution" meaning it is much better than my attempt!

what is that structure what does it do. Sorry kinda new

@peruviantank

Take a look at this link.

https://www.tutorialspoint.com/cplusplus/cpp_data_structures.htm

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