7. diel - Polia v jazyku C
V predchádzajúcom cvičení, Riešené úlohy k 6. lekcii Céčka, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V minulej lekcii, Riešené úlohy k 6. lekcii Céčka , sme si ukázali cykly. Dnes si v tutoriálu predstavíme dátovú štruktúru poľa a vyskúšame si, čo všetko vie.
Poľa
Predstavte si, že si chcete uložiť nejaké údaje o viac prvkoch. Napr.
chcete v pamäti uchovávať 10 čísel, políčka šachovnice
alebo mena 50ti užívateľov. Asi vám dôjde, že v programovaní
bude nejaká lepšia cesta, než začať búšiť premenné
uzivatel1, uzivatel2... až uzivatel50.
Nehľadiac na to, že ich môže byť potrebné 1000. A ako by sa v tom potom
hľadalo? Brrr, takze nie 
Ak potrebujeme uchovávať väčšie množstvo premenných rovnakého
typu, tento problém nám rieši poľa. Môžeme si ho predstaviť ako
rad priehradiek, kde v každej máme uložený jeden prvok. Priehradky sú
očíslované tzv. Indexy, prvý má index 0.

(Na obrázku je vidieť pole ôsmich čísiel) Programovacie jazyky sa veľmi líšia v tom, ako s poľom pracujú. V nižších kompilovaných jazykoch, ktorým je práve aj jazyk C, sa musí špecifikovať pevná veľkosť poľa v zdrojovom kóde, ktorá už za behu nemožno meniť. Do poľa teda nie je možné pridávať ďalšie priehradky a preto musíme myslieť na to, aby nám vždy stačilo. Jazyk C nám ďalej umožňuje vytvoriť tzv. Dynamicky alokovanej poľa alebo využívať napr. Spojových zoznamov, aby sme tento problém obišli. Jedná sa však o pomerne pokročilú problematiku, ku ktorej sa dostaneme neskôr. Naopak niektoré interpretované jazyky umožňujú nielen deklarovať pole s ľubovoľnou veľkosťou, ale dokonca túto veľkosť na už existujúcom poli meniť (napr. PHP).
Pre hromadnú manipuláciu s prvkami poľa sa používajú cykly.
Pole deklarujeme ako bežnú premennú, iba za jej názov uvedieme hranaté zátvorky s počtom prvkov:
int pole[10];
Slovo pole je samozrejme názov našej premennej. Teraz máme v
premennej pole poľa veľkosti desiatich typov int.
Keďže sme polia ešte len založili a operačný systém nám pre neho
pridelil nejakú pamäť, ktorú mohla predtým používať iná aplikácia,
nemôžeme sa spoľahnúť na to, že sú v poli samé nuly. Rovnako dobre v
ňom zatiaľ môžu byť ľubovoľná náhodné čísla.
K prvkom poľa potom pristupujeme opäť cez hranatú zátvorku, poďme na
prvý index (teda index 0) uložiť číslo 1.
int pole[10]; pole[0] = 1;
Plniť poľa takto ručne by bolo príliš pracné, použijeme cyklus a
naplníme si pole číslami od 1 do 10. K naplneniu
použijeme for cyklus:
int pole[10]; int i; for (i = 0; i < 10; i++) { pole[i] = i + 1; }
Pozn .: i + 1 do poľa ukladáme preto, že i
ide od nuly a my chceme do poľa uložiť čísla od 1.
Aby sme pole vypísali, môžeme za predchádzajúci kód pripísať:
{C_CONSOLE}
int pole[10];
int i;
for (i = 0; i < 10; i++)
{
pole[i] = i + 1;
}
for (i = 0; i < 10; i++)
{
printf("%d ", pole[i]);
}
{/C_CONSOLE}
výsledok:
Konzolová aplikácia
1 2 3 4 5 6 7 8 9 10
Pole samozrejme môžeme naplniť ručne a to aj bez toho, aby sme dosadzovali postupne do každého indexu. Použijeme na to zložených zátvoriek a prvky oddeľujeme čiarkou:
int cisla[] = {15, 8, 3, 10, 9, 2, 2};
Všimnite si, že nemusíme udávať veľkosť poľa, prekladač si ju odvodí z počtu prvkov vo výpočte.
Pole často slúži na ukladanie medzivýsledkov, ktoré sa potom ďalej v programe používajú. Keď niečo potrebujeme 10x, tak to nebudeme 10x počítať, ale spočítame to raz a uložíme do poľa, odtiaľ potom výsledok len načítame.
Konštanty
Keďže musíme uviesť veľkosť poľa v zdrojovom kóde a túto veľkosť
zvyčajne používame na niekoľkých miestach, hodilo by sa ju mať niekde
uloženú. Nie je nič horšie, než rozmyslieť si, že chceme pole miesto
15 prvkov veľké len 10 a zabudnúť niekde v dlhom
kóde nejakú pätnástku prepísať, napr. V cykle, ktorý polia vypisuje.
Preto sa veľkosť polí často ukladá do tzv. Konštánt.
Konštanta je hodnota ľubovoľného dátového typu, ktorý sa nemôže
zmeniť. Môžeme ju chápať ako premennú, z ktorej možno iba čítať.
Využíva sa pre prípady, keď chceme definovať v programe nejaké hodnoty,
ktoré sa síce za jeho behu nemení, ale my programátori by sme ich občas
mohli chcieť v kóde zmeniť v rámci nejaké úpravy. Konstanty definujeme
pomocou príkazu #define, ich názvy je zvykom zapisovať
VELKYMI_PISMENY. Hodnotu uvedieme iba za medzeru alebo tabulátor,
nie je tu rovná sa. Definícia uvádzame tesne za objednávok
#include. Uveďme si kompletný zdrojový kód programu vyššie
tak, aby pre veľkosť poľa využíval konštantu:
#include <stdio.h>
#include <stdlib.h>
#define POCET 10
int main(int argc, char** argv) {
// Vytvorenie poľa
int pole[POCET];
// Naplnenie poľa
int i;
for (i = 0; i < POCET; i++)
{
pole[i] = i + 1;
}
// Výpis poľa
for (i = 0; i < POCET; i++)
{
printf("%d ", pole[i]);
}
return (EXIT_SUCCESS);
}
Pozn .: Príkazy začínajúcich # nie sú príkazy
prekladača, ale tzv. Preprocesoru. To je program, ktorý spracováva zdrojový
kód ako prvý a vkladá do neho určitej úseky kódu, aby to mal prekladač
následne jednoduchšie. Preprocesor v našom prípade do súboru s programom
vloží definície funkcií zo systémových knižníc stdio.h a
stdlib.h a ďalej nahradí každý výskyt POCET za
hodnotu 10. Presnejšie je konštanta tzv. Makrom a preprocesor
toho vie ešte oveľa viac. Pre naše účely to však teraz zabudneme.
Medze pole
Pozor! Jazyk C žiadnym spôsobom nestráži, či sa pohybujeme v medziach poľa. Je tomu tak kvôli rýchlosti. Môžeme teda napr. Uložiť dáta na 15. prvok, aj keď ich má pole iba 10. Pole je v pamäti uložené ako blok bajtov a céčko počíta podľa indexu adresu, na ktorú prvok zapíše. Môžeme teda chybne zapísať na príliš vysoký index a do pamäti, ktorá nám nepatrí. Týmto spôsobom si môžeme nabúrať nejaká iná dáta v našej aplikácii, ktorá s poľom vôbec nesúvisí, ale náhodou bola uložená v pamäti za ním. Tieto chyby sa všeobecne veľmi ťažko hľadajú a je dobré snažiť sa im vyvarovať.
Polia s dĺžkou, ktorú určíme až za behu aplikácie
Standard C99 umožňuje deklarovať tzv. VLA (Variable Length Array), polia s dĺžkou, ktorú zadáme až za behu programu. Zafunguje teda aj takýto kód:
int velikost; printf("Zadaj veľkosť poľa a ja ho vytvorím: "); scanf("%d", &velikost); int pole[velikost];
Hoci je to práve platiaci štandard, je možné, že kód nebude fungovať na všetkých prekladačom. Podobné funkcionality možno docieliť aj pomocou dynamických polí, s ktorými sa zoznámime v nasledujúcej sekcii seriálu. Stále platí, že akonáhle polia raz vytvoríme, nemôžeme jeho veľkosť zmeniť.
Veľkosť poľa
Pole, ktoré sme vytvorili, je tzv. Staticky alokované. U tohto typu poľa môžeme získať jeho veľkosť aj týmto spôsobom:
{C_CONSOLE}
int pole[10]; // Založíme si pole veľkosti 10
printf("Veľkosť poľa je: %d", sizeof(pole)/sizeof(int));
{/C_CONSOLE}
Jednoducho zistíme koľko bajtov zaberá celé pole a toto číslo vydelíme veľkosťou dátového typu jednej položky. Tým získame počet položiek.
výsledok:
Konzolová aplikácia
Veľkosť poľa je: 10
U dynamických polí a textových reťazcov tento spôsob použiť nedá, skôr si na neho nezvykajte.
Zoradenie polia
Veľmi často sa nám stane, že pole prvkov potrebujeme zoradiť, napr.
Budeme chcieť nájsť najnižšie / najvyšší plat, počet bodov, náklady,
počet kusov a podobne. Hoci je tento typ úlohy s obľubou zadávaný
študentom ako algoritmus na precvičenie, štandardná knižnica jazyka C
poskytuje na tento účel funkciu qsort(). Jej volanie je trochu
zložitejšie, takže si ho popíšeme skôr intuitívne. Vôbec nič nám však
nebráni, aby sme funkciu používali už teraz, detailne kód pochopíme až
ďalej v seriáli.
#include <stdio.h>
#include <stdlib.h>
int porovnej(const void * a, const void * b)
{
return (*(int*)a - *(int*)b);
}
int main(int argc, char** argv)
{
int cisla[] = {15, 8, 3, 10, 9, 2, 2};
qsort(cisla, 7, sizeof(int), porovnej);
int i;
for (i = 0; i < 7; i++)
{
printf("%d ", cisla[i]);
}
return (EXIT_SUCCESS);
}
Okrem funkcie main() tu máme navyše porovnávaciu funkciu,
ktorá definuje ako porovnať 2 prvky v poli. Funkcia qsort()
totiž vnútorne funguje tak, že porovnáva vždy 2 prvky medzi sebou a vďaka
tomu vo finále poľa zoradí. Syntax hviezdičiek si nemusíte všímať, ide o
to, že funkcia vracia výraz a - b, ktorý je kladný ak je
a > b, nulový ak a = b a záporný ak
a < b. Podľa tejto hodnoty qsort() potom
porovnáva. Ak by sme chceli pole radiť naopak (zostupne), zadali by sme tu
b - a.
Samotné vytvorenie poľa by malo byť jasné. Pri volaní funkcie
qsort() je potrebné uviesť okrem pole, ktoré má zoradiť, tiež
počet jeho prvkov, veľkosť jedného prvku v bajtoch a práve porovnávaciu
funkciu. Odteraz sú prvky v poli zoradené a my si ich pre kontrolu vypíšeme
pomocou cyklu for.
výsledok:
Konzolová aplikácia
2 2 3 8 9 10 15
To by pre dnešok stačilo, môžete si s poľom hrať. V budúcej lekcii,
Riešené úlohy k 7. lekcii Céčka , si konečne uvedieme ako pracovať s textovými reťazcami a naučíme
sa ukladať text do premenných 
V nasledujúcom cvičení, Riešené úlohy k 7. lekcii Céčka, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.

David sa informačné technológie naučil na