Почему мой массив char пуст

следующий скетч будет работать совершенно нормально и, как и ожидалось :

#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);
}

Однако если я заменю ExtEEPROM.put(0 + sizeof(username), "greatnewpassword"); на ExtEEPROM.put(0 + sizeof(username), password);, то yyy печатает пустой в последовательном мониторе. Почему?

, 👍2

Обсуждение

Попробуйте сделать последовательную печать пароля, чтобы увидеть, сделал ли вызов toCharArray то, что он должен был сделать., @Nick Gammon

OT: Не пишите any_boolean == false, используйте !any_boolean. Если вы думаете, что думаете, вы должны убедиться, что кто-то понимает, тогда я бы рекомендовал (any_boolean == false) == true.: - D, @the busybee

OT: sizeof - это оператор, а не функция, поэтому используйте sizeof variable. Однако его операндом может быть тип, и тогда он нуждается в круглых скобках по синтаксическим причинам. Это приводит к этой вездесущей вредной привычке писать его как функцию., @the busybee

Вы уверены, что ставите фактический _array_ password, а не указатель, созданный его распадом (например, char *foo = password; ExtEEPROM.put (..., foo);)?, @Edgar Bonet

256kbit-это не 256000 бит. Это 256 * 1024 бита, или 262144., @Majenko


3 ответа


Лучший ответ:

1

проблема, похоже, в том, что я использую lib. Я думаю, что он не может обрабатывать данные, перекрывающие размер страницы.

если я заменю это

char username[33] = "";
char password[65] = "";

к этому:

char username[16] = "";
char password[16] = "";

все работает нормально, так как он сохраняет и считывает данные с EEPROM через I2C.

,

разговор был [перенесен на chat](https://chat.stackexchange.com/rooms/134577/discussion-on-answer-by-musa-why-is-my-char-array-empty)., @Juraj


1

.get и .put передают указатель char, а не содержимое массива char. Таким образом, вы записываете не содержимое строки, а адрес в памяти, где она хранится.

С помощью строкового литерала, который фиксирован и никогда не меняется, так что то, что вы пишете, и то, что вы читаете, прекрасно. Однако с переменной адрес может быть любым, и хранить адрес некоторой оперативной памяти, где хранится строка, бессмысленно.

.get() и .put() следует использовать только для атомарных, автономных типов, таких как int или float, а не для указателей, таких как char *.

Вместо этого вам нужно использовать функции .read(address, buffer, size) и .write(address, buffer, size) для чтения и записи содержимого ваших массивов символов.

,

В коде операции get() и put() передаются фактические массивы, а не указатели. Поскольку массивы передаются _ by reference_, они не распадаются на указатели., @Edgar Bonet


2

Как уже упоминает Маенко:

.get() и .put() следует использовать только для атомарных, автономных типов, таких как int или float, а не для указателей, таких как char *.

Не уверен, что здесь означает atomic, но вы можете .put и .get любой тип данных, особенно 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); 
   ...
}

Конечно, если тип данных является указателем или строковым объектом (содержащим только указатель), вы не будете довольны .put / .get

,

Под атомарным я подразумеваю "это вещь полная в себе". Структура завершена. Int завершен. Char * не является полным, так как он не содержит данных, это всего лишь указатель на них. Так что это не "атомно". То же самое относится и к строковому объекту, поскольку объект не содержит строковых данных, а только указатель на выделенную память, содержащую строковые данные., @Majenko