Kurz C++ (6.) V tΘto lekci dostßvßme mo₧nß k nejobtφ₧n∞jÜφ problematice programovßnφ a to k ukazatel∙m. ╚tenß° se za prvΘ dozvφ, co to je ukazatel, dßle se dozvφ, jak ukazatel zφskß a jak s nφm pracuje. UkazateleKa₧dß prom∞nnß, kterou v programu deklarujeme, se nachßzφ v pam∞ti poΦφtaΦe, kterß je rozd∞lena na bu≥ky o velikosti jednoho bytu, tedy 8 bit∙. Ka₧dß bu≥ka mß n∞jakΘ Φφslo, pomocφ kterΘho ji lze jednoznaΦn∞ urΦit. Tomuto Φφslu se °φkß adresa. Ukazatel (angl. pointer) je prom∞nnß nebo konstanta, kterß v sob∞ udr₧uje adresu n∞jakΘ jinΘ prom∞nnΘ (°φkß se, ₧e ukazatel "ukazuje na prom∞nnou"), nebo i adresu n∞jakΘ libovolnΘ bu≥ky v pam∞ti. Ukazatelem je mo₧nΘ Φφst nebo m∞nit hodnotu na adrese, kam ukazuje. Jako v₧dy, ukß₧eme si p°φklad:
Nejd°φve jsme deklarovali ukazatel Dßle jsme ukazatel nastavili na adresu prom∞nnΘ Na dalÜφm °ßdku jsme nep°φmo p°i°adili prom∞nnΘ Ukazatel m∙₧e b²t pevnΘho datovΘho typu, to znamenß, ₧e ukazatel "vφ", na jak² datov² typ ukazuje, a p°i dereferenci vrßtφ p°esn∞ ten datov² typ. Existuje jeÜt∞ jeden typ ukazatele, tzv. obecn², kter² m∙₧e ukazovat na prom∞nnou jakΘhokoli datovΘho typu, ale datov² typ "si nepamatuje", a z tohoto d∙vodu nem∙₧e b²t na n∞m provedena dereference. Obecn² ukazatel se deklaruje klφΦov²m slovem void:
Kompilßtor ohlßsφ chybu na °ßdku
Poslednφ dva °ßdky m∙₧eme spojit do jednoho, je to rozumn∞jÜφ zßpis, a urΦit∞ elegantn∞jÜφ, proto₧e se vyhneme deklaraci zbyteΦnΘho ukazatele p2:
Pozor, obecn² ukazatel m∙₧eme p°etypovat na ukazatel na libovoln² datov² typ, ale v²sledek dereference nebude sprßvn².
Ukazatel m∙₧e b²t i prßzdn², tedy neukazuje na ₧ßdnou adresu. K tomu se pou₧φvß zvlßÜtnφ hodnota
NULL, v C++ lze pou₧φvat i 0.
Mo₧nß se ptßte, k Φemu vlastn∞ ukazatele jsou. Je pravda, ₧e jsme si neukßzali ₧ßdnΘ jejich smysluplnΘ pou₧itφ. Dßle vysv∞tlφm souvislost mezi ukazateli a poli. A₧ si vysv∞tlφme zßznamy ukß₧eme si dalÜφ pou₧itφ v²znamnΘ ukazatel∙ a zßznam∙. Dßle v kurzu probereme t°φdy a tam takΘ uvidφte, jak jsou ukazatele d∙le₧itΘ. Ukazatele a polePole a ukazatele majφ v jazycφch C a C++ k sob∞ velice blφzko. Bez ohledu na rozdφlnou syntaxi se tyto jazyky dφvajφ na pole a ukazatele stejn∞: pole je vlastn∞ ukazatel n∞kam do pam∞ti, kde se nachßzφ seznam prom∞nn²ch stejnΘho typu t∞sn∞ za sebou. ╪ekli jsme si, ₧e se meze polφ nekontrolujφ. Te∩ chßpeme, proΦ tomu tak je: pole je ukazatel, kter² pouze ukazuje na prom∞nnou na n∞jakΘ adrese, ale nelze °φci, kolik je za nφ dalÜφch prom∞nn²ch stejnΘho typu, to vφ pouze programßtor. TakΘ jsme si °ekli, ₧e velikost prvku pole zφskßme zßpisem Ukazovali jsme si, ₧e °et∞zce lze deklarovat zßpisem: Ze skuteΦnostφ v²Üe uveden²ch vypl²vß i to, ₧e s ukazatelem m∙₧eme zachßzet jako s polem,
nap°φklad:
Existujφ i p°φpady, kdy pole a ukazatel nejsou totΘ₧. Typick² p°φpad je pou₧itφ operßtoru
sizeof:
Velikost pole je 20 (5 * 4), ale velikost ukazatele je 4 (ukazatel je 32bitovß prom∞nnß).
TakΘ je nutnΘ si uv∞domit rozdφl mezi deklaracφ pole (pop°. °et∞zce) a deklaracφ ukazatele.
Aritmetika ukazatel∙Jednou z p°ednostφ jazyka C a C++ je aritmetika ukazatel∙. To nßm dovoluje zachßzet s ukazatelem jako s Φφselnou prom∞nnou: m∙₧eme k n∞mu p°iΦφtat Φφsla, odeΦφtat, zv∞tÜit a zmenÜit, porovnßvat s jin²m ukazatelem a tak podobn∞. Nap°φklad aritmetikou ukazatel∙ m∙₧eme nahradit pou₧itφ hranat²ch zßvorek (to v∞tÜinou ned∞lßme, ale n∞kdy se nßm to m∙₧e hodit):
DalÜφ pou₧itφ je posuv v °et∞zci:
TypickΘ pou₧itφ je prochßzenφ °et∞zce za ·Φelem n∞jakΘho zpracovßnφ. P°edstavte si, ₧e bychom pot°ebovali vypsat
°et∞zec tak, ₧e p°eskakujeme nadbyteΦnΘ mezery (tj. kdy₧ jich je vφce za sebou, vypφÜeme jen jednu). Nejd°φve musφme vymyslet algoritmus (jak to budeme
provßd∞t): projdeme vÜechny znaky pole a pokud znak nenφ mezera vypφÜeme ho, jinak ho vypφÜeme pouze pokud p°edchozφ zpracovan² znak nebyl mezera:
Poznßmka: sna₧il jsem se napsat funkci vypis() tak, aby byla pochopitelnß. OvÜem jazyk C++ je znßm² pro svou struΦnost a eleganci, tak₧e si ukß₧eme, jak naÜi funkci napsat v tomto duchu. Podmφnka cyklu while ( *s != 0 ) bude mφt
hodnotu false (0) pokud hodnota *s bude 0, a hodnotu true (1, ale takΘ jakßkoli nenulovß hodnota)
pokud hodnota *s bude r∙znß od 0. To znamenß, ₧e hodnota podmφnky je stejnß s hodnotou *s . To vyu₧ijeme k tomu,
abychom napsali cyklus while takto: while (*s) . Je to naprosto totΘ₧.
Dßle zam∞°φme svou pozornost na p°φkazy if. Trochu vadφ, ₧e p°φkaz pro vypsßnφ se opakuje dvakrßt, tak₧e zkusφme napsat podmφnku
pro if tak, abychom si vystaΦili s jednφm
if. Platφ, ₧e se znak vypφÜe pokud nenφ mezera nebo pokud mezera je a souΦasn∞ posledn∞
zpracovan² nenφ mezera. P°φkaz if, kter² tomu odpovφdß, je
Jsme skoro u cφle, ale nenφ to ·pln∞ ono. V²raz *s == ' ' za druhou zßvorkou bude v₧dy pravdiv². Do jeho zßvorky se
toti₧ dostaneme pouze pokud
prvnφ v²raz (*s != ' ' ) je nepravdiv², a to znamenß, ₧e v²raz *s == ' ' je
pravdiv². M∙₧eme nadbyteΦnou podmφnku
vypustit, a dostaneme:
Poslednφ "fφgl", kter² Vßm chci ukßzat, se t²kß obou dvou poslednφch °ßdk∙ funkce
vypis(). Z p°edchozφch Φßstφ vφte, ze v C a C++ existuje operßtor
++, kter² zv∞tÜφ prom∞nnou o jedniΦku. Mφsto s = s + 1 budeme psßt s++ . ╪ekn∞te, nenφ to hezΦφ? A te∩ ta nejlepÜφ Φßst:
operßtor ++ psan² za m∞n∞nou hodnotou funguje tak, ₧e jeÜt∞ p°ed zv∞tÜenφm vracφ p∙vodnφ (nezv∞tÜenou) hodnotu - v naÜem p°φpad∞ p∙vodnφ ukazatel (v²sledek s++ bude s).
To vyu₧ijeme k nastavenφ prom∞nnΘ last, a napφÜeme: last = *s++ . Tak₧e naÜe upravenß funkce vypadß takto:
Pokud nerozumφte vÜem ·pravßm, nic si z toho ned∞lejte. Jste p°ece jen na zaΦßtku a C++ je dost slo₧it²
jazyk. Pokud se budete alespo≥ trochu zab²vat
programovßnφm, p°ijdete na tyto skuteΦnosti sami. M∞li byste alespo≥ pochopit zjednoduÜenφ podmφnky cyklu
while, je to v C a C++ opravdu pou₧φvan² zßpis.
Ukazatele a funkceKdy₧ jsme si ukßzali funkce pro prßci s °et∞zci uvedl jsem jejich syntaxi, ale znaΦn∞ zjednoduÜen∞. Nynφ, vyzbrojenφ znalostmi o ukazatelφch, si m∙₧eme
ukßzat hlaviΦky t∞chto funkcφ. Funkce pro zpracovßnφ °et∞zc∙ mohou dostat jako parametry i °et∞zce znaΦnΘ velikosti. Kdyby se musel funkci p°edat
takov² °et∞zec tak, ₧e by se "do funkce" zkopφroval cel², mohlo by to trvat dost dlouho. Proto existuje mnohem lepÜφ zp∙sob p°edßvßnφ °et∞zc∙
(a nejenom, ale jak²chkoliv prom∞nn²ch velk²ch datov²ch typ∙): funkci se p°edß pouze ukazatel na °et∞zec. Nap°φklad:
P°edßvßnφ parametr∙ tak, ₧e se p°edß pouze ukazatel, je takΘ p°edßvßnφ odkazem. V minulΘm dφlu jsme si ukßzali p°edßvßnφ odkazem operßtorem &.
Je to mo₧nΘ i ukazatelem:
Jako parametry aritm a geom samoz°ejm∞ p°edßme adresy prom∞nn²ch, do kter²ch se pr∙m∞ry majφ ulo₧it, ty zφskßme operßtorem &.
To byl v jazyce C jedin² zp∙sob p°edßvßnφ odkazem. V jazyce C++ mßme lepÜφ zp∙sob, a to je operßtor
& (operßtor reference - angl. reference operator),
jak jsme si ukßzali minule.
Reference v sob∞ udr₧uje adresu n∞jakΘ prom∞nnΘ, ale syntakticky se chovß jako ta prom∞nnß. Ale jak² je rozdφl mezi p°edßvßnφ parametru
ukazatelem a referencφ? Je to jednoduchΘ, nulovß reference neexistuje, nulov² ukazatel ano. Tedy p°edßvßnφ ukazatelem m∙₧eme pou₧φt tam, kde
chceme mφt mo₧nost v parametru nep°edat nic. Jako p°φklad vylepÜφme funkci
prumery():
Funkce prumery() nynφ umφ poΦφtat pouze aritmetick² pr∙m∞r, nebo pouze geometrick², nebo dokonce ani jeden z nich. Budeme-li mφt zßjem pouze o
aritmetick² pr∙m∞r, zavolßme funkci takto:
Toto bychom referencφ neud∞lali. Ale reference se takΘ hodφ, nap°φklad kdy₧ naopak chcete mφt jistotu, ₧e se skuteΦn∞ p°edala n∞jakß prom∞nnß.
Poznßmka: v²znam klφΦovΘho slova const u parametr∙ string2 a strSource v deklaraci v²Üe uveden²ch funkcφ znamenß,
₧e funkce nem∞nφ °et∞zce p°edanΘ v t∞chto parametrech, tak₧e lze p°edat i konstantnφ °et∞zec (deklarovan² takΘ
klφΦov²m slovem const - const char *str = "Ahoj"; ). Bez klφΦovΘho slova const by to mo₧nΘ nebylo.
To je pro tento m∞sφc vÜechno. Pilujte, zkouÜejte, nebojte se experimentovat, za m∞sφc nashledanou.
|
|
⌐ 2001 Vogel Publishing, design by ET NETERA