Functions returning character arrays

Trying to understand how to return an array from a function. Can you help me understand what I should be doing to get a reference to the breakfast array in the code below?

void setup() {
  Serial.begin(9600);
  char food[] = "Pizza";
  char* food_ptr = food;
  Serial.print("\nfood_ptr before the call: "); Serial.println(food_ptr); // prints "Pizza"
  food_ptr = foo();
  Serial.print("food_ptr after the call: "); Serial.println(food_ptr); // prints nothing
}
char* foo(){
  char breakfast[] = "bagel";
  return breakfast;
}

You can't return a a pointer to a variable that's local to the function. Define the array in the calling function and pass that into the called function (along with the array's size).

1 Like

Oh yes you can - but it is a very bad thing to do!! :scream: :scream: :scream:

The pointer will continue to point at the memory location where the local variable once was - but that memory will no longer be occupied by that variable!

You will create some very bewildering and hard-to-debug bugs this way!

Therefore, you really do not want to do this!

Instead, as @gfvalvo said, pass-in a pointer to a buffer for your function to use.

2 Likes

Alternatively (if that’s the need) return a pointer to constant and statically allocated memory

1 Like

If you're just looking to have one from a list of food names, maybe have an array of strings, and return the index ... ?

const char * foods[] = { "bagel",  "Pizza" };

:thinking:

1 Like

Not if you want your code to work reliably, which is something I think we can safely assume from anyone here.

Exactly! See the rest of that sentence - and, in fact, the rest of the post!

You can - but you most certainly should not!

Which raises the question:

Is there a warning on this which can be enabled?

Something along the lines of, "returning pointer to auto object" ... ?
:thinking:

EDIT

It seems the -Wreturn-local-addr does exist ...

EDIT 2

Current documentation only seems to mention an option to turn this off - so it is, presumably, on by default?

Well a pedant would take a minute to point out that you can return a pointer to a variable that's local to the function, if it is declared static.

And another minute to carefully make clear that he is not recommending that in case someone somehow thinks he is. :expressionless:

It might could be just what you want to do. I'll ask the AI I have trained on 50000 lines of my own code to see if I ever happened to do that, and see if it was for any good reason.

a7

Is this not clear enough, then?

:roll_eyes:

Normally I would pass a pointer to an array, have the function operate on that and have my array done if the function does not return a 0.

That is the way that most string.h functions work btw.

1 Like

Thank you all very much for your responses. You've given me lots to think about and to look up.
To alto777's point, I saw in a digitalOceans tutorial that you could return a pointer that points to a local static array, like this:

char* foo(){
  static char breakfast[] = "bagel";
  return breakfast;
}

and that works (in this case anyway) but I think you are saying that is a bad idea. Can you explain why it's bad? Is it because I can't use that memory somewhere else now? Thank you again!
EDIT: I changed static function to static array (thanks to awneil for pointing that out).

That's a static array - not a function

Yes: because the data is static - which is not what you showed in post #1.

Being static means that the data will always be present in the same location - so it is safe to return a pointer to it.

The reason why it's bad to return a pointer to a non-static local was explained in post #3

Being called a pedant before even finishing my post...

An other remark would be that returning a pointer to a string literal is safe too, e.g.,

char const* foo(size_t const idx) {
  char const* msg[] {"zero", "one", "two"};
  return msg[idx];
}

It is common practice to send the array pointer and the size of the array as function arguments...
That way you can prevent writing ouside array biundaries...
Like with snprintf(char* ptr, int size)...

1 Like

But perhaps not reentrant-safe or recursive-safe.

1 Like

It turns out that this is a relatively difficult thing to do in C.
The best solution is usually to define the array outside of the function, and pass the array (and its length) to the function as arguments:

  char *food = "Pizza";
  Serial.print("\nfood before the call: "); Serial.println(food);
  foo(food, sizeof(food));
  Serial.print("food after the call: "); Serial.println(food);
}
char *foo(char* s, size_t len){
  strncpy(s, "bagel", len);
  return s;
}
2 Likes

No, perfectly clear. Your response was thorough and detailed, I was not trying to throw you under the bus.

There's a function strtok() that I believe uses static internal storage, and is thus is not reentrant.

Looking just now I see in the time I've been not paying attention, there is now strtok_r(), a modern version that is. Re-enterable.

a7

1 Like

Right. The whole post makes sense except for the quote of @gfvalvo and the

which appears to be a retort. Everything else works. But this retort only works if you've not made the assumption that the OP wants working code. I think that assumption is safe. If we allow that assumption then there's nothing wrong with the previous post and you could have said all of that without the retort.

Recursive code has the potential to grow the hell out of the stack.
If the function always finishes before too many recursions it won't crash your sketch. How many too many is depends on space left.

Strange though, I write functions that get called a lot, finish a short step and return to be called again and again to achieve results I might use recursion to achieve in a larger memory computer.

I think he was just playing in the words. You « can » do stupid things but you should not.

1 Like