Trouble reading/writing struct to and from EEPROM using put/get

Hi all,

I am rather new to Arduino programming and would like your guidance on a problem I am facing with writing and reading structs to EEPROM using put/get.

Here is a brief overview of what I am trying to do:
I have added an OLED screen to a Pro Trinket board (ATmega 328) and am trying to create a simple sketch that adds/browses todo items. The user inputs the text using a 5-way navigation switch and he can later on scroll through the items. Each item has an id, a title and the content.

Here is how I declared my struct:

typedef struct Todo {
  uint8_t id;
  char title[10];
  char todo_content[20];
};

And here is the function that handles the text input:

void text_input(char input[], char *temp)
{
  uint8_t position = 0;
  uint8_t i;
  
  oled.clearDisplay();
  display_text("Enter text",1,0,0);

  while( 1 == 1 )
  {

    if (digitalRead(BTN_UP) == LOW)
    {
      if( input[position] < 127 )
        input[position] = input[position]+1;
       
      delay(MENU_DELAY);
    }

    if (digitalRead(BTN_DOWN) == LOW)
    {
      if( input[position] > 33 )
        input[position] = input[position]-1;
       
      delay(MENU_DELAY);
    }

    if (digitalRead(BTN_RIGHT) == LOW)
    {
      if( position < strlen(input)-1 )
        position++;
       
      delay(MENU_DELAY);
    }

    if (digitalRead(BTN_LEFT) == LOW)
    {
      if( position > 0 )
        position--;
       
      delay(MENU_DELAY);
    }

    if (digitalRead(BTN_CLICK) == LOW)
    {
      return;
    }
    
    for( i = 0; i < strlen(input); i++)
    {
      if( position == i )
      {
        oled.setTextSize(2);
        oled.setTextColor(BLACK,WHITE);
        oled.setCursor((i*12)+1,17);
        oled.println(input[i]);
      }
      else
      {
        oled.setTextSize(2);
        oled.setTextColor(WHITE,BLACK);
        oled.setCursor((i*12)+1,17);
        oled.println(input[i]);
      }
      temp[i] = input[i];
    }

    oled.display();
  }
}

where input is the initial text (sample text) and temp is the char array to fill (since I cannot return a char array from a function as I found out). Ignore the oled* and display_text() stuff, it is used to output to the screen.

Now here is the function that stores the struct:

void on_menu_add(MenuComponent* p_menu_component)
{
  oled.clearDisplay();
  display_text("Add item",1,0,0);

  char temp[11];

  text_input("my todo", temp);

  Todo new_todo = {
    1,
    "get milk",
    temp
  };

  EEPROM.put( EEPROM.read(TODO_CNT)+20, new_todo);
}

As you can see, I am trying to use the temp variable, filled by the text_input function in the struct, which I later write to the EEPROM using EEPROM.put.
However, this does not seem to be working exactly as I thought (seasoned Arduino programmers probably already know what I am doing wrong...) since if I use EEPROM.get like so:

void on_menu_browse(MenuComponent* p_menu_component)
{
  oled.clearDisplay();
  Todo get_todo;
  EEPROM.get(20, get_todo);
  oled.setTextSize(1);
  oled.setTextColor(WHITE);
  oled.setCursor(0,0);
  oled.println(get_todo.id);
  oled.setCursor(0,9);
  oled.println(get_todo.title);
  oled.setCursor(0,17);
  oled.println(get_todo.content);
  oled.display();
  delay(4000);
}

I can get the id and title, but not the content, which comes as a single garbage like character (using strlen() reports a length of 1 too).
I am 90% certain I am doing something wrong while creating the struct, but I can't figure out what it is. If anyone can point me in the right direction, that would be great!

P.S. Pro Trinket does not have a Serial monitor, so I can only debug by writing stuff on the screen...

You got into the trap of C arrays vs. pointers. Although you make a struct that reserves a few bytes for the byte array, if you assign a byte array to the struct part, you just have a pointer to that byte array in the struct. To circumvent this program a serialize function for your struct that make a string from the complete content.
Another way to circumvent it (not what I would suggest!):

  Todo new_todo = {
    1,
    "get milk",
    "dummy"
  };
  strncpy(new_todo.todo_content, temp, 20);

But that way you store unused bytes that may hold any other content. And you might step into the same trap next time... :wink: