Pascal – #7 Pole

Dnes si vysvětlíme problematiku polí, v programovacím jazyce Pascal. Pole se používají v každém jazyce a je to další z nezbytných součástí programování. Řekněme si tedy co to je. Jedná se o setříděnou množinu prvků stejného datového typu. Teď tedy co si pod touto definicí představit. Do pole můžeme přehledně ukládat data o stejném datovém typu. A proč přehledně? Protože každá informace uložená v poli má svůj index. Index chápej jako určitou ordinální hodnotu většinou celé číslo pod, kterým k datům přistupujeme

Index Hodnoty
1 28
2 59
3 7
4 88
5 22

 

Takhle si lze představit dvojrozměrné pole. Jako tabulku, kde první sloupec jsou indexy a v druhém jsou uložená libovolná data.

Techniku polí využijeme například v příkladu, kdy bychom chtěli uložit 10 čísel. Až do dnešní lekce bychom museli deklarovat deset proměnných a čísla ukládat jednotlivě. Teď však můžeme uložit 10 čísel do jednoho pole s velikosti 10. Z toho vyplývá, že i Indexů bude 10. Úplně laicky řečeno, pole v sobě  ukrývá 10 proměnných.

Obecná syntaxe: deklarace pole

Var pole_cisel : array [1..10] of byte;

Vysvětlení kodu. Tady se jedná o deklaraci, jak naznačuje příkaz Var, za ním následuje název, to zatím není nic nového za dvojtečkou, však uvádíme, že se jedná o pole (klíčové slovo array) hned za tímto musíme uvést velikost, chcete-li počet indexu, který je uveden intervalem. Většinou se udává od 1 do námi požadované velikosti, jako poslední dáme programu vědět, jaká data bude do pole ukládat, v tomto případě of byte.

Obecná syntaxe: uložení

Pole_cisel[1]:=28;
Pole_cisel[2]:=59;

Je třeba si uvědomit, že jakmile chceme pracovat s polem, musíme vždy uvést index. Asi lépe si to představíme, pokud budeme uvažovat pole jako deset proměnných v jedné a ve chvíli kdy chceme cokoliv ukládat nebo číst musíme si „vytáhnout“ tu jednu proměnnou, se kterou chceme pracovat, pomoci indexu. Zde vidíme ukázku uložení čísla do pole. Indexy se píšou v hranatých závorkách. Jakmile uvedeme index, stává se z pole svým způsobem samostatná proměnná, se kterou pracujeme tak, jak jsme již zvyklí.

Obecná syntaxe: vypsání prvku

Writeln(pole_cisel[1]);

Pojďme si ukázat praktický příklad zápisu do pole pomocí cyklu. Příklad bude znít: Zapište do pole 10 čísel, program se následně zeptá, poté uživatel zadá index od 1-10 a vypíše se příslušné číslo, které je pod tímto indexem uložené v poli.

program pole1;
uses crt;
var pole_cisel : array [1..10] of byte;
var i : byte;
var pozice: byte;
begin
      clrscr;
      writeln('zadej 10 čísel');
      for i:=1 to 10 do
      begin
            readln(pole_cisel[i]);
      end;
      writeln('zadej index který chces z pole vypsat');
      readln(pozice);
      writeln(pole_cisel[pozice]);
      repeat until keypressed;
end.

Vysvětlení kódu

zde je třeba si uvědomit, že index pole muže být reprezentován proměnnou stejně tak dobře jako konstantou (číslem), tak jak jsme si to ukazovali ze začátku lekce. V našem případě uvádíme na místě indexu proměnnou i, která v tomto příkladu zastává také funkci počítadla cyklu. Z logiky věci tedy plyne následující. Víme, že počítadlo se při každém průchodu navýší o hodnotu 1. Z toho vyplývá, že při prvním průchodu cyklu bude námi popisovaný řádek vypadat takto:

Program narazí na příkaz readln a ví, že bude načítat data od uživatele, jako parametr požaduje, kam je bude načítat, zde jsme mu nabídli pole s indexem i, který při prvním průchodu má hodnotu 1. Takže na první pozici se zapíšou vstupní data a program pokračuje dál. Skočí na začátek cyklu, navýší počítadlo čili proměnnou i o hodnotu jedna a pokračuje dál vykonávat příkazy, zase narazí na readln a bude požadovat místo kam data uloží, zde se mu nabídne zase pole ale s indexem i ale je důležité si uvědomit, že v této chvíli je již index reprezentován číslem 2. Pokud pořád přemýšlíme o poli jako o 10 proměnných najednou tak si uvědomíme, že nyní již požadujeme v pořadí druhou proměnnou a do ní ukládáme.

Tento příklad je možná trošičku složitější na pochopení nicméně v podstatě se jedná o využití dvou věcí. Za prvé, možnost index reprezentovat proměnnou. Za druhé, využití počítadla do role indexu (zda si nejste jistí funkci počítadla, přečtěte si lekci 5 tam je to probíráno). Pokud si uvědomíme tyto dvě věci samostatně, neměl by být problém představit si to v příkladu.

Po této lekci byste měli být schopni odpovědět na tyto otázky:

  1. Jak vypadá pole, či jak je možné si pole představit
  2. Deklarace polí
  3. Jak přistupujeme (pracujeme) s jednotlivými záznamy v poli
  4. Co je to index, k čemu slouží a čím může být reprezentován

Shrnutí:

Při práci s poli je důležité uvědomit si, s jakým indexem momentálně program pracuje. I přestože v této lekci jsme pracovali s poměrně malým polem velikosti 10, je důležité mít na paměti, že můžeme použít i mnohem větších polí. Nejčastější chyby pak bývají právě s deklarací příliš malého rozsahu polí a program poté může pracovat nestandardně, proto se všeobecně doporučuje deklarovat pole s jistou rezervou.

Víc už si v této lekci neukážeme, příště se podíváme na cykly ukončené podmínkami. Pokud Vám v této lekci nebylo něco jasného, ptejte se v komentářích.

#5 Pole a ukazatel

V dnešním článku se podíváme na velice důležitou část v céčku, ukazatel nebo také pointer. Jak ukazatel funguje, si ukážeme hned na několika příkladech. S ukazateli se budeme potýkat i v dalších lekcích, takže se pokusím co nejlépe vysvětlit jak s nimi pracovat. V druhé části si ukážeme využití pole.

Ukazatel

Ukazatele uchovávají adresu na nějaké místo v paměti. Při deklaraci proměnné typu ukazatel se specifikuje i datový typ, tento typ je totožný s hodnotou místa paměti, na kterou ukazuje, tzn. že ukazuje na hodnotu určitého datového typu.

Deklarace ukazatele na datový typ:

int* nazev_ukazatele

Operátor reference (&)

Vrací adresu (pozici v paměti) svého parametru, následná hodnota lze přiřadit do ukazatele.

int cislo = 5;
int*pCislo = &cislo;

Konvence o pojmenovávání ukazatelů: Název proměnné typu ukazatel se skládá z písmene p (od slova pointer) a z názvu proměnné (bude začínat velkým písmenem) na kterou ukazuje.

Operátor dereference (*)

Vrací hodnotu na určitém místě paměti, adresa toho místa je uložena v argumentu.

Nyní si ukážeme jak správně vypsat hodnotu ukazatele. Použijeme deklarace, které jsou znázorněny na obrázku.

printf("%d\n", *pCislo); //vypise hodnotu promenne cislo, tedy 5
printf("%d\n", pCislo); //vypise adresu v pameti promenne cislo

Více ukazatelů může ukazovat na stejné místo v paměti. Následující zápis je správný pokud používáme předešlé deklarace.

int* pCislo2 = &cislo;

Pole

Jedná se o skupinu proměnných, které mají stejný datový typ a jsou označený stejným názvem. Pro přístup k jednotlivým prvkům v poli se využívají tzv. indexy, kterými jsou všechny prvky v poli identifikovány. V paměti je pole uloženo souvisle.

Jazyk C nehlídá meze polí, z důvodu rychlosti, proto pokud budete zapisovat mimo pole, obvykle to vede k chybě a program spadne.

Jednorozměrné pole

  • K prvkům pole se přistupuje pomocí operátoru [] (hranaté závorky)
  • Indexy prvků začínají vždy od nuly.

Obecná deklarace jednorozměrného pole:

datovy_typ nazevpole[velikost_pole]; //velikost_pole urcuje pocet prvku v poli.

Pokud bychom chtěli již při deklaraci proměnné inicializovat i jednotlivé prvky pole, použijeme tento zápis:

int array[5] = {8,6,9,-1,25};

Jestli použijeme takto plně inicializované pole, je možné vynechat hodnotu, která určuje velikost pole, velikost se automaticky zjistí z počtu inicializovaných prvků.

Pokud neinicializujeme všechny prvky v poli, ale např. pouze 2, tak se ostatní prvky nastaví na hodnotu 0. Pokud bychom chtěli mít celé pole vynulované, použijeme tento zápis:

int array[5] = {0};

Pro zápis konkrétního prvku v poli použijeme následující zápis, ostatní neinicializované hodnoty se opět nastaví na hodnotu 0.

int array[5] = {[1] = 5, [4] = 10};

Inicializace prvku pole se většinou neprovádí ihned při samotné deklaraci pole, ale později v kódu na základě vstupu ze souboru či z klávesnice. Pro procházení prvku se nejlépe použije cyklus. Aritmetika nad prvcích pole je stejná jako u obycejné proměnné.

int array[10];
for (int i = 0; i < 10; i++)
    array[i] = i; //zapis do pole

for (int i = 0; i < 10; i++)
    printf("%d\n", array[i]); //vypis prvku z pole

Vícerozměrné pole

  • Deklarace je stejná jako u jednorozměrného pole, pouze za názvem pole tolik určení velikosti, kolik chceme rozměru. Velikosti se zapisují za sebou, opět do hranatých závorek.
  • Přístup k prvkům je stejný, opět musíme uvést tolik hodnot v hranatých závorkách, kolik je rozměrů.

Deklarace dvourozměrného pole, jedná se v podstatě o matici prvků:

int array[2][3];
int array2D[2][3];
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        array2D[i][j] = i + j;

for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        printf("%d\n", array2D[i][j]);

Nejčastěji z vícerozměrných polí se používá právě matice. Jednoduší je ale realizovat dvourozměrné pole jako jednorozměrné a o správný zápis do pole řešit později v programu. Deklarace je jednoduchá, stačí provést násobení mezi oběma rozměry. Přístup k prvku je o něco složitější:

array1D[radek * pocet_sloupcu + sloupec];

Převod naší matice 2 x 3 na jednorozměrné pole.

int array1D[2*3];
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        array1D[i * 3 + j] = i + j;

for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        printf("%d\n", array1D[i * 3 + j]);

Pole a ukazatel

Vztah mezi ukazateli a poli je velmi blízky, totiž pole je možno realizovat pomoci ukazatele, tento způsob je rychlejší ale asi o trošku hůř pochopitelný.

    int array[10];
    for (int i = 0; i < 10; i++)
        array[i] = i;

    int* pArray = array; //pArray ukazuje na prvni prvek v poli

    printf("%d\n", *pArray); //vypise prvni prvek
    printf("%d\n", *(pArray + 5));

    pArray++; //posun na prvek nasledujici
    //*pArray++; //spatny posun prvku (warning)
    *pArray = -20; // prirazeni hodnoty do aktualniho prvku
    *(pArray + 3) = -10; // prirazeni hodnoty do aktualniho prvku + 3

    printf("Vypis pole: ");
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", array[i]); //vypis vsech prvku
    }

    pArray++;
    pArray++;
    printf("\n%d\n", pArray - array); //vypise pocet prvku mezi zacatkem pole a aktualnim prvkem

K dnešní lekci to bude vše doufám, že jsem vám dostatečně vysvětlil práci s ukazateli. Příště se podíváme na různé funkce vstupu.