So...I know that the atoi function in the C++ standard library is supposed to convert a string into an integer...how does it work?...(I'm trying to learn stuff and I was just wondering)...if you could show me the code from it or make your own that would do the same task it'd be greatly appreciated...thanks in advance.
6 Answers
Something like this:
int atoi( const char *c ) {
int value = 0;
int sign = 1;
if( *c == '+' || *c == '-' ) {
if( *c == '-' ) sign = -1;
c++;
}
while ( isdigit( *c ) ) {
value *= 10;
value += (int) (*c-'0');
c++;
}
return value * sign;
}
You loop through the characters in the string as long as they are digits. For each one, add to the counter you're keeping - the value to add is the integer value of the character. This is done by subtracting the ascii value of '0' from the ascii value of the digit in question.
Note that this code doesn't handle overflow. If you pass in "887452834572834928347578423485273" (which won't fit in an int
), the result is undefined.

- 56,086
- 21
- 82
- 121
-
2you forgot to do `value *= 10;` at the top of the loop. – Tim Apr 18 '11 at 23:54
-
1This sums the digits instead of producing the number. – JaredPar Apr 18 '11 at 23:55
-
2But note that there can be an optional plus/minus sign before the digits that is not handled by this code. Int is a signed type. – hubalazs Sep 07 '13 at 12:21
-
Fixed to handle an optional +/- at the beginning. Maybe that will satisfy the drive-by downvoters. – Graeme Perrow Dec 18 '13 at 18:39
Digit by digit:
A char *
, strictly speaking, is a pointer to a char
. A pointer is just an address to some place in memory. In C/C++ (and Java), strings are made up of characters that can, individually, be treated as integers (usually one byte), thanks to ASCII.
In C (and C++), a pointer to an item of some type is the same as a pointer to an array of elements of that type. Strings in pure C are just arrays of char
s, with a '\0'
(NUL) at the end so that you know when you've hit the end of a string without having to pass around its length everywhere (a pointer is only an address, it knows nothing about what it points to).
Ignore the const
keywords for now.
The C version of atoi
loops through each character in the string. The *str++
does several things (it's important to understand how it works, but it's a horrible way to actually write C). It's equivalent to *(str++)
. The str++
returns the value of str
(a pointer) and then increments it by one (but it returns the old value!). The *
"dereferences" the pointer, basically reading in a char
from memory. This char
is stored in digit
and then compared to NUL
. Characters are stored in ASCII, which represents digits contiguously, so we can just check that digit
is between 0 and 9. We know now that we're reading in a new digit, so we multiply the previous value by 10 to "shift" the value over and then add in the digit.
Pure C version:
int atoi(const char* str) {
int num = 0;
char digit;
while ((digit = *str++) != '\0') {
if (digit < '0' || digit > '9') {
return num; /* No valid conversion possible */
}
num *= 10;
num += c - '0';
}
return num;
}
A C++ string is an object to make dealing with strings easier. You can get a char *
from a C++ string with .c_str()
.
C++ version (more likely an inlined call to the char* version with "return atoi(str.c_str());"):
int atoi(const std::string& str) {
int n = 0;
for (int i = 0; i < str.size(); i += 1) {
char digit = str.at(i); /* Could probably use iterator here,
* but this is more explicit. */
if (digit < '0' || digit > '9') {
return n; /* No valid conversion possible. */
}
n *= 10;
n += digit - '0';
}
return n;
}
Edit: Fixed issue where <> would not display properly.
Edit: C++ string version added
Edit: Fixed so it returns 123 in 123a
case.
Edit: Changed stray num to n in C++ version

- 1
- 1

- 740
- 3
- 6
-
I think this is the closest to what I'm thinking...but it's a conversion between a string and an int not a char to an int...also...I'm just learning so if you could explain what char* and *str means...that would be appreciated greatly...(I'm pretty sure I've heard they're "pointers"? but I don't understand what they do...) – JacKeown Apr 19 '11 at 00:17
-
Either of your versions will return 0 for a string like "123a", whereas atoi (I believe) would return 123. Nice detail in the description though. +1 – Graeme Perrow Apr 19 '11 at 13:00
-
@Graeme: My understanding was that it would return zero if the string was not all digits based [on this](http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/). However, this version also doesn't handle signs and doesn't max/min out. – Hoa Long Tam Apr 19 '11 at 18:32
-
On that page, we have this comment: "The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function." If I run the example on that page and enter "1234asdf" I get "The value entered is 1234." – Graeme Perrow Apr 19 '11 at 19:12
-
@Graeme: Ah, yes it does. I only saw the "If no valid conversion could be performed, a zero value is returned." line. – Hoa Long Tam Apr 19 '11 at 20:57
Turn the question around: how do you do it? When you see "31" written down, how do you understand how many of X you need to count out to equal that?
1 * the value in the leftmost column
+ 10 * the value in the next column to the right
+ 100 * the value in the next column to the right
...
Well, you can code that up.
Actually is is often implemented from the right most character for easy of use with streams. How might you do that?

- 98,632
- 24
- 142
- 234
The logic is simply to process each character into it's integer value (adjusting for position within the string).
Here's how I did it in C#. Same general idea.

- 65,341
- 71
- 269
- 466
Here's an implementation that also checks for error conditions and works for any integer types.
#include <limits>
#include <string>
#include <cctype>
#include <cassert>
#include <type_traits>
template<typename TChar, typename TNumber> bool my_atoi(const std::basic_string<TChar>& str, TNumber& result)
{
typedef std::make_unsigned<TNumber>::type TNumberUnsigned;
// check if result type is integer
assert(std::numeric_limits<TNumber>::is_integer);
auto currChar = str.cbegin();
// use corresponding unsigned type to accumulate number to avoid overflows for numbers such as -128
TNumberUnsigned number = 0;
bool isNegative = *currChar == '-';
if (isNegative) {
// negative numebers can only be parsed into signed types
if (!std::numeric_limits<TNumber>::is_signed)
return false;
++currChar;
}
// empty string or string containing just - sign are not valid integers
if (currChar == str.cend())
return false;
while (currChar != str.cend()) {
auto digit = *currChar - '0';
// check that the next digit is valid
if (digit < 0 || digit > 9)
return false;
// check for overflow
if (number > std::numeric_limits<TNumberUnsigned>::max() / 10)
return false;
number *= 10;
// check for overflow
if (number > std::numeric_limits<TNumberUnsigned>::max() - digit)
return false;
number += digit;
++currChar;
}
if (isNegative) {
// correctly check for negative overflow (-128)
if (number > static_cast<TNumberUnsigned>(std::numeric_limits<TNumber>::max()) + 1)
return false;
result = static_cast<TNumber>(-1 * number);
}
else {
if (number > static_cast<TNumberUnsigned>(std::numeric_limits<TNumber>::max()))
return false;
result = static_cast<TNumber>(number);
}
return true;
}

- 7,545
- 7
- 30
- 44
Basically by subtracting ASCII zero ('0') and checking if it is a digit or not. You need to know the position:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int atoi( const char* nptr )
{
int result = 0;
int position = 1;
const char* p = nptr;
while( *p )
{
++p;
}
for( --p; p >= nptr; p-- )
{
if( *p < 0x30 || *p > 0x39 )
{
break;
}
else
{
result += (position) * (*p - 0x30);
position *= 10;
}
}
result = ((nptr[0] == '-')? -result : result);
return result;
}
int main()
{
char buffer[BUFSIZ] = {0};
printf( "Enter an integer: " );
fgets( buffer, BUFSIZ, stdin );
buffer[strlen(buffer)-1] = 0;
printf( "You entered %d\n", atoi( buffer ) );
return 0;
}