10. díl - Vícerozměrná pole v jazyce C

C a C++ Céčko Základní konstrukce C Vícerozměrná pole v jazyce C

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

V minulé lekci, Textové řetězce v jazyce C podruhé - Práce se znaky, jsme pracovali s jednotlivými znaky textových řetězců, tedy s prvky v poli charů. Řetězce dnes již opustíme. Dosud jsme pracovali pouze s jednorozměrnými poli. Jednorozměrné pole si můžeme představit jako řádku přihrádek v paměti počítače.

Ukázka pole

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

Ačkoli to není tak časté, v programování se občas setkáváme i s vícerozměrnými poli a to zejména pokud programujeme nějakou simulaci. Například ve hrách může dvourozměrné pole simulovat hrací plochu, v matematice třeba matici.

Dvourozměrné pole

Dvourozměrné pole si můžeme v paměti představit jako tabulku a mohli bychom takto reprezentovat např. rozehranou partii piškvorek. Pokud bychom se chtěli držet reálných aplikací, které budete později v zaměstnání tvořit, můžeme si představit, že do 2D pole budeme ukládat informace o obsazenostech sedadel v kinosálu. Situaci bychom si mohli graficky znázornit např. takto:

Použití dvourozměrného pole pro místa v kině

(Na obrázku je vidět 2D pole reprezentující obsazenost kinosálu)

Kinosál by byl v praxi samozřejmě větší, ale jako ukázka nám toto pole postačí. 0 znamená volno, 1 obsazeno. Později bychom mohli doplnit i 2 - rezervováno a podobně. Pro tyto stavy by bylo správnější vytvořit nějaké konstanty, ale s tím se setkáme až později, takže si teď musíme vystačit pouze s čísly.

2D pole deklarujeme v C následujícím způsobem:

int kinosal[5][5];
int i, j;
// Naplnění nulami
for (j = 0; j < 5; j++)
        for (i = 0; i < 5; i++)
                kinosal[j][i] = 0;

Nesmíme zapomenout pole vyplnit nulami, protože u C nevíme jaké hodnoty mohou být v poli aktuálně uloženy. Také si je potřeba uvědomit (a ideálně i někam do komentáře zapsat) jaké je pořadí souřadnic. V našem případě bude první číslice indexovat sloupec, druhá řádky.

Modifikace

Nyní kinosál naplníme jedničkami tak, jak je vidět na obrázku výše. Protože budeme jako správní programátoři líní, využijeme k vytvoření řádku jedniček for cykly :) Pro přístup k prvku 2D pole musíme samozřejmě zadat 2 souřadnice.

kinosal[2][2] = 1; // Prostredek
for (i = 1; i < 4; i++) // 4. radek
{
        kinosal[i][3] = 1;
}
for (i = 0; i < 5; i++) // Posledni radek
{
        kinosal[i][4] = 1;
}

Výpis

Výpis pole opět provedeme pomocí cyklu. Na 2D pole budeme potřebovat cykly 2 (jeden nám proiteruje sloupce a druhý řádky). Cykly zanoříme do sebe tak, aby nám vnější cyklus projížděl řádky a vnitřní sloupce v aktuálním řádku. Po výpisu řádku je nutné odřádkovat. Oba cykly musí mít samozřejmě jinou řídící proměnnou:

for (j = 0; j < 5; j++)
{
        for (i = 0; i < 5; i++)
                printf("%d", kinosal[i][j]);
        printf("\n");
}

Výsledek:

Konzolová aplikace
00000
00000
00100
01110
11111

N-rozměrné pole

Někdy může být příhodné vytvořit si pole o ještě více dimenzích. My všichni si jistě dokážeme představit minimálně 3D pole. S příkladem s kinosálem se nabízí případ užití, kdy má budova více pater (nebo obecně více kinosálů). Vizualizace by vypadala asi nějak takto:

Ilustrace 3D pole

3D pole můžeme vytvořit tím samým způsobem, jako 2D pole:

int kinosaly[5][5][3];

Kód výše vytvoří 3D pole jako na obrázku. Přistupovat k němu budeme opět přes indexer (hranaté závorky) jako předtím, jen již musíme zadat 3 souřadnice.

kinosaly[3][2][1] = 1; // Druhý kinosál, třetí řada, čtvrtý sloupec

Zkrácená inicializace

Ještě si ukážeme, že i vícerozměrná pole je možné rovnou inicializovat hodnotami (kód vytvoří rovnou zaplněný kinosál jako na obrázku):

int kinosal[5][5] = {
        { 0, 0, 0, 0, 1 },
        { 0, 0, 0, 1, 1 },
        { 0, 0, 1, 1, 1 },
        { 0, 0, 0, 1, 1 },
        { 0, 0, 0, 0, 1 }
};

(Pole je v tomto zápisu otočené, jelikož definujeme sloupce, které zde zapisujeme jako řádky).

Nezarovnané pole

Dosud jsme mluvili pouze o tzv. pravoúhlých polích. U takového pole víme, že je vždy obdélníkové. Céčko nám nedovolí staticky vytvořit pole, které by mělo v jednotlivých dimenzích rozdílný počet prvků (anglicky zvané jagged array). Takové pole by vypadalo nějak takto:

Ukázka nezarovnaného pole v jazyce C

Taková pole samozřejmě vytvořit lze, ale musíme si pro každou dimenzi pamatovat počet členů, protože na rozdíl od ostatních jazyků, C si velikost pole nepamatuje. Také je třeba využít dynamické alokace paměti, a proto toto téma necháme až na kurz dalších konstrukcí céčka, kdy se k němu vrátíme.

Na závěr bych rád dodal, že někteří lidé, kteří neumí správně používat struktury, využívají 2D polí k ukládání více údajů o jediné struktuře. Např. budeme chtít uložit výšku, šířku a délku pěti mobilních telefonů. Ačkoli se vám nyní může zdát, že se jedná o úlohu na 3D pole, ve skutečnosti se jedná o úlohu na obyčejné 1D pole (přesněji seznam) struktur typu TELEFON. Struktury se naučíme používat ještě na konci tohoto kurzu. Pole si můžete vyzkoušet ještě v cvičení k této sekci.

V příští lekci, Matematické funkce v jazyce C, se podíváme na matematickou knihovnu math.h a na celočíselné dělení.


 

Stáhnout

Staženo 47x (62.37 kB)
Aplikace je včetně zdrojových kódů v jazyce c

 

 

Článek pro vás napsal patrik.valkovic
Avatar
Jak se ti líbí článek?
1 hlasů
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
Aktivity (10)

 

 

Komentáře

Avatar
lastp
Redaktor
Avatar
lastp:16.7.2016 13:12

N-rozměrné pole je také možné alokovat dynamicky. To se hodí v případech, kdy má pole velké rozměry a normální deklarace pole uvnitř funkce by způsobovala chybu stack overflow.

int(*pole)[1080] = (int(*)[1080]) calloc(1920*1080, sizeof(int));
pole[200][100] = 1;
printf("%d", pole[200][100]);
free(pole);
 
Odpovědět 16.7.2016 13:12
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na lastp
patrik.valkovic:16.7.2016 13:22

Dynamická alokace je probrána až v dalších dílech.

Odpovědět 16.7.2016 13:22
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
dfdfdf
Člen
Avatar
dfdfdf:31.12.2016 12:50

Cus.Muze nekdo poradit kde je chyba?

main.c:20:25: error: invalid initializer
int kinosal [2][2]= 1;

Editováno 31.12.2016 12:51
 
Odpovědět 31.12.2016 12:50
Avatar
Odpovídá na dfdfdf
Jaroslav Polívka:31.12.2016 13:47

Chyba je v tom, že v deklaraci int kinosal [2][2] je chybně provedená inicializace. Chápu to tak, že chceš do souřadnic 2,2 přiřadit hodnotu jedna, proto bych nejdříve provedl deklaraci int kinosal [2][2] a až na dalším řádku bych hodnotu přiřadil int kinosal [2][2] = 1

Odpovědět 31.12.2016 13:47
Velice často si věci žijí svým životem
Avatar
dfdfdf
Člen
Avatar
Odpovídá na Jaroslav Polívka
dfdfdf:31.12.2016 14:19

Stejně vzniká chyba

 
Odpovědět 31.12.2016 14:19
Avatar
Odpovídá na dfdfdf
Jaroslav Polívka:31.12.2016 14:20

Kdybych si chtěl deklarované pole řádně inicializovat, abych tam neměl náhodné hodnoty. Provedl bych to následující rutinkou:

int main(int argc, char* argv[])
{

const int SIRKA = 4, VYSKA = 2;
int policko[SIRKA][VYSKA];

for(int i = 0; i<VYSKA; i++){

        for(int j = 0; j<SIRKA; j++){
        policko[j][i]=0;
        }

}

system("PAUSE");
return 0;
}

Potvrď mi prosím řešení :)

Odpovědět 31.12.2016 14:20
Velice často si věci žijí svým životem
Avatar
Odpovídá na dfdfdf
Jaroslav Polívka:31.12.2016 14:37

No jasan, IDE ti vždycky vyhodí chybu, protože deklaruješ pole o velikosti [2][2] a pak chceš for smyčkami procházet pole o velikosti [5][5], takže ihned ze začátku je třeba deklarovat tu větší velikost a pokud tam chceš nuly, tak to ze začátku inicializovat podle té rutinky, kterou jsem ti tady napsal.

Prosím tě o přiznání řešení.

Odpovědět 31.12.2016 14:37
Velice často si věci žijí svým životem
Avatar
Odpovídá na Jaroslav Polívka
Libor Šimo (libcosenior):31.12.2016 14:56

kinosal[2][2] = 1
je v tomto pripade blbost, pretoze pole moze nabudat indexy [0,1[0,1]

Odpovědět 31.12.2016 14:56
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na dfdfdf
Jaroslav Polívka:31.12.2016 15:17

Tak jestli bys mohl zkusit ještě tento kód:

#define SIRKA 5
#define VYSKA 5

int main(int argc, char* argv[])
{

int i,j;
int kinosal[SIRKA][VYSKA];

for(i = 0; i<VYSKA; i++){

        for(j = 0; j<SIRKA; j++){
        kinosal[j][i]=0;
        }
}

kinosal[2][2] = 1;

for (i = 1; i < 4; i++)
{
        kinosal[i][3] = 1;
}
for (i = 0; i < 5; i++)
{
        kinosal[i][4] = 1;
}

for (j = 0; j < 5; j++)
{
        for (i = 0; i < 5; i++)
                printf("%d", kinosal[i][j]);
        printf("\n");
}

system("PAUSE");
return 0;
}

Trošku jsem se ještě opravil oproti předchozí verzi, měl jsem IDE přepnuté na C++.

Odpovědět 31.12.2016 15:17
Velice často si věci žijí svým životem
Avatar
DarkCoder
Člen
Avatar
Odpovídá na dfdfdf
DarkCoder:31.12.2016 15:23
  1. Chybně inicializuješ dvourozměrné pole. Motáš dohromady inicializaci spolu s přiřazovacím příkazem.
  2. První cyklus postrádá jakýkoli smysl.
  3. Nehlídáš si meze pole a v klidu se snažíš přiřadit hodnotu mimo jeho rozsah
  4. Nepoužíváš klíčové slovo return pro navrácení hodnoty funkce main.
 
Odpovědět 31.12.2016 15:23
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 10.