[Obsah] | [Cvičení 2] |
notepad.exe text.txt
představuje
spuštění programu notepad (poznámkový blok) s jedním parametrem - jménem souboru, který má být automaticky otevřen.
Abychom v hlavním programu v jazyce C mohli přistupovat k parametrům, musíme deklarovat hlavičku hlavního programu takto:
int main(int argc, char **argv) { ... return 0; }nebo
int main(int argc, char *argv[]) { ... return 0; }Hodnota argc nese počet parametrů na příkazovém řádku. Tento počet je včetně jména spouštěného programu! Pokud bychom programovali poznámkový blok v jazyce C a spouštěli jej
notepad.exe text.txt
, měl by parametr argc hodnotu 2. V případě spouštění fiktivního programu
progr
se dvěma parametry, progr nadpis 12
, má argc hodnotu 3.
Parametr argv je ukazatel na pole řetězů, které představují parametry příkazové řádky, včetně názvu programu. Tedy, argv[0]
je ukazatel
na řetězec s názvem spouštěného programu, který může být včetně cesty, záleží na platformě, operačním systému apod. Dále, argv[1]
je řetězec s prvním parametem, argv[2]
je řetězec s druhým parametrem atd.
Vrátíme-li se k příkladu s poznámkovým blokem a uvažujeme-li standardní instalaci systému Windows, pak argv[0]
je řetězec
C:\WINDOWS\notepad.exe
, argv[1]
má hodnotu text.txt
.
Ve druhém příkladu s programem prog obsahuje argv[0]
název programu (event. včetně cesty), argv[1]
obsahuje řetězec
nadpis
a argv[2]
řetězec (!) 12
.
Hlavní program v úvodu kapitoly je deklarován jako funkce s návratovou hodnotou typu int
(hlavní program může vracet pouze
celé číslo). Každý program může při ukončení předat operačnímu systému (vrátit) číslo, tzv. návratový kód.
Platí nepsané pravidlo, že hodnota 0 znamená úspěšné ukončení programu, nenulová hodnota chybu.
Význam nenulových návratových hodnot není dán a záleží jen na programátorovi, jak hodnoty využije
(měl by vše popsat v dokumentaci programu).
Princip se využívá zejména v dávkových souborech (typu .bat
, skriptech v UNIXu/Linuxu), kdy po skončení programu
je možné větvit algoritmus dávky právě podle návratového kódu (test proměnné errorlevel).
Principiálně vypadá programování návratových kódu takto:
int main(int argc, char **argv) { kód; if (chyba) return 1; kód; return 0; }Pokud programátor nehodlá využívat parametry hlavního programu, ani vracet hodnotu, může deklarovat hlavní program jako proceduru bez parametrů:
void main(void) { ... }
Napište jednoduchou kalkulačku. Program s názvem kalk bude mít povinně 3 parametry: číslo operátor, číslo, např.kalk 3.5 + 2
. Na obrazovku pak vypíše výsledek operace. Uvažujte tyto operátory:+ - * /
. Ošetřete chybu dělení nulou a správný počet parametrů programu. Není-li počet argumentů správný, vypište chybové hlášení ve tvaru:
Spouštění: kalk číslo operátor číslo
Jméno programu kalk získejte z argumentuargv[0]
, odstraňte cestu.
(Návod: číselné hodnoty z řetězců převádějte pomocí funkcesscanf
, jméno programu nekopírujte - najděte poslední výskyt znaku '\\' a při tisku jména programu předejte ukazatel na další znak.)Polotovar:
Dev C++: kalkp.dev, kalkp.c CodeBlocks: kalkp.cbp, kalkp.c Řešení:
Dev C++: kalk.dev, kalk.c CodeBlocks: kalk.cbp, kalk.c
typedef
lze definovat vlastní typ.
Obecně má definice typu podobu:
typedef definice_typu identifikátor_typu;Jako první příklad uvedeme vytvoření de facto aliasu typu
float
:
typedef float TPrvek;Definovali jsme nový typ TPrvek, který je evivalentem typu
float
. Čtenář si možná klade otázku, proč jsme
uvedli tento jednoduchý příklad, jenž se může zdát nesmyslným. Nesmyslný příklad není, naopak, ukazuje možnost, jak psát
programy odolnější proti chybám. Představme si, že zpracováváme dynamické pole prvků typu int
. V kódu se
určitě vyskytují tyto řádky:
int main() { int *pole; ... pole = (int *)malloc(n*sizeof(int)); ... }Pokud se rozhodneme pracovat s prvky typu float, musíme přepsat typ
int
všude tam, kde se s prvky pole pracuje (zde na dvou
místech kódu - v deklaraci pole a při volání funkce malloc). Je nebezpečí, že někde v kódu zapomeneme typy zaměnit nebo zaměníme omylem typy v té části
kódu, která se prvků pole vůbec netýká (např. hlavičky procedur a funkcí).
Pokud nadefinujeme uživatelský typ a dodržujeme důsledně jeho použití v kódu všude tam, kde se pracuje s polem, stačí pak upravit pouze definici typu:
typedef int TPrvek; int main() { TPrvek *pole; ... pole = (TPrvek *)malloc(n*sizeof(TPrvek)); ... }Ukážeme si ještě dva příklady definice typů:
typedef int* TPint; // typ TPint je typ ukazatel na int, proměnnou pi typu ukazatel pak deklarujeme: TPint pi; typedef float TPoledeset[10]; // TPoledeset je typ pole o deseti prvcích typu float, vlastní pole A pak deklarujeme: TPoledeset A;Poznámka: Bývá zvykem, že identifikátory uživatelsky definovaných typů programátoři začínají písmenem T (jako typ)
typedef enum { CERVENA, MODRA, ZELENA, BILA, CERNA } TBarvy;Obsahem proměnné typu TBarva jsou tedy hodnoty CERVENA, MODRA, ZELENA, BILA nebo CERNA.
Proměnnou barva_auta
typu TBarvy
nadeklarujeme standardně:
TBarvy barva_auta;V kódu pracujeme se proměnnými výčtového typy a symbolickými hodnotami běžně jako s jinými standardními datovými typy , např.:
barva_auta = CERVENA; if (barva_auta == CERVENA) ...V jazyce C jsou hodnoty výčtového datového typu interně reprezentovány celými čísly počínaje 0, tj. v našem příkladě s barvami je hodnota CERVENA reprezentována 0, MODRA 1 atd. Při definici typu máme možnost ovlivnit vnitřní reprezentaci přiřazením hodnot:
typedef enum { CERVENA, MODRA=5, ZELENA, BILA=10, CERNA } TBarvy;V tomto případě je hodnota CERVENA vnitřně reprezentována 0, MODRA 5, ZELENA 6, BILA 10, CERNA 11. Překladač přiřazení nekontroluje, takže v jazyce C je bez problémů přeložitelná tato definice:
typedef enum { CERVENA, MODRA=5, ZELENA, BILA=3, CERNA, SEDA } TBarvy;Zde ale mají symbolické hodnoty MODRA a SEDA přiřazeny interní reprezentaci číslem 5, nejsou tedy v kódu rozlišitelné!
Poznámka: V jazycích se silnou typovou kontrolou (např. Pascal) je dovolenou používat v kódu pouze symbolická jména hodnot výčtového typu. Jazyk C je jazyk se slabou
typovou kontrolou, kdy se provádějí kontroly pouze na úrovni vnitřní reprezentace. Je tedy možné zapsat do kódu přiřazení barva_auta = 2;
Používat
tento způsob se zásadně nedoporučuje, protože snižuje přehlednost a čitelnost kódu!
[Obsah] | [Cvičení 2] |