sprintf() with Arduino | Print multiple variables to the serial monitor

sprintf() – Ugly to say, but incredibly useful to master. Sprintf() stands for “string print format(ted)”. It’s your go-to function if you’re looking for a more efficient way to combine text and variables into a string for output to the Serial Monitor. I’ll get into the details shortly, but here’s the main reason you should master sprintf():

Leaner, clearer, less-cluttered code.

How much leaner, you ask?

What would take you nine lines of code with standard serial.print commands you could do in just three using sprintf(). Add that up over a whole project, and it’s a pretty big deal. If that sounds like a handy chunk of knowledge, you’re in the right place. In this lesson, you’ll learn all the above and a little bit more.

Ready? Let’s go.

First, let’s revisit the clunky way to print a string

So here’s an Arduino 101 question for you. How would you print a string using text and variables using good old Serial.print()? Let’s say you want to print this line of text to the Serial Monitor:

“The 3 burritos are 147.7 degrees F”

In this example, consider both the number of burritos and the temperature value as variables. Using Serial.print() you’d typically write five lines of code to print out that single line of text.

Serial.print("The ");
Serial.print(numBurritos);
Serial.print(" burritos are ");
Serial.print(tempStr);
Serial.println(" degrees F");

Now to be clear, there’s nothing inherently wrong with using Serial.print() to build a string. It’ll do the trick. But Great Auntie Gertrude’s Carbunkle, is it clunky. In fact, using Serial.print() to build a string gets even more clunky the more variables you add.

What if you wanted to print a line with 4 variables inserted into a string like this:

“The 3 burritos are 147.7 degrees F, weigh 14oz, and were finished 3 minutes ago.”

For every variable you add to the output, you add two more serial prints in the code. So for this helpfully informative burrito update, you’d be staring down the barrel of nine lines of code.

sprintf() to the rescue

This is where sprintf() comes in handy. We can print out as many variables into our string as we want, and the amount of code required always stays at a manageable three lines.

Here are the three lines of code you’ll need:

char buffer[40];
sprintf(buffer, "The %d burritos are %s degrees F", numBurritos, tempStr);
Serial.println(buffer);

Programming Electronics Academy members, check out the Arduino Course for Absolute Beginners to practice using the Serial Library in your code.

Not a member yet?  Sign up here.

Let’s break each line down.

  1. First, you’ll create in a character array to save the output string.
  2. Then you use the sprintf() function to combine our text and variables into a string.
  3. Finally, you’ll tell Serial.print() to display the formatted string.

Let’s take a closer look at each line of code.

char buffer[40];

The character array needs to be as large, or larger than the final output string. Just count the characters you plan to store in that string and make sure the buffer is at least that large.

The next line of code is the actual sprintf() function.

sprintf(buffer, "The %d burritos are %s degrees F", numBurritos, tempStr);

Note that sprintf() requires a minimum of 2 arguments. The first argument is where you plan to store the string that sprintf() will be making for you. This is where you use the character buffer that you created on the previous line.

show buffer argument in sprintf()

The next argument is the string you want to create, filled in with format specifiers where you want to insert your variables. The format specifier is the % sign. The letter following the format specifier is called the format character, and it tells sprintf() what datatype will be used for that variable.

show the second string argument for sprintf(), with format specifiers labeled
  "The 3 burritos are 147.7 degrees F"

In this example, we have two format specifiers (%). This means we want two variables inserted into the output string. The character specifiers are a little weird at first. They are simply letters that stand for the kind of data type that will be inserted.

It starts to make a lot more sense once you learn what each letter means, so let’s look at that now.

Programming Electronics Academy members, check out the Arduino Course for Absolute Beginners to jump start your Arduino programming skills.

Not a member yet?  Sign up here.

Character specifiers

Here are some of the common character specifiers:

d or i – signed decimal integer
u – unsigned decimal integer
s – a string of characters

For example, if you use %d, you’re telling sprintf() to format the inserted variable as a signed decimal integer.

You may be wondering what it means when a character is defined as a signed decimal integer. Here’s the scoop:

  • Signed means it can be positive or negative.
  • Decimal means we want it to show up in decimal form, instead of formatted into octal or hexadecimal
  • Integer means it is a whole number, that is, there aren’t any decimal points.

Now, where does sprintf() actually find the variables to insert? Well, we don’t have to look too far, because those are the arguments added right after the string.

sprintf(buffer, "The %d burritos are %s degrees F", numBurritos, tempStr);

For every format specifier, you must pass a matching value. These values are added as additional arguments to sprintf(), each one separated by a comma.

shows sprintf() with arrows from the last arguments showing where they get inserted into the string at the format specifiers

In this example, we have two format specifiers, and therefore we have two arguments at the end. The first one, numBurritos, is inserted at the first format specifier. The second one, tempStr, is inserted at the second format specifier.

If we had more format specifiers in our string, we’d need to add more arguments to sprint(). However, it all goes onto that one line of code. That’s what makes sprintf() such a useful function to add to your coding toolkit.

What about floating point numbers?

Now you might be like… “Wait a second now – I thought you said the “s” character formatter was for a string of characters, but the temperature in Fahrenheit is a floating point value – what gives?!”

Well, here’s the deal.

Sprintf() with Arduino cannot handle floating point values. So if you have to print something that has a decimal point, like 3.14 or 156.7, then you need to convert that float value to a character string first, and then print the string. A handy way to do that is with dtostrf(), which converts a floating point value to a string. I won’t get into that now, but be sure to check out our other video on using dtostrf() with Arduino.

The final line of code in our trifecta is the good ol’ Serial.print(). What we pass as an argument is the character buffer where sprintf() stored our formatted string. You’ll notice that sprintf() isn’t returning the string itself. It saves that string into the character buffer we specified. This is why all we have to do is print the buffer’s contents to display our string.

Whew. OK, so yes, let’s name the elephant in the room; floating numbers are a lil’ bit more fiddly than working with other values. However, the incentive to use the sprintf() approach still applies — once you get used to using it, you’ll be writing leaner, better code.

Oh, and before I dive into a quick review of everything you’ve learned, here’s an interesting detail to store away at the back of your mind. It’s worth noting that sprintf() does return a value if you choose to use it, which is the total number of characters that have been stored in the buffer, excluding the null terminating character added by sprintf().

A quick sprintf() review

OK, let’s do a 30-second review of sprintf().

Here’s a line of code using the sprint(f) function:

sprintf() function labeled with the appropriate arguments

Here’s what it does:

  1. The first value sprintf() expects is a character buffer. This is where the formatted string will be stored.
  2. The second value in sprintf() is the string you want to format, including any format specifiers.
  3. The final arguments are the values that’ll replace the format specifiers.

And if you’re feeling ambitious…

Hungry for even more efficiency? You’re a productivity animal! (I mean that in a good way.) Believe it or not, there’s a ton of additional stuff you can do with sprintf(). Try playing with sub-specifiers. These optional elements live between the % sign and the character specifier. You can use sub-specifiers to perform useful formatting functions, such as left-justifying inserted values and adding leading zeros.

optional sub-specifiers for sprintf()

So there you have it; proof positive that sometimes life isn’t a marathon but a good old-fashioned sprintf. Let us know in the comments if you’re interested in a follow-on lesson including more detail on those optional sprintf() sub-specifiers.

Have a great one!

installing Arduino libraries

Installing Arduino Libraries | Beginners Guide

IoT sewage project

Pumping poo! An IoT sewage project

ESP32 webOTA updates

How to update ESP32 firmware using web OTA [Guide + Code]

error message Brackets Thumbnail V1

expected declaration before ‘}’ token [SOLVED]

Compilation SOLVED | 1

Compilation error: expected ‘;’ before [SOLVED]

Learn how to structure your code

22 Comments

  1. Chris on June 5, 2021 at 9:52 am

    You need to put all these excellent explications in an “arduino programming for dummies “. I would buy that !

  2. Willem on June 6, 2021 at 3:37 am

    Great stuff! Thank you so much.

    And I would be interested in a follow-on lesson about using the optional sprintf() sub-specifiers.

  3. Chris Ward on June 7, 2021 at 5:57 am

    You have to be aware of where the data is being sent and via. If using Bluetooth, it is best to send values only and decorate them at the receiving end (Phone App, Desktop Program) because the size of a Bluetooth LE packet for example (carrying the data) defaults to just 23 bytes.

  4. AliusC on June 30, 2021 at 1:22 pm

    Look to floating point export using format %5,3f

  5. Tushar Anand on October 18, 2021 at 2:29 pm

    Very Nicely Explained!

  6. David on March 23, 2022 at 9:53 am

    Hi
    Thanks for these explanations. I would like to know if I use the same buffer many times, should I have to reset it each time ? If yes, how can I do this ?
    Thanks

    • Michael James on March 23, 2022 at 10:56 am

      Great question David! I do not believe you should have to reset the buffer when you use the buffer multiple times. This is because sprintf() adds a null terminating character to the end of the char array it returns. Serial print will stop printing at when it comes to the null terminating character – see even though there may be more chars past the null terminating character from a previous use of the buffer, it will “effectively” be unreachable by a print function.

  7. Ralph W. Fricker on April 30, 2022 at 8:02 pm

    Do you have any posts on using two or more interrupts in a program. I cannot get two interrupts to work (int0, and int1). They seem to call both ISRs. They work fine if I only use one and comment out the other. I am using an Arduino Uno.

    • Michael James on May 1, 2022 at 8:51 am

      Hi Ralph – we don’t have and posts on our public website about using multiple ISRs (we cover ISRs in our training courses). But if you post your code, maybe I could help troubleshoot.

  8. SimonOsteopath on May 11, 2022 at 1:06 pm

    Definitely interested in A follow-up. I’m building a systems control, which has a large number of variables to display. I’d also like to know if something similar could be used when displaying variables on say, an OLED display!

  9. Renato Lima (Rio Branco, ACRE/BRAZIL) on May 13, 2022 at 2:20 pm

    My friend after much research and unsuccessful attempts, your article, with detailed explanations solved my problem. Congratulations, very grateful.

  10. Alejandro on January 9, 2023 at 1:54 pm

    Thanks you!
    solve my problem with sprintf function.
    about a Flags, any help?

    • Michael James on January 9, 2023 at 2:00 pm

      I’ll see if we can add some flag info to this post – thanks!

  11. Sébastien on June 13, 2023 at 1:25 am

    Interesting but be aware of the existence of

    Serial.printf(“the value is %d”, value);

    which is available on some (few) Arduino boards and on ESP8266, NodeMCU, ESP32 boards

    • Michael James on June 13, 2023 at 9:29 am

      Thanks for passing this on Sébastien – I didn’t realize this! Can’t wait to try…

  12. Doug Rice on September 4, 2023 at 1:00 pm

    I tried this on a DigiSpark to printout millis(). It included the libuary. So I tied a function that subtracted a power of 10 and incremented ‘0’.

  13. Stone on October 10, 2023 at 4:02 pm

    Congrats on your most excellent display of practical breakdown of Arduino code.
    Fabulously produced content.

Leave a Comment