user82014: following sketch will run totally fine and as expected :
#include <Wire.h>

#include "SparkFun_External_EEPROM.h"
ExternalEEPROM ExtEEPROM;
char username[33] = "";
char password[65] = "";

void setup()
{
  Serial.begin(115200);
  delay(1000);
  Wire.begin();
  #define EEPROM_ADDRESS 0b1011000 // 0x58
  ExtEEPROM.setMemorySize(256000/8); // 256kbit = 32kbyte
  ExtEEPROM.setPageSize(64); // 64 byte page size.
  ExtEEPROM.enablePollForWriteComplete();
  ExtEEPROM.setPageWriteTime(10); // max. ms for AT24C128
  if (ExtEEPROM.begin(EEPROM_ADDRESS, Wire) == false) 
  {
    Serial.println("No memory detected. Freezing.");
    while (1);
  }
  Serial.println("Memory detected!");

  String uuu = "myusername";
  String ppp = "mypassword";

  uuu.toCharArray(username, sizeof(username) - 1);
  ppp.toCharArray(password, sizeof(password) - 1);
  Serial.print("password=");Serial.println(password);
  ExtEEPROM.put(0, username);
  //delay(100);
  ExtEEPROM.put(0 + sizeof(username), "greatnewpassword");
}
  
void loop() {
  char xxx[33] = "";
  ExtEEPROM.get(0, xxx);
  Serial.print("xxx=");Serial.println(xxx); // prints the username

  char yyy[33] = "";
  ExtEEPROM.get(0 + sizeof(username), yyy);
  Serial.print("yyy=");Serial.println(yyy); // prints the password
  delay(1000);
}

However, if I replace ExtEEPROM.put(0 + sizeof(username), "greatnewpassword"); to ExtEEPROM.put(0 + sizeof(username), password);, then yyy prints empty in the serial monitor. Why?

user4143: .get and .put are being passed a char pointer, not the contents of a char array. Thus you're not writing the content of the string but the address in memory where it's being stored.
With a string literal that is fixed and never changes, so what you write and what you read are fine. With a variable though the address could be anything, and storing the address of some RAM where a string is stored is pointless.
.get() and .put() should only be used for atomic, self-contained, types like int or float, not pointers like char *.
Instead you need to be using the .read(address, buffer, size) and .write(address, buffer, size) functions to read and write the contents of your char arrays.

user82014: problem seems to be the lib I am using. I think it can not handle data overlapping page size.
if I replace from this
char username[33] = "";
char password[65] = "";

to this:
char username[16] = "";
char password[16] = "";

everything works fine as it saves and reads from the EEPROM via I2C.

user16780: As Majenko already mentions:

.get() and .put() should only be used for atomic, self-contained,
types like int or float, not pointers like char *.

Not sure what atomic means here, but you may .put and .get any data type, especially a struct.
struct EPROMData {
  char username[33];
  char password[65];
}; 
EPROMData data {"myusername","mypassword"};

void setup() {
   ...
   ExtEEPROM.put(0,data);
}
void loop() {
   EPROMData d;
   ExtEEPROM.get(0,d);
   Serial.print("user="); Serial.println(d.username); 
   ...
}

Sure, if the data type is a pointer or a String object (containing a pointer only), you won't be happy with .put / .get

82014: <p>following sketch will run totally fine and as expected :</p>
<pre><code>#include &lt;Wire.h&gt;

#include &quot;SparkFun_External_EEPROM.h&quot;
ExternalEEPROM ExtEEPROM;
char username[33] = &quot;&quot;;
char password[65] = &quot;&quot;;

void setup()
{
  Serial.begin(115200);
  delay(1000);
  Wire.begin();
  #define EEPROM_ADDRESS 0b1011000 // 0x58
  ExtEEPROM.setMemorySize(256000/8); // 256kbit = 32kbyte
  ExtEEPROM.setPageSize(64); // 64 byte page size.
  ExtEEPROM.enablePollForWriteComplete();
  ExtEEPROM.setPageWriteTime(10); // max. ms for AT24C128
  if (ExtEEPROM.begin(EEPROM_ADDRESS, Wire) == false) 
  {
    Serial.println(&quot;No memory detected. Freezing.&quot;);
    while (1);
  }
  Serial.println(&quot;Memory detected!&quot;);

  String uuu = &quot;myusername&quot;;
  String ppp = &quot;mypassword&quot;;

  uuu.toCharArray(username, sizeof(username) - 1);
  ppp.toCharArray(password, sizeof(password) - 1);
  Serial.print(&quot;password=&quot;);Serial.println(password);
  ExtEEPROM.put(0, username);
  //delay(100);
  ExtEEPROM.put(0 + sizeof(username), &quot;greatnewpassword&quot;);
}
  
void loop() {
  char xxx[33] = &quot;&quot;;
  ExtEEPROM.get(0, xxx);
  Serial.print(&quot;xxx=&quot;);Serial.println(xxx); // prints the username

  char yyy[33] = &quot;&quot;;
  ExtEEPROM.get(0 + sizeof(username), yyy);
  Serial.print(&quot;yyy=&quot;);Serial.println(yyy); // prints the password
  delay(1000);
}
</code></pre>
<p>However, if I replace <code>ExtEEPROM.put(0 + sizeof(username), &quot;greatnewpassword&quot;);</code> to <code>ExtEEPROM.put(0 + sizeof(username), password);</code>, then <code>yyy</code> prints empty in the serial monitor. Why?</p>
 4143: <p><code>.get</code> and <code>.put</code> are being passed a char pointer, not the contents of a char array. Thus you're not writing the content of the string but the address in memory where it's being stored.</p>
<p>With a string literal that is fixed and never changes, so what you write and what you read are fine. With a variable though the address could be anything, and storing the address of some RAM where a string is stored is pointless.</p>
<p><code>.get()</code> and <code>.put()</code> should only be used for atomic, self-contained, types like <code>int</code> or <code>float</code>, not pointers like <code>char *</code>.</p>
<p>Instead you need to be using the <code>.read(address, buffer, size)</code> and <code>.write(address, buffer, size)</code> functions to read and write the contents of your char arrays.</p>
 82014: <p>problem seems to be the lib I am using. I think it can not handle data overlapping page size.</p>
<p>if I replace from this</p>
<pre><code>char username[33] = &quot;&quot;;
char password[65] = &quot;&quot;;
</code></pre>
<p>to this:</p>
<pre><code>char username[16] = &quot;&quot;;
char password[16] = &quot;&quot;;
</code></pre>
<p>everything works fine as it saves and reads from the EEPROM via I2C.</p>
 16780: <p>As Majenko already mentions:</p>
<blockquote>
<p>.get() and .put() should only be used for atomic, self-contained,
types like int or float, not pointers like char *.</p>
</blockquote>
<p>Not sure what atomic means here, but you may .put and .get any data type, especially a struct.</p>
<pre><code>struct EPROMData {
  char username[33];
  char password[65];
}; 
EPROMData data {&quot;myusername&quot;,&quot;mypassword&quot;};

void setup() {
   ...
   ExtEEPROM.put(0,data);
}
void loop() {
   EPROMData d;
   ExtEEPROM.get(0,d);
   Serial.print(&quot;user=&quot;); Serial.println(d.username); 
   ...
}
</code></pre>
<p>Sure, if the data type is a pointer or a String object (containing a pointer only), you won't be happy with .put / .get</p>
