# Ukazatele Tato kapitola přináší první prostředek, který nám umožní s objekty pracovat «nepřímo» – rozhodnutí o tom, se kterým objektem budeme pracovat, provedeme «výpočtem» (za běhu programu). Zejména tedy konkrétní použitý objekt v pevně zvoleném příkazu může záviset na tom, s jakými vstupními daty byl program spuštěn. ## Objekt, identita, adresa Pojem «ukazatel» je těsně svázán s «objekty» a jejich «identitou». Proto se nejprve vrátíme k těmto pojmům – bez nich není možné ukaztele správně zadefinovat.¹ ¹ Ukazuje se, že použití ukazatelů činí mnoha studentům značné problémy. Domníváme se, že je tomu zejména proto, že mají chybnou představu o tom, co ukazatel je. V obecném povědomí žel koluje mnoho mýtů a polopravd, a je pravděpodobné, že jste se s nimi už setkali. Zkuste prosím pro tuto chvíli zapomenout, že jste někdy něco o ukazatelích slyšeli, nebo je nějak používali. Ukazatele zejména nejsou nijak magické ani záhadné, jedná se o velice přímočarý koncept (i přesto, že jejich správné použití nemusí být vždy jednoduché). ### Hodnota Ukazatele jsou zejmena novým «typem hodnoty» – proto je potřeba mít na paměti, co je hodnota – prozatím jsme se v tomto kurzu setkali pouze s tzv. celočíselnými typy a jejich hodnotami. Může být tedy těžké oddělit koncept hodnoty od konceptu čísla, ale je to krok bezpodmínečně nutný pro hlubší pochopení výpočtu (a tedy i programování jako takového). Jak jsme již zmiňovali ve druhé kapitole, výpočet je posloupnost «operací» (které s hodnotami «pracují») nad sbírkou «objektů» (které hodnoty «uchovávají»). Abychom o něčem mohli říct, že je to hodnota, musí tedy vykazovat právě tyto dvě vlastnosti: 1. musí existovat nějaké «operace», pro které jsou tyto hodnoty vstupy (operandy) a/nebo výstupy (výsledky), 2. hodnoty musí být možné «ukládat» (pamatovat si). Naopak, není nutné, aby bylo možné libovolnou hodnotu přímo zapsat do programu (jako literál/konstantu), aby ji bylo možné „vypsat na obrazovku“ (vytvořit řetězec, který tuto hodnotu nějak reprezentuje) ani není určena žádná operace, která musí vždy existovat (některé hodnoty nemusí být možné sčítat, některé hodnoty nemusí být možné srovnávat, atp.). Hodnoty také «nemají identitu» – není například možné říct, je-li kopie hodnoty (která vznikne načtením hodnoty z objektu a následným uložením do nového objektu) nějaká „nová hodnota“ nebo „tatáž hodnota“ – tuto otázku nedává smysl pokládat¹ – vztah „být tentýž“ na hodnotách vůbec není definovaný.² ¹ Jedná se o podobně nesmyslnou otázku jako „a mám přičíst tu jedničku, co mám v sešitě, nebo tu, co máte na tabuli?“ ² «Pozor!» Jiná je «rovnost hodnot» – v tomto případě se jedná o «operaci» na hodnotách a neurčuje, zda se jedná o „tutéž“ hodnotu. Nakonec při vyhodnocení výrazu ‹a == a› dojde na levé straně k načtení hodnoty z objektu určeného proměnnou ‹a› a totéž se stane na pravé straně – jakákoliv intuice typu „je to přece tatáž hodnota, protože je uložena v tom stejném objektu“ ve skutečnosti také nefunguje. ### Objekt │ • buňka pro uložení hodnoty │ • typicky skrze proměnnou │ • má identitu │ • nemá pevnou adresu Základním prvkem paměti programu v jazyce C (ale i mnoha jiných, včetně jazyka Python) je «objekt». Pro pochopení ukazatelů není vůbec důležité, jak je takový objekt realizován – jestli a jak je reprezentován v paměti, jestli má nebo nemá nějakou adresu, atp. Podobně jako je nutné vyčlenit pojem hodnoty, je také nutné rozlišovat mezi hodnotami a objekty a pochopit vztah mezi nimi. Pro práci s objekty jsou důležité jen dvě vlastnosti – jeho «obsah» a jeho «identita» – vše ostatní je „implementační detail“ – podobně, jako při běžném programování nemusíte uvažovat o tom, jaké instrukce se použijí pro překlad kterého výrazu, nemusíme (a ani nechceme) uvažovat o tom, jak bude (nebo nebude) který objekt uložen v paměti. Do této chvíle jsme s objekty pracovali pouze skrze proměnné – každá proměnná pevně identifikuje právě jeden objekt.¹ Typ tohoto objektu je stejný, jako typ proměnné, a je do něj možné uložit pouze hodnoty tohoto typu. ¹ Platí pro jazyk C a některé jiné, ale zdaleka ne všechny. Vztah proměnných a objektů v Pythonu je například mnohem volnější. ### Identita objektu │ • identita je abstraktní │ • ??? Zejména klíčový je pojem «identity» objektu.¹ Není důležité, jak taková identita vnitřně vypadá (podobně jako není důležité, jak jsou vnitřně reprezentovaná celá čísla), důležité ale je, že se jedná o «hodnotu». Základní vlastností hodnoty je, že je možné ji ukládat (do objektů, a tedy i do proměnných) a že jsou na ní definované nějaké «operace». Základní operace s identitami jsou dvě: 1. máme-li nějaký «objekt», můžeme získat jeho identitu, 2. máme-li identitu, můžeme s její pomocí získat příslušný «objekt», 3. máme-li dvě identity, můžeme zjistit, jestli jsou stejné nebo různé (na identitách je definovaná «rovnost»). Protože různé objekty mají různé identity, a každý objekt má právě jednu identitu, rovnost identit přesně rozhoduje, identifikují-li obě tentýž objekt. ¹ Spoiler alert: možné hodnoty ukazatelů jsou právě identity objektů. ### Adresa │ • číselné označení buňky │ • adresu lze vypočítat │ • označuje «slabiky»/slova │ ◦ «nikoliv hodnoty» jazyka │ ◦ čtení/zápis z/na adresu ### Adresa vs identita │ • jak reprezentovat identitu │ • adresa prvního bajtu │ • co objekt v registru? │ • co přesun objektu ### Ukazatel │ • identita jako hodnota │ • načti/zapiš «hodnotu» │ ◦ nikoliv slabiku/slovo ### Typ ukazatele │ • obsahuje «typ objektu» │ • zapisujeme ‹typ *› │ • existuje pro každý typ │ • kolik různých typů? ### Operátor adresy │ • nový tvar výrazu – ‹&var› │ • pracuje s «objektem» │ • výsledek je «ukazatel» │ • použití «fixuje» adresu objektu Adresa ~ reprezentace identity. ### Operátor dereference ‹*› │ • nové tvary výrazů │ ◦ ‹*e₁› – výsledek je «objekt» │ ◦ ‹*e₁ = e₂› (nepřímé přiřazení) │ • objekt vs hodnota │ ◦ l-hodnota vs r-hodnota │ ◦ l-kontext vs r-kontext Identity ‹&*›, ‹*&›. ### Platnost ukazatele │ • platná adresa ≠ platný ukazatel │ • «musí» ukazova na objekt │ • typ ukazatele = typ objektu │ • vstupní podmínka dereference ### Výstupní parametr │ • realizace ukazatelem │ • ‹void foo( int *out )› │ • ‹out› → kam zapsat výsledek │ • volající odpovídá za objekt ## Přetypování ### Přetypování aritmetických typů ### Přetypování ukazatelů ### Typy a objekty XXX vznik objektu zápisem do pole bajtů