72

I have a string of digits, e.g. "123456789", and I need to extract each one of them to use them in a calculation. I can of course access each char by index, but how do I convert it into an int?

I've looked into atoi(), but it takes a string as argument. Hence I must convert each char into a string and then call atoi on it. Is there a better way?

Andy
  • 3,794
  • 24
  • 28
jonsb
  • 2,016
  • 3
  • 21
  • 24
  • Why do you need to extract each one, instead of treating a series of digits as an actual number? – Calyth Jan 13 '09 at 22:35
  • The string is not really a number, but individual digits, To be exact, a social security number. I want to run a calculation validating the ssn. – jonsb Jan 15 '09 at 08:10
  • 3
    Duplicate of [Convert char to int in C and C++](https://stackoverflow.com/questions/5029840/convert-char-to-int-in-c-and-c) (first interpretation) – user202729 Sep 02 '21 at 14:38

11 Answers11

173

You can utilize the fact that the character encodings for digits are all in order from 48 (for '0') to 57 (for '9'). This holds true for ASCII, UTF-x and practically all other encodings (see comments below for more on this).

Therefore the integer value for any digit is the digit minus '0' (or 48).

char c = '1';
int i = c - '0'; // i is now equal to 1, not '1'

is synonymous to

char c = '1';
int i = c - 48; // i is now equal to 1, not '1'

However I find the first c - '0' far more readable.

Liam Potter
  • 1,732
  • 8
  • 24
  • 47
Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
  • 3
    Is there any encoding in which '9'-'0' != 9 ? I'm not even sure if such an encoding would be allowed per ISO C++. – MSalters Jan 14 '09 at 13:46
  • 5
    On encodings and the order of digits, I asked this question http://stackoverflow.com/questions/782373/are-digits-represented-in-sequence-in-all-text-encodings. The short answer is "Any encoding based on Ascii or EBCDIC, yes" (which means 99.9% of encodings we'll meet in everyday life and the web). Also interestingly the c/c++ standards seem to state that they only support encodings where the digits are ordered. – Binary Worrier May 24 '09 at 09:24
  • Is there any encoding where it does not hold '0' < '1' < '2' < '3' It would be at least a very very strange decision – Friedrich Oct 21 '09 at 15:36
  • 6
    The C++ standard guarantees that `'0'` through `'9'` occur adjacently and in the right order in the character set. So the `c - '0'` works on all systems, whereas `c - 48` wouldn't work on EBCDIC for example. – M.M Jan 16 '16 at 22:23
  • @Friedrich — in pre-digital telecoms, with pulse dialling, the `0` digit was 10. How many clicks did it take to dial `9`? To dial `0`? Why is `0` after `9` on keyboards (and below `9` on numeric keypads)? – Jonathan Leffler Apr 10 '20 at 19:57
  • 2
    Note that C11 [§5.2.1 Character sets ¶3](http://port70.net/~nsz/c/c11/n1570.html#5.2.1p3) says: _In both the source and execution basic character sets, the value of each character after `0` in the above list of decimal digits shall be one greater than the value of the previous._ The C++ standard will have a similar rule. – Jonathan Leffler Apr 10 '20 at 20:02
24
#define toDigit(c) (c-'0')
Antonius RC
  • 249
  • 2
  • 2
8

Or you could use the "correct" method, similar to your original atoi approach, but with std::stringstream instead. That should work with chars as input as well as strings. (boost::lexical_cast is another option for a more convenient syntax)

(atoi is an old C function, and it's generally recommended to use the more flexible and typesafe C++ equivalents where possible. std::stringstream covers conversion to and from strings)

jalf
  • 243,077
  • 51
  • 345
  • 550
4

You can make use of atoi() function

#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[]){
    int num ;
    num = atoi(argv[1]);
    printf("\n%d", num);
}
arun.rajput
  • 127
  • 2
  • 3
3

The answers provided are great as long as you only want to handle Arabic numerals, and are working in an encoding where those numerals are sequential, and in the same place as ASCII.

This is almost always the case.

If it isn't then you need a proper library to help you.

Let's start with ICU.

  1. First convert the byte-string to a unicode string. (Left as an exercise for the reader).
  2. Then use uchar.h to look at each character.
  3. if we the character is UBool u_isdigit (UChar32 c)
  4. then the value is int32_t u_charDigitValue ( UChar32 c )

Or maybe ICU has some function to do it for you - I haven't looked at it in detail.

Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137
2
#include<iostream>
#include<stdlib>
using namespace std;

void main()
{
     char ch;
     int x;
     cin >> ch;
     x = char (ar[1]);
     cout << x;
}
Community
  • 1
  • 1
1

By this way You can convert char to int and int to char easily:

int charToInt(char c)
{
   int arr[]={0,1,2,3,4,5,6,7,8,9};
   return arr[c-'0'];
}
Ravi Singh
  • 93
  • 2
  • 12
  • `arr[x] == x` for all valid values of `x`. Since acessing an array out-of-bound is UB it's possible to assume `arr[x] == x` for all `x`. – user202729 Apr 08 '18 at 02:12
1

If you are worried about encoding, you can always use a switch statement.

Just be careful with the format you keep those large numbers in. The maximum size for an integer in some systems is as low as 65,535 (32,767 signed). Other systems, you've got 2,147,483,647 (or 4,294,967,295 unsigned)

user54650
  • 4,388
  • 2
  • 24
  • 27
  • How can a simple switch-statement help with different encodings? – gimpf Jan 13 '09 at 16:26
  • Because unicode digits cover exactly 10 positions, and ascii digits cover exactly 10 positions. Am I missing something? – user54650 Jan 13 '09 at 16:30
  • 2
    you don't need to be worried about encoding. even if the numbers are not from 48 to 58 - the numbers must all be adjacent in their encoding. so you can still subtract '0' from any digit and get correct results. i believe i read that in the standard – Johannes Schaub - litb Jan 13 '09 at 21:23
1

Any problems with the following way of doing it?

int CharToInt(const char c)
{
    switch (c)
    {
    case '0':
        return 0;
    case '1':
        return 1;
    case '2':
        return 2;
    case '3':
        return 3;
    case '4':
        return 4;
    case '5':
        return 5;
    case '6':
        return 6;
    case '7':
        return 7;
    case '8':
        return 8;
    case '9':
        return 9;
    default:
        return 0;
    }
}
jonsb
  • 2,016
  • 3
  • 21
  • 24
  • 11
    None, except that it's a lot of duplicated code to do something fairly trivial. Binary Worrier's answer is a lot simpler as long as the input encoding is known, and allows this shortcut. My version is shorter too, and works no matter the encoding, but will be a bit slower. – jalf Jan 14 '09 at 21:33
  • @jalf Binary Worrier's answer is guaranteed to work with any C++ or POSIX compliant encoding – osvein Oct 01 '17 at 13:27
1

I agree with @jalf. Using the sstream library and stoi appears to be the recommended approach:

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

int main() {

  stringstream st;
  st << 1  << '2';

  cout << stoi(st.str()) + 1; 

  return 0;
}

Output

13

I am a new student of C++ but a long-time LAMP stack developer. I was hoping the string class had more things to smoothly transition between chars and strings, but I've not yet found such a thing that is natively supported.

Spencer Williams
  • 821
  • 10
  • 20
-1

For me the following worked quite well:

QChar c = '5';
int x = c.digitValue();
// x is now 5

Documentation: int QChar::digitValue() const which says:

Returns the numeric value of the digit, or -1 if the character is not a digit.

KYL3R
  • 3,877
  • 1
  • 12
  • 26