strtol(3)

Fonction de la bibliothèque C

Convertit le début d'une chaîne en long dans la base choisie, indique où la lecture s'est arrêtée via endptr et signale les débordements avec errno.

Synopsis
#include <stdlib.h>
long strtol(const char *restrict nptr, char **restrict endptr, int base);

Description

strtol lit un entier au début de nptr. Elle saute les blancs, accepte un signe, puis lit autant de chiffres valides que possible dans la base base, de 2 à 36 : au-delà de 9, les lettres a à z (ou A à Z) valent 10 à 35. En base 16, un préfixe 0x est accepté. Avec base à 0, le préfixe choisit : 0x pour l'hexadécimal, un 0 initial pour l'octal, sinon le décimal.

Si endptr n'est pas NULL, strtol y range l'adresse du premier caractère qu'elle n'a pas utilisé. Quand aucun chiffre n'a pu être lu, elle y range nptr lui-même. C'est ce qui fait toute la différence avec atoi(3).

Valeur de retour

L'entier converti, ou 0 si aucune conversion n'a eu lieu. Si la valeur dépasse ce que peut contenir un long, strtol renvoie LONG_MAX ou LONG_MIN et met errno à ERANGE. En cas de succès, errno n'est pas modifiée.

Pièges

0, LONG_MAX et LONG_MIN sont aussi des résultats valides. Pour savoir s'il y a eu débordement, il faut donc mettre errno à 0 juste avant l'appel, puis le tester juste après. Sans cette remise à zéro, tu lis peut-être l'erreur d'un appel précédent.

Une conversion complète demande trois vérifications : fin == nptr (aucun chiffre), errno == ERANGE (hors limites), *fin != '\0' (des caractères restent après le nombre). L'exemple les fait dans cet ordre.

Le résultat est un long. Pour le ranger dans un int, vérifie d'abord qu'il est entre INT_MIN et INT_MAX : c'est l'exercice fits_in_int.

En base 0, "010" vaut 8, pas 10, parce que le zéro initial annonce de l'octal. Si tu lis des nombres tapés par un humain, passe 10 explicitement.

Depuis C23, les bases 0 et 2 acceptent aussi le préfixe 0b. La glibc le gère depuis sa version 2.38, quand le programme est compilé en C23 : le même appel donne alors un résultat différent selon -std. musl, la bibliothèque C de l'environnement des exercices Grademe, renvoie 0 pour "0b101" même en C23. Ne compte pas sur ce préfixe si ton code doit tourner ailleurs.

Les blancs du début sont acceptés sans rien dire. Si tu veux les refuser, teste le premier caractère avec isspace avant l'appel.

Exemple

lire_nombre.c
#include <errno.h>#include <stdio.h>#include <stdlib.h>
int main(int argc, char **argv){    for (int i = 1; i < argc; i++) {        char *fin;        long v;
        errno = 0;        v = strtol(argv[i], &fin, 10);        if (fin == argv[i])            printf("\"%s\" : aucun chiffre\n", argv[i]);        else if (errno == ERANGE)            printf("\"%s\" : hors limites, strtol renvoie %ld\n", argv[i], v);        else if (*fin != '\0')            printf("\"%s\" : %ld, puis \"%s\" non lu\n", argv[i], v, fin);        else            printf("\"%s\" : %ld\n", argv[i], v);    }    return 0;}
Terminal
$ gcc -Wall -Wextra lire_nombre.c -o lire_nombre$ ./lire_nombre 42 "  -17abc" abc 99999999999999999999"42" : 42"  -17abc" : -17, puis "abc" non lu"abc" : aucun chiffre"99999999999999999999" : hors limites, strtol renvoie 9223372036854775807

Et l'effet de la base 0, compilé en C23 (le mode par défaut de GCC 15) puis en C17 :

bases.c
#include <stdio.h>#include <stdlib.h>
int main(void){    const char *essais[] = {"010", "0x1A", "0b101"};
    for (int i = 0; i < 3; i++) {        char *fin;        long v = strtol(essais[i], &fin, 0);
        printf("\"%s\" en base 0 : %ld, reste \"%s\"\n", essais[i], v, fin);    }    return 0;}
Terminal
$ gcc -Wall -Wextra bases.c -o bases$ ./bases"010" en base 0 : 8, reste """0x1A" en base 0 : 26, reste """0b101" en base 0 : 5, reste ""$ gcc -Wall -Wextra -std=gnu17 bases.c -o bases17$ ./bases17"010" en base 0 : 8, reste """0x1A" en base 0 : 26, reste """0b101" en base 0 : 0, reste "b101"

En C17, 0b101 se lit comme le nombre 0 suivi d'un texte que strtol n'a pas su convertir : fin pointe sur le b.

C

strtol

Écris gm_strtol, qui lit un long dans la base donnée, déduit la base du préfixe quand elle vaut 0 et place *endptr sur le premier caractère non converti.

Ouvrir l'exercice

À toi d'écrire le code.