-3

If I understand correctly, default Arduino versions of printf() and related functions do not support conversion of float type variables, as noted in this thread and many other places. A common suggestion is to use dtostrf() to convert the float variable to a char array variable then use that in printf().

I tried to be clever and make my code more compact by defining a similar function which, rather than modifying a passed-by-reference buffer, generates and returns a pointer to a char array so that I could use the returned char array directly inline inside my printf's. Based on this thread, I prototypes the following (demo):

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

const char* floatToStr(float val, int decimalPlaces);

int main()
{
    float speed[] = {234.5634, 43.234};
    printf("speed0: %s, speed1: %s\n", floatToStr(speed[0],2), floatToStr(speed[1],2));
    return 0;
}

const char* floatToStr(float val, int decimalPlaces){
    char formatStr[12];
    char *outstr = malloc(17);
    if(decimalPlaces==0){
        snprintf(outstr,16,"%i", (int)val );
    } else {
        snprintf(formatStr,10,"%%i.%%0%ii",decimalPlaces);
        snprintf(outstr,16,formatStr, (int)val, ((int)((val>0?1:-1)*val*pow(10,decimalPlaces))%(int)pow(10,decimalPlaces)) );
    }
    return outstr;
}

It works! Or so it seemed. I had overlooked a comment in the second thread noted above regarding needing to free the buffer that was malloc'ed in the floatToStr function. Failing to free the buffer constitutes a memory leak.

I believe the best solution may be to follow the model provided in that thread about making a dedicated char buffer in the calling function and using dtostrf() to write to that buffer before calling printf, and forget about generating the full string purely inline. But before I give up hope on this method...

Question 1: can someone confirm (or guide me on how to confirm this myself) that the buffer that gets generated by floatToStr does not automatically get cleaned up (freed) after the printf is done?

Question 2: Is there some other way to keep the syntax at the caller level short and sweet, i.e. without needing to define the char array buffers outside of the printf call?

8
  • 4
    If you use the Arduino framework, remove the C tag, because it is not C. Otherwise, clarify you really use C, not the C++-based framework. it might be a simple C question, though, so you can remove the arduino tag completely. And we are not a tutoring/"explain this code I found somewhere" site. Read How to Ask. As a sidenote: using dynamic memory allocation on a platform like Arduino is a very bad idea. Commented Jul 22, 2017 at 19:12
  • 1
    Thanks for the tips. Would it not be better to delete the arduino tag? The code snippet is pure C, and the general aim of my questions is about C memory management, although the need for this functionality may be unique to Arduino framework. That's why I figured both tags were relevant. Please also help me understand what is wrong with the question. This is not a "fix this code I found somewhere" question. The code I posted has evolved a few steps beyond what was referenced and my question is specifically about the inline syntax which was not in the scope of the previous threads. Commented Jul 22, 2017 at 19:27
  • 4
    In case I was not already clear enough in my first comment: If you use the Arduino Framework, your code is not C. If you use a different toolchain, your code might be C. Either way, you as the programmer should know. if not, please get a C book and an arduino book. and work through the lessons. Just get the tags correct. (A book about embedded programming might be useful anyway; your code is nothing to be recommended on small platforms. Commented Jul 22, 2017 at 19:32
  • 1
    Whjy don't you use Arduino's String? Commented Jul 22, 2017 at 21:09
  • 1
    What's the point of the arduino tag, if you are obviously not using the Arduino framework? Commented Jul 23, 2017 at 23:33

2 Answers 2

0

Question 1: can someone confirm (or guide me on how to confirm this myself) that the buffer that gets generated by floatToStr does not automatically get cleaned up (freed) after the printf is done?

Yes, you are right. Memory allocated with malloc needs to be manually deallocated by calling free. Otherwise, the program will leak memory.

Question 2: Is there some other way to keep the syntax at the caller level short and sweet, i.e. without needing to define the char array buffers outside of the printf call?

In standard C your options are fairly limited in that regard. In C++, you have the std::string class, which avoids the manual memory management that you have when using raw char*.

I'm not familiar with Arduino, but according to the documentation it has the String object. From my understanding that could simplify your floatToStr function. It also supports conversions, see the examples in the String constructor documentation.

Sign up to request clarification or add additional context in comments.

Comments

0

In answer to your first question, no confirmation is needed. There is no such thing in C as automatic cleanup. If you allocate memory, you must free it. End of story. The answer to your second question is self-evident. If you don't have a reference to the memory "in-hand", then there is no way to free it. Either cache the result of the call to floatToStr() in a pointer variable that you can free after the call to printf(), or have the floatToStr() function write to a specified buffer.

In response to your first post on SO, welcome to StackOverflow. I see from your user card that you haven't read the Tour Page. This is generally considered bad form for new users, since it gives the impression (whether justified or not, I leave to you) that one can't be bothered to familiarize oneself with how things work on SO. Another useful resource is the Help Portal.

If the (from the comments)

general aim of my questions is about C memory management

then I would suggest removing the Arduino tag. The tag system is one of the primary methods of organizing the HUGE amount of content on the SO site, and as such, is often rigorously monitored by users who follow given tags. This is especially true for tags like C, which a great many people seem to think is a "catch-all" tag.

1 Comment

Thanks @MarkBenningfield for responding. Good point regarding the need to maintain references to each buffer - that fundamentally is what's wrong with the method I proposed.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.