LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (11) - Čtení a konverze čísel

Už umíme načíst text ze standardního vstupu. Dnes se zaměříme na čísla a to samozřejmě včetně detekce chyb.

30.12.2004 15:00 | Jan Němec | Články autora | přečteno 56009×

Standardní vstup a čísla

Minule jsme četli řetězce i jednotlivé znaky ze standardního vstupu. Dost často je také zapotřebí získat od uživatele číslo. V Céčku máme hned několik možností, jak načtení čísla implementovat.

Formátovaný vstup - scanf

Podobně jako funkcí printf můžeme vypsat libovolný počet hodnot různého typu na standardní výstup, lze se scanf naopak načíst hodnoty ze standardního vstupu do připravených proměnných.

int scanf(const char *format, ...);

Prvním parametrem je formátovací řetězec, který stejně jako u printf obsahuje řídící sekvence například %i (int), %x (unsigned šestnáctkově), %f (float) nebo %lf (double) a následují ukazatele na proměnné příslušného typu.

int i;
double f;
puts("Zadej jedno celé a jedno reálné číslo");
scanf("%i%lf", &i, &f);
printf("Zadal jsi %i a %f\n", i, f);

Všimněte si, že zatímco do printf se vkládají přímo hodnoty (proměnné), scanf potřebuje ukazatele na proměnné, neboť je modifikuje. Funkce scanf vrací počet načtených hodnot (čte se, dokud nedojde k chybě vstupu nebo chybě konverze na číslo) nebo EOF, pokud již na začátku čtení končí vstupní soubor. Problémem scanf a podobných funkcí je detekce chyb (nikdo nepřinutí uživatele, aby zadal skutečně číslo, aby nezmáčkl Ctrl + D, ...), neboť při uživatelském vstupu z klávesnice lze chyby očekávat a je obvykle třeba na ně přiměřeným způsobem reagovat. Z návratové hodnoty lze leccos vyčíst, ale pro dostatečně přesné vynadání uživateli to nemusí stačit. Pokud načítáme čísla pomocí scanf, nerozlišíme v některých případech chyby standardního vstupu od chyb konverze řetězce na číslo. Může být proto lepší nejprve načíst ze standardního vstupu řetězec pomocí fgets nebo moje_gets z minulého dílu a teprve potom jej zkonvertovat.

Konverze pomocí atoi, atol a atof

#include <stdlib.h>

 int atoi(const char *s);
 long atol(const char *s);
 double atof(const char *s);

Pro konverzi řetězce na číslo typu int, long nebo double můžeme použít některou z výše uvedených funkcí ze stdlib.h. V případě chyby konverze vracejí 0, takže praktická použitelnost i těchto funkcí je poněkud omezená. Nerozlišíme korektně zadanou nulu od řetězce, který nereprezentuje číslo.

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

int main(void) {
  char s[256];
  int i;

  fgets(s, 256, stdin);
  i = atoi(s);
  if (!i)
    puts("Chyba nebo nula");
  else
    printf("Korektně zadáno číslo %i\n", i);
  return 0;
}

Konverze pomocí strtol a strtod

V stdlib.h jsou naštěstí i funkce s rozumnějším chováním.

long strtol(const char *nptr, char **endptr, int base);
double strtod(const char *nptr, char **endptr);

Funkce strtol se snaží zkonvertovat počáteční část řetězce nprt na číslo. Řetězec je zapsán v soustavě base, lze tedy konvertovat nejen čísla z desítkové soustavy, ale jakékoli o základu od 2 do 36. Pokud je base nula, je soustava určená implicitně a sice stejným způsobem, jako při zápisu číselných konstant ve zdrojácích jazyka C. Konverze skončí na prvním znaku, který do příslušné soustavy nepatří. Pokud není ani jedna cifra platná, vrací funkce 0, v opačném případě zkonvertované číslo. K detekci chyb slouží prostřední parametr endptr typu ukazatel na ukazatel na char. Pokud do něj při volání vložíme adresu nějakého řetězce (ukazatele na char), funkce jej namíří na první znak, který nepatří do zvolené číselné soustavy. Pokud tedy konvertovaný řetězec nptr obsahuje pouze číslo, měl by po bezchybném průběhu konverze *endptr ukazovat na ukončovací nulu řetězce nptr. Pokud nás detekce chyb nezajímá, můžeme jako endptr použít konstantu NULL.

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

 int main(void) {
  char s[256];
  long l;
  char *chyba;

  fgets(s, 256, stdin);
  l = strtol(s, &chyba, 10);
  if (chyba == s) {
    puts("Úplný nesmysl");
    return 1;
  }
  if (*chyba != '\n' && *chyba != 0) {
    puts("Za číslem byly ještě další znaky, nevadí.");
  }
  printf("Zadáno %i\n", (int) l);
  return 0;
}

Pro konverzi řetězce na reálná čísla použijeme strtod. Chová podobně, pouze neumožňuje volbu číselné soustavy, musíme se spokojit s desítkovou.

Pokud nestačí ani detekce chyb, jakou implementují tyto funkce, je třeba napsat konverzi řetězce na číslo ručně. Díky přístupu k jednotlivým znakům řetězce je to jen jednoduché programátorské cvičení.

Převod čísla na řetězec

Občas je třeba převod opačným směrem, z čísel na řetězec. Zde můžeme použít funkci sprintf, která se od printf liší pouze prvním parametrem - řetězcem, do něhož je přesměrován výstup.

char s[256];
sprintf(s, "%i + %i = %i", 1, 1, 2);
puts(s);

Při použití funkce sprintf je třeba dát pozor na velikost řetězce. Nelze třeba volat

char s[256];
sprintf("Uživatel zadal %s", neznamy_retezec);

neboť hrozí přetečení řetězce s podobně jako v minulém dílu u funkce gets. Zde je situace přece jen o něco lepší, neboť konvertované proměnné narozdíl od standardního vstupu máme (měli bychom mít) pod kontrolou. Problém řeší funkce snprintf, která má jako druhý parametr maximální délku řetězce. Bohužel snprintf není zcela standardní (například v MS Visual C++ se jmenuje _snprintf), zájemce proto odkazuji na man snprintf.

Parametry funkce main

Zatím jsme používali funkci main bez parametrů. Norma C připouští ještě jeden způsob definice.

int main(int argc, char *argv[])

Tímto způsobem lze snadno získat parametry programu zadané při spuštění. V argc je jejich počet a argv je pole řetězců - parametrů. Názvy proměnných argc a argv sice nejsou stanoveny, ale snad žádný C programátor by je nepojmenoval jinak. Díky kompatibilitě polí a ukazatelů lze argv definovat také jako ukazatel na ukazatel na char. Pokud například v shellu spustíme program

./program 1 2

bude v argc 3, v argv[0] "./program", v argv[1] "1" a v argv[2] "2". Prvním parametrem je tedy samotný program. Nelze se na to však zcela spoléhat, při spuštění pomocí příslušných funkcí (viz man fork, man execlp) lze programu podstrčit libovolné parametry, nicméně jakýkoli slušný nástroj nastaví první parametr tak, jak jsem popsal.

Příklad pro dnešní díl

Ukážeme si, program suma, který sečte své parametry a výsledek vypíše na standardní výstup.

/* cc suma.c -o suma */

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

int main(int argc, char **argv) {
  int suma = 0, i;
  char *chyba, *s;

  /* Pro všechny parametry kromě prvního */
  for (i = 1; i < argc; i++) {
    /* do s dej adresu i-tého řetězce */
    s = argv[i];
    /* přičti číslo do sumy */
    suma += (int) strtol(s, &chyba, 10);
    if (chyba == s) {
      /* číslo bylo úplně špatně */
      printf("Chyba: formát čísla %s\n", s);
      return 1;
    }
    if (*chyba)
      /* nebylo úplně špatně, jen nějaké znaky navíc */
      printf("Varování: divná znaky v čísle \"%s\" na pozici %i\n",
        s, chyba - s + 1);
  }
  printf("%i\n", suma);
  return 0;
}

Když program spustíme v shellu s číselnými parametry

./suma 1 2 3 4 5

vypíše na standardní výstup 15.

Pokračování příště

V dalším dílu se podíváme na preprocesor. Ukážeme si, jak lze definovat konstanty na lexikální úrovni, vkládání souboru, podmíněný překlad.

Verze pro tisk

pridej.cz

 

DISKUZE

Super :) 31.12.2004 07:28 Pajus




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

15.5.2017 23:50 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 18. května od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.5.2017 16:42 /Honza Javorek
PyCon CZ, česká konference o programovacím jazyce Python, se po dvou úspěšných ročnících v Brně bude letos konat v Praze, a to 8. až 10. června. Na konferenci letos zavítá např. i Armin Ronacher, známý především jako autor frameworku Flask, šablon Jinja2/Twig, a dalších projektů. Těšit se můžete na přednášky o datové analytice, tvorbě webu, testování, tvorbě API, učení a mentorování programování, přednášky o rozvoji komunity, o použití Pythonu ve vědě nebo k ovládání nejrůznějších zařízení (MicroPython). Na vlastní prsty si můžete na workshopech vyzkoušet postavit Pythonem ovládaného robota, naučit se učit šestileté děti programovat, efektivně testovat nebo si v Pythonu pohrát s kartografickým materiálem. Kupujte lístky, dokud jsou.
Přidat komentář

2.5.2017 9:20 /Eva Rázgová
Putovní konference československé Drupal komunity "DrupalCamp Československo" se tentokrát koná 27. 5.2017 na VUT FIT v Brně. Můžete načerpat a vyměnit si zkušenosti z oblasti Drupalu 7 a 8, UX, SEO, managementu týmového vývoje, využití Dockeru pro Drupal a dalších. Vítáni jsou nováčci i experti. Akci pořádají Slovenská Drupal Asociácia a česká Asociace pro Drupal. Registrace na webu .
Přidat komentář

1.5.2017 20:31 /Pavel `Goldenfish' Kysilka
PR: 25.5.2017 proběhne v Praze konference na téma Firemní informační systémy. Hlavními tématy jsou: Informační systémy s vlastní inteligencí, efektivní práce s dokumenty, mobilní přístup k datům nebo využívání cloudu.
Přidat komentář

15.4.2017 15:20 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě IoT a radiokomunikace? Přijď na sraz spolku OpenAlt, který se bude konat ve středu 19. dubna od 18:30 v Šenkovně (Sokolská 60, Praha 2).
Přidat komentář

5.3.2017 19:12 /Redakce Linuxsoft.cz
PR: 23. března proběhne v Praze konferenci na téma Cloud computing v praxi. Hlavními tématy jsou: Nejžhavější trendy v oblasti cloudu a cloudových řešení, Moderní cloudové služby, Infrastruktura současných cloudů, Efektivní využití cloudu, Nástrahy cloudových řešení a jak se jim vyhnout.
Přidat komentář

27.2.2017 22:12 /František Kučera
Pozvánka na 137. sraz OpenAlt – Praha: Tentokrát jsme si pro vás připravili neobvyklou akci. Ve středu 1.3. v 17:30 nás přivítá sdružení CZ.NIC ve svých prostorách v Milešovské ulici číslo 5 na Praze 3, kde si pro nás připravili krátkou prezentaci jejich činnosti. Následně navštívíme jejich datacentrum pod Žižkovskou věží. Provedou nás prostory, které jsou běžnému smrtelníkovi nedostupné!
Po ukončení prohlídky se všchni odebereme do hostince U vodoucha, Jagelonská 21, Praha 3 pochutnat si na některém z vybraných piv či dát si něco na zub. Rezervaci máme od 19:30, heslo je OpenAlt.
Ale pozor! Do prostor datového centra máme omezený přístup, dostane se tam pouze 10 lidí! Takže kdo přijde dříve, ten má přednost, a občanky s sebou! Kdo nebude chtít na prohlídku datového centra, může se pomalu přesunout do hostince U vodoucha a u nepřeberné nabídky piv počkat na ostatní.
Přidat komentář

18.1.2017 0:49 /František Kučera
Členové a příznivci spolku OpenAlt se pravidelně schází v Praze a Brně. Fotky z pražských srazů za uplynulý rok si můžete prohlédnout na stránkách spolku. Příští sraz se koná už 19. ledna – tentokrát je tématem ergonomie ovládání počítače – tzn. klávesnice, myši a další zařízení. Také budete mít příležitost si prohlédnout pražský hackerspace Brmlab.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

1.8.2017 7:32 / Cassidy
structural consultants

30.7.2017 11:12 / Jaromir Obr
Národní znaky

27.7.2017 12:24 / Jaromir Obr
Cteni/zapis

26.7.2017 21:12 / Jaromir Obr
Podminka

15.6.2017 9:34 / Ondřej Havlas
php,

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2017) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze