tags:

views:

2086

answers:

7

If I want to convert a single numeric char to it's numeric value, for example, if:

char c = '5';

and I want c to hold 5 instead of '5', is it 100% portable doing it like this?

c = c - '0';

I heard that all character sets store the numbers in consecutive order so I assume so, but I'd like to know if there is an organized library function to do this conversion, and how it is done conventionally. I'm a real beginner :)

+1  A: 

Yes. This is safe as long as you are using standard ascii characters, like you are in this example.

Joe Corkery
+3  A: 

You can use atoi, which is part of the standard library, see http://www.cppreference.com/wiki/c/string/atoi

weloytty
+4  A: 

Try this :

char c = '5' - '0';

lsalamon
+4  A: 

Yes, this is a safe conversion. C requires it to work.

There is no library function to do it for a single char, you would need to build a string first:

int digit_to_int(char d)
{
 char str[2];

 str[0] = d;
 str[1] = '\0';
 return (int) strtol(str, NULL, 10);
}

You could also use the atoi() function to do the conversion, once you have a string, but strtol() is better and safer.

As commenters have pointed out though, it is extreme overkill to call a function to do this conversion; your initial approach to subtract '0' is the proper way of doing this. I just wanted to show how the recommended standard approach of converting a number as a string to a "true" number would be used, here.

unwind
This is an unecceasrily complex and expensive way to do what is a very straight forward operation i.e. int i = d - '0'
Binary Worrier
This is an answer to your question but not the best answer. This is overkill. You answered your own question with c=c-'0'; - that is the best answer.
zooropa
Yes, of course using a function is overkill. Perhaps I should have been clearer on that part.
unwind
The overkill isn't just the function aspect. Using strtol is overkill as well.
zooropa
This answer doesn't address the portability aspect of this question. This function isn't portable. It wouldn't work on the multi-byte character sets. The char d parameter would produce compiler errors when variables of type wchar_t are attempted to be passed in.
zooropa
+1  A: 

Since you're only converting one character, the function atoi() is overkill. atoi() is useful if you are converting string representations of numbers. The other posts have given examples of this. If I read your post correctly, you are only converting one numeric character. So, you are only going to convert a character that is the range 0 to 9. In the case of only converting one numeric character, your suggestion to subtract '0' will give you the result you want. The reason why this works is because ASCII values are consecutive (like you said). So, subtracting the ASCII value of 0 (ASCII value 48 - see ASCII Table for values) from a numeric character will give the value of the number. So, your example of c = c - '0' where c = '5', what is really happening is 53 (the ASCII value of 5) - 48 (the ASCII value of 0) = 5.

When I first posted this answer, I didn't take into consideration your comment about being 100% portable between different character sets. I did some further looking around around and it seems like your answer is still mostly correct. The problem is that you are using a char which is an 8-bit data type. Which wouldn't work with all character types. Read this article by Joel Spolsky on Unicode for a lot more information on Unicode. In this article, he says that he uses wchar_t for characters. This has worked well for him and he publishes his web site in 29 languages. So, you would need to change your char to a wchar_t. Other than that, he says that the character under value 127 and below are basically the same. This would include characters that represent numbers. This means the basic math you proposed should work for what you were trying to achieve.

zooropa
+2  A: 
int i = c - '0';

You should be aware that this doesn't perform any validation against the character - for example, if the character was 'a' then you would get 91 - 48 = 49. Especially if you are dealing with user or network input, you should probably perform validation to avoid bad behavior in your program. Just check the range:

if ('0' <= c &&  c <= '9') {
    i = c - '0';
} else {
    /* handle error */
}

Note that if you want your conversion to handle hex digits you can check the range and perform the appropriate calculation.

if ('0' <= c && c <= '9') {
    i = c - '0';
} else if ('a' <= c && c <= 'z') {
    i = 10 + c - 'a';
} else if ('A' <= c && c <= 'Z') {
    i = 10 + c - 'A';
} else {
    /* handle error */
}

That will convert a single hex character, upper or lowercase independent, into an integer.

spinfire
A: 

Normally, if there's no guarantee that your input is in the '0'..'9' range, you'd have to perform a check like this:

if (c >= '0' && c <= '9') {
    int v = c - '0';
    // safely use v
}

An alternative is to use a lookup table. You get simple range checking and conversion with less (and possibly faster) code:

// one-time setup of an array of 256 integers;
// all slots set to -1 except for ones corresponding
// to the numeric characters
static const int CHAR_TO_NUMBER[] = {
    -1, -1, -1, ...,
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // '0'..'9'
    -1, -1, -1, ...
};

// Now, all you need is:

int v = CHAR_TO_NUMBER[c];

if (v != -1) {
    // safely use v
}

P.S. I know that this is an overkill. I just wanted to present it as an alternative solution that may not be immediately evident.

Ates Goral
#include <ctype.h> .... if (isdigit(c)) { ... }
sigjuice