2.1 Identifikátory,
klíčová slova a komentáře.
2.2 Základní typy dat
2.3 Konstanty a 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.
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:
prvním symbolem smí být písmeno nebo podtržítko
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.
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.
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.
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é 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:
0
(číslice nula) uvádí konstanty v
osmičkové soustavě 0x
nebo 0X
(číslice nula následovaná
znakem x) uvádí konstanty v šestnáctkové soustavě 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 long
13
. Oba sufixy je možno spojit, takže například:
123UL
je (desítková) konstanta 123 typu unsigned long
.
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é 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ě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é 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
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:
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ý
Název: | Programování v jazyce C |
Autor: | Petr Šaloun |
Do HTML převedl: | Kristian Wiglasz |
Poslední úprava: | 19.11.1996 |