C-keeles stringi teisendamine arvuks: Kuidas kasutada atoi ja strtol turvaliselt

1. Sissejuhatus

C-keele programmeerimisel tuleb tihti ette olukordi, kus on vaja teisendada tekst arvuks. Näiteks juhul, kui kasutaja sisestab andmeid või loetakse numbreid failist. Sellistel puhkudel on väga mugav kasutada standardteegis sisalduvat atoi-funktsiooni. Kuid kuigi atoi on lihtne ja mugav, peituvad selles ka mõned lõksud. Käesolevas artiklis selgitame atoi kasutusviise, selle piiranguid ja alternatiive. Saame neist korralikult aru, et kasutada seda turvaliselt ja tõhusalt.

2. Mis on atoi-funktsioon?

atoi (ASCII to Integer) on üks C-keele standardteegis pakutavatest funktsioonidest, mille ülesanne on teisendada tekst (string) täisarvuks. Konkreetsemalt kasutatakse seda järgmiselt:

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

int main() {
    int num = atoi("12345");
    printf("%dn", num);  // Väljund: 12345
    return 0;
}

Selles koodinäites teisendatakse string “12345” täisarvuks 12345. Kasutamine on lihtne ja sobib hästi ka algajatele programmeerijatele.

3. Kuidas atoi-funktsioon töötab

atoi-funktsioon loeb stringi algusest järjestikuseid numbreid ja teisendab need täisarvuks. Kui kohtab märki, mis ei ole number, siis teisendamine lõppeb. Siin on mõned näited:

printf("%dn", atoi("123abc"));   // Väljund: 123
printf("%dn", atoi("abc123"));   // Väljund: 0

atoi töötleb ainult esimesena esinevad numbrid ja ignoreerib kõike, mis tuleb pärast seda. Tänu sellele saab segatud stringist välja võtta vajaliku arvulise osa.

4. atoi-funktsiooni piirangud

atoi-funktsiooni suurim puudus on see, et see ei toeta veatöötlust. Näiteks kui teisendamine ebaõnnestub, tagastab atoi lihtsalt 0, mistõttu ei ole võimalik aru saada, kas sisend oli vigane või sisestati tõesti 0. Samuti toetab atoi ainult märgiga täisarve ning väga suurte või vahemikust väljas olevate väärtuste korral võib tekkida ületäitumise (overflow) oht.

printf("%dn", atoi("abc"));   // Väljund: 0
printf("%dn", atoi("0"));     // Väljund: 0

Nagu näha, ei saa eristada viga ja korrektset teisendustulemust. Seetõttu ei ole atoi sobiv kasutamiseks olukordades, kus on vajalik täpne veatöötlus.

5. Tähelepanekud mitme lõimega (multithread) keskkonnas

atoi ei ole lõimesõbralik (thread-safe) funktsioon mitme lõimega keskkonnas. Kui mitu lõime kasutavad atoi-funktsiooni samaaegselt, võib see põhjustada andmete konflikte ning anda valesid tulemusi. Seetõttu on soovitatav kasutada alternatiive, nagu strtol, mis on lõimesõbralik ja turvalisem sellistes olukordades.

6. Sisendi valideerimise olulisus

Enne kui annad kasutaja sisendi otse atoi-funktsioonile, tuleks kindlasti teostada valideerimine. Näiteks saab isdigit-funktsiooni abil kontrollida, kas string koosneb ainult numbrimärkidest.

const char* str = "123abc";
int i = 0;
while (str[i] != '\0') {
    if (!isdigit(str[i]) && str[i] != '-') {
        printf("Vigane sisend.\n");
        return 1;
    }
    i++;
}

Sellise valideerimise abil saab ennetada vigase sisendi töötlemist ja vältida ootamatuid tulemusi programmis.

7. strtol-funktsioon: alternatiiv atoi-le

Kui vajad veatöötlust, on soovitatav kasutada strtol-funktsiooni atoi asemel. strtol võimaldab määrata teisenduse lõppkoha endptr abil, mis teeb võimalikuks tuvastada, kus teisendus ebaõnnestus.

char *end;
long num = strtol("123abc", &end, 10);
printf("%ldn", num);   // Väljund: 123
printf("%sn", end);    // Väljund: abc

Selles näites teisendatakse “123” edukalt arvuks ning teisendamata osa (“abc”) jääb end muutuja kaudu kättesaadavaks. Selline detailne veahaldus ei ole atoi puhul võimalik.

8. Näide veatöötlusega koodist

Vaatame järgmiseks näidet, kus kasutatakse strtol-funktsiooni koos veatöötlusega. See näitab, kuidas saab tuvastada, kui teisendus ebaõnnestub.

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

int main() {
    char *end;
    long num = strtol("123abc", &end, 10);

    if (*end != '\0') {
        printf("Teisendamine ebaõnnestus: %sn", end);
    } else {
        printf("Teisendamine õnnestus: %ldn", num);
    }

    return 0;
}

strtol võimaldab kontrollida teisendamata osa olemasolu ning selle abil saab kirjutada palju töökindlamaid ja turvalisemaid programme.

9. Parimad tavad

Järgmistes olukordades tasub kaaluda, kas kasutada atoi või strtol funktsiooni:

  • Kui sisend on lihtne ja veatöötlust pole vaja: atoi on sobiv ja mugav valik.
  • Kui vajad veatöötlust või töötled väga suuri arve: soovitatav on kasutada strtol-funktsiooni, kuna see on turvalisem.

Lisaks on väga oluline kontrollida kasutaja sisestatud andmeid või väliseid sisendeid. Korralik valideerimine aitab ennetada ootamatuid vigu ning vähendab turvariske.

10. Kokkuvõte

atoi on kasulik ja lihtne tööriist stringi täisarvuks teisendamiseks C-keeles. Kuid kuna see ei toeta veatöötlust, ei sobi see olukordadesse, kus on vaja usaldusväärsust. Kui tuleb töötada suurte arvudega või vajad täpset veakontrolli, tasub kaaluda strtol-funktsiooni kasutamist. Turvaliste ja tõhusate programmide kirjutamiseks on oluline valida olukorrale sobiv funktsioon.

年収訴求