Obsah
V této části se budeme zabývat standardním textovým vstupem a výstupem a zaměříme se na možnosti jeho formátování. Každý program zpracovává nějaká vstupní data a sděluje nám výsledky touto činností získané. Pokud by tomu tak nebylo, neměli bychom zřejmě důvod takový program vůbec psát a spouštět. Vstup a výstup budeme obvykle zkráceně zapisovat I/O (Input / Output).
Vstup do programu provádíme pomocí vstupních funkcí. Tyto funkce nám umožňují zpracování vstupu buď opravdu po jednotlivých znacích, nebo po celých slovech či řádcích. Nejpokročilejší z možností vstupu je vstup formátovaný, kdy symbolicky určíme očekávaný formát vstupu a proměnnou, do níž má vstup proběhnout, a příslušná funkce takový vstup provede, nebo ohlásí chybu.
Potřebné znalosti | |
K zvládnutí obsahu této kapitoly je nutné mít znalosti z kapitoly 2 až 6 - rozumět doposud probrané látce, umět vytvářet funkce, vědět jak funkcím předávat argumenty a jak z nich získávat hodnoty zpět. Umět vytvářet rekurzivní funkce a používat cizí funkce. |
Ikdyž jsou čísla důležitá, budou naše programy často potřebovat načítat z klávesnice také znaky. Pro vstup znaků používáme getchar a putchar, případně jim odpovídající volání funkcí pracujících se standardním vstupním a výstupním proudem - getc(stdin) a putc(c, stdout).
Projděme si nyní syntaxi těchto příkazů:
Přečte ze standardního vstupu jeden znak, který vrátí jako svou návratovou hodnotu. V případě chyby vrátí hodnotu EOF.
int putchar(int c);
Zadaný znak zapíše na standardní výstup. Zapsaná hodnota je současně návratovou hodnotou, v případě chyby vrací EOF.
Nyní si použití právě probraných příkazů ukažme na příkladu. Naším úkolem bude načíst znak a vytisknout jeho ASCII hodnotu.
Standardní vstup a výstup řádků je jednoduchou nadstavbou nad čtením znaků.
Syntaxe:
Tyto funkce používají hlavičkový soubor stdio.h. Funkce gets() čte zadávané znaky z klávesnice, dokud není načten znak "návrat na začátek řádku" (tj. dokud uživatel nestiskl klávesu ENTER). Přečtené znaky ukládá do pole str. Znak "návrat na začátek řádku" se k řetězci nepřidává. Místo toho je převeden na nulový ukončovací znak. Při úspěchu vrací gets() ukazatel na začátek str. Nastane-li chyba, vrací se nulový ukazatel.
Funkce puts() vypíše na obrazovku řetězec, na který ukazuje str. K řetězci se automaticky přidává sekvence "návrat na začátek řádku" a "nový řádek". Při úspěchu vrací puts() nezápornou hodnotu. Nastane-li chyba vrací se EOF.
Správné pochopení funkcí gets() a puts() si prověříme na příkladu. Ukážeme si jak použít návratovou hodnotu funkce gets() pro přístup k řetězci obsahující zadané vstupní informace. Zároveň budeme také testovat, zda při zpracování gets() nedošlo k chybě.
Pro formátovaný výstup používáme funkci printf(). Přesná syntaxe je následující:
První argument format určuje formátovací řetězec. Ten může obsahovat popis formátu pro každý argument, nebo text, který bude zapsán do výstupu. Popis formátu vždy začíná znakem %. Chceme-li znak % použít jako text, zdvojíme jej: %%. Návratová hodnota reprezentuje počet znaků zapsaných do výstupu, nebo EOF v případě chyby. Plné určení formátu je poněkud obsáhlejší:
[flags] [width] [.prec] [l|L] type_char
Určení formátu ve funkci printf():
Určení datového typu položky ve funkci printf():
Tabulka 7.2.
|
Na několika příkladech si ukážeme možnosti funkce printf(). V prvním příkladu si ukážeme možnosti tisku s určitou přesností.
Příklad 7.3. | |
/****************************** * printf_1.c * 19.03.2002 ******************************/ #include <stdio.h> int main(void) { printf("%.5d\n",10); printf("$%.2f\n",54.32); printf("%.10s", "Ne vsechno co je napsane se vytiskne\n"); return 0; } |
Výpis programu pak vypadá následovně:
00010 $54.32 Ne vsechno
Na dalším příkladu si ukážeme možnosti formátování. Vypíšeme hodnotu 25 čtyřmi různými způsoby: desítkově, osmičkově, šestnáctkově malými písmeny a šestnáctkově velkými písmeny. Vytiskneme také číslo v semilogaritmickém tvaru a malým ´e´ a s velkým ´E´.
Příklad 7.4. | |
/****************************** * printf_2.c * 19.03.2002 ******************************/ #include <stdio.h> int main(void) { printf("%d %o %x %X\n", 25, 25, 25, 25); printf("%e %E\n", 25.123, 25.123); return 0; } |
Výpis programu pak vypadá následovně:
25 31 19 19 2.512300e+01 2.512300E+01
Pro formátovaný standardní vstup použijeme funkci scanf() s následující syntaxí.
První argument je formátovací řetězec. Obsahuje podobné možnosti popisu formátu, jako u funkce printf().
Druhý argument je paměťovou oblast (adresa paměťové oblasti), do níž bude odpovídající vstupní hodnota uložena. V praxi jde nejčastěji o adresu proměnné, nebo o ukazatel na pole znaků.
Čtení ze vstupu probíhá tak, že první formátovací popis je použit pro vstup první hodnoty, která je uložena na první adresu, druhý formátovací popis je použit pro vstup druhé hodnoty uložené na druhou adresu, ...
Návratová hodnota funkce scanf nás informuje kladným celým číslem o počtu bezchybně načtených a do paměti uložených položek, nulou o nulovém počtu uložených položek a hodnotou EOF o pokusu číst ze vstupu více položek, než v něm bylo k dispozici.
Určení datového typu položky ve funkci scanf():
Tabulka 7.3.
|
Následující dva programy ukáží možnosti formátovaného vstupu. V prvním programu načítáme sadu znaků, do které patří pouze malá a velká písmena. Jestliže zadáme nějaké znaky, poté třeba číslice a poté opět nějaké znaky a stiskneme ENTER budou vytištěna jenom malá a velká písmena zadaná předtím, než jste stiskli klávesu s nějakým jiným znakem než je písmeno.
Příklad 7.5. | |
/****************************** * scnf_a-z.c * 19.03.2002 ******************************/ #include <stdio.h> int main(void) { char str[80]; printf("Zadejte znaky: \n"); scanf("%[a-zA-Z]",str); printf(str); return 0; } |
Další program umožňuje uživateli zadat číslo následované operátorem, za kterým následuje další číslo, například 5*6. Program pak provede zadanou operaci s čísly a zobrazí výsledek.
Příklad 7.6. | |
/****************************** * scnf_opr.c * 19.03.2002 ******************************/ #include <stdio.h> int main(void) { int i,j; char op; printf("Zadejte operaci: "); scanf("%d%c%d",&i, &op, &j); switch(op) { case '+': printf("%d",i+j); break; case '-': printf("%d",i-j); break; case '*': printf("%d",i*j); break; case '/': printf("%d",i/j); break; } return 0; } |
V paměti počítače můžeme provádět prakticky stejné operace, jako při standardním vstupu a výstupu. Jen musíme specifikovat vstupní respektive výstupní řetězec. Tyto operace se provádějí pomocí funkcí sprintf() a sscanf() s následující syntaxí.
int sprintf(char *buffer, const char *format[,argument, ...]); int sscanf(const char *buffer, const char *format[,address, ...]); |
Vstupní a výstupní řetězec je buffer, ostatní argumenty mají stejný význam jako u funkcí pro formátovaný standardní vstup a výstup.
A příklad na závěr. Máme za úkol vypsat úhly sinus a kosinus. Uživatel je vyzván, aby zadal mez, do kolika stupňů mají být obě funkce tabelovány. Ke zpracování vstupu a přípravě výstupu používáme dostatečně dimenzovaný řetězec.
Příklad 7.7. | |
/****************************** * v-v_buff.c * 19.03.2002 ******************************/ #include <stdio.h> #include <math.h> #define N 80 const od = 0; int main(void) { char b[N], *zahlavi = "\n x\tsin(x)\t cos(x)"; int x, po; double si, co, rad; printf("\nZadej do kolika stupnu:"); gets(b); sscanf(b, "%d", &po); puts(zahlavi); for ( x = od; x < po; x++) { rad = x / 180.0 * M_PI; si = sin(rad); co = cos(rad); sprintf(b, "%2d %10.5f %10.5f", x, si, co); puts(b); } printf("\nKONEC!\a\n"); return 0; } |
Po výzvě uživatele je jím žádaný vstup načten jako řetězec do připraveného znakového pole. Z něj je vstup zpracován pomocí funkce sscanf. Podobně je realizován výstup v těle cyklu. Řetězec je nejprve pomocí funkce sprintf naformátován do stejného pole, které již pro vstup nepotřebujeme. Pak je na výstup zapsán připravený řetězec pomocí funkce puts.
Následuje možný výstup:
zadej do kolika stupnu:3 x sin(x) cos(x) 0 0.00000 1.00000 1 0.01745 0.99985 2 0.03490 0.99939 KONEC!