64 votes

convertir une chaîne en entier sscanf ou atoi

Gcc 4.4.4 c89

Quel est le meilleur moyen de convertir une chaîne de caractères en une valeur entière.

J'ai essayé 2 méthodes différentes : atoi et sscanf. Les deux fonctionnent comme prévu.

char digits[3] = "34";
int device_num = 0;

if(sscanf(digits, "%d", &device_num) == EOF) {
    fprintf(stderr, "WARNING: Incorrect value for device\n");
    return FALSE;
}

ou en utilisant atoi

device_num = atoi(digits);

Je pensais que le sscanf serait meilleur car il permet de vérifier les erreurs. Cependant, atoi ne fait aucune vérification.

Merci beaucoup pour tout conseil,

109voto

R.. Points 93718

Vous avez 3 choix :

  • atoi : C'est probablement le plus rapide si vous l'utilisez dans du code à performances critiques, mais il ne fait aucun rapport d'erreur. Si la chaîne ne commence pas par un entier, elle renvoie 0. Si la chaîne contient des éléments inutiles après le nombre entier, elle convertira la partie initiale et ignorera le reste. Si le nombre est trop grand pour tenir dans int le comportement n'est pas spécifié.
  • sscanf : Quelques rapports d'erreur, et vous avez beaucoup de flexibilité pour le type à stocker (versions signées/non signées de char/short/int/long/long long/size_t/ptrdiff_t/intmax_t). La valeur de retour est le nombre de conversions qui ont réussi, donc la recherche de "%d" retournera 0 si la chaîne de caractères ne commence pas par un nombre entier. Vous pouvez utiliser "%d%n" pour stocker l'index du premier caractère après l'entier qui est lu dans une autre variable, et ainsi vérifier si la chaîne entière a été convertie ou s'il y a des déchets après. Cependant, comme atoi Le comportement en cas de dépassement d'entier n'est pas spécifié.
  • strtol et la famille : Rapports d'erreurs robustes, à condition de définir errno à 0 avant d'effectuer l'appel. Les valeurs de retour sont spécifiées en cas de débordement et errno sera définie. Vous pouvez choisir n'importe quelle base numérique de 2 à 36, ou spécifier 0 comme base pour l'auto-interprétation des chiffres principaux. 0x y 0 en hexadécimal et octal, respectivement. Les choix de types à convertir sont les versions signées/non signées de long/long long/intmax_t. Si vous avez besoin d'un type plus petit, vous pouvez toujours stocker le résultat dans un fichier temporaire de type long o unsigned long et vérifiez vous-même le débordement. Puisque ces fonctions prennent un argument de type pointeur vers pointeur, vous obtenez également un pointeur vers le premier caractère suivant l'entier converti, gratuitement, afin de pouvoir dire si la chaîne entière était un entier ou analyser les données suivantes dans la chaîne si nécessaire.

Personnellement, je recommande le strtol famille pour le plus objectifs. Si vous faites quelque chose de rapide et sale, atoi pourrait répondre à vos besoins.

Par ailleurs, j'ai parfois besoin d'analyser des nombres pour lesquels les espaces en tête, les signes, etc. ne sont pas censés être acceptés. Dans ce cas, il est très facile de créer sa propre boucle for ( for (x=0; (unsigned)*s-'0'<10; s++) x=10*x+(*s-'0'); ) Ou vous pouvez utiliser if (isdigit(*s)) x=strtol(s, &s, 10); else /* error */ pour la robustesse.

10voto

Alok Singhal Points 33073

*scanf() La famille de fonctions renvoie le nombre de valeurs converties. Vous devez donc vérifier que sscanf() retourne 1 dans votre cas. EOF est retourné pour "échec de l'entrée", ce qui signifie que ssacnf() ne reviendra jamais EOF .

Pour sscanf() la fonction doit analyser la chaîne de format, puis décoder un nombre entier. atoi() n'a pas cette surcharge. Les deux souffrent du problème des valeurs hors limites qui entraînent un comportement indéfini.

Vous devez utiliser strtol() o strtoul() qui fournissent une détection et une vérification des erreurs bien meilleures. Elles vous permettent également de savoir si toute la chaîne a été consommée.

Si vous voulez un int vous pouvez toujours utiliser strtol() puis vérifiez la valeur retournée pour voir si elle se situe entre INT_MIN y INT_MAX .

4voto

PickBoy Points 54

A @R.. Je pense qu'il n'est pas suffisant de vérifier errno pour la détection des erreurs dans strtol appeler.

long strtol (const char *String, char **EndPointer, int Base)

Vous devrez également vérifier EndPointer pour les erreurs.

2voto

Steven Penny Points 18523

Combinaison des réponses de R.. et PickBoy pour des raisons de brièveté.

long strtol (const char *String, char **EndPointer, int Base)

// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);

0voto

Raghuram Points 2039

Si l'utilisateur entre 34abc et que vous le passez à atoi, il retournera 34. Si vous voulez valider la valeur saisie, vous devez utiliser isdigit sur la chaîne saisie de manière itérative.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X