Получение искаженного массива символов, возвращаемого функцией
Я возвращаю массив char[300]
из функции. Если я инициализирую с ним переменную char*
, результат будет искажен, но не в том случае, если я добавлю его к String
. Что дает?
const char* post2 = uploadHourCsv(timeNow,pulseChangeHour) ;
String postS2 = "";
postS2 = uploadHourCsv(timeNow,pulseChangeHour) ;
//const char* post2 = { uploadHourCsv(timeNow,pulseChangeHour) };
if( debug ) {
Serial.print("received in loop() as : [");
Serial.println(post2);
Serial.print("String : [");
Serial.println(postS2);
}
...
char postStr[300] = "";
// populate array
if( debug ) {
Serial.print("postStrCsv generated: ");
Serial.println(postStr);
}
return postStr;
postStrCsv создано: 00000003;3| 0,00;8|17,55;9|17,55;10|18,12;11|16,92;20|93817;22|93789;101|6;время|1559646000;
получено в цикле() как: [000?⸮@⸮⸮?" ⸮⸮?17,55;9|17,58! @0⸮⸮⸮⸮G% @5~`⸮h⸮?⸮⸮
Строка: [00000003;3| 0,00;8|17,55;9|17,55;10|18,12;11|16,92;20|93817;22|93789;101|6;время|1559646000;
@tony gil, 👍3
Обсуждение2 ответа
Лучший ответ:
Это потому, что вы возвращаете указатель на локальную переменную.
Вы возвращаете только адрес в памяти, где размещен ваш массив символов. Это выделение находится в стеке и существует только на время жизни функции. Но у вас все еще есть адрес, по которому была выделена эта память, и вы используете ее так, как если бы она все еще была выделена.
Когда вы добавляете его к объекту String, в куче выделяется место, и данные копируются в него. Это выделение кучи сохраняется до тех пор, пока объект String не будет уничтожен либо путем выхода за пределы области действия, либо путем его уничтожения вручную.
Это чистая случайность, что данные все еще доступны и не повреждены на момент копирования.
Короче:
- Вы должны никогда возвращать указатель на локально выделенный (нестатический) массив.
Вещи, которые вы можете сделать правильно:
- Передайте указатель массива на функцию, которая будет заполнена функцией
- Возвращает указатель на статически размещенный локальный массив
- Возвращает объект
String
(хотя я бы не рекомендовал использовать String ни для чего)
Я предпочитаю первый метод, при котором вы определяете массив во внешней области видимости, а затем передаете его (и, возможно, длину массива) в функцию. Затем функция заполняет переданный массив. Это также имеет то преимущество, что функция может использовать возвращаемое значение для указания статуса или другого количества.
Например:
void myFunc(char *buf, int len) {
for (int i = 0; i < len - 1; i++) {
buf[i] = 'A';
}
buf[len - 1] = 0;
}
char myBuf[20];
myFunc(myBuf, 20);
Serial.println(myBuf);
--> AAAAAAAAAAAAAAAAAAAA
У да человек! ПРОГОЛОСОВАНО и ПРИНЯТО. Повторное использование String
: полностью согласен, небезопасное выделение памяти в классе String., @tony gil
Следуя бесценному совету Маженко и включив другой аналогичный подход, окончательная рабочая реализация заключалась в том, чтобы рассматривать функцию как метод работы в массиве char[300]
как "выходной параметр".
char postStr[300] = "";
uploadHourCsv(timeNow,pulseChangeHour,postStr) ;
...
void uploadHourCsv(int unixtimeEvent, int pulseChange, char* postStr) {
// подготавливаем данные и переменные
strcat(postStr, stationId);
strcat(postStr,";3|"); // чува гора
strcat(postStr, dtostrf(rainHour,6,2,charDummy));
...
}
Если вы сделаете первый strcat
вместо этого strcpy
, вы можете избежать первой инициализации массива. (И обратите внимание, что то, как вы инициализируете его в вызывающем объекте, заполняет всю длину нулевыми байтами, а не только первый элемент, так что это занимает намного больше времени, чем необходимо, если только он не будет оптимизирован.), @Peter Cordes
- C++ против языка Arduino?
- Как использовать SPI на Arduino?
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Ошибка: expected unqualified-id before 'if'
- Что лучше использовать: #define или const int для констант?
- Функции со строковыми параметрами
- Библиотека DHT.h не импортируется
- ошибка: ожидаемое первичное выражение перед токеном ','
Что именно возвращает
uploadHourCsv
? Поскольку post2 объявлен как указатель без указания размера, для этого функция должна вернуть указатель на уже выделенную строку., @chrislchar postStr[300]
с содержимым, отображаемым в кавычках., @tony gilКак это специфично для Arduino? Несмотря на два отличных (и получивших одобрение) ответа ниже, я говорю, что такие вопросы 1) относятся к https://stackoverflow.com/ и 2) быстрее получат лучшие ответы (не в обиду тем, кто здесь), @Mawg says reinstate Monica
спасибо как вы думаете, что мы должны перенести это на SO? отметьте для внимания модератора или отметьте, чтобы закрыть фразу «принадлежит так», @tony gil