web-dev-qa-db-fra.com

Conversion de caractère à int en C

Si je veux convertir un seul char numérique en sa valeur numérique, par exemple, si:

char c = '5';

et je veux que c conserve 5 au lieu de '5', est-il portable à 100% comme cela?

c = c - '0';

J'ai entendu dire que tous les jeux de caractères stockent les numéros dans un ordre consécutif, je suppose donc, mais j'aimerais savoir s'il existe une fonction de bibliothèque organisée pour effectuer cette conversion et comment procéder de manière classique. Je suis un vrai débutant :)

34
Ori Popowski

Oui, c'est une conversion en toute sécurité. C exige que cela fonctionne. Cette garantie figure à la section 5.2.1, paragraphe 2, de la dernière norme ISO C, dont un projet récent est N1570 :

Les jeux de caractères source et d'exécution de base doivent avoir les éléments suivants membres:
[...]
les 10 décimales chiffres
0 1 2 3 4 5 6 7 8 9
[...]
Dans les jeux de caractères de base source et d'exécution, le la valeur de chaque caractère après 0 dans la liste de chiffres décimaux ci-dessus doit être supérieure à la valeur de la précédente.

ASCII et EBCDIC, ainsi que les jeux de caractères dérivés de ceux-ci, satisfont à cette exigence. C'est pourquoi le standard C a pu l'imposer. Notez que les lettres sont pas contiguës dans EBCDIC, et que C n’en a pas besoin.

Il n'y a pas de fonction de bibliothèque pour le faire pour une seule char, vous devez d'abord créer une chaîne:

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

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

Vous pouvez également utiliser la fonction atoi() pour effectuer la conversion, une fois que vous avez une chaîne, mais strtol() est meilleur et plus sûr.

Comme les commentateurs l'ont souligné, il est extrêmement excessif d'appeler une fonction pour effectuer cette conversion; votre approche initiale pour soustraire «0» est la bonne façon de faire cela. Je voulais simplement montrer comment l'approche standard recommandée consistant à convertir un nombre sous forme de chaîne en un nombre "vrai" serait utilisée, ici.

27
unwind

Essaye ça :

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

Vous devez savoir que cela n'effectue aucune validation sur le caractère - par exemple, si le caractère était 'a', vous obtiendriez 91 - 48 = 49. Surtout si vous avez affaire à une entrée utilisateur ou réseau, vous devriez probablement effectuez la validation pour éviter les mauvais comportements dans votre programme. Il suffit de vérifier la plage:

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

Notez que si vous souhaitez que votre conversion traite les chiffres hexadécimaux, vous pouvez vérifier la plage et effectuer le calcul approprié.

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

Cela convertira un seul caractère hexadécimal, indépendant des majuscules ou des minuscules, en un entier.

5
spinfire

Vous pouvez utiliser atoi , qui fait partie de la bibliothèque standard.

5
weloytty

Comme vous ne convertissez qu'un seul caractère, la fonction atoi () est excessive. atoi () est utile si vous convertissez des représentations sous forme de chaîne de nombres. Les autres publications en ont donné des exemples. Si je lis votre message correctement, vous ne convertissez qu'un seul caractère numérique. Ainsi, vous n'allez convertir qu'un caractère compris entre 0 et 9. Si vous ne convertissez qu'un seul caractère numérique, votre suggestion de soustraire «0» vous donnera le résultat souhaité. La raison pour laquelle cela fonctionne est que les valeurs ASCII sont consécutives (comme vous l'avez dit). Ainsi, soustraire la valeur ASCII de 0 (valeur ASCII 48 - voir ASCII Tableau pour les valeurs) d'un caractère numérique donnera la valeur du nombre. Ainsi, votre exemple de c = c - '0' où c = '5', ce qui se passe réellement est 53 (valeur ASCII de 5) - 48 (valeur ASCII de 0) = 5.

Lorsque j'ai posté cette réponse pour la première fois, je n'avais pas pris en compte votre commentaire selon lequel vous pouviez être 100% portable entre différents jeux de caractères. J'ai fait quelques recherches plus poussées et il semble que votre réponse soit encore généralement correcte. Le problème est que vous utilisez un caractère qui est un type de données 8 bits. Ce qui ne fonctionnerait pas avec tous les types de caractères. Lisez cet article de Joel Spolsky sur Unicode pour plus d’informations sur Unicode. Dans cet article, il dit qu'il utilise wchar_t pour les caractères. Cela a bien fonctionné pour lui et il publie son site Web en 29 langues. Donc, vous devez changer votre caractère en wchar_t. Autre que cela, il dit que le caractère sous la valeur 127 et en dessous sont fondamentalement les mêmes. Cela inclurait des caractères qui représentent des nombres. Cela signifie que les calculs de base que vous avez proposés devraient fonctionner pour ce que vous tentiez d'atteindre.

2
zooropa

Oui. Ceci est sûr tant que vous utilisez des caractères ascii standard, comme dans cet exemple.

1
Joe Corkery

Comme d'autres l'ont suggéré, mais enveloppés dans une fonction:

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

Maintenant, utilisez simplement la fonction. Si, en bout de ligne, vous décidez d'utiliser une méthode différente, il vous suffit de modifier l'implémentation (performances, différences de jeu de caractères, etc.), vous n'aurez pas besoin de changer les appelants.

Cette version suppose que c contient un caractère représentant un chiffre. Vous pouvez vérifier cela avant d'appeler la fonction, en utilisant la fonction isdigit de ctype.h.

0
MyNameIsZero

Vous pouvez simplement utiliser la fonction atol()function:

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

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

}
0
Dylan halls

Normalement, si rien ne garantit que votre saisie se situe dans la plage "0" .. "9", vous devez effectuer une vérification comme celle-ci:

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

Une alternative consiste à utiliser une table de recherche. Vous obtenez une conversion de plage simple et avec moins de code (et éventuellement plus rapide):

// 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. Je sais qu'il s'agit d'un overkill. Je voulais juste la présenter comme une solution alternative qui n’est peut-être pas immédiatement évidente.

0
Ates Goral

Puisque les codes ASCII pour "0", "1", "2" ... sont placés de 48 à 57, ils sont essentiellement continus. Maintenant, les opérations arithmétiques nécessitent la conversion du type de données char en un type de données int. Par conséquent, vous procédez comme suit: 53-48 et stocke donc la valeur 5 avec laquelle vous pouvez effectuer toutes les opérations sur les nombres entiers. Notez que lors de la conversion d’intérieur en caractère, le compilateur ne génère aucune erreur mais effectue simplement une opération modulo 256 pour placer la valeur dans sa plage acceptable

0
chinmay