Store a struct in EEPROM...why the indexing fails?

Hi all!

I want to store several struct instances at the internal EEPROM memory, for testing I wrote this code:

#include <avr/eeprom.h>

struct settings_t
{
  uint8_t first;
  uint8_t second;
  uint8_t third;
} settings;


void setup()
{ 
  Serial.begin(9600);
  delay(100);
  
  for (int i=0;i<2;i++){
    settings.first = 'A';
    settings.second = 'B';
    settings.third = 'C';
    eeprom_write_block((const void*)&settings, (void*)i, sizeof(settings)); }
    delay(10);

 
}

void loop()
{
  for (int j=0;j<2;j++){
  eeprom_read_block((void*)&settings, (void*)j, sizeof(settings));
  
  Serial.write(settings.first);
  Serial.write(settings.second);
  Serial.write(settings.third);
  Serial.println();
 
  }
  
  delay(1000);
}

For some reason the print of this code get me this:

AAA
AAA
AAA
AAB
ABC

What can be wrong?

In fact what I'm looking for are two functions to save/restore my struct by indexing several instances:
(Is like to have a struct mystruct[100] but not in RAM stored in EEPROM).

void WriteEntry(struct settings_t structure,uint8_t Index){}

struct settings_t ReadEntry(uint8_t Index){}

Best Regards!
Frank

void setup()
{
...
eeprom_write_block((const void*)&settings, (void*)(i * sizeof(settings)), sizeof(settings)); }
...
}

void loop()
{
...
eeprom_read_block((void*)&settings, (void*)(j * sizeof(settings)), sizeof(settings));
...
}

Sonow the functions looks like this:

void WriteEntry(struct RoutingTable structure,uint8_t Index){ 
    RoutingTableEntry = structure; 
    eeprom_write_block((const void*)&RoutingTableEntry, (void*)(Index 
* sizeof(RoutingTableEntry)), sizeof(RoutingTableEntry)); 
} 

struct RoutingTable ReadEntry(uint8_t Index){ 
    eeprom_read_block((void*)&RoutingTableEntry, (void*)(Index * 
sizeof(RoutingTableEntry)), sizeof(RoutingTableEntry)); 
    return RoutingTableEntry; 
}

But the structure definition is this:

    struct RoutingTable 
    { 
        uint8_t      dest;      
        uint8_t      next_hop;  
        uint8_t      state;     
    } RoutingTableEntry;

Now can I declare it and operate it as a typedef?, like this:

    typedef struct
    {
	uint8_t      dest;  
	uint8_t      next_hop; 
	uint8_t      state;  
    } RoutingTableEntry;

What I need to re-declare?
Best Regards!!
Frank

You can define it as a named struct, or a typedef, or both. In my opinion it is better to refer to the type using a typedef (so that it behaves consistently with the standard types and classes) in which case the struct name is redundant and it can be left anonymous. Others may have other preferences.

The code below defines a struct RoutingTableEntry - you can use struct RoutingTableEntry anywhere in your code that needs a type.

// defined as a struct
struct RoutingTableEntry
{ 
    uint8_t      dest;      
    uint8_t      next_hop;  
    uint8_t      state;     
}; 
struct RoutingTableEntry myEntry;

The following code defines the struct RoutingTableEntry but also defines a typedef RoutingTableEntry. This means you can use RoutingTableEntry anywhere a type is needed; it is syntactically equivalent to struct RoutingTableEntry. The name of the struct and the typedef don't need to be the same, and some people prefer to make them different.

// defined as a typedef and a named struct
typedef struct RoutingTableEntry
{ 
    uint8_t      dest;      
    uint8_t      next_hop;  
    uint8_t      state;     
} RoutingTableEntry ; 

struct RoutingTableEntry myEntry1; // uses the struct declaration
RoutingTableEntry myEntry2; // uses the typedef

The following code defines the struct without giving it a name (it is left anonymous) and then defines a typedef for it the anonymous struct. This means that you can use RoutingTableEntry anywhere a type is needed.

// defined as a typedef and anonymous struct
typedef struct 
{ 
    uint8_t      dest;      
    uint8_t      next_hop;  
    uint8_t      state;     
} RoutingTableEntry ; 

// struct RoutingTableEntry myEntry1; // we didn't name the struct so we can't refer to it
RoutingTableEntry myEntry2; // uses the typedef to refer to the anonymous struct

Hi Peter!
The only way that I fount to get it work is this:

typedef struct RoutingTableEntry
    { 
        uint8_t      dest;      ///< Destination node address 
        uint8_t      next_hop;  ///< Send via this next hop address 
        uint8_t      state;     ///< State of this route, one of RouteState 
    } RoutingTableEntry;

And...

struct RoutingTableEntry ReadEntry(uint8_t Index){ 
    RoutingTableEntry mytable;
    eeprom_read_block((void*)&mytable, (void*)(Index * sizeof(RoutingTableEntry)), sizeof(RoutingTableEntry)); 
    return mytable; 
}


void WriteEntry(struct RoutingTableEntry structure,uint8_t Index){ 
    eeprom_write_block((const void*)&structure, (void*)(Index * sizeof(RoutingTableEntry)), sizeof(RoutingTableEntry)); 
}

I don't know why but the only way that I can pass the struct at the function call is declaring both times as RoutingTableEntry.
The code is working but it's wrote in the correct way?

I have others lines like this:

uint8_t RF22Router::route(RoutedMessage* message, uint8_t messageLen)
{
    // Reliably deliver it if possible. See if we have a route:
    uint8_t next_hop = RF22_BROADCAST_ADDRESS;
    if (message->header.dest != RF22_BROADCAST_ADDRESS)
    {
	RoutingTableEntry* route = getRouteTo(message->header.dest);
	if (!route)
	    return RF22_ROUTER_ERROR_NO_ROUTE;
	next_hop = route->next_hop;
    }

    if (!RF22ReliableDatagram::sendtoWait((uint8_t*)message, messageLen, next_hop))
	return RF22_ROUTER_ERROR_UNABLE_TO_DELIVER;

    return RF22_ROUTER_ERROR_NONE;
}

I think that message->header.dest means that it evaluate the dest variable from the message's header rigth?
And this:
next_hop = route->next_hop;
This loads the next_hop element...but where goes that value? looks that never store it?

Best Regards!!
Frank

its c++, the typedef on struct is really not necessary for specifying types.

struct RoutingTableEntry
    { 
        uint8_t      dest;      ///< Destination node address 
        uint8_t      next_hop;  ///< Send via this next hop address 
        uint8_t      state;     ///< State of this route, one of RouteState 
    };

RoutingTableEntry myObject;

you will also probably want to pass by reference not value, especially if you want the address of operator to return the original pointer not the one for the temporary

void WriteEntry( RoutingTableEntry &structure,uint8_t Index){ 
    eeprom_write_block((const void*)&structure, (void*)(Index * sizeof(RoutingTableEntry)), sizeof(RoutingTableEntry)); 
}

EDIT: To be safer you should pass a const pointer, as this is all your function needs.