Използването на метод 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