Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Arduino & Microcontrollers

Arduino String Formatting: sprintf, dtostrf and Print Tips

Arduino String Formatting: sprintf, dtostrf and Print Tips

March 11, 2026 /Posted byJayesh Jain / 0

Displaying sensor readings, building log messages, or formatting data for serial output — Arduino string formatting with sprintf is one of those skills that separates beginner sketches from professional code. In this tutorial, you’ll learn how to use sprintf(), dtostrf(), and snprintf() on Arduino, how to avoid the pitfalls of float formatting on AVR processors, and practical techniques for padding, alignment, and building structured output strings that look clean on LCD displays, serial monitors, and OLED screens.

Table of Contents

  • Why Use sprintf Instead of Multiple print() Calls
  • sprintf Basics and Format Specifiers
  • The Float Problem on AVR Arduino
  • dtostrf: Arduino’s Float-to-String Solution
  • snprintf: Buffer-Safe sprintf
  • Padding and Alignment Techniques
  • LCD and OLED Display Formatting
  • When to Use the String Class (and When Not To)
  • FAQ

Why Use sprintf Instead of Multiple print() Calls

The most common way beginners format output in Arduino is chaining multiple Serial.print() calls:

// Beginner approach — works but verbose
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("°C  Humidity: ");
Serial.print(humidity);
Serial.println("%");

This works, but has several problems:

  • You can’t reuse the formatted string (e.g., for displaying on both LCD and serial)
  • No control over decimal places, field width, or padding
  • Can’t store the result in a variable for further processing
  • More function call overhead than a single formatted write

Using sprintf() lets you build the complete string first, then use it anywhere:

char buf[64];
sprintf(buf, "Temperature: %dC  Humidity: %d%%", temperature, humidity);
Serial.println(buf);
lcd.print(buf); // Same string, different destination
Recommended: Arduino Uno R3 Beginners Kit — includes an LCD display module so you can immediately apply formatted output to a real display, not just the serial monitor.

sprintf Basics and Format Specifiers

sprintf(buffer, format, args...) works identically to C’s standard printf() but writes to a char array instead of stdout. Here are the format specifiers most useful in Arduino work:

Specifier Type Example Output
%d int 42
%u unsigned int 65535
%ld long 1234567890
%s char* Hello
%c char A
%x hex (lower) ff3c
%X hex (upper) FF3C
%05d zero-padded int 00042
%-10s left-aligned string Hello     
%% literal % %

Notice that %f (float) is intentionally missing — that’s because on AVR-based Arduinos (Uno, Nano, Mega), sprintf does NOT support floating point by default. This is the single most confusing aspect of Arduino string formatting.

The Float Problem on AVR Arduino

If you try this on an Arduino Uno:

float temperature = 24.67;
char buf[32];
sprintf(buf, "Temp: %f", temperature);
Serial.println(buf);
// Output: "Temp: " (empty float!) or garbage

You won’t get the number you expect. This happens because the AVR-libc implementation of sprintf deliberately excludes float support to save flash memory (the full printf with floats adds ~2 KB of code). The %f specifier is silently ignored or outputs unexpected characters.

You have four solutions:

Option 1 — Integer arithmetic: Multiply the float by a power of 10 and use integer formatting with manual decimal point.

float temp = 24.67;
int tempInt = (int)temp;
int tempFrac = abs((int)(temp * 100) % 100);
sprintf(buf, "Temp: %d.%02d C", tempInt, tempFrac);
// Output: "Temp: 24.67 C"

Option 2 — dtostrf(): Arduino’s built-in float-to-string function (covered in the next section).

Option 3 — Enable float printf: Add this to your sketch to link the full printf with float support (costs ~1.5 KB of flash):

// Add to sketch before setup():
extern void __floats_in_avr_libc_printf_enable();
// Or via linker flag in platform.local.txt:
// build.extra_flags = -Wl,-u,vfscanf -lscanf_flt -Wl,-u,vfprintf -lprintf_flt

Option 4 — ARM Arduino (Nano 33 IoT, Due, RP2040): On ARM-based boards, float printf works natively without any workarounds.

Recommended: Arduino Nano 33 IoT with Header — ARM Cortex-M0+ processor with full float support in sprintf, eliminating the AVR float formatting headache entirely while adding WiFi and BLE.

dtostrf: Arduino’s Float-to-String Solution

dtostrf() is an AVR-specific function that converts a float (double) to a string. It’s the cleanest solution for float formatting on Uno/Nano/Mega.

Signature:

char* dtostrf(double val, signed char width, unsigned char prec, char* s);
// val   — the float to convert
// width — minimum total field width (negative = left-aligned)
// prec  — number of decimal places
// s     — output char buffer
// returns: pointer to s

Examples:

char buf[10];
float temperature = 24.678;

dtostrf(temperature, 6, 2, buf);
// buf = " 24.68" (6 chars wide, 2 decimal places, right-aligned)

dtostrf(temperature, -8, 1, buf);
// buf = "24.7    " (8 chars wide, 1 decimal place, left-aligned)

dtostrf(temperature, 4, 0, buf);
// buf = "  25" (0 decimal places, rounded)

// Combine with sprintf:
char floatStr[8];
char output[32];
dtostrf(temperature, 5, 2, floatStr);
sprintf(output, "Temp:%s C  Hum:%d%%", floatStr, humidity);
Serial.println(output);

Buffer size warning: Always allocate at least width + 1 bytes for the dtostrf output buffer (the +1 is for the null terminator). A common bug is allocating exactly width bytes and getting a buffer overflow. For safety, use char buf[16] for most temperature/sensor values.

Negative numbers: dtostrf handles negative values correctly — the minus sign counts towards the total width, so dtostrf(-24.5, 6, 1, buf) gives " -24.5" (6 chars, right-aligned).

snprintf: Buffer-Safe sprintf

Regular sprintf() has a critical vulnerability: if your format string produces more characters than the buffer can hold, it writes past the end of the buffer — a classic buffer overflow. On Arduino, this can corrupt the stack, cause seemingly random crashes, or corrupt other variables.

snprintf(buffer, maxLen, format, args...) adds a maximum length parameter:

char buf[32];
int written = snprintf(buf, sizeof(buf), "Sensor %d: %.2f", sensorId, value);

if (written >= sizeof(buf)) {
  // Output was truncated! Handle this case.
  Serial.println("Warning: output truncated");
}

snprintf never writes more than maxLen - 1 characters (always null-terminates). It returns the number of characters that WOULD have been written — if this is >= maxLen, your string was truncated. Always use sizeof(buf) for the length parameter rather than a hardcoded number, so the check stays correct if you ever change the buffer size.

On ARM-based Arduino boards, snprintf supports %f natively. On AVR, combine it with dtostrf as shown in the previous section.

Recommended: Arduino Nano RP2040 Connect with Header — dual-core ARM processor with full libc including float printf support, ideal for data-heavy projects that need extensive string formatting without AVR workarounds.

Padding and Alignment Techniques

Clean, aligned output is crucial when displaying tables of values on a serial monitor or LCD. Here are the key techniques:

Right-aligned integers with leading spaces:

sprintf(buf, "%5d", 42);   // "   42"
sprintf(buf, "%5d", 1234); // " 1234"
sprintf(buf, "%5d", 99999);// "99999"

Zero-padded integers:

sprintf(buf, "%05d", 42);  // "00042" — useful for timestamps
sprintf(buf, "%04d", 7);   // "0007"

Left-aligned strings:

sprintf(buf, "%-10s|", "Hello"); // "Hello     |" — padded to 10 chars

Fixed-width table output:

// Print a 3-column sensor table
void printSensorRow(int id, float temp, int humidity) {
  char tempStr[8];
  dtostrf(temp, 6, 2, tempStr);
  char row[40];
  snprintf(row, sizeof(row), "Sensor %02d | %s C | %3d%%", id, tempStr, humidity);
  Serial.println(row);
}

// Output:
// Sensor 01 |  24.67 C |  68%
// Sensor 12 | 100.00 C | 100%

Time formatting (HH:MM:SS):

// Format millis() as HH:MM:SS
void printTime() {
  unsigned long t = millis() / 1000;
  int h = t / 3600;
  int m = (t % 3600) / 60;
  int s = t % 60;
  char buf[10];
  sprintf(buf, "%02d:%02d:%02d", h, m, s);
  Serial.println(buf);
}

LCD and OLED Display Formatting

For 16×2 LCD displays, proper formatting is essential — you have exactly 16 characters per row and any overflow just wraps (or is cut off). Here are patterns for common LCD display needs:

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

void displaySensorData(float temp, int humidity) {
  char line1[17]; // 16 chars + null terminator
  char line2[17];
  char tempStr[7];
  
  dtostrf(temp, 5, 1, tempStr);
  snprintf(line1, sizeof(line1), "Temp: %s C", tempStr);
  snprintf(line2, sizeof(line2), "Humidity: %3d%%", humidity);
  
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print(line1);
  lcd.setCursor(0, 1); lcd.print(line2);
}

// Output:
// Line 1: "Temp:  24.5 C   "
// Line 2: "Humidity:  68%  "

Clearing to end of line: When updating LCD in place (without lcd.clear() to avoid flicker), pad shorter strings to fill the full 16 characters:

// Pad string to fill LCD line (prevents leftover characters)
snprintf(line1, sizeof(line1), "%-16s", myString); // Left-align, pad to 16
Recommended: 1.8 Inch SPI 128×160 TFT LCD Display Module for Arduino — a colour TFT display with enough resolution to show multiple formatted sensor readings with large, easy-to-read text using the Adafruit GFX library.

When to Use the String Class (and When Not To)

Arduino provides a high-level String class with operator overloading, which is tempting for formatting:

String msg = "Temp: " + String(temperature, 2) + "C";
Serial.println(msg);

This looks clean, but has serious downsides on AVR Arduino:

  • Heap fragmentation: String creates and destroys dynamic memory allocations. In long-running sketches, this fragments the heap, eventually causing random crashes.
  • Memory overhead: Each String object has 16+ bytes of overhead on top of the string data.
  • Unpredictable timing: Memory allocation can take variable time, affecting timing-sensitive code.

Rule of thumb: Use char arrays + sprintf/dtostrf for performance-critical or long-running sketches. Use the String class only in simple sketches that run for a short time or on ARM boards with abundant RAM (like Nano 33 IoT, which has 32 KB RAM vs Uno’s 2 KB).

A safe alternative that avoids heap fragmentation while keeping some String convenience:

// Build strings in static buffers — no heap allocation
static char tempBuf[8];
static char msgBuf[32];
dtostrf(temperature, 6, 2, tempBuf);
snprintf(msgBuf, sizeof(msgBuf), "T:%sC H:%d%%", tempBuf, humidity);
Recommended: Arduino Mega 2560 R3 Board — 8 KB of RAM and 256 KB flash means more headroom for complex formatting and larger string buffers, without the constant memory anxiety of the Uno’s 2 KB.

FAQ

Why does sprintf print ‘?’ or nothing for my float values?

This is the AVR float printf limitation. The default AVR-libc sprintf does not support %f, %e, or %g format specifiers. The float argument is ignored and the specifier outputs nothing or a ‘?’ depending on the libc version. Use dtostrf() to convert your float to a string first, then use %s to include it in sprintf.

How large should my sprintf buffer be?

Add up the maximum possible length of all formatted elements plus literal characters in your format string. Add 1 for the null terminator. For safety, add another 10-20% buffer. For example: "Sensor %02d: %s C, %3d%%" with max int 99, temp string 7 chars, humidity max 100 → 2 + 7 + 5 literal chars + 3 + 1 null = ~20 chars → use 32 to be safe. The snprintf return value tells you the actual required length.

Does sprintf work the same on all Arduino boards?

No. AVR-based boards (Uno, Nano, Mega, Leonardo) use AVR-libc’s sprintf which lacks float support. ARM-based boards (Nano 33 IoT, Due, Nano RP2040 Connect, Arduino Zero) use newlib-nano’s sprintf which fully supports %f and other float specifiers. The dtostrf() function is AVR-specific and may not be available on all ARM boards.

Is there a way to format directly to the Serial port without a buffer?

Yes — use Serial.printf() on boards that support it (ESP32, Nano 33 IoT, RP2040-based boards). This works like printf() but writes directly to the serial port without a manual buffer. On standard AVR Arduino (Uno/Nano), this method doesn’t exist and you must use a char buffer with sprintf.

Why does my sprintf output have extra spaces or wrong alignment?

Check that your format specifier matches the data type exactly. On Arduino, %d is for int (16-bit on AVR). If you pass a long, use %ld. If you pass an unsigned int, use %u. Type mismatches in printf family functions cause undefined behaviour that often manifests as weird spacing, garbage characters, or values that are off by powers of 2.

Write better Arduino code today. Mastering sprintf, dtostrf, and snprintf will make your sensor readouts cleaner, your LCD displays more professional, and your debugging much faster. Browse our full range of Arduino boards and display modules at Zbotic to build your next formatted-output project.

Tags: Arduino, C++, dtostrf, programming, Serial, sprintf, string formatting
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Arduino Seven-Segment Display ...
blog arduino seven segment display driver max7219 for digits 594772
blog arduino cnc shield run 3 axis cnc with grbl firmware 594780
Arduino CNC Shield: Run 3-Axis...

Related posts

Svg%3E
Read more

Arduino Batch Programming: Flash Multiple Boards Quickly

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Based Radar System with Ultrasonic Sensor

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Automatic Plant Monitor: Sunlight, Moisture, Temperature

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Lie Detector: GSR Sensor Polygraph Project

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Metal Detector: Build a Treasure Finder

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now