Obsah
V této části se seznámíme s identifikátory, klíčovými slovy, komentáři. Řekneme si něco o číslech, konstantách - a to celočíselných, racionálních a znakových a nezapomeneme ani na řetězce, proměnné a ukazatele.
Potřebné znalosti | |
K zvládnutí obsahu této kapitoly je nutné mít znalosti z kapitoly 2 - tedy znát základní strukturu programu v jazyce C a alespoň intuitivně chápat vstup a výstup programů v jazyce C. |
Identifikátory jsou jména, která dáváme například proměnným, funkcím a typům. Délka identifikátoru je v normě ISO C omezená 31 znaky.
Pro vytváření identifikátorů platí:
|
Příklad: | |
identifikátor a Identifikátor |
jsou dva různé identifikátory
Klíčová slova jsou zvláštní identifikátory, které mají speciální význam pro jazyk C. Proto je nesmíme používat v jiném významu, než jak určuje norma ISO C, což znamená, že nesmí být použita jako jména proměnných nebo funkcí.
Použití malých písmen v klíčových slovech je také důležité. Například RETURN nebude považováno za klíčové slovo return.
V jazyce C jsou definovány následující klíčová slova:
Komentář je poznámka, kterou přidáváme do zdrojového kódu programu. Všechny komentáře jsou překladačem ignorovány. Komentáře se používají hlavně pro popis významu a účelu zdrojového kódu. Je to část programu umístěná mezi dvojici párových symbolů /* */. V tomto případě jde o komentář, který může zasahovat přes více řádků.
Příklad: | |
printf("Ahoj"); /* toto je jednořádkový komentář */ /* Toto je viceradkovy komentar */ |
V jazyku C může být komentář umístěn kdekoliv, jen ne uprostřed klíčového slova, jména funkce nebo jména proměnné.
Komentář lze také použít pro dočasné vynechání řádků zdrojového textu. Stačí uzavřít vynechávanou část symboly pro začátek a konec komentáře.
Pozn: | |
Jazyk Java zavádí dokumentační komentář, který je podkladem pro generovaní dokumentace. |
Pozn: | |
Jazyk C++ zavádí jednořádkový komentář uvozený dvojicí lomítek \\ - více viz Komentáře v jazyce C++. |
Odsazovače, jinak také bílé znaky, jsou následující symboly:
V obvyklém zdrojovém textu se nejčastěji můžeme setkat s prvními třemi představiteli odsazovačů. Odsazovače spolu s operátory a oddělovači stojí mezi identifikátory, klíčovými slovy, řetězci a konstantami použitými ve zdrojovém textu. Všechny uvedené pojmy se společně označují jako lexikální symboly. Pro překladač představují dále nedělitelné celky. Překladač považuje rovněž komentář za odsazovač.
Čísla jsou v počítači uloženy ve formě nul a jedniček - tedy základní soustavou není soustava desítková, ale dvojková. Čísla jsou proto v paměti počítače uložena takovým způsobem, že jen celá čísla jsou uložena přesně - ovšem jen ve stanoveném rozsahu hodnot - zatímco u čísel reálných je k dispozici nejvýše jistý počet platných číslic plus exponent. Z výše uvedených skutečností musí vycházet každý programovací jazyk. V jazyce C dělíme základní typy dat na:
Úvodní dva typy společně nazýváme aritmetické datové typy.
Pozn: | |
Racionálním typům se často říká dle jejich základního představitele float,
správně se však jmenují čísla v pohyblivé řádové čárce. |
Celočíselné datové typy mohou být takzvaně bezznaménkové, což znamená, že použijeme modifikátor unsigned. Tatáž vlastnost u znaků, například unsigned char, může být zajímavá kvůli kódování neanglických abeced v různých operačních systémech.
Základní typy dat:
Dále platí:
Nebudete-li si jisti rozsahem hodnot jednotlivých aritmetických typů, podívejte se ve vašem systému do souboru limits.h - pro celočíselné typy, respektive do souboru float.h - pro typy racionální. V nich najdete nejmenší případně i největší možné hodnoty, které příslušný překladač připouští.
S konstantami a proměnnými jsou úzce spjaty dva pojmy - deklarace a definice.
Deklarací určujeme typ objektu. Informace o typu je překladačem používána při typové kontrole, typových konverzích apod.
V místě definice definujeme hodnotu proměnné či posloupnost příkazů funkce.
Konstanty jsou pevně dané hodnoty, které nesmí být programem změněny.
Konstanty definujeme po klíčovém slově const následovaném typem konstanty, jejím identifikátorem a po rovnítku její hodnotou ukončenou středníkem. Jedná-li se o vektor (jednorozměrné pole), následuje za identifikátorem dvojice hranatých závorek, zpravidla obsahující jeho dimenzi. První prvek pole má vždy index 0. Nejlépe si možné definice konstant vysvětlíme na příkladech.
Příklad: | |
const int konstanta = 15; const konstanta = 21; // neuvedeme-li typ je implicitně přiřazen typ int const char pismeno = 'r'; const char *retezec = "Jazyk C"; const float pole[3] = {-1, 0, 1}; /* pokud uvedeme všechny hodnoty pole na jeho pravé straně nemusíme uvádět dimenzi */ const char pole[] = {'a', 'b'} |
Překladač jazyka C přidělí konstantám typ, který odpovídá přiřazované hodnotě. Z konstant odpovídajících si typů můžeme vytvářet konstantní výrazy. Tyto výrazy musí být vyhodnotitelné během překladu. Nesmí obsahovat žádný z následujících operátorů (nejsou-li použity mezi operandy operátoru sizeof):
Celočíselné konstanty jsou specifikovány jako čísla bez desetinné části. Jazyk C umožňuje použít tři typy celočíselných konstant:
|
Příklad: | |
desítkové - 15, 7, -25 oktalové - 065, 01, 036 hexadecimální - 0x12, 0x3A, 0XCD |
Typ konstanty je určen implicitně, její velikostí, nebo explicitně používáním přípony L (nebo l - pozor snadno zaměnitelné s číslicí jedna) jako long, například 1234L. Druhá přípona, která explicitně určuje typ celočíselné konstanty je U (nebo u), jako unsigned, například 129U. Samozřejmě, že můžeme naspat i 21UL. Pak jde o unsigned long číslo.
Racionální datový typ ukládá čísla do paměti ve tvaru mantisa a exponent, obojí s případným znaménkem. Není-li uvedeno jinak, je typ racionální konstanty double. U konstant s pohyblivou řádovou čárkou je třeba použít desetinnou tečku následovanou desetinnou částí čísla. Jazyk C umožňuje zapisovat čísla s pohyblivou řádovou čárkou v semilogaritmickém tvaru. |
Je však nutné dodržet následující formát:
mantisa E znaménko exponent
Příklad: | |
123.45E1 |
Na výše uvedeném příkladu jsme pomocí semilogaritmické notace zapsali číslo 1234,5. Znaménko je nepovinné.
Norma ISO C říká, že rozsah exponentů pro všechny racionální datové typy je 10-38 až 10+38 a že přesnost typu float je nejméně šest platných číslic, přesnost typů double a long double je pak nejméně deset platných číslic.
Přesněji viz tabulka:
Tabulka 3.4.
Typ | Počet bitů | Mantisa | Exponent | Rozsah absolutních hodnot |
---|---|---|---|---|
float | 32 | 24 | 8 | 3.4*10-38 - 3.4*10+38 |
double | 64 | 53 | 11 | 1.7*10-308 - 1.7*10+308 |
long double | 80 | 64 | 15 | 3.4*10-4932 - 3.4*10+4932 |
Má-li naše číslo větší absolutní hodnotu, než je hodnota pro typ tohoto čísla uvedená v tabulce dochází k přetečení a nastává chyba. V opačném případě, tedy když je absolutní hodnota čísla pro daný typ menší než je hodnota uváděná v tabulce, dochází k podtečení a výsledkem výrazu je nula.
Příklad: | |
'a' 'A' 'Š' 'ň' '}' '"' |
Někdy však musíme jako znakovou konstantu použít i speciální znaky (řídící symboly, znaky nenacházející se na klávesnici). Zde si pomáháme symbolem zpětného lomítka a nejméně jedním dalším znakem. Těmto posloupnostem říkáme escape sekvence. Escape sekvence mohou být jednoduché - kdy zpětné lomítko následuje jediný znak. Nebo následuje osmičkový či šestnáctkový kód znaku. Tak jsme schopni zadat i znak, který se na klávesnici nenachází, ale jehož číselný kód je nám znám.
Příklad: | |||||||||||||||||||||||||||||||
Tabulka 3.5.
|
Řetězec je posloupnost (pole) jednoho či více znaků. Začátek a konec řetězce jsou vymezeny uvozovkami. |
Příklad: | |
"Jazyk C" "několik znaků v řetězci" "r" //řetězcová konstanta tvořená řetězcem délky jeden znak = r "Jazyk C\n" //speciální symboly zapisujeme opět pomocí escape sekvencí |
Proměnné jsou paměťová místa přístupná prostřednictvím identifikátoru. Hodnotu proměnných můžeme během výpočtu měnit. Tím se proměnné zásadně odlišují od konstant, které mají po celou dobu chodu programu hodnotu neměnnou - konstantní. |
Proměnné mohou obsahovat písmena, číslice 0-9 a podtržítko. Jména však nesmí začínat číslicí.
Během provádění programu se veškeré informace nacházejí v paměti. Tamtéž jsou umístěny pomocné hodnoty, mezivýsledky i výsledky. Rozhodně by nebylo vůbec příjemné k takovým hodnotám přistupovat prostřednictvím jejich adresy. Proto je vhodné si odpovídající paměťová místa pojmenovat a pak se na ně odkazovat jménem. Nejprve tedy deklarujeme typy a identifikátory proměnných, čímž pro ně vyhrazujeme v paměti počítače místo a současně si překladač spojuje s identifikátorem proměnné informaci o jejím umístění v paměti (adrese).
Proměnné deklarujeme uvedením datového typu, za kterým následuje identifikátor, nebo seznam identifikátorů, navzájem oddělených čárkami. Deklarace končí středníkem. Současně s deklarací proměnné můžeme, ale nemusíme, definovat i její počáteční hodnotu:
Příklad: | |
int a, b, c; float pi=3.14; |
Ukazatel je proměnná, která obsahuje paměťovou adresu jiného objektu. Například obsahuje-li proměnná nazvaná p adresu jiné proměnné nazvané q, pak se p nazývá ukazatel na q. Je-li proměnná q uložena v paměti na adrese 100, pak by měla proměnná p hodnotu 100.
Pro deklaraci proměnné typu ukazatel použijeme tento obecný formát:
Typ zde znamená základní typ ukazatele. Základní typ určuje typ objektu, na který může ukazatel ukazovat. Všimneme si hvězdičky před jménem proměnné. Ta říká překladači, že se vytváří ukazatelová proměnná.
Uveďme si jednoduchý příklad ukazatele na celé číslo:
Příklad: | |
int *p; |
Jazyk C má dva speciální ukazatelové operátory: * a &. Operátor & vrací adresu proměnné, před kterou stojí. Operátor * vrací hodnotu uloženou na adrese, před kterou stojí.
Pozn: | |
Ukazatelový operátor * nemá nic společného s operátorem násobení, který používá stejný symbol. |
Příklad 3.1. | |
/****************************** * pointer1.c * 19.03.2002 ******************************/ #include <stdio.h> int main (void) { int *p, q; q = 199; /* priradi q hodnotu 199 */ p = &q; /* priradi p adresu q */ printf("%d", *p); /* zobrazi hodnotu q pomoci ukazatele */ return 0; } |
Tento program vypíše na obrazovku hodnotu 199.
Projděme si však jednotlivé části programu.
První řádek
int *p, q;
nadefinuje dvě proměnné. p - ukazatel na celé číslo a q - což je celé číslo.
Poté je q přiřazena hodnota 199
q = 199;
Následně přiřadíme p adresu q. Tento řádek můžeme přečíst jako: Přiřaď p adresu q.
p = &q;
Nakonec vytiskneme hodnotu ukazatele q. Operátor * můžeme vyjádřit jako: na adrese a celý řádek pak přečíst jako: vypiš hodnotu na adrese q.
printf("%d", *p);
Nyní přepišme tento program tak, že hodnotu do q přiřadíme nepřímo přes ukazatel p.
Příklad 3.2. | |
/****************************** * pointer2.c * 19.03.2002 ******************************/ #include <stdio.h> int main (void) { int *p, q; p = &q; /* ziskani adresy q */ *p = 199; /* priradi q hodnotu pomoci ukazatele */ printf("hodnota q je %d", q); return 0; } |
Nyní si ukážeme jak jednoduše lze udělat chybu.
Příklad: | |
int q; double *p; p = &q; p = 100.2; |
Ikdyž je tento úsek syntakticky v pořádku přesto není správný. Ukazateli p je přiřazena adresa čísla int. Tato adresa je pak použita na levé straně přiřazovacího příkazu pro přiřazení hodnoty s pohyblivou řádovou čárkou. Jelikož je však číslo typu int obvykle kratší než double, způsobí tento přiřazovací příkaz přepsání paměti sousedící s q. Proto jsou důležité základní typy ukazatelů.
Další možný chybný zápis vzniká tehdy, pokud se snažíme použít ukazatel dříve než je do něj přiřazena adresa proměnné. V takovém případě program pravděpodobně zhavaruje. Je důležité si uvědomit, že deklarace ukazatelové proměnné pouze vytvoří proměnnou schopnou pojmout adresu paměti. Nedá ji však žádnou smysluplnou hodnotu.
Příklad: | |
int *p; *p = 10; //chyba - ukazatel p na nic neukazuje! |
Místa, na která se ukazatel odkazuje (jejichž adresu obsahuje) se mohou lišit. Takže můžeme například psát cykly, v nichž pomocí jediného ukazatele postupně přistupujeme ke všem prvkům pole. Je nemyslitelné, psát takový kód "natvrdo". Další možnosti použití ukazatelů se otevírají při dynamickém přidělování paměti.
Je zde i jedno nebezpečí. Spočívá vtom, že nelze v programu zadávat absolutní adresu a očekávat, že bude použitelná jako paměťové místo. |
Příklad: | |
int *p; p = 1024; *p = 102; //takže takto rozhodně NE!! |
Na závěr poměrně rozsáhlé části o ukazatelích se pokusíme znázornit problematiku ukazatelů graficky. |
Předpokládejme že máme tuto část kódu:
int *p, q;
Dále mějme zadáno že q je umístěno v paměti na adrese 102 a p na adrese 100.
Poté následující příkaz
p = &q;
způsobí, že ukazatel p bude obsahovat hodnotu 102.
a po provedení příkazu
*p = 500;
bude obsah paměti vypadat takto