3. díl - Proměnné a typový systém v Céčku

C a C++ Céčko Základní konstrukce C Proměnné a typový systém v Céčku

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Z minulé lekce, Instalace NetBeans a kompilátoru C, již umíme pracovat s NetBeans IDE a vytvořit konzolovou aplikaci. Dnes se v tutoriálu podíváme na tzv. typový systém, ukážeme si základní datové typy a práci s proměnnými. Výsledkem budou 3 jednoduché programy včetně kalkulačky.

Proměnné

Než začneme řešit datové typy, pojďme se shodnout na tom, co je to proměnná (programátoři mi teď jistě odpustí zbytečné vysvětlování). Určitě znáte z matematiky proměnnou (např. x), do které jsme si mohli uložit nějakou hodnotu, nejčastěji číslo. Proměnná je v informatice naprosto to samé, je to místo v paměti počítače, kam si můžeme uložit nějaká data (jméno uživatele, aktuální čas nebo databázi článků). Toto místo má podle typu proměnné také vyhrazenou určitou velikost, kterou proměnná nesmí přesáhnout (např. číslo nesmí být větší než 32.000).

Proměnná má vždy nějaký datový typ, může to být číslo, znak, text a podobně. Záleží na tom, k čemu ji chceme používat. Většinou musíme před prací s proměnnou tuto proměnnou nejdříve tzv. deklarovat, čili říci jazyku jak se bude jmenovat a jakého datového typu bude (jaký v ní bude obsah). Jazyk ji v paměti založí a teprve potom s ní můžeme pracovat. Podle datového typu proměnné si ji jazyk dokáže z paměti načíst, modifikovat, případně ji v paměti založit. O každém datovém typu jazyk ví, kolik v paměti zabírá místa a jak s tímto kusem paměti pracovat.

Typový systém

Existují dva základní typové systémy: statický a dynamický.

  • Dynamický typový systém nás plně odstiňuje od toho, že proměnná má vůbec nějaký datový typ. Ona ho samozřejmě vnitřně má, ale jazyk to nedává najevo. Dynamické typování jde mnohdy tak daleko, že proměnné nemusíme ani deklarovat. Jakmile do nějaké proměnné něco uložíme a jazyk zjistí, že nebyla nikdy deklarována, sám ji založí. Do té samé proměnné můžeme ukládat text, potom strukturu uživatele a potom desetinné číslo. Jazyk se s tím sám popere a vnitřně automaticky mění datový typ. V těchto jazycích jde vývoj rychleji díky menšímu množství kódu. Zástupci jsou např. PHP nebo Ruby.
  • Statický typový systém naopak striktně vyžaduje definovat typ proměnné a tento typ je dále neměnný. Jakmile proměnnou jednou deklarujeme, není možné její datový typ změnit. Jakmile se do čísla pokusíme uložit strukturu uživatel, dostaneme vynadáno.

Céčko je staticky typovaný jazyk, všechny proměnné musíme nejprve deklarovat s jejich datovým typem. Nevýhodou je, že díky deklaracím je zdrojový kód poněkud objemnější a vývoj pomalejší. Obrovskou výhodou však je, že nám kompilátor před spuštěním zkontroluje, zda všechny datové typy sedí. Dynamické typování sice vypadá jako výhodné, ale zdrojový kód není možné automaticky kontrolovat a když někde očekáváme objekt uživatel a přijde nám tam místo toho desetinné číslo, odhalí se chyba až za běhu a interpret program shodí. Naopak céčko nám nedovolí program ani zkompilovat a na chybu nás upozorní (to je další výhoda kompilace).

Pojďme si nyní něco naprogramovat, ať si nabyté znalosti trochu osvojíme, s teorií budeme pokračovat až příště. Řekněme si nyní tři základní datové typy:

  • Celá čísla: int
  • Desetinná čísla: float
  • Znak (písmeno, text se naučíme později): char

Program vypisující proměnnou

Zkusíme si nadeklarovat celočíselnou proměnnou a, dosadit do ní číslo 56 a její obsah vypsat do konzole. Založte si nový projekt a pojmenujte ho Vypis (i ke všem dalším příkladům si vždy založte nový projekt). Kód samozřejmě píšeme jako minule do těla funkce main(), čili ji zde již nebudu opisovat.

int a;
a = 8;
printf("%d", a);

První příkaz nám nadeklaruje novou proměnnou a datového typu int, proměnná tedy bude sloužit pro ukládání celých čísel. Druhý příkaz provádí přiřazení hodnoty do proměnné, slouží k tomu operátor "rovná se". Poslední příkaz je nám známý, vypíše do konzole obsah proměnné a. Všimněte si %d v uvozovkách, tím definujeme jaký typ proměnné to má vypsat, %d označuje celá čísla (jako decimal).

Konzolová aplikace
8

Pro desetinnou proměnnou by kód vypadal takto:

float a;
a = 56.6F;
printf("%f", a);

Je to téměř stejné jako s celočíselnou, ovšem za hodnoty float píšeme ještě znak F. Jako desetinný oddělovač používáme tečku a změníme %d na %f (jako float), abychom řekli počítači, že chceme vypisovat desetinné číslo.

Program zdvojnásobovač

Minulý program byl poněkud nudný, zkusme nějak reagovat na vstup od uživatele.

Z konzole jsme ještě nezkoušeli nic načítat. Slouží k tomu funkce scanf(), která uživateli umožní zadat do konzole řádku textu a nám do naší proměnné uloží zadanou hodnotu. Abychom si to zkusili, založíme si nový projekt s názvem Zdvojnasobovac. Nyní se přesuňme k samotnému kódu programu a do funkce main() píšeme:

int a;
printf("Zadejte číslo k zdvojnásobení: ");
scanf("%d", &a);
a = a * 2;
printf("%d", a);

To už je trochu zábavnější :) Zdvojnásobovač si vyžádá na vstupu číslo a to poté zdvojnásobí a vypíše. První řádek je jasný, deklaruje proměnnou "a" typu celé číslo. V céčku bychom všechny proměnné měli definovat na začátku.

Konzolová aplikace
Zadejte číslo k zdvojnásobení: 1024
2048

Do "a" se přiřadila hodnota z funkce scanf() z konzole, tedy to, co uživatel zadal. Znak & si vysvětlíme později, prozatím se spokojíme s tím, že ho funkce scanf() vyžaduje, aby hodnotu mohla uložit do nějaké proměnné. Opět jsme využili sekvenci %d, čímž říkáme, že vstup se má načíst jako celé číslo. Jen tak mimochodem, znak bychom načetli nebo vypsali pomocí sekvence %c (jako char).

Jednoduchá kalkulačka

Ještě jsme nepracovali s desetinnými čísly, zkusme si napsat slibovanou kalkulačku. Bude velmi jednoduchá, na vstup přijdou dvě čísla, program poté vypíše výsledky pro sčítání, odčítání, násobení a dělení.

float a;
float b;
float soucet;
float rozdil;
float soucin;
float podil;
printf("Vítejte v kalkulačce \n");
printf("Zadejte první číslo: \n");
scanf("%f", &a);
printf("Zadejte druhé číslo: \n");
scanf("%f", &b);
soucet = a + b;
rozdil = a - b;
soucin = a * b;
podil = a / b;
printf("Součet: %f \n", soucet);
printf("Rozdíl: %f \n", rozdil);
printf("Součin: %f \n", soucin);
printf("Podíl: %f \n", podil);

Konzolová aplikace
Vítejte v kalkulačce
Zadejte první číslo:
5
Zadejte druhé číslo:
7
Součet: 12.000000
Rozdíl: -2.000000
Součin: 35.000000
Podíl: 0.714286

Vidíme, že v C můžeme použít nám známé aritmetické operace (+ - * /). C navíc definuje další operaci (%), která značí zbytek po celočíselným dělení. Všimněte si, že místo %c nebo %d používáme %f. To značí, že chceme použít float neboli desetinná čísla. Pokud by vás zajímaly všechny znaky, které můžete použít, najdete vysvětlení v dokumentaci.

Všechny programy máte samozřejmě opět v příloze, zkoušejte si vytvářet nějaké podobné, znalosti již k tomu máte :)

V příští lekci, Typový systém v céčku podruhé: Datové typy, se budeme datovým typům věnovat podrobněji.


 

Stáhnout

Staženo 1231x (105.2 kB)

 

 

Článek pro vás napsal Samuel Kodytek
Avatar
Jak se ti líbí článek?
9 hlasů
Autor se věnuje Javě, Kotlinu, PHP, C, HTML. Zajímá ho spíše game design.
Miniatura
Všechny články v sekci
Základní konstrukce jazyka C
Miniatura
Následující článek
Cvičení k 1.-3. lekci Céčka
Aktivity (11)

 

 

Komentáře
Zobrazit starší komentáře (33)

Avatar
patrik.valkovic
Šéfredaktor
Avatar
patrik.valkovic:12.7.2016 19:13

To jsou defaultní hodnoty. scanf může selhat (například když uživatel zadá "asdf" namísto čísla) a potom by program sečetl dvě náhodné čísla, které byly zrovna v paměti. Takto máme alespoň jistotu, že se bude vždy jednat o čísla 12 a 5, ale být to tam nemusí.

Odpovědět 12.7.2016 19:13
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Veronika L
Člen
Avatar
Odpovídá na patrik.valkovic
Veronika L:12.7.2016 19:27

Aha, super díky moc! :)

 
Odpovědět 12.7.2016 19:27
Avatar
majky1997
Člen
Avatar
majky1997:14.9.2016 16:51

Ahoj, prosimtě, jak je to s inicializací proměnné? Je tam automaticky nastavena nula? A kdy jo a kde ne? Žil jsem v tom, že to tak není.

 
Odpovědět 14.9.2016 16:51
Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Odpovídá na majky1997
Zdeněk Pavlátka:14.9.2016 17:12

V C proměnné výchozí hodnoty nemají. Když je vytvoříš obsahují to co bylo na jejich místě uloženo předtím (tzn. naprosto náhodnou hodnotu).

Odpovědět 14.9.2016 17:12
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Ivanna Novotna:5.10.2016 13:49

Dobry den, jsem tady zacatecnik, zkousim Papousek, a nejde mi to. Je tam porad run

 
Odpovědět 5.10.2016 13:49
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Zdeněk Pavlátka
DarkCoder:5.10.2016 14:31

To co tvrdíte není pravda. Je třeba odlišit globální proměnné od lokálních. Globální proměnné, které nejsou explicitně inicializovány, jsou automaticky nastaveny na nulu. Lokální proměnné, které nejsou inicializovány, mohou obsahovat libovolnou neznámou hodnotu. Některé překladače jazyka C mohou nastavovat neinicializované proměnné na nulu, ale na to bych se rozhodně nespoléhal.

 
Odpovědět 5.10.2016 14:31
Avatar
Odpovídá na Ivanna Novotna
Ivanna Novotna:5.10.2016 15:28

Pardon, mam to vyreseny, udelala jsem chybu

 
Odpovědět 5.10.2016 15:28
Avatar
DarkCoder
Člen
Avatar
DarkCoder:5.10.2016 20:55

Více méně první díl výkladu jazyka C a hned v něm spousta nepřesností, neúplných informací a učení špatným návykům! Některé už zde padly v diskuzi, přesto nebyly opraveny. Nováček tak už na začátku pobírá informace, které ho učí nesprávným postupům a zvykům, což by se stávat nemělo.

Takže pojďme na to:

Proměnné
To co zpracovává informace ohledně datových typů není jazyk C ale překladač jazyka C. Jazyk C a obecně programovací jazyk je pouze soubor pravidel a prostředek pro zápis algoritmů.

Program vypisující proměnnou
Už to zde v diskuzi padlo a za více než dva roky to nebylo opraveno. Zadání programu by se nemělo lišit od toho, co se skutečně v programu vypisuje (viz hodnota 8 a 56).
Pokud pracujeme s konstantami, je třeba hlídat si datové typy. Hodnota 56.6 sama o sobě není hodnotou float ale double, která je ovšem konvertována v přiřazovacím příkaze na typ float. Pokud chci zadat konstantu jako float, je třeba ji zapsat jako 56.6F. Program se však chová správně neboť typ pravé strany se převádí na typ levé strany.
Pro výpis proměnné typu float se užívá %f nikoli %g. %g popřípadě %G se používá pro výpis normálního nebo semilogaritmického tvaru, podle toho, který je kratší.

program papoušek
Zde je toho opravdu dost špatně. Funkce scanf() se nepoužívá pro načítání znaků! Důvodem je, že načítání se provádí dokud nestiskneme klávesu Enter. Na obrazovce se vypíše první znak ale ostatní znaky zůstávají ve vstupním buferu, což může být a dost často je, nežádoucí pro další vstupní operace. Pro načítání znaků se užívají funkce getchar(), getche(), getch(). Dále proměnná a je definována jako znaková proměnná, ne jako pole znaků!!! Jak do této proměnné, kam se vejde pouze jeden znak, chcete uložit řetězec znaků?! Dále nepřesnosti v popise, celé číslo místo znakové proměnné a /n místo \n pro výpis nového řádku.

Program zdvojnásobovač
Existuje pouze ASCII (American Standard Code for Information Interchange) ne ASCI.

Jednoduchá kalkulačka
Pokud inicializujeme proměnnou s desetinnou čárkou typu float, nelze psát

float a = 12; // spatne

ale

float a = 12.0F;

je třeba udávat číslo s desetinnou tečkou a případným sufixem. Ve vašem případě dochází v příkazu k implicitnímu přetypování z typu int na float! O použití escape sekvence %g a %f viz výše v odstavci - Program vypisující proměnnou.

Při výkladu je třeba být důsledný, vyvarovat se chybných informací a špatným návykům.

 
Odpovědět  ±0 5.10.2016 20:55
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na DarkCoder
David Čápka:13. února 18:33

Program Papoušek jsem odstranil, Monarezio se jej snažil portovat z příkladů z vyšších jazyků, kde se dá rozumně načítat i text, ale bohužel tady byl spíše matoucí. Nějaké tvé připomínky jsem zapracoval, ale dost z nich mi přijde zbytečných a určitě bych neoznačoval to, že se někde přetypuje hodnota za špatný návyk, vždyť se to kompiluje.

Odpovědět 13. února 18:33
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
DarkCoder
Člen
Avatar
Odpovídá na David Čápka
DarkCoder:13. února 19:39

Je skvělé, že se zapracovalo na korektuře. Je mi jasné, že není v silách pročítat a opravovat vše co se zde na fóru napíše. Příspěvků je opravdu hodně, což je jedině dobře. Ale pro výukové bloky, jakými tutoriály bezesporu jsou, je to nezbytné. Nováčci to jistě ocení a rozhodně to přispěje ke zlepšení jejich dovedností v daném tématu.

K programu Papoušek, myšleno to bylo určitě dobře, ale přesně jak píšeš, bylo to matoucí. Co se týká implicitního přetypování, ano, kompiluje se to, ale programátor by měl vědět, že dochází k manipulaci s jeho proměnnou. Je to důležité a to hned ze dvou důvodů. Tím prvním je, že v určitých situacích může dojít k určité ztrátě informace, která může být důležitá a tato chyba se pak velmi těžko dohledává. Ta druhá je naučit programátora pozornosti a korektnímu přebírání argumentů funkci správných typů. Jak tak totiž sleduji příspěvky a zejména zdrojové kódy zde na fóru, je to neřest, která se vyskytuje opravdu v hojné míře. Vskutku málokdo si uvědomuje, jak důležité je odladění. Varovné hlášky kompilátoru mají svůj účel, proto jsem se o tom ve svém příspěvku zmínil.

Zde bych chtěl určitě vyzdvihnout uživatele Martin Dráb, který opravdu této problematice věnuje zvýšenou pozornost, bez které by funkčnost skutečného (náročného) projektu byla velmi nestabilní.

Každopádně skvělé, že si se do toho pustil a díky za reakci.

 
Odpovědět 13. února 19:39
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 43. Zobrazit vše