Datové typy základní a složené

Datový typ definuje v programování druh nebo význam hodnot, kterých smí nabývat proměnná (nebo konstanta). Datový typ je určen oborem hodnot a zároveň výpočetními operacemi, které lze s hodnotami tohoto typu provádět.

Jednoduché

Jak již bylo zmíněno, jednoduché (také elementární) datové typy jsou většinou přímo zabudovány do jazyka, přičemž v běžně používaných jazycích nejsou parametrizovatelné. Složitější typy pak mohou vznikat skládáním elementárních datových typů.

Každý počítačový jazyk může mít poněkud odlišnou sadu elementárních datových typů. U mnoha počítačových jazyků závisí parametry elementárních datových typů na architektuře procesoru, na kterém má běžet program. To platí zvláště u kompilátorů jazyka C a C++.

Ordinální datové typy

Níže uvedené typy jsou ordinální. Hodnoty ordinálního typu tvoří lineárně uspořádanou množinu, kde pro každý prvek je přesně definovaný předchůdce i následovník (z posledního prvku ve většině jazyků dochází k tzv. přetečení na první). Z funkčního hlediska tak můžeme k jednoduchým celočíselným datovým typům řadit i výčtový typ, i když jeho hodnoty jsou definovány programátorem. Ordinální celočíselné datové typy jsou základem současné informatiky.

Logická hodnota

V Javě a Pascalu odpovídá logické hodnotě typ boolean, který smí nabývat hodnot – true nebo false. Logická hodnota je výsledkem porovnání nebo logického výrazu. Logická hodnota bývá obvykle výsledkem výrazu s relačními nebo logickými operátory. Jazyk Ctento typ nedefinuje, místo hodnoty false používá celé číslo 0, hodnotu true pak reprezentuje jakékoli nenulové celé číslo (i záporné).

Celé číslo

Pro celé číslo se v Pascalu používá typ integer, v jazyce C a C++ int. Čísla 256, 1, 0, -32767, 0xA9 jsou zápisy celočíselných konstant. Poslední konstanta demonstruje možnost hexadecimálního zápisu v jazyce C. Programovací jazyky mohou (ale nemusí) rozlišovat celá čísla bez znaménka a se znaménkem.

Ve většině jazyků mají celá čísla omezený rozsah. Pokud je celé znaménkové číslo omezeno např. na 16 bitů, tak bude mít rozsah -32768 až +32767, což je dané kódováním ve dvojkovém doplňkovém kódu. Pokud výsledek operace překročí rozsah, dochází k tzv.přetečení (32767 + 1 dá -32768). Znaménková i bezznaménková čísla při běžném kódování vytvářejí algebraický okruh.

Některé jazyky (např. Python) místo přetečení pro číslo vyhradí větší množství paměti. Tím je usnadněno programování, avšak snižuje se výkon programu.

Kromě sčítání, odčítání, násobení, celočíselného dělení a zbytku po dělení je možné provádět nad celými čísly i bitové operace, jako jsou logický součin, logický součet a logická negace. Tyto operace se provádí nad jednotlivými bity operandů ve dvojkové reprezentaci.

Znak

Pro znak se typicky používá označení char – např. ‚a‘, ‚A‘, ‚g‘, ‚ ‚, ‚5‘, ‚%‘, atp. Ve skutečnosti je znak v počítači reprezentován pomocí celého čísla. Pro kódování znaků se většinou používá znaková sada ASCII a její národní rozšíření, nebo znaková sada Unicode. Pro reprezentaci kódového bodu unicode podle současných standardů postačí 21 bitů (jak pro kódovou mapu unicode, tak pro ekvivalentní čínskou mapu GB 18030).

Jazyky, které přímo nevyužívají unicode (např. Php) mohou pracovat s unicode zakódovaným po bajtech pomocí kódování utf-8. Další podrobnosti viz článek znaková sada.

Neordinální datové typy

U neordinálních datových typů není jednoznačně určen předchůdce a následovník každé hodnoty.

Reálné číslo

nebo také číslo s plovoucí řádovou čárkou (double, float, real) – 3.14, 0.5 (podle anglosaské konvence zapsané s desetinnou tečkou). V počítači bývá většinou implementováno ve dvojkové soustavě jako mantisa * 2exponent, kde mantisa a exponent jsou celá čísla. Je třeba si uvědomit, že mnohá desetinná čísla nelze v tomto formátu přesně reprezentovat. Např. číslo 0,1 má periodický dvojkový zápis (0,0001100)2. Důsledkem je, že se „reálná“ čísla v počítači mohou chovat jinak, než bychom intuitivně čekali.

Zásadní výhodou reálných čísel je, že mohou ve stejné velikosti paměti reprezentovat mnohem větší rozsah hodnot, než celé číslo. Např. 32bitové celé číslo má rozsah řádově +-109 s krokem 1, zatímco 32bitové reálné číslo má typický rozsah řádově +-10+-38 s 6 až 7 platnými číslicemi. Cenou za vyšší dynamický rozsah je horší přesnost u velkých čísel (která nám často nevadí) a vyšší nároky na architekturu procesoru. Reálná čísla v počítači mohou také nabývat speciálních hodnot, které reprezentují neplatné výsledky.

Prázdný datový typ

  • void – jedná se o specialitu jazyka C. Tento typ nenabývá žádných hodnot, může sloužit např. pro deklaraci funkce, která nemá návratovou hodnotu, nebo označuje data nespecifikovaného typu (ukazatel typu void v jazyce C).

V některých jazycích existuje rovněž „prázdná hodnota“ ošetřující neplatný výsledek – null nebo nil, která je vlastně současně zvláštním datovým typem. Výsledkem většiny operací s konstantou nil je opět nil, takže chování programu je deterministické.

Konstanta NULL vyskytující se v C-jazyce bohužel tento význam nemá, při jejím nevhodném zpracování může snadno dojít k nepředvídatelnému chování programu, které při nedokonalém operačním systému může vést až ke zhroucení počítače.

Složené datové typy

Složené datové typy obsahují jeden nebo více prvků. Můžeme říci, že jsou homogenní, když se skládají z prvků stejného typu.

  • pole (array) – [21, -5, 11], může být vícerozměrné (např. dvourozměrné označujeme jako matici),
  • textový řetězec (string) – „Ahoj“, “ „, „loopback 127.0.0.1“,

Jednotlivé prvky pole jsou dostupné pod číslem, které určuje jejich pořadí (tzv. index). Nejčastější je konvence používaná v C-jazyce, kde indexy začínají číslem 0. Pro výše uvedené příklady: pole[1] = -5, retezec[0] = ‚A‘ (resp. ‚ ‚ a ‚l‘), obdobně pro výčtový typ.

V některých jazycích musí prvky pole obsahovat pouze položky stejného typu, jiné jazyky to nevyžadují. Hlavní výhodou pole je možnost okamžitého přístupu ke kterékoli jeho položce. Rychlý přístup umožňuje např. implementaci rychlých algoritmů pro Řadicí algoritmus položek. Čas potřebný ke vkládání nebo odebírání položek lze zmenšit použitím pomocného pole, ve kterém jsou uloženy pouze indexy položek, zvláště pokud jednotlivé položky zabírají větší množství paměti.

  • seznam (list) – obdoba pole, [‚a‘, ‚b‘, 9, „řetězec“]. Na rozdíl od pole nelze seznam přímo adresovat pomocí indexu. Např. v jazyce Lisp, který je na seznamech založený, jsou základními operacemi nad seznamem získání prvního prvku a zbytku seznamu (což je opět seznam). Seznam je tedy možné procházet pouze postupně, od začátku do konce, sekvenčně. Existují i obousměrné spojové seznamy, které je možné procházet od začátku i od konce, avšak omezení přístupu je výrazné. Výhodou seznamů proti polím je, že je možné snadno přidávat nebo odebírat i prvky nacházející se uprostřed seznamu. U pole to často znamená nutnost překopírovat velký počet prvků. Avšak ve srovnání s polem většinou převažují nevýhody dané složitější vnitřní reprezentací.
Datový typ (Pascal / C) Velikost v paměti Rozsah
Celočíselné typy
Boolean / — 1 bit (ačkoliv obvykle uložen jako 1 bajt) 0 až 1
Byte / unsigned char 8 bitů (= 1 bajt) 0 až 255
Word / unsigned short int 2 bajty 0 až 65 535
Long Word / unsigned long int 4 bajty 0 až 4 294 967 295
Integer / long int 4 bajty –2 147 483 648 až 2 147 483 647
Double Integer / long long int 8 bajtů –9 223 372 036 854 775 808 až 9 223 372 036 854 775 807
Typy s plovoucí čárkou
Real / float 4 bajty 1E-37 až 1E+37 (6 desetinných míst)
Double Float / double 8 bajtů 1E-307 až 1E+308 (15 desetinných míst)

Operace, operátor, priorita operátorů, přetypování, velikost typu, základní typy a jejich bitové vyjádření (celočíselný a znakový typ)

Operátor je v programovacích jazycích symbol používaný ve výrazech, který předepisuje provedení nějaké (nejčastěji matematické nebo logické) operace s hodnotami (operandy) zapsanými ve svém okolí. Výsledkem použití operátoru je podobně jako u funkcehodnota; způsob použití operátorů se však zpravidla od funkcí liší syntakticky i sémanticky.

K nejrozšířenějším operátorům dostupným ve většině programovacích jazyků patří binární operátory +, -, *, / pro sčítání, odčítání, násobení a dělení čísel.

Operátory často tvoří zvláštní lexikální kategorii a zapisují se jedním nealfanumerickým znakem, případně řetězcem nealfanumerických znaků. V některých jazycích se mohou operátory zapisovat jako identifikátory nebo se může jednat o klíčová slova.

Aritmetické operace

Většina programovacích jazyků používá binární operátory +, -, *, / pro sčítání, odčítání, násobení a dělení čísel. Pro celočíselné dělení se zbytkem se v některých jazycích používá zvláštní operátor div, jiné jazyky použijí celočíselné dělení pokud jsou oba operandy celočíselné. Pro zbytek po celočíselném dělení se nejčastěji používá binární infixový operátor % nebo mod. Některé jazyky mají operátor pro umocňování, který má většinou asociativitu zprava.

Relační operace

Jako relační jsou zpravidla označovány operátory, které vracejí logickou (pravdivostní) hodnotu. Typicky mezi ně patří operátory pro test na rovnost a nerovnost zapisované = nebo == (je rovno), příp. <>, !=, =/= (není rovno), < <=, >, >= pro porovnávání čísel nebo lexikografické porovnávání řetězců. Některé jazyky používají operátory, jejichž jména jsou alfanumerické řetězce: obvykle eq pro je rovno, ne nebo neq pro není rovno, lt pro menší než, le nebo lte pro menší nebo rovno, genebo gte pro větší nebo rovno. Pro odlišení od identifikátorů se operátory v některých jazycích píší mezi tečky (.LT.).

Některé jazyky mají pro porovnání dvou hodnot operátory <=> a/nebo cmp, které vracejí hodnoty -1, 0 nebo 1 pro menší než, rovno, větší než.

Logické operace

Většina jazyků má operátory pro logické operace: unární not, ! nebo jiné pro logickou negaci and, & nebo && pro logickou konjunkci (a zároveň), or, | nebo || pro logickou disjunkci (nebo), případně xor nebo ^ pro non-ekvivalenci (buď-anebo).

Při vyhodnocování binárních logických operátorů pro konjunkci a disjunkci je důležité, zda provádějí zkrácené (jazyk C) nebo úplné (standardní Pascal) vyhodnocení. Při zkráceném vyhodnocování se přeskakuje vyhodnocování podvýrazů, které nemohou ovlivnit logickou hodnotu celého výrazu; přeskakuje se vyhodnocování druhého operandu v konjunkci, pokud první operand je nepravdivý (výsledek konjunkce bude nepravdivý bez ohledu na hodnotu druhého operandu); podobně se přeskakuje vyhodnocování druhého operandu v disjunkci, pokud první operand je pravdivý (výsledek disjunkce bude pravdivý bez ohledu na hodnotu druhého operandu). Protože se často jedná o konstrukce, ve kterých by vyhodnocování druhého operandu skončilo chybou, jeví se zkrácené vyhodnocování jako užitečnější.

Podmíněný výraz

Podmíněný výraz je konstrukce, která obsahuje logickou podmínku a další dva výrazy; podle logické hodnoty podmínky se použije buď jeden nebo druhý z výrazů.

V některých jazycích se podmíněný výraz zapisuje podobně jako podmíněný příkaz, tj. pomocí klíčových slov if, then, else, jazyk C zavedl pro podmíněný výraz konstrukci podmínka ? výraz1 : výraz2, která byla převzata do mnoha dalších jazyků.

Operátor přiřazení

Část jazyků považuje přiřazení za operátor, takže lze přiřazení použít v dalším výrazu.

Statická a dynamická alokace paměti

Dynamická alokace paměti je v informatice označení pro rezervaci části operační paměti za běhu počítačového programu. Operační paměť spravuje v počítači část jádra nazývaná správce paměti (anglicky memory manager). Většina operačních systémů umožňuje paměť za běhu programu nejen alokovat (tj. proces paměť od systému získá pro svoji potřebu), ale i vracet (proces vrací nepotřebnou paměť systému, aby mohla být později opět přidělena). U dynamické alokace nemusí být při překladu programu známá velikost potřebné části paměti pro ukládaná data (na rozdíl od statické alokace paměti).

Staticky alokovaná paměť je výhodná z hlediska rychlosti přístupu k uloženým datům. V určitých případech je ale nevýhodná z hlediska neefektivnosti manipulace s datovým prostorem. Představme si program, který setřídí zadané řetězce (slova, věty) podle abecedy. Není známo, kolik řetězců bude zadáno ani jejich velikost. Bylo by možné vytvořit pole o takovém počtu a velikosti položek, které s největší pravděpodobností nebude překročeno, například 500 položek o velikosti 128 bytů. Alokovaná paměť je statická, a proto se bude za běhu programu pracovat s celým polem, což zpomalí výpočet a zabere zbytečně mnoho paměťového prostoru. Možnosti, že bude potřeba setřídit 501 položek nebo že položka bude o něco větší, nejsou nijak ošetřeny.

Výhodou dynamicky alokované paměti je možnost kdykoliv uvolnit již zabraný paměťový prostor, což zvyšuje rychlost samotného programu i přes zvýšené datové nároky.

Vytváření dynamických proměnných v paměti je však časově náročnější než u statických, a proto může při neuváženém používání takových struktur docházet ke zpomalení celé aplikace.

Programovací jazyky – programovací jazyky, jejich druhy (kompilované, interpretované – objektové, procedurální), charakteristika, vývoj a srovnání, oblasti použití, kompilace a interpretace

Existuje několik možností kritérií, podle kterých jazyky dělit.

Dle míry abstrakce:

  • vyšší programovací jazyky (většina jazyků)
  • nižší programovací jazyky (např. jazyk symbolických adres, částečně VHDL)

Dle způsobu překladu a spuštění:

  • kompilované programovací jazyky (např. Pascal, C, Java, Cobol)
    • před spuštěním jsou nejprve kompletně přeloženy kompilátorem
    • výsledkem je větší rychlost, ale také větší náročnost na správně zapsaný kód
  • interpretované programovací jazyky (např. BASIC, Perl, Python, shell, Ruby)
    • interpretované jazyky, které se pouze interpretují (z toho důvodu jsou pomalejší – proto většina jazyků má alespoň nějakou jinou možnost, pokud nejsou stejně zpomalované něčím jiným, jako třeba shell)
    • interpretované jazyky, které se překládají, ale pouze do mezikódu, nikoli do strojového kódu počítače (např. Java, Python)
    • interpretované jazyky, které se po spuštění za běhu programu překládají do strojového kódu počítače (např. Java, pokud se použije systém JIT)

Toto členění není absolutní, řada programovacích jazyků existuje v implementaci jak interpretované, tak kompilované (například zmíněná Java). Navíc jsou oba postupy někdy kombinovány, zdrojový kód je nejprve kompilován do mezikódu, který je poté interpretován.

Vyšší programovací jazyky se dále dělí takto:

  • Procedurální (imperativní)
    • Strukturované (např. C, BASIC, Cobol)
    • Objektově orientované (např. Smalltalk, Java)
  • Neprocedurální (deklarativní)
    • Funkcionální (např. Lisp, Haskell)
    • Logické (např. Prolog, Gödel)

Některé programovací jazyky (např. C++, Python, Object Pascal, Rust, Flex) umožňují programátorovi kombinovat různé přístupy. Část řešení může být například vyjádřena zápisem funkcí a procedur (strukturované programování), část řešení může využívat čistěobjektový přístup. Klasickým příkladem jazyka, ve kterém se mezi těmito přístupy nedělá ostrá hranice, je jazyk C++. Podobný pragmatický přístup využívá jazyk Python, který navíc do určité míry podporuje i funkcionální programování. Jako protiklad k nim uveďme velmi rozšířený jazyk Java, kde se i jednoduchá funkce musí vyjádřit formou metody třídy.

Některé programovací jazyky byly vytvořeny především pro výuku programování a algoritmického myšlení. Mezi takové jazyky patří například Logo, Karel, Baltík, Petr; ostatně prvotním důvodem vzniku jazyka Pascal byla také výuka programovaní.

Objektově orientované programování

  • Objekty – jednotlivé prvky modelované reality (jak data, tak související funkčnost) jsou v programu seskupeny do entit, nazývaných objekty. Objekty si pamatují svůj stav a navenek poskytují operace (přístupné jako metody pro volání).
  • Abstrakce – programátor, potažmo program, který vytváří, může abstrahovat od některých detailů práce jednotlivých objektů. Každý objekt pracuje jako černá skříňka, která dokáže provádět určené činnosti a komunikovat s okolím, aniž by vyžadovala znalost způsobu, kterým vnitřně pracuje.
  • Zapouzdření – zaručuje, že objekt nemůže přímo přistupovat k „vnitřnostem“ jiných objektů, což by mohlo vést k nekonzistenci. Každý objekt navenek zpřístupňuje rozhraní, pomocí kterého (a nijak jinak) se s objektem pracuje.
  • Skládání – Objekt může obsahovat jiné objekty.
  • Delegování – Objekt může využívat služeb jiných objektů tak, že je požádá o provedení operace.
  • Dědičnost – objekty jsou organizovány stromovým způsobem, kdy objekty nějakého druhu mohou dědit z jiného druhu objektů, čímž přebírají jejich schopnosti, ke kterým pouze přidávají svoje vlastní rozšíření. Tato myšlenka se obvykle implementuje pomocí rozdělení objektů do tříd, přičemž každý objekt je instancí nějaké třídy. Každá třída pak může dědit od jiné třídy (v některých programovacích jazycích i z několika jiných tříd).
  • Polymorfismus – odkazovaný objekt se chová podle toho, jaké třídy je instancí. Pozná se tak, že několik objektů poskytuje stejné rozhraní, pracuje se s nimi navenek stejným způsobem, ale jejich konkrétní chování se liší podle implementace. U polymorfismu podmíněného dědičností to znamená, že na místo, kde je očekávána instance nějaké třídy, můžeme dosadit i instanci libovolné její podtřídy, neboť rozhraní třídy je podmnožinou rozhraní podtřídy. U polymorfismu nepodmíněného dědičností je dostačující, jestliže se rozhraní (nebo jejich požadované části) u různých tříd shodují, pak jsou vzájemně polymorfní.

Některé z těchto vlastností jsou pro OOP unikátní, jiné (např. abstrakce) jsou běžnou vlastností i jiných vývojových metodik. OOP je někdy označováno jako programátorské paradigma, neboť popisuje nejen způsob vývoje a zápisu programu, ale i způsob, jakým návrhář programu o problému přemýšlí.