Использование метода strncat на Arduino выводит ошибочное значение

Мне нужно декодировать и отправить сигнал GPS на удаленный сервер с помощью модуля GSM. Я сгенерировал значения широты и долготы отдельно и объединил их в массив char. Таким образом, я могу легко передать char* последовательному write() модулю GSM. Но эта объединенная строка содержит ошибочные значения. Я проверил декодированные значения, и у них есть реальные числа, но это происходит только тогда, когда я объединяю их в свой массив char. Я запускаю этот код на Arduino Uno:

void loop()
{
  char data[128];
  data[0]='\0';
  initialize();

  strncat(data,getLat(),10);
  strncat(data," ",2);
  strncat(data,getLon(),10);

  Serial.write(data);
  Serial.println();

}

char* getLat(){
  char buffer[10];
  dtostrf(flat, 3, 6, buffer);
  Serial.write(buffer);
  Serial.print(" ");
  return buffer;
}

Вывод выглядит следующим образом: первые два столбца содержат значения, только что напечатанные при вызове getLat() методов (в преобразовании нет ошибок), а последние два значения представляют собой конкатенированную часть.

 6.929772 79.947296    Àb 79.947296
 6.929772 79.947296    6.929772 79.947296
 6.929772 79.947296    6.929772 79.947296
 6.929772 79.947296    6.929772 79.947296
 6.929772 79.947296    6.929772 79tdt
 6.929772 79.947296    6.929772 79.947296
 6.929772 79.947296    6.vtet bztbt
 6.929772 79.947296    6.929772 79.947296

Может кто-нибудь сказать мне, что здесь не так? Заранее спасибо.


person Dinal24    schedule 30.08.2014    source источник
comment
getLat() возвращает адрес автоматической переменной. Этот адрес становится недействительным после возврата из функции, и любое разыменование или даже оценка этого адреса вызывает неопределенное поведение.   -  person WhozCraig    schedule 30.08.2014
comment
Я объявил буфер как переменную кучи. Сейчас вроде нормально. спасибо!   -  person Dinal24    schedule 30.08.2014
comment
Надеюсь, вы использовали умный указатель. Удачи.   -  person WhozCraig    schedule 30.08.2014
comment
Я не очень разбираюсь в указателях. Я пойду через Интернет, чтобы узнать лучшие практики. Если у вас есть какие-либо предложения, я был бы рад услышать.   -  person Dinal24    schedule 30.08.2014
comment
У тебя все хорошо, и важно проявить инициативу. Поищите на этой стороне умные указатели C++. Лучший справочник по C++11 и его предложениям можно найти по адресу cppreference.com. Если вы тратите 30-60 минут в день на чтение о чем-то новом для вас на этом сайте, а затем, работая с тем, что вы узнали в небольших примерах программ, ваши навыки будут процветать. проводить время со своими образцами. оно того стоит, поверьте.   -  person WhozCraig    schedule 30.08.2014


Ответы (1)


Если вы измените свой код на практичный и простой файл «helloworld.cpp» и скомпилируете его с помощью компилятора GNU C++, вы будете предупреждены о проблеме с тем, как вы в настоящее время возвращаете указатель на что-то в куче, которая уничтожается, когда getLat( ) выходит за рамки:

#include <stdio.h>
#include <string.h>

char* getLat();

int main(int argc, char **argv)
{
    char test[20] = {0};
    strncpy(test,getLat(),10);
    fprintf(stdout, "%s\n", test);
    return 1;
}

char* getLat(){
  char buffer[10] = {0};
  memset(buffer,0,sizeof(buffer));
  strcpy(buffer, "Testycole");
  // dtostrf(flat, 3, 6, buffer);
  // Serial.write(buffer);
  // Serial.print(" ");
  return buffer;
}

Компиляция:

$ g++ file.cpp 
file.cpp: In function ‘char* getLat()’:
file.cpp:16:8: warning: address of local variable ‘buffer’ returned [-Wreturn-local-addr]
   char buffer[10] = {0};

Во время выполнения я вижу мусор:

$ a.out
 ��

Быстрое решение, но не обязательно лучшее решение, состоит в том, чтобы выделить переменную буфера в куче, а не в области действия getLat(). Измените код GetLat() следующим образом:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* getLat();

int main(int argc, char **argv)
{
    char test[20] = {0};
    char *heapBuffer = getLat();
    strncpy(test,heapBuffer,10);
    fprintf(stdout, "%s\n", test);
    //delete[] heapBuffer; // C++ deallocation; prevents memory leak.
    free(heapBuffer);    // C deallocation; prevents memory leak.

    return 1;
}


char* getLat(){
  //char *buffer = new char[10]; // C++ allocation
  char *buffer = (char*)malloc(10); // C allocation - to be a C purist.

  memset(buffer,0,sizeof(buffer));
  strcpy(buffer, "Testycole");
  // dtostrf(flat, 3, 6, buffer);
  // Serial.write(buffer);
  // Serial.print(" ");
  return buffer;
}

... это дает лучшие результаты:

$ a.out
Testycole

Не забывайте, что вы должны освободить память кучи, хранящую буферный объект char[10], после того, как вы закончите с ним, иначе у вас будет утечка памяти. :-)

person Community    schedule 30.08.2014