9. díl - Pole v C++

C a C++ C++ Základní konstrukce C++ Pole v C++

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Minule jsme si v našem C++ seriálu ukázali ošetření uživatelských vstupů. Dnes si představíme datovou strukturu pole a vyzkoušíme si, co všechno umí.

Pole

Představte si, že si chcete uložit nějaké údaje o více prvcích. Např. chcete v paměti uchovávat 10 čísel, políčka šachovnice nebo jména 50ti uživatelů. Asi vám dojde, že v programování bude nějaká lepší cesta, než začít "bušit" proměnné s názvy uzivatel1, uzivatel2... až uzivatel50. Nehledě na to, že jich může být třeba 1000. A jak by se v tom potom hledalo? Brrr, takle ne :)

Pokud potřebujeme uchovávat větší množství proměnných stejného typu, můžeme použít pole. Můžeme si ho představit jako řadu přihrádek, kde v každé máme uložený jeden prvek. Přihrádky jsou očíslované tzv. indexy, první má index 0.

Struktura pole

(Na obrázku je vidět pole osmi čísel)

Programovací jazyky se velmi liší v tom, jak s polem pracují. V některých jazycích (zejména kompilovaných) není možné za běhu programu vytvořit pole s dynamickou velikostí (např. mu dát velikost dle nějaké proměnné). Pole se zde musí deklarovat s konstantní velikostí přímo ve zdrojovém kódu. Lze to obejít pointery a vlastními datovými strukturami. Naopak některé modernější interpretované jazyky nebo jazyky s virtuálním strojem umožňují nejen deklarovat pole s libovolnou velikostí, ale dokonce tuto velikost na již existujícím poli měnit (např. PHP). C++ je jazyk čistě kompilovaný, u pole tedy budeme vždy velikostně omezeni.

Možná vás napadá, proč se tu zabýváme s polem, když má evidentně mnoho omezení a existují lepší datové struktury. Odpověď je prostá: pole je totiž jednoduché. Nemyslím pro nás na pochopení (to také), ale zejména pro počítač. Rychle se s ním pracuje, protože prvky jsou v paměti jednoduše uloženy za sebou, zabírají všechny stejně místa a rychle se k nim přistupuje. Je to klíčová struktura. Pro hromadnou manipulaci s prvky pole se poté používají cykly.

Pole deklarujeme pomocí hranatých závorek, ve kterých uvedeme jeho velikost. Před název proměnné nezapomene uvést datový typ jeho prvků, zde celá čísla:

int pole[16];

pole je samozřejmě název naší proměnné.

Velikost pole je pevně zadaná číslem ve zdrojovém kódu. Schválně si zkuste místo čísla použít proměnnou. Visual Studio to označí za chybu.

Pokud nám pevná velikost pole stačí, ale chceme jeho velikost zadat proměnnou (např. abychom ji pak použili v podmínce v cyklu), musíme použít tzv. konstantu. To je proměnná, jejíž hodnotu nelze měnit. Vytváří se téměř stejně jako běžné proměnné, jen před datový typ napíšeme klíčové slovo const:

const int delkaPole = 24;
int pole[delkaPole];

Ohledně změny délky jsme si sice za běhu programu nepomohli, nicméně, když si jako programátoři rozmyslíme, že chceme zadat napevno jiný počet prvků, změní se konstanta na všech místech v programu. Kdybychom pole poté vypisovali cykly, mohli bychom např. zapomenou změnit počet prvků i tam a z pole vyjet nebo jej nevypsat celé.

Často potřebujeme délku pole zadat pomocí proměnné. Takové pole musíme založit tzv. dynamicky, což se naučíme v navazujícím C++ kurzu. Probírat tuto problematiku hned v úvodním kurzu by určitě nebyl dobrý nápad.

K prvkům pole přistupujeme přes hranatou závorku. Pojďme na první index (tedy index 0) uložit číslo 1.

const int delkaPole = 24;
int pole[delkaPole];
pole[0] = 1;

Plnit pole takto ručně by bylo příliš pracné, použijeme cyklus a naplníme si pole čísly od 1 do 10. K naplnění použijeme for cyklus:

const int delkaPole = 10;
int pole[delkaPole];
for (int i = 0; i < delkaPole; i++)
        pole[i] = i + 1;

Všimněte si, že délku pole máme opět uloženou v konstantě.

Pozn.: Nikdy se nesnažte přistupovat k prvkům za koncem pole (např k 20. prvku v poli o 10 prvcích). V lepším případě dostanete nedefinovaný výsledek (hodnoty, co byly zrovna náhodou uloženy v paměti), v tom horším případě program spadne.

Abychom pole vypsali, můžeme za předchozí kód připsat:

for (int i = 0; i < delkaPole; i++)
        cout << pole[i] << ' ';

Naplnit pole hodnotami můžeme ještě jedním způsobem. Pokud známe jeho prvky předem, můžeme využít následující syntaxi:

int pole[5] = {1, 2, 3, 4, 5};

Číslo v hranatých závorkách lze vynechat, délka pole se poté určí podle počtu prvků ve složených závorkách. Na druhou stranu můžeme v hranatých závorkách uvést hodnotu větší než počet prvků ve složených závorkách. Pole poté nebude mít všechny prvky nastavené.

Funkce pro práci s poli

Mnoho užitečných funkcí pro práci s poli můžeme najít v souboru "algorithm". Některé z nich si tu ukážeme (nesmíme zapomenout umístit #include <algorithm> na začátek souboru).

find()

Funkce find() nám vrací tzv. ukazatel na první výskyt hodnoty, kterou jsme jí předali. S ukazateli se teprve setkáme, nyní nám bude muset stačit, že se k jejich zápisu používá hvězdička a že když poté odečteme tento ukazatel od pole, získáme skutečnou pozici hodnoty v poli. Pokud funkce prvek nenalezne, vrátí délku pole. Pojďme si vše ukázat na příkladu a nechme si najít pozici hodnoty 7 v poli několika čísel:

#include <iostream>
using namespace std;

int main(void)
{
        const int delkaPole = 5;
        int pole[delkaPole] = { 1, 7, 3, 4, 10 };
        int hledanyPrvek = 7;
        int *i = find(pole, pole + delkaPole, hledanyPrvek);
        int pozice = i - pole;
        if (pozice < delkaPole)
                cout << "Prvek 3 nalezen na pozici: " << pozice << "." << endl;
        else
                cout << "Prvek nenalezen." << endl;
        cin.get();
        return 0;
}

count()

const int delkaPole = 6;
int pole[6] = { 1, 6, 9, 2, 6, 3 };
int c = count(pole, pole + delkaPole, 6);
// c = 2

Funkce count() nám spočítá, kolikrát se v poli vyskytuje předaná hodnota - v ukázce 6.

copy()

const int delkaPole = 5;
int pole[delkaPole] = { 1, 2, 3, 4, 5 };
int pole2[delkaPole] = { 0, 0, 0, 0, 0 };
copy(pole, pole + delkaPole, pole2);
// pole = { 1, 2, 3, 4, 5 }, pole2 = { 1, 2, 3, 4, 5 }

Funkce copy() zkopíruje obsah jednoho pole do druhého.

Pozn.: druhé pole musí být stejně dlouhé jako první pole, nebo delší.

max_element()

const int delkaPole = 5;
int pole[delkaPole] = { 2, 1, 4, 5, 3 };
int *i = max_element(pole, pole + delkaPole);
// i = pole + 3, *i = 5

Funkce max_element() vrací ukazatel na největší hodnotu v poli. Hodnoty porovnává pomocí operátoru <. Pokud se nejvyšší hodnota vyskytuje v poli několikrát, vrácený ukazatel bude ukazovat na její první výskyt. Pozici získáme stejně jako u příkladu s find().

min_element()

const int delkaPole = 5;
int pole[delkaPole] = { 2, 1, 4, 5, 3 };
int *i = min_element(pole, pole + delkaPole);
// i = pole + 1, *i = 1

Funkce min_element() je obdoba předchozí funkce s jediným rozdílem - vrací ukazatel na nejnižší hodnotu v poli. Pozici získáme stejně jako u příkladu s find().

sort()

const int delkaPole = 5;
int pole[delkaPole] = { 2, 1, 4, 5, 3 };
sort(pole, pole + delkaPole);
// pole = { 1, 2, 3, 4, 5 }

Sort() vzestupně seřadí prvky v poli (pomocí operátoru < ).

fill()

const int delkaPole = 5;
int pole[delkaPole] = { 1, 2, 3, 4, 5 }
fill(pole, pole + delkaPole, 5);
// pole = { 5, 5, 5, 5, 5 }

Funkce fill naplní pole zadanou hodnotou.

reverse()

const int delkaPole = 5;
// pole[delkaPole] = { 1, 2, 3, 4, 5 };
reverse(pole, pole + delkaPole);
// pole = { 5, 4, 3, 2, 1 }

Funkce reverse() "převrátí" obsah pole. To znamená, že jeho hodnoty budou pozpátku.

random_shuffle()

const int delkaPole = 5;
int pole[delkaPole] = { 1, 2, 3, 4, 5 };
random_shuffle(pole, pole + delkaPole);
// např. pole = { 3, 1, 5, 2, 4 }

Funkce random_shuffle() náhodně přehází prvky v poli.

To by pro dnešek stačilo, můžete si s polem hrát.


 

  Aktivity (6)

Článek pro vás napsal Zdeněk Pavlátka
Avatar
Autor se věnuje spoustě zajímavých věcí :)

Jak se ti líbí článek?
Celkem (4 hlasů) :
4.754.754.754.754.75


 


Miniatura
Všechny články v sekci
Základní konstrukce jazyka C++
Miniatura
Následující článek
Cvičení k 8.-9. lekci C++

 

 

Komentáře
Zobrazit starší komentáře (1)

Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Zdeněk Pavlátka:

Snad zítra ;) (23.4.)

Odpovědět  +1 22.4.2016 17:21
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Odpovědět 23.4.2016 19:22
"Existuje pouze 10 typů lidí, ti kteří strojovému kódu rozumí a ti kteří ne."
Avatar
Zdeněk Pavlátka
Tým ITnetwork
Avatar
Odpovídá na Jan Doskočil
Zdeněk Pavlátka:

Tak ještě ne, nic nestíhám :/ Ale už to mám rozepsané...

Editováno 24.4.2016 22:05
Odpovědět  +2 24.4.2016 22:05
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Odpovídá na Zdeněk Pavlátka
Jan Doskočil:

Prosím už mě nemuč úvahami o přechodu na C#

Odpovědět 12.6.2016 18:17
"Existuje pouze 10 typů lidí, ti kteří strojovému kódu rozumí a ti kteří ne."
Avatar
Michal Rivola:

Ahoj :D mohl bych se zeptat kde sem udělal chybu :D

 
Odpovědět 19.12.2016 20:50
Avatar
Odpovídá na Michal Rivola
Petr Štechmüller:

Ahoj, nemažeš pole intů
Takto ho definuješ:

int pole[10];
// teď by jsi ho měl vyčistit (vynulovat) pomocí memset

V C nemáš předem jisté, že paměť o kterou jsi si řekl bude prázdná

Odpovědět 19.12.2016 20:53
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Michal Rivola:

jo díky :D já sem zatím hodně začátečník takže si budu muset ještě najít jak se dělá s memset :D

 
Odpovědět 19.12.2016 20:55
Avatar
Cement
Člen
Avatar
Cement:

Jak velké pole můžu nadefinovat? Zkoušel jsem pole o velikosti 20 milionů. Zkompilovalo se to v pořádku. Po spuštěni exe souboru mi program spadl a Win10 hledalo řešení problému.
Pod Ubuntu je to podobné. Jen tam program bere pole int o max velikosti 2 miliony. Ve Win10 max 500 tisíc. Když vytvořím pole bool, tak velikost je asi 4x větší.
V Javě dokáže vytvořit pole velké přes 200 milionů.
Víte někdo, kde je zakopaný pes v C++?
Děkuji za odpovědi.

 
Odpovědět 9. února 16:37
Avatar
Odpovídá na Cement
Lukáš Hruda (Luckin):

Předpokládám, že to pole vytváříš staticky:

int pole[500000];

V takovém případě je velikost pole omezena velikostí zásobníku, která ve Windows je tuším 1MB.
Pokud pole vytvoříš dynamicky:

int* pole = new int[1000000000];

Takto můžeš teoreticky vytvořit pole skoro tak velké, jako je celý tvůj adresní prostor.
Tedy, ne tak docela, protože ti to může zhatit fragmentace paměti, ale každopádně takto můžeš vytvořit mnohem větší pole, klidně i větší než 200 milionů prvků.

 
Odpovědět  +1 9. února 17:13
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Petr Štechmüller
DarkCoder:

V C nemáš předem jisté, že paměť o kterou jsi si řekl bude prázdná

Nemáš tak úplně pravdu. Toto platí o lokálních proměnných. Lokální proměnné, které nejsou inicializovány mohou totiž obsahovat libovolnou neznámou hodnotu. I když některé překladače jazyka C nastavují neinicializované proměnné na nulu, určitě bych se na to nespoléhal. Kdežto globální proměnné, které nejsou explicitně inicializovány, jsou automaticky nastaveny na nulu. Stejně tak vytvářím-li proměnnou dynamicky pomocí funkce calloc(), je po úspěšné alokaci inicializován každý prvek na nulu.

 
Odpovědět 9. února 21:46
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 11. Zobrazit vše