C/C++, Programming
C++ stoi(): Convert a String to an int
The std::stoi function converts a string that holds digits, such as "42", into an int value of 42. It lives in the <string> header, reads the leading numeric portion of the string, and throws an exception when the text is not a number or the result will not fit in an int. This guide walks through the syntax, the optional idx and base parameters, the two exceptions it throws, and the related functions like stof and from_chars, with runnable examples drawn from the same homework patterns our tutors fix on the C++ assignment help desk every week.
What std::stoi does
std::stoi turns a numeric string into an int. You hand it a std::string, it parses the integer at the front of that string, and it returns the matching int. The name reads as “string to int”, which is exactly the job.
The function was added in C++11 to replace the C-era atoi. It is declared in <string>, takes a const std::string& (an overload also accepts std::wstring), and returns int. Two behaviors separate it from the old atoi: it reports failure through exceptions instead of returning a silent 0, and it accepts an optional base so a single call parses binary, octal, decimal, or hexadecimal text.
#include <iostream>
#include <string>
int main() {
std::string text = "256";
int value = std::stoi(text);
std::cout << value + 1 << '\n'; // prints 257
return 0;
}
The result value is a real int, so value + 1 does integer arithmetic and prints 257, not the string concatenation "2561" you would get if text stayed a string.
Syntax and parameters
The declaration of std::stoi takes one required argument and two optional ones:
int stoi(const std::string& str, std::size_t* idx = nullptr, int base = 10);
Each parameter controls a distinct part of the parse:
str: the input string.stoiskips any leading whitespace, reads an optional+or-sign, then consumes as many valid digits as it can.idx: a pointer to astd::size_t. After the call,stoiwrites the index of the first character it did not convert into*idx. Passnullptr(the default) when you do not need that position.base: the radix of the number, from2to36. The default is10. A base of0tellsstoito detect the radix from the prefix.
The return value is the parsed integer. The table below maps a few inputs to their results so the behavior is concrete.
| Call | Returns | *idx after call | Notes |
|---|---|---|---|
stoi("42") | 42 | 2 | clean decimal parse |
stoi(" -17xyz", &idx) | -17 | 6 | skips spaces, reads sign, stops at x |
stoi("0x1F", nullptr, 16) | 31 | n/a | hex, 0x prefix tolerated |
stoi("1010", nullptr, 2) | 10 | n/a | binary |
stoi("755", nullptr, 0) | 755 | n/a | base 0, no prefix, treated as decimal |
The idx value is the detail most students miss. It is the only way to know where the number ended and whether anything followed it.
Convert user input into an integer
The most frequent use of std::stoi is reading a number a user typed. Console input arrives as text, so a program that does math on it converts the text to an int first.
#include <iostream>
#include <string>
int main() {
std::string userInput;
std::cout << "Enter a number: ";
std::getline(std::cin, userInput);
int userNumber = std::stoi(userInput);
std::cout << "You entered: " << userNumber << '\n';
std::cout << "Doubled: " << userNumber * 2 << '\n';
return 0;
}
This version uses std::getline instead of std::cin >> userInput so the whole line is captured, including a value the user pads with spaces. stoi strips the leading whitespace for you, then userNumber * 2 runs as real arithmetic. The one risk left is bad input, which the exception-handling section below addresses.
Read numeric data from a file
std::stoi converts each line of a number file into an int as you stream the file. Files store everything as text, so a data.txt full of figures comes in as strings that need conversion before any total or comparison.
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream inputFile("data.txt");
std::string line;
long long sum = 0;
while (std::getline(inputFile, line)) {
if (line.empty()) continue; // skip blank lines, stoi would throw on them
int num = std::stoi(line);
sum += num;
}
std::cout << "Total: " << sum << '\n';
return 0;
}
The if (line.empty()) continue; guard matters. An empty line throws std::invalid_argument, so one stray blank row at the end of the file crashes a loop that does not check for it. Accumulating into a long long also keeps the running total from overflowing when the file holds many large values.
Parse binary, octal, and hexadecimal strings
The base parameter lets one function read any radix from 2 to 36. Pass the base as the third argument and stoi interprets the digits accordingly.
#include <iostream>
#include <string>
int main() {
std::cout << std::stoi("101010", nullptr, 2) << '\n'; // binary -> 42
std::cout << std::stoi("52", nullptr, 8) << '\n'; // octal -> 42
std::cout << std::stoi("2A", nullptr, 16) << '\n'; // hex -> 42
std::cout << std::stoi("0x2A", nullptr, 16) << '\n'; // hex -> 42 (0x tolerated)
std::cout << std::stoi(" z", nullptr, 36) << '\n'; // base 36 -> 35
return 0;
}
Base 16 tolerates a leading 0x or 0X and ignores it. Base 36 uses digits 0-9 then letters a-z, so z is 35. A special case is base 0: it makes stoi read the prefix and choose the radix itself, the same rule the C++ compiler uses for integer literals.
std::stoi("0x1F", nullptr, 0); // 0x prefix -> hex -> 31
std::stoi("017", nullptr, 0); // leading 0 -> octal -> 15
std::stoi("42", nullptr, 0); // no prefix -> decimal -> 42
Every way stoi can fail, in one table
Only two of stoi’s failure conditions throw anything: std::invalid_argument when no conversion is possible, and std::out_of_range when the digits it read do not fit in an int. Four of the remaining rows are silent. The one row at the foot of the table, an illegal base, is the only condition the standard leaves undefined.
That distinction is what the table below is for. Four of these nine rows throw nothing at all.
| Condition | Input that triggers it | What stoi does | Fix |
|---|---|---|---|
| No conversion is possible, because no digit follows the whitespace and the sign | "", "abc", " ", "+" | throws std::invalid_argument | Reject the empty string first, then catch std::invalid_argument. |
| The first character cannot start a number in the chosen base | stoi("z"), stoi("8", nullptr, 8) | throws std::invalid_argument | Match the base to the data before you blame the string. |
The digits parse and the value overflows the destination type int | "2147483648" where int is 32 bits | throws std::out_of_range | Parse with std::stoll, range-check, then narrow. |
The value is too large for the underlying strtol, which sets errno to ERANGE | "99999999999999999999" | throws std::out_of_range | Widen the destination the same way, or use std::from_chars, which reports std::errc::result_out_of_range. |
| Leading whitespace sits before the sign | " 42", "\t-7" | no exception, returns 42 and -7 | Leave it alone. Whitespace ahead of the number is skipped by design. |
| Trailing whitespace sits after the digits | " 42 " | no exception, returns 42 and sets *idx to 3 | Trim the string before a strict idx == s.size() check runs. |
| Valid digits are followed by other characters | "42px", "3.14", "1,000" | no exception, returns 42, 3 and 1 | Pass idx and require idx == s.size(). |
A 0x prefix is read at base 10 | stoi("0x1F") | no exception, returns 0 and sets *idx to 1 | Pass base 16, or base 0 to detect the prefix. |
| The base argument falls outside 0 and 2 to 36 | stoi(s, nullptr, 1) | undefined by the standard; libstdc++ and libc++ both throw std::invalid_argument | Keep the base at 0 or between 2 and 36. |
Read the four rows that throw nothing twice. A student who reports that stoi “gave the wrong answer” is usually looking at one of them, and none of them can be caught, because nothing was thrown.
The two exceptions stoi throws
std::stoi throws std::invalid_argument when it cannot parse a number and std::out_of_range when the number is too large for an int. Both inherit from std::exception, both live in the standard library, and both terminate the program if you do not catch them.
std::invalid_argument
This exception fires when the first non-whitespace character cannot start a number. An empty string, "abc", or " " all trigger it because stoi finds no digit to read.
#include <iostream>
#include <string>
#include <stdexcept>
int main() {
try {
int n = std::stoi("not a number");
std::cout << n << '\n';
} catch (const std::invalid_argument& e) {
std::cout << "Invalid argument: " << e.what() << '\n';
}
return 0;
}
std::out_of_range
This exception fires when the digits form a valid number that exceeds the int range. On a platform where int is 32 bits, the maximum is 2147483647 (INT_MAX), so "2147483648" is one past the limit and throws.
#include <iostream>
#include <string>
#include <stdexcept>
int main() {
try {
int n = std::stoi("2147483648"); // INT_MAX is 2147483647
std::cout << n << '\n';
} catch (const std::out_of_range& e) {
std::cout << "Out of range: " << e.what() << '\n';
}
return 0;
}
When the magnitude can exceed int, parse with std::stol or std::stoll into a wider type and range-check before narrowing back to int.
Catch both in one block
Production code handles both exceptions together. The order matters only for readability, since the two types are unrelated siblings, not a base and derived pair.
#include <iostream>
#include <string>
#include <stdexcept>
int parseOrZero(const std::string& s) {
try {
return std::stoi(s);
} catch (const std::invalid_argument&) {
std::cout << "\"" << s << "\" is not a number\n";
} catch (const std::out_of_range&) {
std::cout << "\"" << s << "\" is too big for int\n";
}
return 0; // fallback when parsing fails
}
int main() {
std::cout << parseOrZero("123") << '\n'; // 123
std::cout << parseOrZero("x123abc") << '\n'; // invalid -> 0
std::cout << parseOrZero("9999999999") << '\n'; // out of range -> 0
return 0;
}
This is the pattern that turns a crash into a recoverable event. Many autograders feed deliberately malformed input to test exactly this defense, which is why our tutors on the C++ assignment help desk wrap every external parse in a guard like parseOrZero.
What an uncaught stoi exception prints at runtime
An uncaught stoi exception ends the program through std::terminate, and the runtime prints the exception type and its what() string before it aborts. This runtime message, not a compiler error, is what most people mean when they search for the stoi out of range error. On GCC and Clang with libstdc++ the output is this:
terminate called after throwing an instance of 'std::out_of_range'
what(): stoi
Aborted (core dumped)
The no-digit case prints the same shape with the other type:
terminate called after throwing an instance of 'std::invalid_argument'
what(): stoi
Two things about that message catch students out. The what() string is the function name and nothing else, so it never tells you which string failed. And the line that carries the whole diagnosis is the first one: std::out_of_range means the digits parsed and the number is too big for an int, while std::invalid_argument means no digit was read at all.
The Microsoft STL is more helpful here. It reports stoi argument out of range and invalid stoi argument through what(), so the type and the cause both survive into the message.
Apple Clang’s libc++, the default on macOS, prints a third shape. An uncaught std::stoi("2147483648") there aborts with libc++abi: terminating due to uncaught exception of type std::out_of_range: stoi: out of range, and the no-digit case reads std::invalid_argument: stoi: no conversion in the same line. A reader who runs the two examples above on a Mac sees this message, not the libstdc++ transcript above it.
Neither runtime prints the offending input. That is the reason the parseOrZero guard above prints the string itself before it returns the fallback.
The partial-parse trap
std::stoi reads the longest valid prefix and silently ignores the rest, which means stoi("12abc") returns 12 with no error. The function only throws std::invalid_argument when the first character cannot start a number. Trailing garbage slips through.
#include <iostream>
#include <string>
int main() {
std::cout << std::stoi("12abc") << '\n'; // 12, no exception
std::cout << std::stoi("3.14") << '\n'; // 3, stops at the dot
std::cout << std::stoi("100km") << '\n'; // 100, stops at k
return 0;
}
To reject trailing junk, supply idx and confirm the whole string was consumed. After a clean parse, idx equals the string length.
#include <iostream>
#include <string>
#include <stdexcept>
bool parseStrict(const std::string& s, int& out) {
std::size_t idx = 0;
try {
out = std::stoi(s, &idx);
} catch (const std::exception&) {
return false; // invalid_argument or out_of_range
}
return idx == s.size(); // true only if no trailing characters remain
}
int main() {
int n = 0;
std::cout << parseStrict("42", n) << " -> " << n << '\n'; // 1 -> 42
std::cout << parseStrict("42px", n) << " -> " << n << '\n'; // 0 (trailing px)
return 0;
}
parseStrict is the version that grading rubrics reward. It rejects "42px" because idx lands at 2 rather than the string length of 4.
stoi and its sibling conversion functions
C++11 added a full family of string-to-number functions alongside std::stoi, each targeting a different numeric type. The table below lists every member, the type it returns, and the header that declares it.
| Function | Converts string to | Header |
|---|---|---|
std::stoi | int | <string> |
std::stol | long | <string> |
std::stoll | long long | <string> |
std::stoul | unsigned long | <string> |
std::stoull | unsigned long long | <string> |
std::stof | float | <string> |
std::stod | double | <string> |
std::stold | long double | <string> |
std::to_string | number to std::string | <string> |
std::from_chars | int / floats (no throw) | <charconv> |
The stol, stoll, stoul, and stoull variants share the exact (str, idx, base) signature of stoi, so the idx and base lessons above carry over without change. The floating-point trio (stof, stod, stold) drops the base argument because a radix has no meaning for a double, but keeps idx.
#include <iostream>
#include <string>
int main() {
long long big = std::stoll("9000000000"); // fits in long long, overflows int
double ratio = std::stod("3.14159"); // floating-point parse
std::string s = std::to_string(big); // round-trip back to text
std::cout << big << ' ' << ratio << ' ' << s << '\n';
return 0;
}
The C functions atoi, atol, and strtol from <cstdlib> predate this family. atoi returns 0 on failure with no way to tell a real 0 from an error, so the C++ functions replace it. strtol does report errors but through errno and a pointer, a clumsier interface than exceptions. Treat them as legacy.
std::from_chars, the fast no-throw alternative
std::from_chars from <charconv> parses a number without throwing, without allocating, and without consulting the locale, which makes it faster than stoi for bulk parsing. It reports success through a return struct instead of an exception, so it suits hot loops and code that bans exceptions.
#include <charconv>
#include <iostream>
#include <string>
int main() {
std::string s = "12345";
int value = 0;
auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value);
if (ec == std::errc{}) {
std::cout << "Parsed: " << value << '\n'; // Parsed: 12345
} else if (ec == std::errc::invalid_argument) {
std::cout << "Not a number\n";
} else if (ec == std::errc::result_out_of_range) {
std::cout << "Too large for int\n";
}
return 0;
}
The returned ptr points one past the last character consumed, the same information stoi’s idx gives, and ec carries the error code. Pick std::stoi when you want the shorter call and already hold a std::string. Pick std::from_chars when throughput matters or your codebase forbids exceptions. The C++ memory and resource patterns that pair well with parsing pipelines are covered in our guide to Smart Pointers in C++.
stoi quick reference
A short checklist captures the rules that keep std::stoi from biting you:
- Include
<string>, and include<stdexcept>when you catch the exceptions by their full type. - It throws
std::invalid_argumenton no-digit input andstd::out_of_rangewhen the value exceedsint. - It parses the longest valid prefix, so
"12abc"returns12. Useidxand compare againsts.size()to reject trailing characters. - The
baseruns from 2 to 36; base 0 auto-detects from the0xor0prefix. - It handles a leading sign and leading whitespace; it does not handle thousands separators like
"1,000". - Reach for
std::stollfor values pastint, andstd::from_charsfor speed or a no-exception policy.
The same conversion discipline applies when you store parsed numbers in containers, which is why our Vectors in C++ walkthrough and the Templates in C++ reference both lean on validated input before pushing data into a structure.
Frequently asked questions
What header do I include to use std::stoi?
Include <string>. The std::stoi function is declared inside <string>, not <cstdlib>, even though it returns the same int type that the older atoi from <cstdlib> returns. Code that calls std::stoi without including <string> directly may still compile because another header pulls it in, but that is fragile. Include <string> yourself.
Does std::stoi throw an exception on bad input?
Yes. std::stoi throws std::invalid_argument when no conversion can be performed, such as an empty string or a string that starts with a letter. It throws std::out_of_range when the parsed number does not fit in an int, for example 2147483648 where int is 32 bits. Wrap the call in a try-catch block, or switch to std::from_chars for error reporting without exceptions.
What is the idx parameter in stoi?
The idx parameter is a pointer to a std::size_t. After the conversion, std::stoi writes the index of the first character it did not consume into that variable. For the input "42px" with idx supplied, stoi returns 42 and sets idx to 2, the position of p. The idx value lets you continue parsing the rest of the string and detect trailing garbage that stoi ignores by default.
Why does stoi(“12abc”) return 12 instead of throwing?
std::stoi parses the longest valid integer prefix, then stops. The string "12abc" starts with valid digits, so stoi reads 12, stops at a, and returns 12 with no error. It throws std::invalid_argument only when the first character cannot start a number. To reject trailing garbage, pass an idx pointer and confirm it equals the string length after the call.
How do I convert a binary or hexadecimal string with stoi?
Pass the base as the third argument. Use stoi(s, nullptr, 2) for binary and stoi(s, nullptr, 16) for hexadecimal. The base accepts any value from 2 to 36. Passing base 0 makes stoi auto-detect the radix from the prefix: a leading 0x means hex, a leading 0 means octal, and anything else is decimal.
What is the difference between stoi and atoi?
atoi is a C function from <cstdlib> that returns 0 on failure and gives no way to tell a real 0 from a parse error. std::stoi is the C++ replacement: it throws std::invalid_argument and std::out_of_range so failures are explicit, accepts a std::string directly, and supports an idx position and a base. Use std::stoi or std::from_chars in modern C++ and reserve atoi for legacy code.
When should I use std::from_chars instead of stoi?
Use std::from_chars from <charconv> when you parse large volumes of numbers or cannot afford exceptions. from_chars reports errors through a return code rather than throwing, ignores locale, performs no allocation, and runs faster than stoi in tight loops. Reach for std::stoi when you want the shorter call and a std::string in hand, and from_chars when performance or a no-exception policy matters.
Can stoi convert a negative number?
Yes. std::stoi reads an optional leading plus or minus sign, so stoi("-273") returns -273 and stoi("+50") returns 50. It also skips leading whitespace before the sign. If the magnitude falls below INT_MIN or above INT_MAX, stoi throws std::out_of_range rather than wrapping around.
What does the stoi out of range error mean?
It means std::stoi parsed valid digits and the number they form does not fit in an int. On GCC and Clang with libstdc++ the program aborts with terminate called after throwing an instance of 'std::out_of_range' and a what() line reading only stoi. The Microsoft STL reports stoi argument out of range instead. Catch std::out_of_range and print the input yourself, because no runtime names it for you, or parse into std::stoll first when the value can legitimately exceed int.
Does stoi throw an exception on leading whitespace?
No. std::stoi skips leading whitespace before it reads the sign, so stoi(" 42") returns 42. A string holding only whitespace throws std::invalid_argument, because no digit remains once the whitespace is skipped. Trailing whitespace is different: stoi(" 42 ", &idx) returns 42 and leaves idx at the trailing space rather than at the string length, so a strict idx == s.size() check rejects it.
Get help with your C++ assignment
Students bring stoi bugs to our desk most often as a crash on malformed grader input or a silent partial parse that drops a grade. Our C++ tutors have helped university students since 2014 with a 95% first-attempt pass rate, and you pay in two halves: 50% to start and 50% after you confirm the code runs on the version named in your brief. Send the prompt to the C++ assignment help team and a named developer scopes it under NDA, with pricing from $29.
Related articles
-
C/C++C++ Programming: A Complete Introduction
Learn C++ from the ground up: how it compiles, its core data types, functions, and the four pillars of object-oriented programming, with runnable code.
Mar 30, 2023
-
Case StudyAutograder Fixed in Under 24 Hours: 100/100
How our networking expert diagnosed a broken distance vector routing submission and delivered a 100/100 autograder score before the deadline.
Sep 2, 2025
-
ProgrammingCan You Get Caught Using Someone Else's Code?
Yes, you can get caught. MOSS, JPlag, and Codequiry detect copied code even after renaming variables or restructuring. Here is what actually happens if you are.
Jul 17, 2025