Есть ли объяснение такому поведению?

Для приведенного ниже фрагмента кода

const char* fr_fbdb(char tag[30]) // fn для извлечения данных 
{
  char full_path[120]; 
  const char *_dt ; 
  strcpy(full_path , base_path);
  strcat(full_path , tag);
  Serial.print( "retrieving from " ); 
  Serial.println(full_path) ; 
  Firebase.get(firebaseData, full_path);
  _dt = firebaseData.cstrData();
// Serial.print("while ext: "); 
// Serial.println(_dt); 
  return _dt ; 
} 

void retreive_sch()
{
  int no_tag = strlen(*tag) ;
  //Serial.print("количество тегов в БД: ");
  //Serial.println(no_tag);
  const char *_data[no_tag];


  Firebase.get(firebaseData, "/SCHEDULE DETAILS/SELECTED");
  sch_no = firebaseData.cstrData();

  Serial.print("extracting schedule");
  Serial.println(sch_no);

  strcat(base_path , sch_no); // базовый путь w/ sch no.

  for (int i = 0 ; i < 6 ; i++) 
  {
    _data[i] = fr_fbdb(tag[i]); 
    Serial.print("while ext: "); 
    Serial.println(_data[i]);  
    
  }

  for(int i=0 ; i<6 ; i++)
  {
    Serial.print("after extraction:"); 
    Serial.println(_data[i]) ;
  }
}

Вот результат:

retrieving  schedule changes -- setup 
extracting schedule3
retrieving from /SCHEDULE DETAILS/SCHEDULE3/DATE
while ext: [1609612200000,\"inf\"]
retrieving from /SCHEDULE DETAILS/SCHEDULE3/FREQ FR
while ext: \"-2\"
retrieving from /SCHEDULE DETAILS/SCHEDULE3/FREQ TO
while ext: \"-2\"
retrieving from /SCHEDULE DETAILS/SCHEDULE3/WEIGHT
while ext: 29
retrieving from /SCHEDULE DETAILS/SCHEDULE3/TIME
while ext: \"6:30\"
retrieving from /SCHEDULE DETAILS/SCHEDULE3/frequency
while ext: \"-1\"
after extraction:"root":[]
after extraction:\"-1\"
after extraction:keep-alive
after extraction:\"-1\"
after extraction:"root":[]
after extraction:\"-1\"

Как вы можете видеть, вывод одной и той же переменной _data[] внутри этой конкретной функции изменяется. Есть идеи, почему?

, 👍0

Обсуждение

Я бы посоветовал вам взять книгу о C++ и понять, как использовать const, что происходит и область действия локально объявленной переменной внутри функции., @hcheung

`_data - это глобальный var, и оба набора операторов печати находятся в одном и том же Fn. Я использовал const char* fr_fbdb bcos firebaseData.cstrData() возвращает c-строку. Вот как я думал, что поток будет: я вызываю retrieve_sch () в setup (). Тогда я получаю "нет". из тегов из strlen(*tag) (tag содержит строки , такие как ДАТА, ВЕС и т. Д.). Затем, используя цикл for, который вызывает fr_fbdb()` n раз, получите req. Теги. Я также печатаю значение, которое было получено здесь и в цикле for ниже. Пожалуйста, укажите, где могут быть недостатки., @Somasundharam Sampath

_dt - это локально объявленная переменная, ее область действия остается локальной, и когда вызов возвращается из функции, все, что хранится в _dt, может быть освобождено и память может быть переопределена., @hcheung

"_data" имеет значение, возвращаемое функцией `fr_fbdb (), что подтверждается операторами print в 1-м цикле for ` retreive_sch (). Во втором цикле for `retreive_sch() тот же var, _data дает разные значения. Я утверждаю, что если бы существовал pblm (bco области действия переменных), то он должен был быть показан в первом операторе печати. (Если вы еще не заметили, я прокомментировал операторы печати в fr_fbdb()`), @Somasundharam Sampath


1 ответ


1

Проблема заключается в следующих строках кода в вашей функции fr_fddb():

  Firebase.get(firebaseData, full_path);
  _dt = firebaseData.cstrData();

Вы не поделились достаточным количеством кода, чтобы прояснить это, но firebaseData, по-видимому, является глобальным, который вы повторно используете. Когда вы вызываете его метод .cstrData (), вы каждый раз получаете указатель на один и тот же буфер, и этот буфер перезаписывается каждый раз, когда вы вызываете Firebase.get().

Вы можете проверить это, печатая значение указателя каждый раз, как это делается в вашей функции retrieve_sch ():

  for (int i = 0 ; i < 6 ; i++) 
  {
    _data[i] = fr_fbdb(tag[i]); 
    Serial.print("while ext: "); 
    Serial.println(_data[i]);  
    Serial.printf("_data[i] pointer %p\n", _data[i]);
  }

Скорее всего, вы увидите, что 6 указателей идентичны. Значение меняется, потому что вы продолжаете повторно использовать одну и ту же строку.

Простое решение заключается в следующем:

  Firebase.get(firebaseData, full_path);
  _dt = strdup(firebaseData.cstrData());

Это выделяет память и сохраняет в ней дубликат строки, полученной из Firebase. Теперь ваша функция вернет это, и firebaseData можно будет безопасно использовать повторно.

Это решение потребует от вас освободить эту память в какой-то момент, когда вы используете ее, вызвав free(_dt); или что бы вы ни держали указатель, когда закончите. Я оставляю это как упражнение для вас.

,