How to Convert Numbers to Strings in C++

by | C++, Programming

Converting numbers to strings is a common requirement in C++ programming, whether you’re formatting output, processing data, or preparing values for display. In this guide, we’ll explore several methods to convert numbers to strings in C++, each with its own advantages and use cases.

Using std::to_string()

In this section, we’ll explore how std::to_string() makes numeric-to-string conversion a breeze. It’s easy to use, versatile, and works with all the basic numeric types. Let’s dive into how it works and why you’ll find it useful in your projects.

Basic to_string() Usage
#include <iostream>
#include <string>

int main() {
    // Integer conversion
    int num = 42;
    std::string str1 = std::to_string(num);

    // Float conversion
    float pi = 3.14159f;
    std::string str2 = std::to_string(pi);

    // Double conversion
    double e = 2.71828;
    std::string str3 = std::to_string(e);

    // Output results
    std::cout << "Integer to string: " << str1 << '\n';
    std::cout << "Float to string: " << str2 << '\n';
    std::cout << "Double to string: " << str3 << '\n';

    return 0;
}
Output:
Integer to string: 42
Float to string: 3.141590
Double to string: 2.718280

Key points about std::to_string():

  • Simple and straightforward to use
  • Works with all numeric types
  • Limited control over formatting (fixed number of decimal places)
  • Available since C++11

Using String Stream

Have you ever needed more control over how numbers or data are converted to strings? Or perhaps you’ve wanted to combine multiple conversions while fine-tuning the formatting? This is where string streams come to the rescue. With string streams, you can handle complex formatting needs, like setting precision, changing number bases, or formatting text dynamically, all in one go.

In this section, we’ll explore how to use std::stringstream to achieve greater flexibility in your C++ programs.

String Stream Conversion Example
#include <iostream>
#include <sstream>
#include <iomanip>

int main() {
    std::stringstream ss;

    // Integer conversion
    int num = 42;
    ss << num;
    std::string str1 = ss.str();
    ss.str(""); // Clear the stream

    // Float with precision
    double pi = 3.14159265359;
    ss << std::fixed << std::setprecision(4) << pi;
    std::string str2 = ss.str();
    ss.str("");

    // Hexadecimal conversion
    int hex_num = 255;
    ss << std::hex << std::uppercase << hex_num;
    std::string str3 = ss.str();

    // Output results
    std::cout << "Integer to string: " << str1 << '\n';
    std::cout << "Formatted float: " << str2 << '\n';
    std::cout << "Hex conversion: " << str3 << '\n';

    return 0;
}
Output:
Integer to string: 42
Formatted float: 3.1416
Hex conversion: FF

Advantages of string streams:

  • Flexible formatting options using stream manipulators
  • Can combine multiple conversions
  • Supports precision control and different number bases
  • Works with custom types that have stream operators defined

Using sprintf()

If you’ve ever worked with legacy C or early C++ code, you’ve probably encountered sprintf(). While it’s not the most modern or type-safe approach, sprintf() remains a powerful and lightweight tool for string formatting, especially when you need precise control over the output format.

In this section, we’ll revisit sprintf() and see how it can still hold its own in situations where minimalism and C-style formatting are preferred.

sprintf() Conversion Example
#include <iostream>
#include <cstdio>
#include <string>

int main() {
    char buffer[50];

    // Integer conversion
    int num = 42;
    sprintf(buffer, "%d", num);
    std::string str1(buffer);

    // Float with precision
    double pi = 3.14159;
    sprintf(buffer, "%.3f", pi);
    std::string str2(buffer);

    // Padded integer
    int small_num = 7;
    sprintf(buffer, "%04d", small_num);
    std::string str3(buffer);

    // Output results
    std::cout << "Integer to string: " << str1 << '\n';
    std::cout << "Formatted float: " << str2 << '\n';
    std::cout << "Padded integer: " << str3 << '\n';

    return 0;
}
Output:
Integer to string: 42
Formatted float: 3.142
Padded integer: 0007

Important considerations for sprintf():

  • Requires careful buffer size management
  • C-style formatting options
  • Not type-safe
  • Consider using snprintf() for better buffer overflow protection

Understanding sprintf() Format Specifiers

The sprintf() function uses format specifiers to define how variables are converted into strings. Here’s a breakdown of the format specifiers used in the example:

1. %d for Integer Conversion

Format: %d

Explanation: Converts an integer into its decimal (base 10) string representation.

// Example:
int num = 42;
sprintf(buffer, "%d", num);
// Output: "42"

2. %.3f for Float with Precision

Format: %.nf (replace n with the desired number of decimal places)

Explanation: Converts a floating-point number into a string with exactly n digits after the decimal point.

// Example:
double pi = 3.14159;
sprintf(buffer, "%.3f", pi);
// Output: "3.142"

3. %04d for Padded Integer

Format: %0nd (replace n with the minimum field width)

Explanation: Converts an integer into a string with at least n characters, padding with leading zeros if necessary.

// Example:
int small_num = 7;
sprintf(buffer, "%04d", small_num);
// Output: "0007"

General Summary of Format Specifiers

Specifier Meaning
%d Convert an integer to a decimal (base 10) string.
%.nf Convert a floating-point number to a string with n digits after the decimal point.
%0nd Convert an integer to a string with at least n characters, padded with leading zeros.

Using Boost Lexical Cast

In this section, we’ll explore how boost::lexical_cast can simplify type conversions and why it’s a go-to solution for many C++ developers. Let’s take a closer look at its features and a practical example to get started.

Boost Lexical Cast Example
#include <iostream>
#include <boost/lexical_cast.hpp>

int main() {
    try {
        // Integer conversion
        int num = 42;
        std::string str1 = boost::lexical_cast<std::string>(num);

        // Double conversion
        double pi = 3.14159;
        std::string str2 = boost::lexical_cast<std::string>(pi);

        // Output results
        std::cout << "Integer to string: " << str1 << '\n';
        std::cout << "Double to string: " << str2 << '\n';
    }
    catch(const boost::bad_lexical_cast& e) {
        std::cerr << "Error: " << e.what() << '\n';
    }

    return 0;
}
Output:
Integer to string: 42
Double to string: 3.14159

Benefits of Boost lexical_cast:

  • Type-safe conversions
  • Exception handling for conversion errors
  • Works with custom types (requires stream operators)
  • Part of a widely-used, well-tested library

Setting up Boost in CLion

Before you can use Boost's lexical_cast, you’ll need to install and configure Boost in your CLion project. Don’t worry, we’ve got you covered with a step-by-step guide.

Prerequisites:

  • CLion installed
  • CMake 3.15 or higher
  • A C++ compiler (GCC, Clang, or MSVC)

1. Install Boost

First, install Boost on your system:

Ubuntu/Debian
sudo apt-get update
sudo apt-get install libboost-all-dev
macOS (using Homebrew)
brew install boost
Windows (using vcpkg)
vcpkg install boost:x64-windows

2. Configure CMakeLists.txt

Add Boost to your CLion project by modifying CMakeLists.txt:

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(your_project_name)

set(CMAKE_CXX_STANDARD 17)

# Find Boost
find_package(Boost REQUIRED)

# Add include directories
include_directories(${Boost_INCLUDE_DIRS})

# Create executable and link Boost
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})

3. Include in Your Code

Now you can include Boost headers in your C++ files:

main.cpp
#include <boost/lexical_cast.hpp>
// Your code here

Troubleshooting Tips:

  • If CMake can't find Boost, set BOOST_ROOT in CLion's CMake options or your system's environment variables
  • On Windows, you might need to add your Boost installation path to CMAKE_PREFIX_PATH
  • Make sure to reload CMake project after modifying CMakeLists.txt
  • If using vcpkg on Windows, add the toolchain file to your CMake configuration

Best Practices

With so many options for converting numbers to strings, how do you pick the right one? The best choice often depends on your specific use case. Here are some guidelines to help you decide:

  • Use std::to_string(): Perfect for quick and simple conversions with default formatting. It's easy to use and doesn’t require any additional setup.
  • Choose string streams: When you need precise control over formatting, such as setting decimal precision or combining multiple conversions, std::stringstream is your go-to tool.
  • Consider sprintf(): If you're maintaining legacy code or need specific formatting that isn’t easily achieved with modern methods, sprintf() can still get the job done.
  • Use Boost lexical_cast: If you're already using Boost in your project, lexical_cast offers type-safe, robust conversions with exception handling built-in.

Pro Tip: Always choose the method that aligns with your project's needs by considering:

  • Type safety: How important is avoiding runtime type conversion errors?
  • Formatting flexibility: Do you need fine-grained control over how the output looks?
  • Performance: Will the chosen method impact runtime efficiency in performance-critical applications?
  • Project dependencies: Are you already using external libraries like Boost, or do you prefer sticking to the standard library?

Conclusion

Choosing the right method for converting numbers to strings in C++ depends on your project’s requirements. For straightforward conversions, std::to_string() is a reliable choice. When precise formatting or custom operations are needed, string streams provide the flexibility you require. In legacy codebases, sprintf() remains a practical option, while Boost’s lexical_cast shines in projects leveraging the Boost library for robust and type-safe conversions.

By evaluating your needs for type safety, formatting control, and project dependencies, you can confidently select the method that best fits your use case and ensures clean, maintainable code.

Further Reading

  • C++ Reference: std::to_string

    The official C++ reference documentation provides detailed information about std::to_string, including its overloads, return values, and exception handling. Essential reading for understanding the standard library's string conversion capabilities.

  • C++ Reference: std::stringstream

    Comprehensive documentation on string streams, including formatting options, manipulators, and best practices. This resource is particularly valuable for understanding advanced formatting techniques and stream state management.

  • Boost.LexicalCast Documentation

    In-depth guide to Boost's lexical_cast library, covering advanced usage patterns, error handling, and performance considerations. Perfect for developers looking to implement robust type conversion in their applications.

  • Online C++ Compiler

    Try out these number-to-string conversion examples instantly in our free online C++ compiler. Experiment with different formatting options and conversion methods without needing to set up a local development environment.

Attribution and Citation

If you found this guide and tools helpful, feel free to link back to this page or cite it in your work!

Profile Picture
Senior Advisor, Data Science | [email protected] | + posts

Suf is a senior advisor in data science with deep expertise in Natural Language Processing, Complex Networks, and Anomaly Detection. Formerly a postdoctoral research fellow, he applied advanced physics techniques to tackle real-world, data-heavy industry challenges. Before that, he was a particle physicist at the ATLAS Experiment of the Large Hadron Collider. Now, he’s focused on bringing more fun and curiosity to the world of science and research online.

Buy Me a Coffee ✨