Преобразование Char в int в C - PullRequest
34 голосов
/ 23 апреля 2009

Если я хочу преобразовать один числовой char в его числовое значение, например, если:

char c = '5';

и я хочу, чтобы c содержал 5 вместо '5', это на 100% портативно, если делать это так?

c = c - '0';

Я слышал, что все наборы символов хранят числа в последовательном порядке, поэтому я предполагаю, что так, но я хотел бы знать, есть ли организованная библиотечная функция для этого преобразования и как это делается обычным образом. Я настоящий новичок:)

Ответы [ 10 ]

27 голосов
/ 23 апреля 2009

Да, это безопасное преобразование. С требует, чтобы это работало. Эта гарантия содержится в параграфе 2 параграфа 5.2.1 последнего стандарта ISO C, последняя версия которого N1570 :

И базовый, и базовый наборы символов выполнения должны иметь следующие Участники:
[...]
десятичное число цифры
0 1 2 3 4 5 6 7 8 9
[...]
В исходных и исполнительных базовых наборах символов значение каждого символа после 0 в приведенном выше списке десятичных цифр должно быть на единицу больше, чем значение предыдущего.

И ASCII, и EBCDIC, и наборы символов, полученные из них, удовлетворяют этому требованию, поэтому стандарт C смог навязать его. Обратите внимание, что буквы не смежны в EBCDIC, и C не требует, чтобы они были.

Для одной char нет библиотечной функции, вам нужно сначала построить строку:

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

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

Вы также можете использовать функцию <a href="http://www.manpagez.com/man/3/atoi/" rel="noreferrer">atoi()</a> для преобразования, если у вас есть строка, но <a href="http://linux.die.net/man/3/strtol" rel="noreferrer">strtol()</a> лучше и безопаснее.

Как отметили комментаторы, вызывать функцию для этого преобразования крайне сложно; Ваш первоначальный подход к вычитанию «0» является правильным способом сделать это. Я просто хотел показать, как здесь будет использоваться рекомендуемый стандартный подход преобразования числа в виде строки в «истинное» число.

9 голосов
/ 23 апреля 2009

Попробуйте это:

char c = '5' - '0';
5 голосов
/ 24 апреля 2009
int i = c - '0';

Вы должны знать, что это не выполняет никакой проверки по отношению к персонажу - например, если символ был 'a', тогда вы получите 91 - 48 = 49. Особенно если вы имеете дело с пользовательским или сетевым вводом вам, вероятно, следует выполнить проверку, чтобы избежать плохого поведения в вашей программе. Просто проверьте диапазон:

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

Обратите внимание, что если вы хотите, чтобы ваше преобразование обрабатывало шестнадцатеричные цифры, вы можете проверить диапазон и выполнить соответствующий расчет.

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

Это преобразует один шестнадцатеричный символ, независимо от прописных или строчных букв, в целое число.

5 голосов
/ 23 апреля 2009

Вы можете использовать atoi, который является частью стандартной библиотеки.

2 голосов
/ 23 апреля 2009

Поскольку вы конвертируете только один символ, функция atoi () является избыточной. atoi () полезна, если вы конвертируете строковые представления чисел. Другие посты привели примеры этого. Если я правильно прочитал ваш пост, вы конвертируете только один числовой символ. Таким образом, вы собираетесь преобразовать только символ в диапазоне от 0 до 9. В случае преобразования только одного числового символа ваше предложение вычесть «0» даст вам желаемый результат. Причина, по которой это работает, заключается в том, что значения ASCII являются последовательными (как вы сказали). Таким образом, вычитая значение ASCII 0 (значение ASCII 48 - см. Таблица ASCII для значений) из числового символа, получим значение числа. Итак, ваш пример c = c - '0', где c = '5', что на самом деле происходит, это 53 (значение ASCII 5) - 48 (значение ASCII 0) = 5.

Когда я впервые опубликовал этот ответ, я не принял во внимание ваш комментарий о том, что он может быть на 100% переносимым между различными наборами символов. Я еще немного огляделся вокруг, и кажется, что твой ответ все еще в основном правильный. Проблема в том, что вы используете символ, который является 8-битным типом данных. Который не будет работать со всеми типами символов. Прочтите эту статью Джоэл Спольски о Unicode , чтобы узнать больше информации о Unicode. В этой статье он говорит, что он использует wchar_t для символов. Это хорошо сработало для него, и он публикует свой веб-сайт на 29 языках. Итак, вам нужно изменить свой символ на wchar_t. Кроме этого, он говорит, что символы со значением 127 и ниже в основном одинаковы. Это будет включать символы, которые представляют числа. Это означает, что предложенная вами базовая математика должна работать на то, чего вы пытались достичь.

1 голос
/ 23 апреля 2009

Да. Это безопасно, если вы используете стандартные символы ascii, как в этом примере.

0 голосов
/ 03 июня 2017

Вы можете просто использовать функцию atol():

#include <stdio.h>
#include <stdlib.h>

int main() 
{
    const char *c = "5";
    int d = atol(c);
    printf("%d\n", d);

}
0 голосов
/ 21 июня 2014

Поскольку коды ASCII для '0', '1', '2' .... расположены от 48 до 57, они по существу непрерывны. Теперь арифметические операции требуют преобразования типа данных char в тип данных int. Вот что вы в основном делаете: 53-48 и, следовательно, он хранит значение 5, с которым вы можете выполнять любые целочисленные операции. Обратите внимание, что при преобразовании обратно из int в char компилятор не выдает ошибку, а просто выполняет операцию по модулю 256, чтобы поместить значение в приемлемый диапазон * 1001. *

0 голосов
/ 11 мая 2013

Как и предлагали другие, но в функции:

int char_to_digit(char c) {
    return c - '0';
}

Теперь просто используйте функцию. Если, в конце концов, вы решите использовать другой метод, вам просто нужно изменить реализацию (производительность, различия в кодировках и т. Д.), Вам не нужно будет менять вызывающих абонентов.

Эта версия предполагает, что c содержит символ, который представляет цифру. Вы можете проверить это перед вызовом функции, используя функцию isdigit в ctype.h.

0 голосов
/ 24 апреля 2009

Обычно, если нет гарантии, что ваш ввод находится в диапазоне '0' .. '9', вам нужно выполнить проверку следующим образом:

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

Альтернативой является использование справочной таблицы. Вы получаете простую проверку диапазона и преобразования с меньшим (и, возможно, более быстрым) кодом:

// 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. Я знаю , что это перебор . Я просто хотел представить его как альтернативное решение, которое может быть неочевидным.

...