3

I return a char[300] array from a function. If I intialize a char* variable with it, the return is garbled, but not if I append it to a String. What gives?

  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 generated: 00000003;3| 0.00;8|17.55;9|17.55;10|18.12;11|16.92;20|93817;22|93789;101|6;time|1559646000;

received in loop() as : [000?⸮@⸮⸮?" ⸮⸮?17.55;9|17.58! @0⸮⸮⸮⸮G% @5~`⸮h⸮?⸮⸮

String : [00000003;3| 0.00;8|17.55;9|17.55;10|18.12;11|16.92;20|93817;22|93789;101|6;time|1559646000;

4
  • What exactly does the uploadHourCsv return? Since post2 is declared as a pointer, without any size, the function has to return a pointer to an already allocated string to do this.
    – chrisl
    Commented Jun 4, 2019 at 11:16
  • char postStr[300] with contents displayed in blockquote.
    – tony gil
    Commented Jun 4, 2019 at 14:53
  • 1
    How is this Arduino specific? Despite two excellent (and upvoted) answers below, I say that such questions 1) belong on stackoverflow.com and 2) will get better answers more quickly tehre (no offence to those here)
    – Mawg
    Commented Jun 5, 2019 at 6:19
  • tks. do you think that we should move this to SO? flag for moderator attention or flag to close saying "belongs in so"
    – tony gil
    Commented Jun 7, 2019 at 16:55

2 Answers 2

12

It's because you're returning a pointer to a local variable.

You are only returning the address in memory where your char array is allocated. That allocation is on the stack and only exists for the lifetime of the function. But you still have the address where that memory was allocated, and you're using it as if it's still allocated.

When you append it to a String room is allocated on the heap and the data is copied in. That heap allocation remains until the String object is destroyed, either by going out of scope or by you manually destroying it.

It's pure chance that the data is still available and intact at the point of copying.

In short:

  • You must never return a pointer to a locally allocated (non-static) array.

Things you can do that are correct:

My preferred method is the first, whereby you define an array in the outer scope, then pass that (and possibly the array length) to the function. The function then populates the array it has been passed. This also has the advantage that the function can use the return value to indicate a status or other quantity.

For example:

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
1
  • 1
    U da man! UPVOTED and ACCEPTED. Re use of String: totally agree, unsafe memory allocation in String class.
    – tony gil
    Commented Jun 4, 2019 at 14:50
1

Following Majenko's invaluable advice and incorporating another similar approach, final working implementation was to treat the function as a method to operate upon the char[300] array as "out parameter".

char postStr[300] =  "";
uploadHourCsv(timeNow,pulseChangeHour,postStr) ;
...

void uploadHourCsv(int unixtimeEvent, int pulseChange, char* postStr) {
  // prepare data and variables
  strcat(postStr, stationId);
  strcat(postStr,";3|"); // chuva hora
  strcat(postStr, dtostrf(rainHour,6,2,charDummy));
  ...
}
1
  • 2
    If you make the first strcat a strcpy instead, you can avoid initializing the array first. (And note that the way you initialize it in the caller fills the entire length with zero bytes, not just the first element, so that takes a lot longer than necessary unless it gets optimized away.) Commented Jun 5, 2019 at 10:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.