Konwersja Char do int w C

Jeśli chcę przekonwertować pojedynczą liczbę char na jej wartość liczbową, na przykład, jeśli:

char c = '5';

I chcę c trzymać 5 zamiast '5', czy to w 100% przenośne robi to tak?

c = c - '0';

Słyszałem, że wszystkie zestawy znaków przechowują liczby w kolejności po sobie, więc zakładam, że tak, ale chciałbym wiedzieć, czy istnieje zorganizowana funkcja biblioteczna do tej konwersji i jak to się robi konwencjonalnie. Jestem prawdziwym początkującym:)

 33
Author: Binary Worrier, 2009-04-23

10 answers

Tak, to bezpieczna konwersja. C wymaga, aby działało. Gwarancja ta znajduje się w sekcji 5.2.1 pkt 2 najnowszej normy ISO C, której najnowszym projektem jest N1570 :

Zarówno podstawowe zestawy znaków źródłowych, jak i podstawowe zestawy znaków wykonawczych mają następujące członkowie:
[...]
10 cyfr dziesiętnych
0 1 2 3 4 5 6 7 8 9
[...]
Zarówno w źródłowym, jak i wykonawczym podstawowym zestawie znaków, wartość każdego znaku po 0 Na powyższej liście cyfry dziesiętne są o jedną większą od wartość poprzedniego.

Zarówno ASCII, jak i EBCDIC oraz pochodzące z nich zestawy znaków spełniają ten wymóg, dlatego standard C był w stanie go narzucić. Zauważ, że litery nie sąsiadują ze sobą w EBCDIC, A C nie wymaga, aby były.

Nie ma funkcji bibliotecznej, która by to zrobiła dla pojedynczego char, trzeba by najpierw zbudować łańcuch znaków:

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

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

Możesz również użyć funkcji atoi(), aby konwersja, gdy masz ciąg, ale strtol() jest lepsza i bezpieczniejsza.

Jak zauważyli komentatorzy, wywołanie funkcji do tej konwersji jest skrajnym przesadą; Twoje początkowe podejście do odjęcia '0'jest właściwym sposobem na to. Chciałem tylko pokazać, w jaki sposób zostanie użyte zalecane standardowe podejście do konwersji liczby jako ciągu znaków na liczbę "prawdziwą", tutaj.

 27
Author: unwind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 23:27:40

Spróbuj tego:

char c = '5' - '0';
 9
Author: lsalamon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-17 16:43:01

Możesz użyć atoi, która jest częścią biblioteki standardowej.

 5
Author: weloytty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-03 00:40:30
int i = c - '0';

Powinieneś być świadomy, że to nie wykonuje żadnej walidacji względem znaku - na przykład, jeśli znak był 'a', otrzymasz 91-48 = 49. Zwłaszcza jeśli masz do czynienia z wejściem użytkownika lub sieci, prawdopodobnie powinieneś przeprowadzić walidację, aby uniknąć złego zachowania w programie. Wystarczy sprawdzić zakres:

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

Zauważ, że jeśli chcesz, aby konwersja obsługiwała cyfry szesnastkowe, możesz sprawdzić zakres i wykonać odpowiednie obliczenia.

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 */
}

Że konwertuje pojedynczy znak szesnastkowy, niezależny od dużych lub małych liter, na liczbę całkowitą.

 4
Author: spinfire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-15 04:37:27

Ponieważ konwertujesz tylko jeden znak, funkcja atoi() jest overkill. atoi () jest przydatne, jeśli konwertujesz reprezentacje łańcuchowe liczb. Inne posty podały tego przykłady. Jeśli dobrze przeczytałem twój post, konwertujesz tylko jeden znak liczbowy. Tak więc konwertujesz tylko znak, który jest w zakresie od 0 do 9. W przypadku konwersji tylko jednego znaku liczbowego, Twoja sugestia odejścia '0' da Ci pożądany wynik. The reason why to działa, ponieważ wartości ASCII są następujące po sobie (jak powiedziałeś). Tak więc, odjęcie wartości ASCII 0 (wartość ASCII 48-Patrz Tabela ASCII dla wartości) od znaku liczbowego da wartość liczby. Tak więc, twój przykład c = c - '0' gdzie C = '5', to co się naprawdę dzieje to 53 (wartość ASCII 5) - 48 (wartość ASCII 0) = 5.

Kiedy po raz pierwszy zamieściłem tę odpowiedź, nie brałem pod uwagę Twojego komentarza o byciu w 100% przenośnym między różnymi zestawy znaków. Trochę się rozglądałem i wydaje się, że Twoja odpowiedź jest nadal w większości poprawna. Problem polega na tym, że używasz znaku, który jest 8-bitowym typem danych. Co nie pasuje do wszystkich typów postaci. Przeczytaj ten artykuł autorstwa Joela Spolsky ' ego na temat Unicode, aby uzyskać więcej informacji na temat Unicode. W tym artykule mówi, że używa wchar_t dla znaków. Udało mu się to i publikuje swoją stronę internetową w 29 językach. Więc, trzeba by zmienić twój znak na wzar_t. poza tym, mówi, że znak pod wartością 127 i poniżej są w zasadzie takie same. Obejmuje to znaki, które reprezentują liczby. Oznacza to, że podstawowa matematyka, którą zaproponowałeś, powinna działać na to, co starałeś się osiągnąć.

 2
Author: zooropa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 16:26:48

Tak. Jest to bezpieczne, dopóki używasz standardowych znaków ascii, tak jak w tym przykładzie.

 1
Author: Joe Corkery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 13:28:27

Normalnie, jeśli nie ma gwarancji, że dane wejściowe są w "0"..Zakres '9' ,musiałbyś wykonać takie sprawdzenie:

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

Alternatywą jest użycie tabeli wyszukiwania. Otrzymujesz proste sprawdzanie zakresu i konwersję z mniejszym (i ewentualnie szybszym) kodem:

// 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 wiem że to jest przesada . Chciałem tylko przedstawić to jako alternatywne rozwiązanie, które może nie być natychmiast widoczne.

 0
Author: Ates Goral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-24 15:51:51

Jak sugerowali inni, ale zawinięte w funkcję:

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

Teraz wystarczy użyć funkcji. Jeśli, w dół linii, zdecydujesz się użyć innej metody, wystarczy zmienić implementację (wydajność, różnice charset, cokolwiek), nie trzeba zmieniać wywołujących.

Ta wersja zakłada, że c zawiera znak, który reprezentuje cyfrę. Możesz to sprawdzić przed wywołaniem funkcji, używając ctype.funkcja isdigit H.

 0
Author: MyNameIsZero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 22:19:08

Ponieważ kody ASCII dla '0','1','2'.... są umieszczone od 48 do 57 są zasadniczo ciągłe. Teraz operacje arytmetyczne wymagają konwersji typu danych char na typ danych int.Stąd to, co w zasadzie robisz, to: 53-48 i stąd przechowuje wartość 5, z którą można wykonać dowolne operacje integer.Zauważ, że podczas konwersji z powrotem z int do char kompilator nie daje błędu, ale po prostu wykonuje operację modulo 256, aby umieścić wartość w akceptowalnym zakresie

 0
Author: chinmay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-21 15:46:44

Możesz po prostu użyć funkcji atol():

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

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

}
 0
Author: Dylan halls,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-03 00:24:08