Předchozí kapitola

Obsah

Konec

Následující kapitola

2. Konstanty, proměnné a deklarace.

2.1 Identifikátory, klíčová slova a komentáře.
2.2
Základní typy dat
2.3
Konstanty a proměnné.

Konstanty
Celočíselné konstanty
Racionální konstanty
Znakové konstanty
Konstantní řetězce
Proměnné

2.4. Ukazatele.


V této kapitole se seznámíme s klíčovými slovy, identifikátory, komentáři. Poznáme rozdíl mezi konstantou a proměnnou a naučíme se nejen základní datové typy, ale i tvorbu nových typů dat.

2.1. Identifikátory, klíčová slova a komentáře.zpet

Klíčová slova mají speciální význam pro překladač C. Žádný identifikátor nemůže mít ve fázi překladu stejné znění jako klíčové slovo. ANSI norma určuje následující klíčová slova:

auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while

Identifikátory jsou jména, která dáváme například proměnným, funkcím a typům. Identifikátor se musí lišit od kteréhokoliv klíčového slova. Nejvyšší počet znaků identifikátoru je implementačně závislý. ANSI říká, že interní identifikátor může být dlouhý 31 znaků, externí 6.

Identifikátor je tvořen posloupností alfanumerických znaků a podtržítka, přičemž musí být splněny následující podmínky:

Jazyk C v identifikátorech rozlišuje malá a velká písmena1. Následující identifikátory jsou tedy navzájem odlišné:

identifikator Identifikator IDENTIFIKATOR IdEnTiFiKaToR

Komentář je část programu umístěná mezi dvojici párových symbolů /* a */. Komentář může vypadat například takto:

/* Toto je komentář,
 a toto je jeho pokračování na druhém řádku. */
...
/*
  if (uk->chyba)
    {
     ts->pom_info++;
    }
  else
 nepripustim chybu, ladim stejne nasucho
*/
...

Komentáře obvykle umisťujeme do zdrojového textu z důvodu jeho lepší čitelnosti. Často popisujeme některé důležité vlastnosti zdrojového textu právě v komentáři. Komentářem si můžeme rovněž přechodně vypomáhat ve fázi tvorby a ladění programu:

Bílý znak je jeden z následujících symbolů: mezera, tabelátor, nový řádek, posun řádku, návrat vozíku, nová stránka a vertikální tabelátor2. Bílé znaky spolu s operátory a oddělovači stojí mezi identifikátory, klíčovými slovy, řetězci a konstantami3použitými ve zdrojovém textu. Překladač považuje rovněž komentář za bílý znak.

2.2. Základní typy datzpet

Základní typy dat dělíme na celočíselné, racionální4, společně je nazýváme aritmetické datové typy, znaky a na ukazatele. Celočíselné datové typy mohou obsahovat modifikátory unsigned respektive signed, čímž můžeme požadovat hodnoty příslušného typu bez znaménka, resp. se znaménkem5. V céčku máme tedy k dispozici všechny potřebné základní typy i s jejich případnými modifikacemi. Jejich přehled spolu s paměťovými nároky a jejich českým významem následuje:

datový typ počet bitů význam
char, unsigned char, signed char 8 znak
short, unsigned short, signed short 16 krátké celé číslo
int, unsigned int, signed int 16 nebo 32 celé číslo
long, unsigned long, signed long 32 dlouhé celé číslo6
enum 8|16|32 výčtový typ
float 32 racionální číslo
double 64 racionální číslo s dvojitou přesností
long double 80  
pointer 16|32 ukazatel

Pokud nás překvapí více možných hodnot ve sloupci počet bitů, pak vězme, že tuto hodnotu určuje jak překladač, a případně u některých OS i paměťový model, tak skutečnost zásadnějšího významu. Totiž jedná-li se o překladač generující cílový kód šestnáctibitový či třicetidvoubitový (ovlivní typ int).

Nebudete-li si jisti rozsahem hodnot jednotlivých aritmetických typů, podívejte se do souboru LIMITS.H (pro celočíselné typy), respektive 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í.

Při našich prvních krocích vycházejme z následujících zásad, které jsou součástí ANSI C. Jak celočíselné, tak racionální typy je možno co do počtu obsazených bitů7 (a z toho vyplývajícího rozsahu možných hodnot) uspořádat takto:

short <= int <= long
float <= double <= double float
a dále platí, že char vyžaduje 8 bitů.

Na tomto místě věnujme několik slov konverzím aritmetických typů. Výraz složený z operandů různého aritmetického typu bude vyhodnocen a příslušné typové konverze proběhnou automaticky. Tím ovšem není řečeno, že výsledek bude takový, jaký očekáváme na základě znalostí naší školní matematiky. Konverzím aritmetických typů se podrobněji budeme věnovat později.

2.3. Konstanty a proměnné.zpet

Většina objektů (entit), označených identifikátorem musí být deklarována dříve, než je použita. Konstanty, typy, proměnné a funkce k takovým objektům patří.

S konstantami a proměnnými jsou úzce spojeny dva pojmy, deklarace a definice8. Deklarací určujeme typ objektu. Informace o typu je překladačem používána při typové kontrole, typových konverzích, atd. V místě definice definujeme hodnotu proměnné či posloupnost příkazů funkce. Z uvedeného vyplývá důvod, proč můžeme například funkci vícekrát deklarovat, ale pouze jedenkrát definovat.

Konstanty a proměnné mohou nabývat hodnot jak základních datových typů, tak typů uživatelsky definovaných. Přirozeně mohou tvořit i struktury typu pole. V této části se poli konstantních i proměnných vektorů nebudeme zabývat podrobněji, omezíme se na jejich definice.

Konstantyzpet

Konstanty jsou symboly, reprezentující neměnnou číselnou nebo jinou hodnotu. Překladač jazyka jim přiřadí typ, který této hodnotě odpovídá. Z konstant odpovídajících si typů můžeme vytvářet konstantní výrazy. Tyto výrazy musí být regulární (zjednodušeně musí být snadno vyhodnotitelné během překladu). Nesmí obsahovat žádný z následujících operátorů (nejsou-li použity mezi operandy operátoru sizeof):

Konstantám s vhodně zvolenými identifikátory dáváme přednost například před přímým uvedením konstantní hodnoty jako meze cyklu nebo dimenze pole9. Modifikace programu pak probíhá velmi snadno změnou hodnoty konstanty. Odpadá obtížné uvažování, zdali ta či jiná hodnota má býti modifikována či nikoliv. Konstanty mají rovněž určen typ. Tím je umožněna typová kontrola.

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, následuje za identifikátorem dvojice hranatých závorek, zpravidla obsahující jeho dimenzi. První prvek pole má vždy index 0. Konstanty můžeme definovat třeba takto:

const int konstanta = 123;
const celociselna = -987;

const float CPlanck = 6.6256e-34;
const char male_a = 'a';
const char *retezec = "Konstantni retezec."
const float meze[2] = {-20, 60};
const char rimska_znaky[] = {'I', 'V', 'X', 'L', 'C', 'D', 'M'};
const int rimska_hodn[] = {1, 5, 10, 50, 100, 500, 1000};

Neuvedeme-li typ, jako v případě druhé konstanty, je implicitně chápán typ int. Můžeme definovat konstanty všech základních datových typů. Proměnná meze představuje dvouprvkové pole konstant typu float. Prvky pole nabývají se vzrůstajícím indexem hodnoty v pořadí, jak jsou v definici zapsány. Poslední dvě konstanty jsou pole konstantních hodnot. Uvedeme-li všechny požadované hodnoty na pravé straně definice, nemusíme v hranatých závorkách uvádět dimenzi pole10.

Celočíselné konstantyzpet

Celočíselné konstanty jsou tvořeny zápisem celého čísla. Mohou být zapsány v desítkové, osmičkové případně v šestnáctkové číselné soustavě. Nejprve tedy jednoduché zápisy:

123 -987 255 4567 -4567

které představují celočíselné konstanty. V pořadí druhá a poslední představují záporné hodnoty, ostatní jsou kladné.

Nyní si uvedeme pravidla, podle nichž určujeme základ číselné soustavy konstanty:

Následuje několik desítkových konstant zapsaných ve třech možných číselných soustavách11:

desítkový osmičkový šestnáctkový12
123 0173 0x7b
-987 0176045 0xfc25
255 0377 0xff
4567 010727 0x11d7
-4567 0167051 0xee29

Jestliže prefix zápisu celočíselné konstanty určoval základ číselné soustavy, pak sufix, pokud je uveden, určuje celočíselný datový typ. A to následovně: u nebo U modifikuje typ na unsigned, zatímco l nebo L říká, že jde o typ long13. Oba sufixy je možno spojit, takže například:

123UL

je (desítková) konstanta 123 typu unsigned long.

Racionální konstantyzpet

Racionální konstanty umožňují zapsat číselnou konstantu, která nemusí být celočíselná. Vnitřně je reprezentována ve tvaru, který obsahuje mantisu a exponent, obojí s případným znaménkem.

Implicitní typ racionální konstanty je double. Například 12.34e5. Chceme-li, aby konstanta byla typu long double, připojíme k zápisu písmeno L, tedy například

12.34e5L.

Pro lepší představu dává následující tabulka přehled některých vlastností racionálních datových typů:

typ bitů mantisa exponent rozsah absolutních hodnot (přibližně)
float 32 24 8 3.4 10-38 až 3.4 10+38
double 64 53 11 1.7 10-308 až 1.7 10+308
long double 80 64 15 3.4 10-4932 až 1.1 10+4932

Přesně definuje racionální datové typy norma IEEE 754.

Znakové konstantyzpet

Znakové konstanty jsou tvořeny požadovaným znakem, respektive posloupností znaků, uzavřeným mezi apostrofy. Na následujícím řádku je zapsáno několik znakových konstant:

'a' 'A' 'Š' 'ň' '}' '#' '"'

První dvě nás jistě nepřekvapí, další dvě nemusí být nutně k dispozici na všech systémech (byť podpora národního prostředí je čím dál větší samozřejmostí). Další dva znaky zase nejsou k dispozici na standardních českých klávesnicích, ale céčko si bez nich představit nedovedeme. No a poslední znaková konstanta jsou úvozovky. Jimi si připravujeme následující otázku.

Jak zapíšeme znakovou konstantu apostrof? A co případně jiné speciální znaky (řídící symboly, znaky nenacházející se na klávesnici, ...). Zde si pomáháme symbolem opačné lomítko a nejméně jedním dalším znakem. Těmto posloupnostem říkáme escape sequence. Ty mohou být jednoduché, kdy opačné lomítko následuje jediný znak. Nebo následuje osmičkový či (po x) šestnáctkový kód znaku. Tak jsme schopni zadat i znak, který se na klávesnici nenachází, ale jehož kód je nám znám. Přehled escape sequencí obsahuje tabulka:

posloupnost jméno Ctrl-znak význam
\a Alert (Bell) G pípnutí
\b Backspace H návrat o jeden znak
\f Formfeed L nová stránka nebo obrazovka
\n Newline J přesun na začátek nového řádku
\r Carriage return M přesun na začátek aktuálního řádku
\t Horizontal tab I přesun na následující tabelační pozici
\v Vertical tab K stanovený přesun dolů
\\ Backslash   obrácené lomítko
\' Single quote   apostrof
\" Double quote   úvozovky
\? Question mark   otazník
\OOO     ASCII znak zadaný jako osmičková hodnota
\xHHH     ASCII znak zadaný jako šestnáctková hodnota

Konstantní řetězcezpet

Konstantní řetězce - literály jsou na rozdíl od znakových konstant tvořeny více než jedním znakem, zpravidla slovem či větou (tedy znakovou posloupností, řetězcem). Začátek a konec řetězce jsou vymezeny úvozovkami. Následující řetězce jsou úmyslně psány cesky:

"dve slova" "Cela tato veta tvori jeden retezec." "a" "Ahoj!"

Na předposlední řetězec musíme upozornit. Jedná se o řetězcovou konstantu tvořenou písmenem a, tedy řetězcem délky jeden znak. Nesmíme ji zaměňovat se znakovou konstantou. Ta je vymezena dvěma apostrofy. Navíc, znaková konstanta, bez ohledu na její zápis, představuje jeden jediný znak, zatímco řetězcová konstanta může mít i značnou délku.

Pokud konstantní řetězec obsahuje speciální symboly, zapisujeme je obdobně, jako jsme to činili u znakových konstant. Například:

"\tPo uvodnim tabelatoru prejdeme na novy radek\na pipneme\a."

Použili jsme jednoduché escape sequence. Pokud bychom po nich udělali mezeru, byla by tato rovněž obsažena i ve výsledném řetězci. A to nechceme. A ještě jedna ukázka delší řetězcové konstanty:

"Tato delsi retezcova konstanta obsahuje opacne lomitko \\, \
a pokracuje na dalsim radku od jeho zacatku. " "Navic je takto \
rozdelena."

"Jednodussi pokracovani na dalsim radku "

"vypada takto, pak nemusime zacinat hned na zacatku."

Prvni dva řádky jsou ukončeny opačným lomítkem. Tím je řečeno, že řetězec pokračuje na následujícím řádku. Jednodušší je ovšem konstrukce, při níž ukončit řetězec úvozovkami, ukončíme řádek a pokračuneme novým řetězcem kedkoliv na novém řádku. Překladač totiž dva řetězce, oddělené pouze bílými znaky, spojí v řetězec jeden.

Proměnnézpet

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é deklarujeme uvedením datového typu, jež je následován identifikátorem, nebo seznamem 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:

int a, b, c, pocet = 0;
float x, prumer = 0.0, odchylka = 0.0;
float y;

ANSI C považuje konstanty za proměnné s neměnnou hodnotou. V závislosti na použitém překladači může být tato hodnota umístěna ve výrazu přímo. Pak jí nemusí být vyhrazeno paměťové místo tak, jak by bylo vyhrazeno pro proměnnou.14

2.4. Ukazatelé.zpet

Ukazatel představuje adresu paměťového místa. Jeho hodnota říká, kde je uložen nějaký objekt. Součástí deklarace ukazatele je i informace o typu dat, které jsou na získané adrese očekávány.

int *integer_ptr; /* integer_ptr je ukazatel na integer */

Hodnota integer_ptr představuje adresu paměti a *integer_ptr je celočíselná hodnota uložená na této adrese. Často používáme pojem dereference ukazatele. Následující hypotetický příklad pracuje s adresou 1004, kam zapíše hodnotu 123:

int *p; p = 1004; *p = 123;

Paměť by po těchto příkazech vypadala následovně (změněná hodnota je zvýrazněna, ostatní paměťová místa mají náhodný obsah):

Hodnoty 15 0 123 65
Adresy 1002 1003 1004 1005

Obvyklou chybou začátečníků je použití ukazatele bez jeho předchozí inicializace (alokace paměťového místa). Neinicializovaný ukazatel může ukazovat na kritické oblast paměťi a jeho použití může vést (v operačních systémech jako je MS-DOS) i k havárii systému. Takto tedy ne:

Ukazatele

Zatím vystačíme bez alokace paměti. Potřebujeme ovšem prostředek ke získání adresy existující proměnné. Pak se budeme korektně odkazovat na vyhrazené paměťové místo.

int i, *pi;
pi = &i;
*pi = 123;

Po definici proměnné i typu int, a ukazatele pi na typ int v prvním řádku následuje získání adresy proměnné i. Na tuto adresu se odkazuje ukazatel pi. Jeho dereferencí na levé straně příkazu přiřazení, uložíme příslušnou hodnotu na paměťové místo, na které ukazuje.

Ukazatele, o kterých jsme dosud pojednávali, byly spojené s nějakým konkrétním typem. Tato skutečnost je přínosem, neboť umožňuje typovou kontrolu. Jsou však okamžiky, kdy prostě potřebujeme ukazovat ukazatelem do paměti a nemáme na mysli konkrétní datový typ. ANSI norma pro takovou situaci zavádí prázdný fiktivní typ void.


Výsvětlivky:

1 Tato skutečnost činí obtíže zejména začátečníkům přecházejícím k céčku z většiny jiných jazyků.
2 V obvyklém zdrojovém textu se nejčastěji můžeme setkat s prvními třemi představiteli bílých znaků.
3 Všechny uvedené pojmy se společně označují jako tokeny. Pro překladač představují dále nedělitelné
4 Tento termín nejlépe vystihuje omezenou délku mantisy, kterou mohou čísla s desetinnou tečkou
5 Tato varianta je často používána u typu char, kde může být rovněž zdůrazněno jak signed char,
6 Celočíselný typ long rovněž můžeme psát jako long int. Obdobně short představuje totéž, co
7 Později se dozvíme, že ke zjištění potřebné paměti pro hodnotu příslušného typu je možno použít
8 Tyto pojmy budeme později diskutovat i v souvislosti s funkcemi.
9 Konstantám uvedeným přímo ve zdrojovém textu se říká magická čísla. Vhodný identifikátor leccos
10 Pro hloubavější čtenáře můžeme uvést i možnost, jak později zjistit, kolik prvků takové pole má.
11 Nutno podotknout, že se jedná o šestnáctibitový kód, tedy i typ int je šestnáctibitový.
12 Osmičkové a šestnáctkové konstanty jsou chápány bez znaménka. Šestnáctkové cifry můžeme
13 Často se jako sufix používá velké L, neboť malé l je snadno zaměnitelné s číslicí jedna.
14 Tato skutečnost závisí rovněž na použití konstanty. Odvoláváme-li se na její adresu, je jí paměťový


Předchozí kapitola

Obsah

Začátek

Následující kapitola


Název: Programování v jazyce C
Autor: Petr Šaloun
Do HTML převedl: Kristian Wiglasz
Poslední úprava: 19.11.1996