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 62334×
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
|
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|

Vyhledávání software

Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
12.8.2018 16:58 /František Kučera Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář
16.7.2018 1:05 /František Kučera Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|