web-dev-qa-db-de.com

Umwandlung von Zeichen in int in C

Wenn ich ein einzelnes numerisches char in seinen numerischen Wert konvertieren möchte, zum Beispiel:

char c = '5';

und ich möchte, dass c5 anstelle von '5' hält. Ist es zu 100% portabel, so zu tun?

c = c - '0';

Ich habe gehört, dass alle Zeichensätze die Zahlen in aufeinanderfolgender Reihenfolge speichern. Ich gehe also davon aus, aber ich würde gerne wissen, ob es eine organisierte Bibliotheksfunktion gibt, die diese Konvertierung vornimmt, und wie dies herkömmlich geschieht. Ich bin ein echter Anfänger :)

34
Ori Popowski

Ja, das ist eine sichere Konvertierung. C erfordert, dass es funktioniert. Diese Garantie befindet sich in Abschnitt 5.2.1, Absatz 2 der neuesten ISO-C-Norm. Ein neuer Entwurf davon ist N1570 :

Sowohl der grundlegende Quell- als auch der grundlegende Ausführungszeichensatz haben die folgenden Mitglieder:
[...]
die 10 Dezimalstellen Ziffern
0 1 2 3 4 5 6 7 8 9
[...]
Sowohl in den Quell- als auch in den Ausführungsgrundzeichensätzen wird der Der Wert jedes Zeichens nach 0 in der obigen Liste der Dezimalstellen muss um eins größer als .__ sein. der Wert des vorherigen.

Sowohl ASCII als auch EBCDIC und die daraus abgeleiteten Zeichensätze erfüllen diese Anforderung, weshalb der C-Standard dies durchsetzen konnte. Beachten Sie, dass Buchstaben in der EBCDIC nicht zusammenhängend sind und C dies nicht erfordert.

Es gibt keine Bibliotheksfunktion für eine einzelne char. Sie müssen zuerst eine Zeichenfolge erstellen:

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

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

Sie können auch die Funktion atoi() für die Konvertierung verwenden, sobald Sie eine Zeichenfolge haben. strtol() ist jedoch besser und sicherer.

Wie die Kommentatoren darauf hingewiesen haben, ist es extrem übertrieben, eine Funktion für diese Konvertierung aufzurufen. Ihr erster Ansatz, um '0' abzuziehen, ist der richtige Weg, dies zu tun. Ich wollte nur zeigen, wie der hier empfohlene Standardansatz, eine Zahl als Zeichenfolge in eine "echte" Zahl umzuwandeln, verwendet wird.

27
unwind

Versuche dies :

char c = '5' - '0';
9
lsalamon
int i = c - '0';

Sie sollten sich dessen bewusst sein, dass dies keine Überprüfung des Zeichens vornimmt. Wenn das Zeichen beispielsweise "a" wäre, würden Sie 91 - 48 = 49 erhalten. Insbesondere wenn Sie sich mit Benutzer- oder Netzwerkeingaben beschäftigen, sollten Sie dies wahrscheinlich tun Validierung durchführen, um Fehlverhalten in Ihrem Programm zu vermeiden. Überprüfen Sie einfach den Bereich:

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

Wenn Sie möchten, dass Ihre Konvertierung Hex-Ziffern verarbeitet, können Sie den Bereich überprüfen und die entsprechende Berechnung durchführen.

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

Dadurch wird ein einzelnes Hex-Zeichen (unabhängig von Groß- oder Kleinbuchstaben) in eine Ganzzahl umgewandelt.

5
spinfire

Sie können atoi verwenden, das Teil der Standardbibliothek ist.

5
weloytty

Da Sie nur ein Zeichen konvertieren, ist die Funktion atoi () ein Overkill. atoi () ist nützlich, wenn Sie Zeichenfolgendarstellungen von Zahlen konvertieren. Die anderen Beiträge haben Beispiele dafür gegeben. Wenn ich Ihren Beitrag richtig gelesen habe, konvertieren Sie nur ein numerisches Zeichen. Sie konvertieren also nur ein Zeichen im Bereich von 0 bis 9. Wenn Sie nur ein numerisches Zeichen konvertieren, erhalten Sie mit Ihrem Vorschlag zum Subtrahieren von '0' das gewünschte Ergebnis. Der Grund, warum dies funktioniert, ist, dass die Werte von ASCII aufeinander folgen (wie Sie sagten). Wenn Sie also den ASCII - Wert von 0 (ASCII-Wert 48 - siehe ASCII - Tabelle für Werte) von einem numerischen Zeichen abziehen, wird der Wert der Zahl angegeben. Ihr Beispiel für c = c - '0', wobei c = '5' ist. Was wirklich passiert, ist 53 (der ASCII - Wert von 5) - 48 (der ASCII - Wert von 0) = 5.

Als ich diese Antwort zum ersten Mal veröffentlichte, habe ich nicht berücksichtigt, dass Ihr Kommentar zu 100% tragbar zwischen verschiedenen Zeichensätzen ist. Ich habe mich ein bisschen umgesehen und es scheint, als ob Ihre Antwort noch immer richtig ist. Das Problem ist, dass Sie ein Zeichen verwenden, bei dem es sich um einen 8-Bit-Datentyp handelt. Was nicht mit allen Charaktertypen funktioniert. Lesen Sie diesen Artikel von Joel Spolsky über Unicode , um weitere Informationen zu Unicode zu erhalten. In diesem Artikel sagt er, dass er wchar_t für Zeichen verwendet. Das hat für ihn gut funktioniert und er veröffentlicht seine Website in 29 Sprachen. Sie müssten also Ihren Charakter in einen wchar_t ändern. Ansonsten sagt er, dass die Zeichen unter dem Wert 127 und darunter im Wesentlichen gleich sind. Dies würde Zeichen enthalten, die Zahlen darstellen. Dies bedeutet, dass die von Ihnen vorgeschlagene grundlegende Mathematik für das, was Sie erreichen wollten, funktionieren sollte.

2
zooropa

Ja. Dies ist sicher, solange Sie Standard-ASCII-Zeichen verwenden, wie Sie es in diesem Beispiel tun.

1
Joe Corkery

Wie andere vorgeschlagen haben, aber in eine Funktion verpackt:

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

Nutzen Sie jetzt einfach die Funktion. Wenn Sie sich später für eine andere Methode entscheiden, müssen Sie lediglich die Implementierung ändern (Leistung, Zeichensatzunterschiede, was auch immer).

Diese Version geht davon aus, dass c ein Zeichen enthält, das eine Ziffer darstellt. Sie können dies vor dem Aufruf der Funktion mit der isdigit-Funktion von ctype.h überprüfen.

0
MyNameIsZero

Sie können einfach die Funktion atol() verwenden:

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

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

}
0
Dylan halls

Wenn es keine Garantie gibt, dass Ihre Eingabe im Bereich '0' .. '9' liegt, müssen Sie normalerweise eine Prüfung wie folgt durchführen:

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

Eine Alternative ist die Verwendung einer Nachschlagetabelle. Sie erhalten eine einfache Bereichsüberprüfung und -Umwandlung mit weniger (und möglicherweise schnellerem) 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. Ich know, dass dies ein Overkill ist. Ich wollte es nur als alternative Lösung vorstellen, die vielleicht nicht sofort ersichtlich ist.

0
Ates Goral

Da die ASCII -Codes für '0', '1', '2' ... von 48 bis 57 gesetzt werden, sind sie im Wesentlichen kontinuierlich. Jetzt erfordern die arithmetischen Operationen die Konvertierung des char-Datentyps in den int-Datentyp. Daher tun Sie im Wesentlichen Folgendes: 53-48 und speichert somit den Wert 5, mit dem Sie beliebige Ganzzahloperationen ausführen können. Beachten Sie, dass der Compiler beim Konvertieren von int nach char keinen Fehler ausgibt, sondern lediglich eine modulo 256-Operation ausführt, um den Wert in den zulässigen Bereich zu bringen

0
chinmay