2009-04-23 15 views
33

Se voglio convertire un singolo numerica char al suo valore numerico, ad esempio, se:Char a int conversione in C

char c = '5'; 

e voglio c tenere 5 invece di '5', è al 100% portatile farlo in questo modo?

c = c - '0'; 

Ho sentito che tutti i set di caratteri memorizzare i numeri in ordine consecutivo quindi immagino che così, ma mi piacerebbe sapere se c'è una funzione di libreria organizzata per fare questa conversione, e come si è fatto in modo convenzionale. Sono un vero principiante :)

+0

@ Binary- il duplicato postato è per C++, anche se la risposta è la stessa, si applica ad una lingua diversa – TStamper

+0

È vero, la sfumatura mi sfuggì. –

+0

Buona domanda .. – SNce

risposta

27

Sì, questa è una conversione sicura. C lo richiede per funzionare. Questa garanzia è nella sezione 5.2.1 comma 2, del più recente standard ISO C, un progetto di recente delle quali è N1570:

Sia la fonte di base e set di caratteri di base di esecuzione avranno i seguenti membri:
[ ...]
10 decimali cifre
0 1 2 3 4 5 6 7 8 9
[...]
in entrambe le sorgenti ed esecuzione set di caratteri di base, il valore di ogni carattere dopo 0 nella abov L'elenco delle cifre decimali deve essere maggiore di il valore del precedente.

Sia ASCII che EBCDIC e set di caratteri derivati ​​da essi soddisfano questo requisito, motivo per cui lo standard C è stato in grado di imporlo. Si noti che le lettere sono non in EBCDIC contiguo e C non richiede che siano.

Non v'è alcuna funzione di libreria di farlo per un singolo char, si avrebbe bisogno di costruire una stringa prima:

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

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

È anche possibile utilizzare la funzione atoi() per eseguire la conversione, una volta che hai una stringa , ma strtol() è migliore e più sicuro.

Come i commentatori hanno sottolineato, tuttavia, è estremamente eccessivo chiamare una funzione per eseguire questa conversione; il tuo approccio iniziale per sottrarre '0' è il modo corretto per farlo. Volevo solo mostrare come sarebbe stato usato l'approccio standard raccomandato per convertire un numero come stringa in un numero "vero", qui.

+3

Questo è un modo semplice e costoso per fare ciò che è un'operazione molto semplice, int i = d - '0' –

+2

Questa è una risposta alla tua domanda ma non la migliore risposta. Questo è eccessivo. Hai risposto alla tua stessa domanda con c = c-'0 '; - questa è la migliore risposta – zooropa

+1

Sì, ovviamente l'uso di una funzione è eccessivo. Forse avrei dovuto essere più chiaro da quella parte. – unwind

1

Sì. Questo è sicuro finché si utilizzano caratteri ASCII standard, come in questo esempio.

5

È possibile utilizzare atoi, che fa parte della libreria standard.

9

Prova questo:

char c = '5' - '0'; 
+0

+1. Sto solo suggerendo di avvolgerlo in una funzione. – MyNameIsZero

2

Poiché si sta convertendo solo un carattere, la funzione atoi() è eccessiva. atoi() è utile se si convertono le rappresentazioni di stringa dei numeri. Gli altri post hanno fornito esempi di questo. Se leggo correttamente il tuo post, stai convertendo solo un carattere numerico. Quindi, stai solo convertendo un carattere che è compreso tra 0 e 9.Nel caso della conversione di un solo carattere numerico, il tuo suggerimento di sottrarre '0' ti darà il risultato che desideri. Il motivo per cui questo funziona è perché i valori ASCII sono consecutivi (come hai detto tu). Quindi, sottraendo il valore ASCII di 0 (valore ASCII 48 - vedi ASCII Table per i valori) da un carattere numerico darà il valore del numero. Quindi, il tuo esempio di c = c - '0' dove c = '5', ciò che sta realmente accadendo è 53 (il valore ASCII di 5) - 48 (il valore ASCII di 0) = 5.

Quando I prima ho postato questa risposta, non ho preso in considerazione il tuo commento sull'essere 100% portabile tra diversi set di caratteri. Ho fatto un po 'di più a guardarmi intorno e sembra che la tua risposta sia ancora per lo più corretta. Il problema è che stai usando un char che è un tipo di dati a 8 bit. Quale non funzionerebbe con tutti i tipi di caratteri. Leggi questo articolo per Joel Spolsky on Unicode per molte più informazioni su Unicode. In questo articolo, dice che usa wchar_t per i personaggi. Questo ha funzionato bene per lui e pubblica il suo sito web in 29 lingue. Quindi, avresti bisogno di cambiare il tuo char in un wchar_t. Oltre a questo, dice che il carattere sotto il valore 127 e sotto sono fondamentalmente gli stessi. Ciò include i caratteri che rappresentano i numeri. Ciò significa che la matematica di base che hai proposto dovrebbe funzionare per quello che stavi cercando di ottenere.

4
int i = c - '0'; 

È necessario essere consapevoli che questo non esegue alcuna convalida contro il carattere - per esempio, se il personaggio era 'un' allora si otterrebbe 91-48 = 49. Soprattutto se avete a che fare con l'utente o input di rete, dovresti probabilmente eseguire la convalida per evitare un cattivo comportamento nel tuo programma. Basta controllare la gamma:

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

Si noti che se si desidera la vostra conversione per gestire cifre esadecimali è possibile controllare la gamma e eseguire il calcolo appropriato.

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

Ciò convertirà un singolo carattere esadecimale, in maiuscolo o in minuscolo, in un numero intero.

+0

ctype.h fornisce le seguenti funzioni/macro per l'esecuzione della convalida: isdigit, isxdigit, isspace e molti altri. Vedi la pagina man. –

0

Normalmente, se non c'è alcuna garanzia che l'input è nel range '0' .. '9', che avrebbe dovuto effettuare un controllo del genere:

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

Un'alternativa è quella di utilizzare un tabella di ricerca. Si ottiene semplice controllo gamma e conversione con meno codice (e probabilmente più veloce):

// 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 noto che si tratta di un eccesso di . Volevo solo presentarlo come una soluzione alternativa che potrebbe non essere immediatamente evidente.

+1

#include .... if (isdigit (c)) {...} – sigjuice

0

Come altri hanno suggerito, ma avvolto in una funzione:

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

Ora basta utilizzare la funzione. Se, a valle, si decide di utilizzare un metodo diverso, è sufficiente modificare l'implementazione (prestazioni, differenze di caratteri, qualunque), non è necessario modificare i chiamanti.

Questa versione presuppone che c contenga un carattere che rappresenta una cifra. È possibile verificarlo prima di chiamare la funzione, utilizzando la funzione isdigit di ctype.h.

0

Poiché i codici ASCII per "0", "1", "2" .... sono posizionati da 48 a 57, sono essenzialmente continui. Ora le operazioni aritmetiche richiedono la conversione del tipo di dati char in tipo di dati int.Quindi, ciò che stai facendo in pratica è: 53-48 e quindi memorizza il valore 5 con cui puoi eseguire qualsiasi operazione su interi. Nota che durante la conversione da int a char il compilatore non restituisce alcun errore, ma esegue semplicemente un'operazione modulo 256 per mettere il valore nel suo range accettabile

0

si può semplicemente utilizzare la funzione atol():

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

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

}