Tak - na začátek bych měl říct, že pole není pole brambor, ale množina
určitého počtu prvků určitého datového typu, ke kterým se dostáváme
indexováním. (index je pořadí prvku od začátku, v c-čku je vždy od
nuly) Hah ! Tak tahle věta byla prkenná jako přejetá parním válcem ! 
V C/C++ jdou definovat 2 typy polí. Ten první je pole statické - to
znamená, že velikost pole bude známá už při překladu, takové pole
nelze zvětšovat. A potom pole dynamické, to jde zvětšovat a měnit
Ještě než se pustíme do polí, ukážu vám jeden operátor :

10.0 Operátor sizeof
    Operátor sizeof slouží ke zjišťování velikosti datových objektů,
    vrací hodnotu typu int v Bajtech :


sizeof(char) je 1    // Char je právě 1 bajt ...
sizeof(int) je 4     // Tady už se to může trochu lišit, někdy to je 2
sizeof(float) je 32  // To je už poměrně přesné číslo ..
sizeof(double) je 64 // .. a tohle ještě víc !
U polí ho budeme potřebovat, protože windows chtějí vědět kolik přesně paměti chceme pro naše pole. 10.1 Statická pole Statická pole jsou pole, jejichž velikost se určí při psaní programu a v jeho průběhu už ji nemůžeme měnit. V C-čku se to dělá takhle :

int pole[10]; // toto je pole deseti prvků typu int
Jako v paskalu :

pole : array[0 .. 9] of integer;
Nebo v basicu :

Dim pole(0 to 9) As Integer;
Pole (stejně jako proměnná) se může nějak inicializovat :

int pole[10] = {5, 8, 12, 5, 4, 6, 58, 0, 72, 1};
Ale někde můžete vidět třeba tohle :

int pole[] = {5, 8, 12, 5, 4, 6, 58, 0, 72, 1};
To není chyba, počet prvků pole už kompilátor doplní sám ... Do takového pole se přistupuje takhle :

pole[0] = 10;
pole[9] = 5;
pole[3] = 1;

for(i = 0; i < 10; i ++)
    pole[i] = 0; // Tento cyklus vynuluje celé pole
Ale ...

pole[10] = 8;
.. je chyba, protože na pole se v C/C++ odvolává indexy od 0 do velikosti pole - 1, tyto pravidla nelze měnit, jako třeba v paskalu. Pozor ! Pokud uděláte chybu, jako překročení velikosti pole, při kompilaci to 'projde' ... Také lze definovat pole o dvou (více) rozměrech :

int pole[3][3]; // pole o devíti prvcích
Takové pole by se inicializovalo takhle :

int pole[][] = {{5, 8, 4}, {7, 1, 0}, {9, 2, 6}};
// stejně, jako předtím devět prvků, kompilátor si rozměry doplní sám.
Ty skupinky čísel, co jsou po třech v závorce tvoří řádky. Tudíž by šlo napsat :

int pole[3][3];

pole[0][0] = 5;
pole[1][0] = 8;
pole[2][0] = 4;
pole[0][1] = 7;
pole[1][1] = 1;
pole[2][1] = 0;
pole[0][2] = 9;
pole[1][2] = 2;
pole[2][2] = 6;
// stejnej zápis jako minule, jen stokrát delší ;-)
Do takového pole se přistupuje stejně, jako do normálního :

pole[2][1] = 1;

for(i = 0; i < 3; i ++)
    for(j = 0; j < 3; j ++)
        pole[i][j] = 0; // vynuluje celé pole

pole[3][0] = 5; // Chyba, překročili jste hranice pole
// Ale u takové chyby (v prvním sloupci) se většinou
// přepíše jen další záznam pole, ale ...

pole[3][3] = 5; // Už sahá někam do paměti, což může
// způsobit pád programu, nebo i Windows (fúj)
Pole nemusí být jen int, ale cokoli jiného ...

float pole_floutu[] = {3.1415926, 1.1569847, 0.0000001};
char pole_znaku[] = {'A', 'h', 'o', 'j', ' ', '.', '.', '.' ,0};
// Ta nula je tam velice důležitá, ale o tom až dál ... ale ještě
// je tu jeden pohodlnější způsob :

char druhy_pole_znaku[] = "Ahoj ...";
// Sem už se nula dát nemusí, kompilátor si ji doplní sám.
// Obě dvě pole se tedy doplní samy.
Kopírování polí se nesmí dělat takto :

pole_a = pole_b;
Ale takto :

int i;

for(i = 0; i < velikost_pole; i ++)
    pole_a[i] = pole_b[i];
A nebo pro pole, ukončená nulou :

int i;

while(pole_a[i] = pole_b[i ++]); // wau !
Velikost pole (jen statického) se zjistí takto :

int pole[15], velikost;

velikost = sizeof(pole) / sizeof(int); // velikost bude 15
Tady nám pomáhá operátor sizeof, který umí určit celkovou velikost statického pole. No a vydělením velikostí jednoho prvku logicky získáme počet prvků. Takové pole by se vytisklo :

printf(pole_znaku); // funguje jen pro pole char, ukončené tou nulou
Nebo :

printf("Toto je moje prvni pole znaku : \n%s\n"
    "A toto je moje druhy pole znaku : \n%s\n",
    pole_znaku, druhy_pole_znaku);
Výstup bude : Toto je moje prvni pole znaku : Ahoj ... Toto je moje druhy pole znaku : Ahoj ..., A teď ještě čtení z klávesnice :

scanf("%s", pole_znaku);
Jen je potřeba pamatovat na to, že máte omezenou velikost pole ... 10.2 Pointery Pointery jsou jedna šikovná věc, která v C-čku velice pomáhá. Pointer je vlastně ukazatel na nějakou adresu do paměti, může ukazovat na nějaké číslo, znak, nebo jiný pointer. Deklaruje se takto :

int *poin;
Zapisuje se takto :

*poin = 10; // Na adrese poin bylo zapsáno číslo 10
poin[0] = 10; // ten samý zápis, jenže jinak
Teď pointer ukazuje někam do paměti, takže není příliš bezpečné do něj zapisovat. Adresa se mu přidělí takto :

point = 0x70; // Kdo by zapomněl, 0x70 je hexadecimální číslo
To však také není ono, protože nevíme, co na adrese 0x70 je. Adresu proměnné ukradneme takhle :

float *f, cislo;

cislo = 5; // cislo je 5
f = &cislo; // do f byla uložena adresa proměnné cislo
*f = 0; // cislo je 0 ! Není to skvělé ?
f[0] = 0; // ten samý zápis, ale takhle !
To bylo přidělení adresy, adresu může přidělit ještě systém, ale o tom potom. Teď třeba ještě důležitá věc - adresu můžeme získat jen z l-hodnoty, zápis f = &(cislo + 5) nebude fungovat ! Ještě snad pár slov pro optimalizující jedince : Pointery jsou malé (4 bajty), a tak když máte funkci kde předáváte nějaký monstrózní datový typ, je lepší použít pointer. Potom ošidíte program při kopírování parametrů a tím pádem se funkce bude volat rychleji. Potom se pointery používají v případech, kdy je potřeba u funkce vrátit víc než jeden parametr. Je to něco jako var u parametrů funkce v paskalu. Někdo, kdo zná C++ by použil spíš odkaz (což je v podstatě taky pointer, je to pojem zaváděný s C++) ale o tom až u C ++. 10.3 Dynamická pole Teď přišla ta posvátná chvíle, kdy se naučíte používat jednu z nejsilnějších zbraní C-čka. A taky tu část kde se nadělá nejvíc chyb ;-) Tato zbraň je definovaná v modulu malloc.h :

#include <malloc.h>
Zde jsou funkce pro tzv. alokaci paměti. Zde je 1. z nich. Funkce malloc Tahle funkce vám vrátí pointer na tzv. alokovanou paměť o vámi zadané velikosti. Nejprve malý příklad :

float *f;

f = (float*) malloc(sizeof(float));
// do f teď můžeme s klidem zapisovat, ale ...

Lepší alternativa :

if((f = (float*) malloc(sizeof(float))) == NULL){
    printf("Malo pameti !");
    return 0;
} // Funkce malloc totiž v případě neúspěchu vrátí
  // makro NULL (NULL = 0x00000000)
To (float*) tam musí být, protože malloc vrací pointer na typ void (pokud budete chtít pointer na int, musíte psát (int*)). Taky to Do takto získané paměti můžete jak už sem řekl klidně zapisovat : *f = 3.1415926; Pozor ! Taková alokace zabere kousek paměti, takže je dobré mít na paměti, že musíte vždy kontrolovat, zda se alokace povedla, ale ještě důležitější je, paměť uvolňovat, protože jinak bude zpomalovat systém až do nového startu systému |-) Pozor ! I když je sizeof(char) 1, nezanedbávejte to a násobte vesele počet znaků velikostí znaku. Za chvíli tu máme 128-mi bitové (hlavní) procesory, mohlo by se to změnit ! Stejné pravidlo platí i pro int, long atd. Výjimkou jsou typy __int8, __int16 a __int32, které ovšem nepodporuje aždý překladač. Funkce free Tato funkce uvolní dříve alokovanou paměť : Pozor ! Tohle nesmíte použít na statické pole !

free((void*)f);
Pomocí těchto dvou funkcí už jste schopni pracovat s poli :

int *pole_intu;

if((pole_intu = (int*) malloc(10 *sizeof(int))) == NULL)
    return 0;

// Teď můžete pracovat s polem, je třeba dbát na hranice polí a
// na to, že v poli jsou náhodné hodnoty, je třeba ho nulovat !
int i;

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

*pole_intu[0] = 10; // Pole na pozici 0 bude mít hodnotu 10
*(pole_intu + 0) = 20; // Pole na pozici 0 bude mít hodnotu 20 
*pole_intu[1] = 100; // Pole na pozici 1 bude mít hodnotu 100 
pole_intu ++; // Pole se posune o 1 prvek dopředu (ztratí se adresa 0.) 
*pole_intu[1] = 200; // Pole na pozici 2 bude mít hodnotu 200
pole_intu --; // Pole se posune 0 1 prvek zpět (vše je zpátky)
*pole_intu[1] = 0; // Pole na pozici 1 bude mít hodnotu 0

// Při takovýchto hrátkách je třeba dbát na to, aby jsme z pole
// nevyjeli ... Pokud už ste si s polem dost vyhráli, musíme ho
// uvolnit pro další programy ...

free((void*)pole);
// pro free musíme mít přesně stejný pointer, jako vyplivne malloc() !
// takže pozor na hrátky s ++ a -- ! (ono to potom háže chyby)
Při práci s dynamickými poli si musíme uvědomit : Někomu by se to mohlo zdát, jako dostatečné, ale vemte si třeba takový textový editor, třeba Notepad. Otevřete soubor, naalokujete si pole znaků, ale co, když uživatel připíše nějaké znaky ? Někdo by to rychle vyřešil rezervou třeba na 64 KB textu, ale to můžou jen Masochisti (a Gratz) :-) Normální zdraví lidé, jako ostatní musí znát ještě jednu funkci pro práci s pamětí. Funkce realloc Funkce realloc slouží k zvětšení pole o určitý počet prvků, její syntaxe je zhruba :

char *pole_znaku;
int pocznaku = 0;

// Zde naalokujeme nějakou paměť, pěkně si pohrajeme ...
// ... a najednou už nám pole nestačí, zvětšíme ho o 10 znaků :

if((pole_znaku = (char*) realloc(pocznaku, (pocznaku + 10) * sizeof(char))) == NULL){
    printf("Nedostatek pameti RAM ! Ukonci nekolik programu a zkus to znova.");
    return 0;
} // I u realloc může dojít paměť ...

pocznaku += 10;
// Musíme si zapamatovat novou velikost.
Pozor ! Nesmíte zapomenout, že pro realloc musí být už paměť naalokovaná ! Pokud ale zrovna nechcete alokovat, tak :

x = (typ*) malloc(0);
Tento příkaz přiřadí pointeru adresu, takže s klidem můžete použít free, tudíž může ho použít realloc ... Tím bychom měli probrané dynamické jednorozměrné pole, můžeme se pustit do polí vícerozměrných. 10.4 Vícerozměrná dynamická pole Je několik možností, jak udělat pole tohoto typu. Asi nejjednodušší, nejpoužívanější a nejlépe optimalizovatelné je udělat jednorozměrné pole o velikosti rozmer_x * rozmer_y * rozmer_z ... * rozmer_n a indexem, který se prostě přepočítává. Pokud budou rozměry mocniny dvou, dá se to ještě urychlit, ale o tom až u logických operací. 1. - pointer na pointer Tato možnost je logická, ale asi nejpomalejší. Má však i své výhody, můžete s ní dělat pole různých tvarů, když jednotlivé prvky nepotřebujete. Dejme tomu, že chceme mít pro začátek pole integerů 10 x 10.

int **pole, i;

pole = (int**) malloc(10 * sizeof(int*));
// Teď máme naalokovanou první dimenzi pole ...
for(i = 0; i < 10; i ++)
    pole[i] = (int*) malloc(10 * sizeof(int));
// A teď už máme naalokované i řádky ...
// Jak jsem psal o polích různých tvarů, tak to se dělá
// právě tady změnou délky řádků ...
Na pole se teď můžeme v klidu odkazovat :

pole[2][5] = 1;
Musíme stále pamatovat na meze polí. Pokud použijeme příkaz

pole ++;
Posuneme se o 1 číslo v 0. sloupci. Pokud takhle přejdeme všech 10 čísel, dostaneme se do dalšího sloupce, a pokud přejdeme všech 10 sloupců, tak spadnou Windows. Pokud jsme si dost pohráli, pole tradičně uvolníme :

for(i = 0; i < 10; i ++)
    free((void*)pole[i]);
// uvolnili sme řádky
free((void*)pole);
// Uvolnili jsme sloupce
2. - pole o 1 pevném rozměru Tradiční příklad.. Jen je třeba upozornit na to že teď bude prvním rozměrem pole číslo v hranatých závorkách (10) a druhým to, co je v malloc (8). Na to musíte pamatovat (teda pokud neděláte čtvercové pole) !

int *pole[10], pocet = 0;

if((pole = (int*) malloc(8 * sizeof(int))) == NULL) {
    printf("Nedostatek pameti RAM !\n");
    return;
}

// Teď si můžeme hrát, realokovat, už to snad ani nebudu psát ...
// A tradičně vám ještě řeknu, jak to uvolnit (Masochisti nemusí)

free((void*)pole);
A ještě jedna drobnost s poli znaků :

char jmeno[] = "Pepa z depa";
Toto pole je Read/Write

char *jmeno = "Pepa z depa";
Toto pole je Read only. Parametry funkce main Možná si říkáte, že tohle do polí přece vůbec nepatří, ale ... Parametry předávané funkci main jsou různé zprávy z příkazového řádku. U funkce main můžete mít dva parametry (počet, hodnota argumentů). Jmenují se argc a argv, pojmenovat je jinak je ostuda.

int main(int argc, char *argv[])
{
    int i;
    printf("Program byl spuštěn s %d parametry \n", argc);
    for(i = 0; i < argc; i ++)
        printf("%s \n", argv[i]);
    return 1;
}
Pokud tento program zkompilujete a spustíte pomocí příkazového řádku, dostanete ohromující výsledky, ale : Jednotlivé parametry v sobě nesmí mít mezery - pokud se vyskytne : program.exe /a /p ahoj, pepo Tak argv bude : /a /p ahoj, pepo Toho se lze zbavit : program.exe /a /p "ahoj, pepo" Pak argv bude : /a /p ahoj, pepo Cvičení : 1) - Napište program, který čte čísla a postupně je ukládá do pole. (musí se postupně realokovat) Potom když uživatel zadá 999 (to už v poli nebude) program potom prohodí pořadí čísel a pole vytiskne. 2) - Napište program, který v poli seřadí čísla v poli (zadává se jako minule) vzestupně. Na to jsou metody : 3) - Napište program, který vytiskne počet a hodnotu parametrů se kterými je volán. Zkuste různé kombinace... (z příkazové řádky) 4) - Napište funkci Swap(int *a, int *b), která prohodí hodnoty integerů a a b. (Volat se bude Swap(&a, &b);) Nesmutnite když vám něco nefunguje a klidně napište. Stává se že prosedíte dny nad programem, který padá, a padá, a padá. Tak taky občas vylezte ven a provětrejte svoje mozkový závity třeba s holkou (a holky třeba s klukama :-)) -tHE SWINe-
Zpátky