Returning text from a class method

Hi, I’m writing a small library to handle a common task in my routine. I need to read a bit of hardware and return a bit of text. I’m not saying ‘string’ because I know not to use the String functions for this. I think this is a good opportunity to finally learn to use pointers properly. As I understand it, my method should return a pointer to a buffer created by the calling function. But that seems counter to the idea of encapsulating all the steps in a class. Shouldn’t I be able to create the buffer in the class? And if so, how do I access it from the main program? For example, if my method is tinyDate(), how do I do something like print(inst.tinyDate() ) ? I’ve read a lot of pointers on pointers, but nothing really addresses how to pass text from a class method, out to the calling function.

one variant is to hand over a reference of the buffer to your member function and let the member function use that reference.
The return value of the member function could be success/error flag or void.

class A {
  public:
    A() {}

    template <size_t n>
    int foo(char (&buf)[n]) {
      strncpy(buf, "hello world", n);
      return 0;
    }
};
A a;

void setup() {
  Serial.begin(115200);
  const size_t  buffersize = 42;
  char buffer[buffersize];

  a.foo<buffersize>(buffer);
  Serial.println(buffer);

}

void loop() {
  // put your main code here, to run repeatedly:

}

another way to think is:
why do you need the "text" in a buffer in your program anyway?
Why not hand over the destination (e.g. a reference to the object to where the text should be printed) and let the member function print to that destination.

1 Like

The size of buffer will be deduced automatically:

void setup() {
  Serial.begin(115200);
  char buffer[42];

  a.foo(buffer);  // Works too.
  Serial.println(buffer);
}

Make sure your buffer stored at class level though.

If you make a new buffer locally within your method, then pass the pointer outside of the method, the memory in that pointer location will eventually get over ridden.

Not necessarily at the class level, the main thing is that the buffer should be valid in the scope from which the method is called

If a pointer is returned, then the issue is not scope but lifetime, the pointer will obviously be "in scope" when the function returns it. But, if it's pointing to a local (stack) variable from the called function, then it will not be pointing to valid data as that variable's lifetime has ended.

It's likely @theboot mean "instance level" as that would be persistent for the life of the object. A pointer to a class level (aka static class) variable would also be valid. But, there's only one such variable for the entire class rather than one per instance.

Thanks, everyone, for the advice. I think I have a better concept in my head now. I'll play around a bit with different strategies and see which one works best.

Look at this RTC example and their toString function for an idea when the calling function hands over the buffer to modify (fill in).

   char buf1[] = "hh:mm";
   Serial.println(now.toString(buf1));

   char buf2[] = "YYMMDD-hh:mm:ss";
   Serial.println(now.toString(buf2));

   char buf3[] = "Today is DDD, MMM DD YYYY";
   Serial.println(now.toString(buf3));

(It’s a good practice to have the ownership of the pointer staying with the requester)

Thanks, great example. And coincidentally, this touches exactly what I'm working on: a way to return a custom-formatted string from an RTC. I think I need to relearn how to extend a class and simply add some code to this library.

Not a coincidence :slight_smile:
I picked that example because you mentioned your code was about reading a date

Providing a buffer to the library ensures the library does not have to worry about scope or lifetime of whatever it returns. You leave that responsibility to the caller.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.