strtol și strtod în C

Transformă text în număr și îți spune unde s-a oprit citirea și dacă valoarea a depășit limitele.

Sintaxă
#include <stdlib.h>
long strtol(const char *s, char **sfarsit, int baza);
double strtod(const char *s, char **sfarsit);

Ce face strtol și strtod

strtol citește un număr întreg ca atoi, dar prin al doilea argument îți spune unde s-a oprit: *sfarsit arată primul caracter necitit. Dacă sfarsit == s, nu a fost citită nicio cifră. Dacă *sfarsit != '\0', după număr a mai rămas text.

Al treilea argument este baza: 10 pentru zecimal, 16 pentru hexazecimal, 2 pentru binar, sau 0 ca funcția să recunoască singură prefixele 0x și 0.

Dacă numărul nu încape în long, funcția întoarce LONG_MAX sau LONG_MIN și setează errno la ERANGE. De aceea pui errno = 0 înainte de apel. strtod funcționează la fel pentru double. Există și strtoll, strtoul, strtof.

Parametri

Parametru Descriere
s Textul de convertit.
sfarsit Adresa unui char * în care se pune poziția unde s-a oprit citirea; poate fi NULL.
baza Baza de numerație (2–36) sau 0 pentru detectare automată.

Ce returnează

Valoarea citită; 0 dacă nu s-a citit nimic; LONG_MAX/LONG_MIN la depășire (cu errno = ERANGE).

Exemple

Exemplul 1: Validarea unei note

O funcție care acceptă doar un număr întreg complet, între 1 și 10.

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

static bool citeste_nota(const char *text, int *nota) {
    char *sfarsit;
    errno = 0;
    long valoare = strtol(text, &sfarsit, 10);
    if (sfarsit == text || *sfarsit != '\0' || errno == ERANGE || valoare < 1 || valoare > 10) {
        return false;
    }
    *nota = (int)valoare;
    return true;
}

int main(void) {
    const char *intrari[] = {"9", "10", "9a", "", "11", "99999999999999999999"};
    for (size_t i = 0; i < 6; i++) {
        int nota;
        if (citeste_nota(intrari[i], &nota)) {
            printf("\"%s\" -> nota %d\n", intrari[i], nota);
        } else {
            printf("\"%s\" -> invalid\n", intrari[i]);
        }
    }
    return 0;
}

Rezultat

"9" -> nota 9
"10" -> nota 10
"9a" -> invalid
"" -> invalid
"11" -> invalid
"99999999999999999999" -> invalid

Exemplul 2: Alte baze de numerație

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

int main(void) {
    printf("%ld\n", strtol("ff", nullptr, 16));
    printf("%ld\n", strtol("0x1A", nullptr, 0));
    printf("%ld\n", strtol("1011", nullptr, 2));
    printf("%ld\n", strtol("0755", nullptr, 0));
    return 0;
}

Rezultat

255
26
11
493

Exemplul 3: Mai multe numere dintr-o linie cu strtod

Fiecare apel continuă de unde s-a oprit cel precedent, prin pointerul sfarsit.

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

int main(void) {
    const char *preturi = "12.50 3.99 101.2";
    const char *p = preturi;
    char *sfarsit;
    double total = 0;
    for (double v = strtod(p, &sfarsit); sfarsit != p; v = strtod(p, &sfarsit)) {
        total += v;
        p = sfarsit;
    }
    printf("Total: %.2f lei\n", total);
    return 0;
}

Rezultat

Total: 117.69 lei

Greșeli frecvente

  • Nu verifici sfarsit: fără el, strtol nu este mai sigur decât atoi.
  • Verifici errno fără să-l fi pus pe 0 înainte; poate avea o valoare rămasă de la alt apel.
  • Treci rezultatul direct într-un int: long poate fi mai mare decât int (pe sisteme de 64 de biți, Linux și macOS). Verifică limitele înainte de conversie.

Comenzi înrudite

  • atoi, atol și atof: Transformă rapid textul de la începutul unui șir într-un număr, fără să semnaleze erori.
  • errno, perror și strerror: errno păstrează codul ultimei erori a unei funcții de bibliotecă; perror și strerror îl transformă într-un mesaj citibil.
  • scanf: Citește valori de la tastatură după un șablon (%d, %lf, %s) și le scrie la adresele primite; returnează câte valori a citit.
  • stdint.h și limits.h: Tipuri întregi cu dimensiune exactă (int32_t, uint8_t) și constantele cu valorile minime și maxime ale tipurilor (INT_MAX).
  • fgets: Citește un rând întreg (cu tot cu spații) într-un tablou de caractere, fără să depășească dimensiunea dată.