Kurz C++ (2.)
Dostává se vám do rukou druhá lekce kurzu o programování v C++.
V této lekci se konečně dostaneme k vlastnímu programování, i
když se bude jednat o pouhé základy C bez kterých se ovšem neobejdete.
Součástí kurzu je příklad, na kterém budeme společně pracovat a který
si nakonec budete moci uložit na disk a spustit. Vřele
ovšem doporučuji si příklad napsat vlastníma rukama a třeba
si ho zkusit modifikovat.
2.1 Základní datové typy
Datové typy jsou typy proměnných, které je možno vytvořit.
Proměnná může představovat paměťovou buňku,
ale většinou se jedná o blok paměti, kde je uložena informace jistého typu.
Právě typ proměnné je nejdůležitější atribut proměnné. Jedna proměnná může
uchovat záporné číslo a druhá zase jen kladné. Musíte předem vědět k čemu
proměnnou chcete využít, aby program fungoval správně. Některé chyby odhalí
kompilátor při překladu, ale pozor si musíte dát především na ty skryté, které
se projeví nesprávnou funkcí programu.
V průběhu programu se hodnota proměnné mění, podle druhu operace.
Můžeme například sešíst dvě proměnné stejného typu atd. Lze použít i jisté konverze
typů, ale o tom si podrobně povíme v některé příští lekci.
Přehled nejpoužívanějších jednoduchých typů jazyka C :
Deklarace | Typ informace | Velikost v bytech |
int | celé číslo | 4 (2) |
long | celé číslo | 4 |
short | celé číslo | 2 |
float | reálné číslo | 4 |
double | reálné číslo | 8 |
long double | reálné číslo | 8 |
char | znak | 1 |
unsigned char | byte | 1 |
BOOL | 0 nebo 1 (v C definován jako int) | jako int |
unsigned short | 16-bitové slovo | 2 |
unsigned long | dvojnásobné slovo | 4 |
unsigned int | neznaménkový int | 4 |
a další | | |
Některé typy mají dvě varianty a to sice znaménkové (signed) a neznaménkové
(unsigned). Implicitně jsou tyto
typy znaménkové. Pokud chcete vytvořit neznaménkový typ, stačí před klíčové slovo typu
vložit další klíčové slovo unsigned .
Co ale přesně znamená znaménkový a neznaménkový typ? Je to snadné. Znaménkové
typy mohou nabývat i záporných hodnot, ale mají oproti neznaménkovým typům
poloviční maximální hodnotu, takže například platí:
Typ | Rozsah hodnot |
char | -128 až +127 |
unsigned char | 0 až 255 |
Maximální hodnotu znaménkové proměnné zjistíme takto: 2^(n-1), kde n je počet bitů,
které proměnná zabírá v paměti (viz tabulka nahoře - 1 bajt má 8 bitů).
Poznámka: V 16-bitovém OS má typ int int velikost 2 bajty, ale ve Windows a jiných 32-bitových OS má 4 bajty!
Co z toho plyne? Pokud například pod DOSem zapíšete do souboru dvě
proměnné typu int (2x2bajty) a pak je pod Windows přečtete,
vznikne chyba, protože
původně dvě hodnoty se přečtou jako jedna a při pokusu o další
čtení program vyhodí nejspíš vyjímku (exception).
Zabráníte tomu používáním vhodnějších typů pro zápis do souboru.
2.2 Definice proměnné v programu
Za prvé si musíme uvědomit, jaký typ informace chceme „skladovat“. Pak můžeme určit
datový typ proměnné.
Tak tedy jak definovat proměnnou v programu? Definovat znamená, že překladač přidělí
jméno a paměť pro naší proměnnou zatímco deklarace pouze přiřadí
jméno proměnné – překladač nealokuje žádnou paměť!!!
Příklad definice proměnné :
int i;
double d = 1.0;
Takto vytvoříme celočíselnou a reálnou proměnnou. Reálná proměnná typu
double je ihned inicializována na hodnotu 1.0.
Proměnná totiž po vytvoření není inicializována, takže v ní může prakticky
cokoliv (většinou je to dost obludné záporné číslo)
a tímto se vyvarujem zbytečných chyb. Překladač nás upozorní pokud
používáme nějakou proměnnou, aniž by jsme jí před tím inicializovali.
Definice může být buď vně nebo uvnitř těla funkce. Proměnným, které jsou mimo
tělo jakékoliv funkce říkáme globální a jsou přístupné ze všech funkcí
daného modulu (souboru .cpp ). Globální proměnná je zrušena,
když je ukončen celý program. Pokud je proměnná definována uvnitř těla funkce,
její platnost se omezuje pouze na dobu trvání funkce tzn. že když program
ukončí funkci zároveň je zrušena i lokální proměnná. K lokální
proměnné můžeme přistupovat pouze z funkce, kde je tato proměnná definována.
Příklad definice globální a lokální proměnné :
int i; //globalni celociselna promenna viditelna v celem programu
main()
{
double d; //lokalni realna promenna
viditelna pouze z funkce main()
}
Poznámka:Obecně platí, že v souborech s příponou .cpp provádíme definici a
hlavičkových souborech .h provádíme deklaraci proměnných a funkcí.
K čemu tedy používáme
hlavičkové soubory? Právě k deklaraci globálních proměnných či deklaraci funkčních prototypů
(vše bude vysvětleno později). Navíc, pokud používáte více modulů najednou (více na sobě
závislých implementačních souborů .cpp ), můžete použít společný hlavičkový soubor
common.h , ve kterém budou definovány společné globální proměnné a funkce.
Více si o hlavičkových souborech povíme dál v této lekci.
2.3. Přiřazení
Nyní máme definované jméno proměnné v programu a můžeme začít
s proměnnou pracovat. Kompilátor nám přiřadil buňky v paměti, takže můžeme získat adresu naší proměnné.
Adresu využijeme až se budeme zabývat ukazately
(ukazatel = pointer) někdy v příštích lekcích, ale
dneska to pro nás znamená, že proměnná, právě protože má adresu v paměti, je tzv. l-hodnota (l-value).
Hodnotu proměnné přiřadíme operátorem „rovná se“ ( = ). Takže například,
pokud chceme do proměnné i uložit číslo 5, napíšeme :
int i; // definice promenne
i = 5; // v i je nyní hodnota 5
Důležité ovšem je, aby na levé straně příkazu byla vždy l-hodnota.
L-hodnota představuje adresu, tedy proměnná je l-hodnota, konstatna 5 l-hodnotou není.
Následuje triviální příklad:
int u = 3; // definice a inicializace promenne u
i = u; // promenna muze byt vlevo i vpravo, i = 3
i = 2 + u; // i = 5
i = u * 5 + 10; // i = 25, vyraz muze byt jen na prave strane
i + 1 = u; // CHYBA!!! Prekladac nastesti tyto chyby odhali pri prekladu...
1 = u; // JESTE VETSI CHYBA!!!
V C je navíc možné několikanásobné přiřazení. Takto
můžeme inicializovat několik proměnných najednou.
u = i = 5; //promenne i a u budou mit hodnotu 5
Poznámka: Všimněte si, že na konci každého řádku je středník! Každý příkaz v C
je ukončen středníkem. Mezi základní slušné mravy programátora patří psát každý
příkaz na nový řádek.
2.4. Funkce main()
Ve starém C musel mít každý program funkci
main() , která se použila jako vstupní bod (entry point) do
vašeho programu. To znamená, že když se váš program zkompiloval a spustil, jako první se vždy
zavolala tato funkce. Z této funkce jste pak volali vaše funkce a váš program se prováděl
dokud funkce main() neskončila. Takže touto funkcí
vše začalo a taky to pěkně skončilo.
Toto platilo až na vyjímky (pokud jste třeba pracovali s více vlákny (threads)) na 100%.
V objektovém modelu programování se na tomto až zas tak moc nemění. A proč tedy o tom vůbec mluvím?
Ve Visual C++ (VC++), ve kterém se nyní učíte programovat pracují programy zcela jinak! Neplatí to však
jen pro VC++. Vývojové nástroje jako Visual Basic nebo Delphi pracují naprosto stejně. Je to dáno
tím, že se jedná o nástroje pro Windows. Takže původce těchto změn jsou právě Windows (a jiné
multitaskingové OS - znamená to, že může pracovat více programů najednou).
Způsob, kterým pracují Windows je na delší povídání a nás zatím nezajímá, ale nebojte se určitě
se k němu časem prokousáme.
Nyní vám stačí vědět, že programy, které budeme vytvářet budou mít "zatím" jen funkci
main() , kterou začíná a končí program.
Funkce je ohraničena složenými závorkami {}, jako
každá funkce, kterou kdy v C napíšete. Funkci main()
nikdy nebudete muset volat z vašeho kódu.
Tuto funkci volá operační systém, ať už stařičký DOS nebo padavá Windows.
Funkce main() může, ale nemusí mít parametry,
ale zpravidla vrací nějakou návratovou hodnotu, většinou
typu int. Pokud má funkce main() parametry,
tak je to řetězec, který napíšete jako parametr, když
program spouštíte y příkazové řádky. Možná se vám to zdá složité a tak uvedu jednoduchý
příklad, jak taková funkce
může vypadat.
Jak tedy může funkce main() vypadat? V různých vývojových prostředích různě,
například takto:
//prvni priklad
void main()
{//zde jsou videt slozene zavorky
//zadne vstupni parametry
//zadna navratova hodnota
//i takovato funkce se muze vyskytnout
//ale neni to zvykem
}
//jiny priklad fce main(), casteji viditelny
int main()
{
//zadne vstupni parametry
//ale vraci hodnotu, nejcasteji int
return 0;
}
//tak do tretice priklad fce main()
int main(char args[])
{
//tato fce prijima jako parametr retezec z prikazove radky
//a vraci hodnotu int jako v predchozim priklade
//jmeno vstupniho parametru se muze lisit od ruznych IDE
//dokonce jich muze byt i vic!
return 0;
}
Poznámka: Opět si všimněte dobrého zvyku. Vidíte, že tělo funkce
je o kousek odsazeno oproti složeným závorkám a jmenu funkce.
Toto odsazení samozřejmě nemá vliv na funkci programu, ale
výrazně zpřehledňuje kód!
O funkcích si samozřejmě povíme více nejspíš v příští lekci
našeho kurzu.
Když program spouštíte z příkazového řádku (Windows)
nebo v DOSu, můžete zapsat nějaký parametr, který je pak předán
funkci main() jako argument
args[] , což je pole znaků čili řetězec. Tedy například:
C:\WINNT\
C:\WINNT\cd..
C:\cd Programs
C:\Programs\cd Main
C:\Programs\Main\main.exe test
Zde předáváte funkci main() řetězec
"test" , to znamená, že po spuštění programu
v proměnné args[]
bude opravdu řetězec "test" a vy s ním můžete
cokoliv dělat, třeba vypsat na obrazovku. Takto
může uživatel vašeho programu měnit chování programu, aniž by znal,
jak vypadá vlastní kód.
My si ukážeme konkretní příklad, jak parametry fungují ve Visual C++, pokud
vytvoříte konzolovou aplikaci (postup je vysvětlený v kurzu o IDE VC++). Když se podíváte na
funkci main() , určitě vám přijde složitá,
protože vůbec nevypadá tak, jak
jsem před chvilkou říkal. Máte pravdu ve VC++ vypadá funkce main() jinak než
jinde. Na první pohled vidíte, že má dva parametry, místo jednoho.
První parametr argc určuje počet vámi zadaných
parametrů v příkazové řádce.
Jeho minimální hodnota je 1, protože se jako parametr bere i název programu,
tedy například "main.exe" a i tento řetězec
"vniká" do funkce main() .
Druhý parametr argv[] je trošičku složitější,
ale o to vychytanější. Je to
ukazatel (že nevíte co to je? tím se zatím netrapte) čili adresa nějaké
buňky v paměti. Ukazatel na pole znaků. Zní to nesmírně složitě,
ale ve skutečnosti
je to velmi jednoduché. Zkrátka parametr argv[] uchovává všechny řetězce,
které jste zapsali do příkazové řádky. K jednotlivým řetězcům přistupujeme pomocí
indexů v intervalu 0 až (argc -1).
Následující příklad vypíše všechny parametry v
příkazové řádce nezávisle na jejich počtu.
#include "stdafx.h"
//vlozeni standardniho hlavickoveho souboru (kvuli fci cout)
#include <iostream.h>
int main(int argc, char* argv[])
{
//smycka typu for bezi od 0 do argc-1
for(int i = 0; i < argc; i++) {
//funce cout vypisuje jednotlive parametry
//na obrazovku
//vsimnete si formatovaní jednotlivych radku
//funkci cout a cin si popiseme pozdeji
cout << "Argument #" << i << " :" << argv[i] << "\n";
}
return 0;
}
Poznámka: O cyklu for se více dozvíte v příští lekci, která
se bude zabývat mimojiné také iteračními cykly! Opět si ale všimněte
odsazení uvnitř těla cyklu.
2.5. Hlavičkové soubory a funkce cout a cin
"Funkce" cout a cin jsou deklarovány v hlavičkovém souboru
iostream.h , který musíte vložit do
svého programu, abyste je mohli použít. Vkládání hlavičkových souborů je vidět na předchozím
příkladu. Pokud se jedná o standardní hlavičkový soubor, tzn. o
soubor vytvořený týmem fy Microsoft, uzavírá se jméno souboru do lomených
závorek: <>.
Pokud jde o váš hlavičkový soubor, který jste napsali vy, uzavírá se jméno
souboru do úvozovek: "".
IDE tak pozná odkud má vkládat hlavičkové soubory. Standardní hlavičkové
soubory jsou uloženy
v adresáři vlastního IDE (např. C:\Program Files\Microsoft
Visual Studio\VC98\Include ) a vaše
soubory jsou uloženy v adresáři vašeho programu (např.
C:\Programs\Main\ ).
Možná se divíte, že za funkcemi cout a cin nepíši závorky jako u
funkce main() . Je to proto, protože
cout a cin vlastně nejsou funkce:-) Jedná se o objekty jazyka C++,
které používají tzv. proudy (streams).
Proudy mohou být různé, například vstup a výstup na tiskárnu, do
souboru a na obrazovku (cout a cin).
V C pod DOSem se používali funkce printf()
a scanf() , ale my
budeme požívat objekty cin a cout , protože se učíme C++.
Pro přístup k proudům se používají speciální operátory: << a >>, jak jste si jistě všimli
v předchozím případě.
Objekt cout , který jsme před chvilkou použili, se používá pro výstup na monitor. Použití si
ukážeme na jednoduchém příkladu:
int i = 5;//definice promene i = 5
cout << "Ahoj\n";// vypise na monitor "Ahoj" a odradkuje
cout << i << "\n";// vypise na monitor obsah promene i a odradkuje
cout << "Obsah i: " << i << "\n";//vypise na monitor "Obsah i:", obsah i a odradkuje
Je vidět, že cout můžeme použít k zobrazení řetězce i obsahu proměné. Asi se
divíte, copak dělají znaky "\n".
Tento "dvojznak" je ve skutečnosti jeden znak, který zajistí odřádkování.
Odborně se nazývá escape sekvence, kterých
je celá řada:
Sekvence | Hodnota | Význam |
\n | 0x0A | nová řádka (newline, linefeed - LF) |
\r | 0x0D | návrat na začátek řádky (carrige return - CR) |
\f | 0x0C | nová stránka (formfeed - FF) |
\t | 0x09 | tabulátor (tab - HT) |
\b | 0x08 | posun doleva (backspace - BS) |
\a | 0x07 | písknutí (alert - BELL) |
\\ | 0x5C | zpětné lomítko (backslash) |
\' | 0x2C | apostrof (single quote) |
\0 | 0x00 | nulový znak (null character - NUL) |
Poznámka: Pokud znáte HTML, tak escape sekvence jsou něco podobného jako znaková entita.
Objekt cin (nyní víte, že se jedná o objekt)
se používá velmi podobně. Následuje opět jednoduchý příklad:
int i; //definice promene i
cin >> i;//nacteni ciselne hodnoty do promene i
cout << "Obsah i: " << i << "\n";//vypsani obsahu i (viz vyse)
Všiměte si, že "šipky" u cin jsou na opačnou stranu než u
cout .
To proto, že se jedná o opačný směr
proudu - z klávesnice do proměnné je >>, zatímco z proměnné na monitor jsou "šipky" opačně
<<. A to je celé kouzlo vstupu a výstupu na obrazovku. Pokud jste to pochopili, pak máte vyhráno a
pokud ne, tak si s tím nelámejte hlavu, protože časem se všechno vyjasní :-)
2.6. Operátory
Pomocí operátorů provádíme aritmetické, ale i logické operace s proměnnými.
Nyní už víte, jak proměnnou vytvořit (definovat), takže už nezbývá nic
jiného, než se naučit s proměnnými pracovat.
Uvedu krátký přehled,
kde by měly být uvedeny všechny základní operátory. Všechny tyto operátory jsou binární tzn, že
potřebují dva operandy a vrací výsledek.
Binární operátory |
Význam operace |
Syntaxe |
Příklad |
Sčítání |
+ |
50 + 50 = 100 |
Odečítání |
- |
100 - 50 = 50 |
Násobení |
* |
10 * 10 = 100 |
Dělení |
/ |
100 / 10 = 10 |
Dělení modulo |
% |
7 % 3 = 1 (zbytek po dělení) |
Bitový posun doleva |
<< |
10 >> 1 = 5 |
Bitový posun doprava |
>> |
10 << 1 = 20 |
Logický součin |
& |
1 & 2 = 0 nebo 3 & 6 = 2 |
Logický součet |
| |
1 | 2 = 3 nebo 3 | 6 = 7 |
Dále rozlišujeme unární operátorý, kterým
stačí jeden operand.
Unární operátory |
Význam operace |
Syntaxe |
Příklad |
Unární plus - kladné číslo |
+ |
+12547 |
Unární minus - záporné číslo |
- |
-12547 |
Speciální unární operátory
- inkrement ++
- dekrement --
Význam:
++proměnná - proměnná je inkrementována (zvětšená o jedničku) před použitím
- nejdříve je proměnná zvětšena o jedničku a poté je vrácena tato nová hodnota
proměnná-- - proměnná je dekrementována (zmenšená o jedničku) před použitím
- je vrácena původní hodnota proměnné a poté je proměnná zmenšena o jedničku
Poznámka:Operátor inkrement a dekrement lze použít pouze na l-hodnotu čili proměnnou.
Oba operátory mohou být použity buď jako předpona (prefix) nebo jako přípona (suffix).
C navíc poskytuje celou řadu dalších přiřazovacích operátorů, které oproti binárním operátorům
zkracují zápis.
Zkrácený zapis | Normální zápis |
l-hodnota += výraz | l-hodnota = l-hodnota + výraz |
l-hodnota -= výraz | l-hodnota = l-hodnota - výraz |
l-hodnota *= výraz | l-hodnota = l-hodnota * výraz |
l-hodnota /= výraz | l-hodnota = l-hodnota / výraz |
l-hodnota %= výraz | l-hodnota = l-hodnota % výraz |
l-hodnota <<= výraz | l-hodnota = l-hodnota << výraz |
l-hodnota >>= výraz | l-hodnota = l-hodnota >> výraz |
l-hodnota &= výraz | l-hodnota = l-hodnota & výraz |
l-hodnota |= výraz | l-hodnota = l-hodnota | výraz |
2.7. Co bude v příští lekci?
Příště si povíme něco o řídících strukturách (if a if-else )
a iteračních cyklech (for, while a do-while ), abyste
dovedli řídit běh programu. Dále si povíme něco o příkazech switch, break a continue .
Pokud budete mít nějaké dotazy, napište mi na emailovou adresu
jiri.formanek@seznam.cz.
Těším se příště nashledanou.
|