[Solved] Array of structs or pointer indexing ... Options / Best practice?

I currently have an array of structs tht I need to iterate through. NB. There is a separate thread asking about the use of String, I don't want to get into that in this thread as the two things are separate, at least in my head they are.

                                                                                     // Test data, will be dynamic when in use.
float BatVolts = 13.5;
float ACVolts = 236;
float PV1_Current = 5;
float PV2_Current = 6;


                                                                                    // New struct (xVar Type)
typedef struct{
  String Name;                                                                
  float * Ptr;
}xVar;

xVar ExposedVars[20];                                                       // make an array of xVars

void MapFloatName(float * NewVarPtr, String NewName){
  static int VarCount = 0;
  ExposedVars[VarCount].Ptr = NewVarPtr;
  ExposedVars[VarCount].Name = NewName;
  VarCount++;
}
                                                                                     // Lots of other stuff and nonsense

Is this the right approach or should I be creating structs and indexing through their pointers without the array? I believe this is possible but haven't ever tried and would know how to.

typedef struct{
  float Value;
  String Name;
  float * Ptr;
}BatVolts;

typedef struct{
  float Value;
  String Name;
  float * Ptr;
}ACVolts;

typedef struct{
  float Value;
  String Name;
  float * Ptr;
}PV1_Current

typedef struct{
  float Value;
  String Name;
  float * Ptr;
}PV2_Current

With structs defined as above can I get a pointer to the first and then increment it, to return a pointer to the second and so on? If I can how would I know when I had reached the last one in memory?

Of course I may have simply missed the point somewhere ... Feel free to be blunt.

Thanks Al

With structs defined as above can I get a pointer to the first and then increment it, to return a pointer to the second and so on?

The only way that would make sense would be if you had an array of the structs, in which case, you might as well use an array index. If you mean can I mix an array of these different structures, then the answer is no. You could combine them as an array of unions, or you could add forward and backward pointers and form a list.

Sorry, perhaps I wasn’t clear , I do that quite a bit these days, its this foreign C language that is messing with my head.

I have an array of struct’s now, it is working just fine and is cleaner that two arrays of different types.

However I have heard tell that pointers can be incremented / decremented, causing them to point somewhere else, the next similar type I assume.
(To be fair it came up in another one of my threads but I cant find the post)

The question is should I keep my array of structs, which is east yo iterate through, or can I have separately defined structs, which ,akes for more readable code, and still be able to iterate through them?

However I have heard tell that pointers can be incremented / decremented, causing them to point somewhere else, the next similar type I assume.

Yes, incrementing a pointer will always point to the address of the next element of that datatype. However, consider the following contrived example.

int array [4];
int* pA = &array [3]; // point to the last element of array
...
pA++;  // what does pA point to now? An "int" for sure, but who does that "int" belong to? Answer: Not you!

typedef struct{ String Name; float * Ptr; }xVar;

A pointer to a float is two bytes, and points to a 4 byte float somewhere else.

A float is 4 bytes.

I fail to see why you are using 6 bytes when 4 would be sufficient, and a whole lot easier.

Yes I see that ... I wasn't thinking of pointing 'inside' an array

My final application will have 20 or so variables that I want to be able to access at runtime by name ... Yes I know, its so a simple interpreter can read a text from from SD replace a few named variables with formatted values and then display the result either on a local display or in a browser. This makes the display definition files easy to read and removes all the static text from the program.

So ... Rather than defining a variable normally I want to do this. (excuse the syntax errors if I make any - I think you will get the gist)

typedef struct{
  float Value;
  char Name[];
  float * Ptr;
}BatVolts;

typedef struct{
  float Value;
  char Name[];
  float * Ptr;
}ACVolts;

void setup(){

BatVolts.Value = 0;
strcat(BatVolts.Name, "BatVolts");
BatVolts.Ptr = &BatVolts;

ACVolts.Value = 0;
strcat(ACVolts.Name, "ACVolts");
ACVolts.Ptr = &ACVolts;

}

When I fine the text BatVolts in a display definition file, denoted by some escape sequence or other I want to iterate through the structs, incrementing currentstructpointer by 1 struct, untill strcmp(* currentstructpointer.ptr , "BatVolts") ==0 A least I think that right. I am doing it now by iterating through an array of structs

The primary advantage is readability of both the main code and display definitions.

What happens if I have defined 5 similar structs, return a pointer to the first and then index it 5 times .... now where am I pointing? I don't expect this will happen, I will always know how many there are, but i like to error handle, or mitigate, where possible.

BatVolts.Ptr = &BatVolts;

So, you want BatVolts.Ptr, which is a pointer to a float, to point to BatVolts, which is a struct. That won't work.

And, of course, you can't create a pointer of type anonymous struct. You could create a struct properly, with a name, and then define a pointer of type struct someName.

However, the only way to get access to the pointer is to have the instance that contains the pointer, so having the instance point to itself seems silly.

Personally, I don't think you understand pointers, so you shouldn't be trying to (mis)use them. At least not yet, and not this way.

OK I got confused with respect to the contents of the struct ... Which I might add C refers to a Type all be it with a structure defined by struct The array of types works just fine and the pointers it contains are references to variables outside the array.

When I modified the code, to ask the question, I just left the structure the same. not clever I will admit.

Obviously If I were iterating through instances of structs/types I would have had to start somewhere and that somewhere would have been a pointer to an instance of that struct. When I find the instance of the struct I want, the one with the matching text in its Name[] member, I would have the correct pointer and could then access its Value member.

And, of course, you can't create a pointer of type anonymous struct. You could create a struct properly, with a name, and then define a pointer of type struct someName.

Anonymous struct - It isnt ... I grant you in C the construct is different. In C

struct MyType{                                 // Definition of the structure of a new type, MyType
  float Value;
  char Name[];
} BatVolts;                                       // A new variable of type, BatVolts,  MyType
                                                     // Or
MyType AcVolts                                // A new variable, AcVolts,  of type MyType

And in Arduino AVR

typedef struct{                                 // Definition of the structure of a new type, MyType
  float Value;
  char Name[];
} MyType;                                        //Most confusing .... Type Name not Instance name, go figure
                                                     // Or
MyType BatVolts                               // A new variable, BatVolts,  of type MyType
MyType AcVolts                                // A new variable, AcVolts,  of type MyType

And the pointer ... (Assume Type Def from above)

MyType * PtrMyTypes;
PtrMyTypes = & BatVolts;                  // I have a pointer to BatVolts which is the first instance of MyType
PtrMyTypes++                                  // Now I have a pointer to the second instance of MyType which is AcVolts

Serial.println((* PtrMyTypes).Value)     // prints the value member of AcVolts
Serial.println(PtrMyTypes->Value)        // So does this alternative construct

This is working ... All I need to know now is ... Is the first instance of a type/struct in memory always the first one that was defined? If not is there a way to get a pointer to the first, the first in memory that is?

The compiler will not permit incrementing the pointer to a 'value/insatace count' that inst valid but I doubt that if I were to have a loop doing the incrementing that the compiler would pick that up. Is there a way to check before I crash the program?

Is the first instance of a type/struct in memory always the first one that was defined?

Does it matter? You still need to maintain a pointer to it, or you won't find it.

You can't just search through memory for an instance of your structure. You can't tell from looking at a byte of memory what that memory contains. It's all just a collection of bits.

If not is there a way to get a pointer to the first, the first in memory that is?

No. You need to define a pointer and initialize it yourself.

The compiler will not permit incrementing the pointer to a 'value/insatace count' that inst valid but I doubt that if I were to have a loop doing the incrementing that the compiler would pick that up.

Incrementing a pointer only makes sense when the pointer points to an array of items. If you create discrete instances, even if they are adjacent in memory, you can't iterate through the instances by incrementing a pointer.

Making assumptions about how variables will be stored in memory is a very dubious practice. Just delare an array of your structs. You should know at compile time how many there are and you can iterate through them looking for the named variable without any need for a pointer.

While you're at it, you'll need to give your name array a size too.

Making assumptions about how variables will be stored in memory is a very dubious practice.

I thought as much which is why I asked ... However it appears to be working, all be it with a simple test. I purposely defined other stuff between the instances that I am iterating through in an attempt to break it. If anyone thinks that global variables will move in memory for some reason I would be interested to understand.

Does it matter? You still need to maintain a pointer to it, or you won't find it.

What's wrong with the first one as, for want of a better description, a base address?

Incrementing a pointer only makes sense when the pointer points to an array of items. If you create discrete instances, even if they are adjacent in memory, you can't iterate through the instances by incrementing a pointer.

It would appear not ... output below code!

typedef struct{                                          // Definition of Type structure for xVar
  String Name;
  float Value;
}xVar;

xVar BatVolts;                                            // New instance of xVar, first instance
int JustJunk1 = 10;                                     // Junk to ensure that the two instances of xVar are not together, at least logically, who knows what the compiler does.
int JustJunk2 = 32000;
xVar AcVolts;                                             // New instance of xVar
xVar *PtrxVar = &BatVolts;                          // pointer to BatVolts, the first instance of xVar


void setup() 
{
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  Serial.begin(9600);
  Serial.println("");
  
  BatVolts.Name = "BatVolts";                       // Stick some values in so I have something to print
  BatVolts.Value = 12.5;
  AcVolts.Name = "AcVolts";
  AcVolts.Value = 236;

  Serial.print(BatVolts.Name);                      // Print BatVolts values just to check
  Serial.print("  >>  ");
  Serial.println(BatVolts.Value);
  Serial.println("");

  Serial.print(PtrxVar->Name);                    // Print BatVolts values again, this time using the pointer as a reference
  Serial.print("  >>  ");
  Serial.println(PtrxVar->Value);                   
  Serial.println("");
  
  PtrxVar = PtrxVar++;                               // Increment the pointer, +1 works just as well.
  Serial.print(PtrxVar->Name);                    // Print values using the pointer as a reference, this should be AcVolts, and it is
  Serial.print("  >>  ");
  Serial.println(PtrxVar->Value);
  Serial.println("");  


  PtrxVar--;                                             // Decrement the pointer, -1 works just as well.
  Serial.print(PtrxVar->Name);                    // Print values using the pointer as a reference, this should be BatVolts again
  Serial.print("  >>  ");
  Serial.println(PtrxVar->Value);
}

void loop() 
{  
digitalWrite(13,!digitalRead(13));
delay(250);
}

The result ...

BatVolts >> 12.50

BatVolts >> 12.50

AcVolts >> 236.00

BatVolts >> 12.50

I am new at this and know very little, if this is likely to break when it is just part of a bigger program, as opposed to an isolated test, that is something I need to know about but as you can see it works.

Please feel free to pull it to pieces so I can learn ... Comments earlier, even the negative ones, have pointed me in this direction and ultimately got this working.

[ I will not be using the String object in the final version but I thought if it worked with that then it would probably work with anything. ]

I mean this in a light-hearted but serious manner.

Dyslexicbloke:

Making assumptions about how variables will be stored in memory is a very dubious practice.

I thought as much which is why I asked … However it appears to be working, all be it with a simple test.

This means you got lucky, is all.

Seriously, this is pure luck that you can’t rely on. The danger is to translate “luck” into “learning”, because you’ve ended up handicapping yourself in the future.

Making assumptions about how variables will be stored in memory is a very dubious practice.

100% correct. Your code should be reliable, not lucky.

Incrementing a pointer only makes sense when the pointer points to an array of items. If you create discrete instances, even if they are adjacent in memory, you can’t iterate through the instances by incrementing a pointer.

Yes, you discovered that the second part of what was said here is not technically correct, but please understand it’s 100% correct in spirit.

Incrementing pointers only works as expected when the things that are being pointed to are adjacent in memory. Arrays force this behaviour. It’s reliable. Therefore, “Incrementing a pointer only makes sense when the pointer points to an array of items” is correct in all aspects.

You did get a good lesson, that you yourself predicted:

xVar BatVolts;                                            // New instance of xVar, first instance
int JustJunk1 = 10;                                     // Junk to ensure that the two instances of xVar are not together, at least logically, who knows what the compiler does.

"who knows what the compiler does."

You got that exactly right. Combine this with what you were told before and turn it into a mantra — “Don’t make assumptions about how variables will be stored in memory. Who knows what the compiler does.”

In this case what would seem “logical” didn’t pan out. The compiler did some optimization and decided that your “logically” wasn’t logical, and rearranged the order of variables. It just happened to place the two structs next to each other.

This is what I mean when I said you got lucky.

Anyhow, I hope this is taken in the friendly spirit that’s intended.

I'd like to point out something else that's dangerous, while we're on the topic.

xVar *PtrxVar = &BatVolts;

This should be initialized in the setup() method. Again, the luck thing.

I got careless just a couple days ago and did something similar. I banged my head against the wall for ten minutes while my servos were doing the cha cha.

Back to the original question:

Dyslexicbloke:
I currently have an array of structs tht I need to iterate through.

Is this the right approach or should I be creating structs and indexing through their pointers without the array?

The general rule:

Create an array of structs and loop through them using the array’s index.

This creates code that is both readable and less error-prone.

Off the top of my head:

struct Volts {
  float Value;
  char* Name;
};

static const int VoltListCount = 2;
Volts voltList[VoltListCount] = {
  {6, "DC"},
  {120, "AC"}
};

void setup() {
  for(int i=0; i<VoltListCount; i++) {
    if(voltList[i] ...
    ...

Dyslexicbloke: NB. There is a separate thread asking about the use of String, I don't want to get into that in this thread as the two things are separate, at least in my head they are.

...   
typedef struct{
  String Name;                                                                
  float * Ptr;
}xVar;

So you don't want me to go on about how using String here is a bad idea? Plus all the other places?

starforgelabs, points well understood and accepted in the spirit that they are offered

I have absolutely no issue with being told when I am wrong, even less being told I'v been lucky. What is a little hard to take is unqualified comments ... You cant do that / You don't understand ...

Don't get me wrong I do not think for a second that I am entitled to or 'deserve' answers, but it gets a little frustrating when some one takes the time to tell me how badly wrong I am without telling me why.

I will go back to my original concept which was an array of types, one member of which is a pointer to a variable that I want refer to by name at runtime.

Can you help me understand this pointer issue a bit further ... You seem to be saying that I should never increment/decrement pointers because I cant know what is where and cant therefore rely on the information I will get back. This is because unless the variable is part of an array its location will chance even if its instance is never destroyed once its been created.

Is that correct, It seems counter intuitive ... Am I missing something? Also why memory allocated to a global variable change in the first place?

Nick, I would very much welcome you going on about It .. Providing you were telling me how to do things as opposed to how not to. I have had some advice already, some from you too I think ... There has been so much. This page http://www.cplusplus.com/reference/clibrary/cstring/ was suggested and I think it will be what I need for now. If I have any issues I will post specific requests for help. That said If there is anything I need to know in order to use the functions on that Page please feel free to put me right

Sadly, memory allocation has bugs at present. Boilerplate:

Please note that, at present, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.).

Even if you code perfectly, the memory bugs will bite you.

I would be happy to make constructive suggestions if I had a better idea of what you are trying to do with your code.

Dyslexicbloke: Can you help me understand this pointer issue a bit further ... You seem to be saying that I should never increment/decrement pointers because I cant know what is where and cant therefore rely on the information I will get back. This is because unless the variable is part of an array its location will chance even if its instance is never destroyed once its been created.

Is that correct, It seems counter intuitive ... Am I missing something? Also why memory allocated to a global variable change in the first place?

Pointers hold the memory location of a piece of data. If you have a pointer to a char, then it holds the address of the memory location where a char is stored. You can alter the value of the char and that is fine - the storage location does not change, the pointer does not change.

When you increment a decrement a pointer, you are changing it to refer to a memory location which is adjacent to the original location. The compiler promises to keep elements of an array next to each other, so it is legitimate to use pointer arithmetic to refer to adjacent elements of the array - as long as you avoid going past the end of the array. But if the thing pointed to is not within an array, you the programmer have no way of knowing what is stored next to the original storage location. In that case, incrementing/decrementing the pointer is wrong - you would be changing it to point to an arbitrary piece of memory that you have no reason to assume holds anything in particular.

Having said all that, you do not need to use pointer arithmetic at all to do what you're doing. You will have an array of structs, and each struct will contain a name and a pointer to a variable. You can access each element of the array using foo [ i ] notation so there is no need for pointer arithmetic, and when you come to dereference the pointer you will just use the '*' operator.

Will all your variables be of the same type? If not, your structure ought to hold multiple pointers (one for each type you need to support) of which only one would be non-null for a given item.

and each struct will contain a name and a pointer to a variable.

Even simpler, of course, is for each instance of the struct to contain a name and a value, rather than a pointer to the value.

How your example code with the incremented pointer ever worked was bothering me on the drive home. It did, I now suspect, because your junk variables are never used for anything and the compiler was able to optimize them away. Use them for something in the code somewhere and I imagine your example will stop working.