Failure to recall and print Value from namespace using Preference.h

I wanted to save wifi credentials from an input. I recieve ssid and password as input, save them in namespace and I can recall them both with "print". But on restart i can only recall the ssid but not the password and instead a blank is printed.

void setup()
{ 
  preferences1.begin("ssdcreden", false); //space for saving credentials
  preferences2.begin("passcred", false); //space for saving credentials

if (before restart){
  setuppage();}

if (after restart){
  initialize();}
}

Where setuppage() is

    Serial.println("Input 1 recieve" + inputParam1 + ": " + inputMessage1);
    Serial.println("Input 2 recieve"+ inputParam2 + ": " + inputMessage2);
    preferences1.putString("ssid_final", inputMessage1 ); 
    preferences2.putString("password_final", inputMessage2);

    Serial.println("SSID Saved" + preferences1.getString("ssid_final")); //printed in terminal    
    Serial.println("password Saved" + preferences2.getString("password_final")); //printed in terminal  

and initialize() is

  const char * ssid2 = preferences1.getString("ssid_final").c_str();
  const char * password2 = preferences2.getString("password_final").c_str(); 

   Serial.println(password2); // not being printed afetr restart.
   Serial.println(ssid2); // being prinetd after restart.

Any clues to why thsi might be happening?

getString most likely returns temporary string and then you take pointer to its data, which gets invalidated at the end of expression.

1 Like

getString(const char* key, char* value, size_t maxLen);

is a function of the Preference.h Library. I doubt it is returning a temp value.

unless the string created inside the function is created on the heap or declared static, it is pretty much temporary, as it gets destroyed when function exits, and it exits at the end of expression

1 Like

yes, but the whole purpose of the library I am using is to make sure the string gets saved permanently on ESP32

it may well be saved permanently on ESP32 but the library doesn’t give you the reference to that string it gives you copy that expires at the end of expression, and you take a pointer to that copy.

1 Like

Why do you need pointer here ^^^^

1 Like

Yes, you might be right. But whatever you are saying is bouncing right off of my head.

But I did try to narrow my problem down.

Serial.println(preferences1.getString("ssid_final")); //This works even after restart

However, this does not work.

const char * ssid2 = preferences1.getString("ssid_final").c_str();
Serial.println(ssid2);

What am I doing wrong?

and thank you for your time.

@ killzone_kid is correct.

From Preferences.h:

String getString(const char* key, String defaultValue = String());

So the function is returning a string on the Stack. So it is indeed a temporary value (an rvalue). This means your usage:

const char * password2 = preferences2.getString("password_final").c_str(); 

will have undefined results as you are taking the address of the dynamically-created character buffer belonging to the temporary String object. After that statement executes, the temporary String object will be deleted and your pointer will be left pointing to freed memory. Thus, dereferencing it will have undefined results.

1 Like

save return of getString into String variable first, this way the value will still exist when you use c_str on it

String blah = whatever.getString(….;
const char *name = blah.c_str();
… println(name)….

1 Like

It also appears that you're not doing an exception handling (as required by good programming practices) in case getString() does not find the specified key. That can make your application unreliable.

1 Like

Wow. Thank you. It worked.

Since you know your way around this problem, can you point me to some resources where I can learn this? I will be really thankful.

Thank you for your input. Can you please point me to some resources or documentation where I can learn this? I will be really thankful.

Just get yourself a good c++ book or course, especially if you want to continue with things like Arduino

1 Like

There is a pretty good tutorial on using Preferences to store key/value pairs on the ESP32 here
https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/

They have an example for network credentials, which demonstrates

  1. how the return value of getString() needs to be assigned to a String.
  2. some basic error checking on the returned String. If you look at the library source code you will see that if the key is not found, or if there is nothing stored at the key an empty String is returned by getString().
#include <Preferences.h>
#include "WiFi.h"

Preferences preferences;

String ssid;
String password;

void setup() {
  Serial.begin(115200);
  Serial.println();
  
  preferences.begin("credentials", false);
 
  ssid = preferences.getString("ssid", ""); 
  password = preferences.getString("password", "");

  if (ssid == "" || password == ""){
    Serial.println("No values saved for ssid or password");
  }
  else {
    // Connect to Wi-Fi
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid.c_str(), password.c_str());
    Serial.print("Connecting to WiFi ..");
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print('.');
      delay(1000);
    }
    Serial.println(WiFi.localIP());  
  }
}

void loop() {
  // put your main code here, to run repeatedly:
}
1 Like