Question
I want to convert a std::string to an int, not to ASCII character codes.
I am working with equations passed in as strings. The goal is to break them down, format them correctly, and solve linear equations. At one stage, I need to extract integer values from strings.
I know the string will contain values in formats such as "-5" or "25", so the content definitely represents an integer. What is the correct way to convert that std::string into an int in C++?
I considered manually looping through the string, checking for digits, collecting them, and then handling a leading - sign myself. However, that feels more complicated than necessary for a simple conversion.
What is the standard or simplest approach?
Example values:
std::string a = "-5";
std::string b = "25";
Short Answer
By the end of this page, you will understand how to convert a std::string to an int in C++, when to use std::stoi, how to handle invalid input safely, and what older alternatives like stringstream and atoi do.
Concept
Converting a string to an integer is called parsing. In C++, this means taking text such as "42" or "-7" and turning it into a numeric int value that your program can calculate with.
This matters because many real programs receive numbers as text first:
- user input from the keyboard
- values read from files
- query parameters in web requests
- configuration settings
- pieces of larger strings, such as equations
If a value starts as a std::string, you cannot do arithmetic with it directly. For example, "25" is text, while 25 is a number.
In modern C++, the most common standard solution is std::stoi, introduced in C++11:
int value = std::stoi("25");
std::stoi converts a string to an int and understands:
- positive numbers like
"25" - negative numbers like
"-5" - optional leading whitespace like
" 12"
If the text is not a valid integer, it throws an exception. That makes error handling possible and explicit.
This is better than manually scanning characters in most cases because:
- it is shorter
- it is easier to read
- it is less error-prone
- it already handles common numeric formats correctly
Mental Model
Think of parsing like reading a label on a box.
- The
std::stringis the label:"25" - The
intis the actual quantity:25
Your program cannot add labels together meaningfully, but it can add quantities.
So conversion is the step where C++ reads the text label and turns it into a real number your code can use.
Instead of building your own reader character by character every time, std::stoi is like using a reliable built-in scanner that already knows how to read signed integers.
Syntax and Examples
The most direct modern syntax is:
int number = std::stoi(text);
Basic example
#include <iostream>
#include <string>
int main() {
std::string a = "-5";
std::string b = "25";
int x = std::stoi(a);
int y = std::stoi(b);
std::cout << x << "\n";
std::cout << y << "\n";
}
Output:
-5
25
std::stoi reads the text and returns an int.
Handling invalid input
#include <iostream>
#include <string>
int main() {
std::string text = "abc";
try {
int value = std::stoi(text);
std::cout << value << "\n";
} catch (const std::invalid_argument& e) {
std::cout << "The string is not a valid integer.\n";
} catch (const std::out_of_range& e) {
std::cout << "The number is too large or too small for int.\n";
}
}
This is useful when the input might be incorrect.
Older alternative with stringstream
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string text = "42";
std::stringstream ss(text);
int value;
ss >> value;
std::cout << value << "\n";
}
This works, but std::stoi is usually simpler when you only need a direct conversion.
C-style alternative with atoi
#include <cstdlib>
#include <iostream>
int main() {
const char* text = "42";
int value = std::atoi(text);
std::cout << value << "\n";
}
This is older C-style code. It is usually not the best choice in modern C++ because it does not report errors clearly.
Step by Step Execution
Consider this example:
#include <iostream>
#include <string>
int main() {
std::string text = "-42";
int value = std::stoi(text);
std::cout << value << "\n";
}
Step by step:
-
std::string text = "-42";- A string variable is created.
- It stores the characters
'-','4', and'2'.
-
int value = std::stoi(text);std::stoiexamines the string.- It sees the leading
-, so it knows the number is negative. - It reads the digits
4and2. - It builds the integer value
-42. - That integer is stored in
value.
-
std::cout << value << "\n";- The numeric value
-42is printed.
- The numeric value
Trace with invalid input
std::string text = "hello";
int value = std::stoi(text);
What happens:
std::stoitries to parse"hello"as an integer.- It finds no valid numeric representation at the start.
- It throws
std::invalid_argument. - If you do not catch that exception, the program will terminate.
Trace with partial numeric text
std::string text = "25abc";
int value = std::stoi(text);
By default, std::stoi reads the numeric prefix:
- It reads
25. - It stops when it reaches
a. - It returns
25.
If you need to make sure the entire string is a valid integer, you should check how many characters were consumed.
Real World Use Cases
String-to-integer conversion appears in many common programming tasks:
- Command-line tools: reading an argument like
"10"and turning it into a loop limit or port number - Equation parsers: extracting coefficients such as
"-5"or"25" - Configuration files: reading settings like timeout values or retry counts
- File processing: turning CSV text fields into numbers
- User input validation: converting form or console input into numeric values
- API handling: reading numeric values sent as strings in requests
Example from a simple equation parser:
std::string coefficientText = "-5";
int coefficient = std::stoi(coefficientText);
Now the program can use coefficient in algebra logic instead of treating it as plain text.
Real Codebase Usage
In real projects, developers usually do more than just call std::stoi once. They often combine it with validation and control flow.
Common patterns
Guard clauses
Reject bad input early:
int parseCount(const std::string& text) {
if (text.empty()) {
throw std::invalid_argument("count cannot be empty");
}
return std::stoi(text);
}
Validation before processing
try {
int age = std::stoi(ageText);
if (age < 0) {
std::cout << "Age cannot be negative\n";
}
} catch (...) {
std::cout << "Invalid age input\n";
}
Parsing tokens from larger strings
When splitting an equation or expression, developers often:
- extract a substring
- convert that substring to
int - store the result in a variable or data structure
std::string token = "25";
int value = std::stoi(token);
Full-string validation
To ensure the whole string is numeric:
#include <iostream>
#include <string>
int main() {
std::string text = "25abc";
std::size_t pos = 0;
try {
int value = std::stoi(text, &pos);
if (pos != text.size()) {
std::cout << "Extra characters after the number\n";
} else {
std::cout << "Valid integer: " << value << "\n";
}
} catch (...) {
std::cout << "Invalid integer\n";
}
}
This pattern is very common when input must be strict.
Common Mistakes
1. Confusing character codes with numeric conversion
A character like '5' is not the same as the integer 5 unless you convert it properly.
Broken idea:
std::string text = "25";
int value = text[0];
This gives the character code of '2', not the number 25.
Use:
int value = std::stoi(text);
2. Using atoi without error checking
#include <cstdlib>
int value = std::atoi("abc");
This returns 0, which is ambiguous because "0" also gives 0.
Prefer std::stoi when possible.
3. Forgetting exception handling
Broken code:
std::string text = "hello";
int value = std::stoi(text);
If text is invalid, this can throw an exception.
Safer version:
try {
int value = std::stoi(text);
} catch (const std::invalid_argument&) {
std::cout << "Invalid number\n";
}
4. Assuming the whole string was parsed
int value = std::stoi("123abc");
This returns 123. It does not automatically reject the trailing abc.
To validate the full string:
std::size_t pos;
int value = std::stoi("123abc", &pos);
if (pos != std::string("123abc").size()) {
std::cout << "Unexpected trailing characters\n";
}
5. Forgetting the required headers
For std::stoi, include:
#include <string>
For exceptions used in catches, you may also commonly include:
#include <stdexcept>
6. Manually parsing when it is unnecessary
Writing a digit loop is possible, but usually slower to write, harder to maintain, and easier to get wrong unless you truly need custom parsing behavior.
Comparisons
| Approach | Style | Error Handling | Works with std::string directly | Recommended? |
|---|---|---|---|---|
std::stoi | Modern C++ | Throws exceptions | Yes | Yes |
std::stringstream | C++ stream-based | Can test stream state | Yes | Sometimes |
std::atoi | Older C-style | Poor error reporting | No, needs C string | Usually no |
std::stoi vs std::stringstream
int a = std::stoi("42");
vs
std::stringstream ss("42");
int a;
ss >> a;
std::stoiis shorter and clearer for simple conversions.stringstreamis useful when parsing several values from one string.
std::stoi vs std::atoi
std::stoiworks naturally withstd::stringstd::stoireports invalid input with exceptionsstd::atoiuses C strings and does not clearly distinguish errors from valid zero values
If you only need integers
Choose std::stoi.
If you are working in very old C++ codebases
You may see stringstream or atoi, but modern C++ generally prefers std::stoi.
Cheat Sheet
#include <string>
int value = std::stoi(text);
Useful forms
int value = std::stoi(text);
int value = std::stoi(text, &pos);
int value = std::stoi(text, &pos, 10);
What std::stoi handles
"25"->25"-5"->-5" 12"->12"25abc"->25unless you checkpos
Exceptions
std::invalid_argument-> no valid integer foundstd::out_of_range-> number does not fit inint
Full-string validation pattern
std::size_t pos = 0;
int value = std::stoi(text, &pos);
if (pos != text.size()) {
// extra characters remain
}
Alternatives
std::stringstream-> okay, more verbosestd::atoi-> older C-style, weak error handling
Best default choice
Use std::stoi for simple std::string to int conversion in modern C++.
FAQ
How do I convert a std::string to an int in C++?
Use std::stoi:
int value = std::stoi(text);
Does std::stoi handle negative numbers?
Yes. It correctly parses strings like "-5".
What happens if the string is not a valid number?
std::stoi throws std::invalid_argument if no valid integer can be parsed.
What happens if the number is too large for int?
std::stoi throws std::out_of_range.
Is std::stoi better than atoi?
Usually yes. It works well with std::string and has better error handling.
Can std::stoi parse only part of a string?
Yes. For example, std::stoi("25abc") returns 25. Use the position argument if you need to ensure the full string was numeric.
Should I manually loop through characters to build the number?
Usually no. Use std::stoi unless you need custom parsing rules.
What if I am using an older C++ standard before C++11?
You can use std::stringstream as a standard C++ alternative.
Mini Project
Description
Build a small C++ program that reads a list of numeric strings, converts them to integers, and reports whether each conversion succeeds. This demonstrates practical string parsing, validation, and error handling using std::stoi.
Goal
Create a program that safely converts several string values to integers and tells the user which inputs are valid or invalid.
Requirements
- Store several test strings in a container.
- Attempt to convert each string to an integer.
- Print the converted integer for valid input.
- Detect and report invalid input.
- Detect and report values that are out of range for
int.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.