Polia,
Pointre a Referencie

Polia Arrays

Pole je postupnosť prvkov jedného typu. Treba si len dávať pozor na to, že indexovať sa začína od nuly.
int a[20]; Vytvoril som pole 20 intov, prvý prvok má index 0, zapisujem ho ako a[0], a posledný, 20ty má index 19 a zapisujem ho teda a[19] Toto je však jasná vec, to len na zopakovanie :) Aj keď je posledným prvkom a[19], prekladač to nekontroluje a dovoľuje mi pristupovať aj k prvku a[100]. Samozrejme, že z toho môžu vzniknúť chyby.
V C++ neexistuje typ viacrozmerné pole. Toto však ale vôbec nevadí, lebo možno vytvoriť pole ľubovoľných prvkov. Teda aj pole polí a to už je vlastne viacrozmerné pole...
int a[10][5]; Toto je teda pole 10x5. Alebo 5x10? No opäť je lepšie si to ozátvorkovať. Ako prvé bolo toto:
... (a[10])...
Toto vraví, že a je pole 10 prvkov...
... ((a[10])[5]);
Konkrétne je to pole 10 polí, z ktorých každé má 5 prvkov...
int a[10][5];
Teda 5 intov. a je pole 10 pätíc intov.
To čo je najviac napravo v deklarácii sa teda mení najrýchlejšie. Ale ja si to aj tak moc nepamätám, tak to hore cez zátvorky je najistejšie...
#include "stdio.h"
int main(int argc, char* argv[])
{
int a[3][4]={ {1,2,3,4},
              {5,6,7,8},
              {9,0,1,2}};

for(int i=0;i<3;i++){
   for(int j=0;j<4;j++)
        printf("%d ",a[i][j]);
        printf("\n");}

char pause=getchar();
        return 0;
}
Takto sa dá pole jednoducho naplniť.

Smerníky Pointers

Smerník je ukazovateľ na objekt. Teda nie je to objekt samotný, len niečo čo na ňho odkazuje. Povedzme, že objekt je obyčajná premenná typu int. Nadefinujem ju takto:
int a;
Smerník na objekt sa urobí tak, že pridám hviezdičku. Smerník na int potom vyzerá takto.
int (*a);
Je síce pekné, že si vytvorím smerník na int, ale treba aj nastaviť aby niekam ukazoval. Lebo takto z toho môžu vzniknúť chyby (ak budem chcieť na miesto kde (zatiaľ ne)ukazuje niečo uložiť, tak bude problém) Je teda dobré hneď mu urobiť miesto v pamäti, kde bude ukazovať, alebo mu aspoň dodať nejakú adresu.
int (*a)=new int;
Teraz je to už ok, a do miesta na ktoré smerník a ukazuje, možno vkladať v pohode hodnoty (hodnoty typu int)...
int x;
int (*a)=&x;
Aj takýto zápis je ok, lebo smerník a hneď ukazuje na adresu kde je uložené x. Nepríjemné (alebo žiadúce?) je že keď mením teraz x mením aj to na čo ukazuje a, a naopak ak mením obsah toho kde ukazuje a, mením zároveň x.

K obsahu smerníka sa pristupuje cez operátor *. A teda ak chcem aby nejaká nová premenná bola zinicializovaná tým na čo ukazuje hore spomínaný smerník a, napíšem:
int nova=*a;

Adresa objektu (ak ju chcem uložiť do smerníka napríklad) sa zisťuje cez operátor &, a teda ak chcem do novovytovreného smerníka, priradiť adresu existujúcej premennej, urobím to presne tak ako je napísané hore. Pre zopakovanie:
int x;
int (*a)=&x;

Smerníky však nemusia ukazovať len na jednoduché objekty ako premenné typu int. Môžu ukazovať na zložitejšie typy, na polia typov, dokonca na funkcie, alebo polia smerníkov na funkcie...

#include "stdio.h"

void Hello(void){
        printf("\nHello World");
        }
int main(int argc, char* argv[])
{

Hello();        //klasicka funkcia

void (*HelloPointer)()=&Hello;

HelloPointer(); //a cez smernik

char pause=getchar();
        return 0;
}
Takto som si urobil smerník na funkciu Hello, a už ju môžem volať aj cez tento nový smerník. Užitočnosť tohto príkladu je nulová, ale skúsim ho trochu modifikovať :)
#include "stdio.h"

void HelloEn(void){printf("\nHello World");}
void HelloSk(void){printf("\nAhoj svet");}
void HelloEs(void){printf("\nHola mundo");}

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

void (*Hello[3])();

Hello[0]=HelloEn;
Hello[1]=HelloSk;
Hello[2]=HelloEs;

enum {English,Slovensky,Espanol}Lang;
Lang=Slovensky;         Hello[Lang]();
Lang=Espanol;           Hello[Lang]();
Lang=English;           Hello[Lang]();

char pause=getchar();
        return 0;
}
Toto je tiež, nie celkom ideálne, lebo stačilo funkcii dávať odkaz na jazyk, ale pointa je, že vďaka poľu smerníkov na funkcie, možno volať zakaždým inú funkciu, a stačí meniť index v poli. Určite sú aj lepšie príklady využitia, toto ma napadlo iba teraz...

Ukazovatele sa dajú využiť, ešte aj na odovzdávanie parametrov funkcií. Načo je to dobré?

#include "stdio.h"

void modifikuj(int vstup){vstup=vstup*2;}
void modifikuj2(int a){a=a*2;}
void modifikuj3(int *vstup){*vstup=*vstup*2;}

int main(int argc, char* argv[])
{
int a=10;
printf("\na=%d",a);
modifikuj(a);
printf("\na=%d",a);
modifikuj2(a);
printf("\na=%d",a);
modifikuj3(&a);
printf("\na=%d",a);

char pause=getchar();

        return 0;
}
Funkcia modifikuj je ako vidím nanič. Mala by zmeniť a ale akosi sa nemá k činu.
Skúsil som teda zadefinovať funkciu modifikuj2, ktorá pracuje s premennou, ktorá má rovnaké meno ako "moje" a. Stále nič.
Toto je spôsobené tým, že do funkcie sa neposiela skutočné a, ale len jeho kópia. (tá vznikne keď som v rámci deklarácie funkcie napísal int a, a zanikne najbližšou } teda koncom funkcie...) Ja teda modifikujem kópiu.
Bolo by dobré funkcii, namiesto hodnoty ktorú chcem meniť, odovzdať radšej miesto kde je tá hodnota. Potom si funkcia spraví kópiu tejto informácie (o tom mieste) a priamo vo funkcii môžem modifikovať obsah miesta. Presne toto robí funkcia modifikuj3, ktorá naozaj robí to čo som chcel...

Referencie References

Smerníky sú fajn vec, keď potrebujem odovzdávať funkcii nejakú premennú, s ktorou chcem plnohodnotne pracovať, ale dávať si pozor na to, kde patria hviezdičky a kde nie je celkom otrava... Našťastie existuje referencia, čo je vlastne smerník, ktorý sa sám dereferencuje.
#include "stdio.h"

int main(int argc, char* argv[])
{
int a=10;
int &b=a;
printf("\na=%d b=%d",a,b);
b=20;
printf("\na=%d b=%d",a,b);

char pause=getchar();

        return 0;
}
Urobil som si teda b, čo je vlastne referencia na a. Znamená to toľko, že čokoľvek teraz robím s b ako keby som robil s a. b je exaktná kópia a (ani nie kópia, je to skôr alias...)
#include "stdio.h"

void modifikuj3(int &vstup){vstup=vstup*2;}

int main(int argc, char* argv[])
{
int a=10;

printf("\na=%d",a);
modifikuj3(a);
printf("\na=%d",a);

char pause=getchar();

        return 0;
}
Funkcia spomínaná vyššie, teda pomocou referencií vyzerá takto. Opäť funguje, a je super, že nemusím písať žiadne hviezdičky. Funguje to preto, lebo hneď ako sa volá funkcia, vytvorí sa v nej referencia (to spôsobí príkaz int &vstup;) na to čo vstupuje. Počas behu funkcie, sa teda pracuje s aliasom, ktorý plne nahradzuje premennú, ktorá vstúpila do funkcie. Vôbec nevadí, že tento alias pri skončení funkcie zanikne, lebo funkcia urobila to čo mala, a nie je dôležité čo sa stane s tým čo na to potrebovala...

Je treba dávať pozor na to, že referenciu treba hneď inicializovať. (Teda jej musím dať nejak vedieť, čoho aliasom je...) Jediná výnimka je v rámci deklarácie funkcie. Ale keď sa nad tým zamyslíme aj tam je vlastne inicializovaná, a to tým čo do funkcie vstúpi...
Taktiež je potrebné inicializovať referenciu existujúcou premennou, a nie hodnotou. Riadok
int &ref=10;
síce nevyhodí chybu, ale referuje nejakú dočasnú premennú, a prekladač ohlási aspoň warning.
Referencia môže byť aliasom len na tú premennú, ktorú jej zadám pri inicializácii, a toto nemožno neskôr meniť a "presmerovať" ju na nejakú inú premennú.
Priamo v maine sa referencie veľmi nevyužívajú, možno ak si chcem urobiť alias na nejakú premennú, ktorá je prístupná len cez nejaký krkolomný a dlhý zápis...

Polia vs. Smerníky

Polia a smerníky spolu veľmi úzko súvisa. Dá sa totiž, povedať, že pole je vlastne smerník... Keď totiž vytvorím pole, tak sa jeho meno správa (väčšinou) ako ukazovateľ na jeho prvý prvok...
#include "stdio.h"

int main(int argc, char* argv[])
{
int a[10];
a[0]=99;

printf("\na=%d  *a=%d",a,*a);

char pause=getchar();

        return 0;
}
Z tohto vidieť, že a je nielen pomenovanie poľa, ale zároveň aj smerník, ukazujúci na prvý prvok poľa. Existuje však pár výnimiek.
#include "stdio.h"

int main(int argc, char* argv[])
{
int a[10];
printf("\nsizeof(a[0])=%d  sizeof(a)=%d",sizeof(a[0]),sizeof(a));

int (&b)[10]=a;
a[1]=77;printf("\n\na[1]=%d  b[1]=%d",a[1],b[1]);
b[2]=88;printf("\na[2]=%d  b[2]=%d",a[2],b[2]);

printf("\n\na=%d &a[0]=%d &a=%d",a,&a[0],&a);

char pause=getchar();

        return 0;
}
Ak zadám meno poľa do sizeof, tak sa to chápe (nie ako spomínaný smerník, ale) ako sizeof celého poľa.
Ak zadám meno poľa ako inicializačnú hodnotu pre novú referenciu, tak som opäť priradil referencii (nie spomínaný smerník, ale) celé pole.
Ak zadám meno poľa ako argument &, a teda sa pýtam na adresu kde je uložené a, tak mi vráti (nie adresu kde je uložený smerník, to už aj znie blbo... ale) adresu kde začína pole a teda smerník na toto pole :)
#include "stdio.h"

int main(int argc, char* argv[])
{
int a[10];      //pole intov
int (*ptr)[10]; //smernik na pole intov
ptr=&a;         //smernik ukazuje na toto pole

a[2]=7;
printf("\na[2]=%d (*ptr)[2]=%d",a[2],(*ptr)[2]);
(*ptr)[3]=8;
printf("\na[3]=%d (*ptr)[3]=%d",a[3],(*ptr)[3]);

*(a+4)=9;
printf("\na[4]=%d (*ptr)[4]=%d",a[4],(*ptr)[4]);
*(*ptr+5)=10;
printf("\na[5]=%d (*ptr)[5]=%d",a[5],(*ptr)[5]);

char pause=getchar();

        return 0;
}
Na tomto príklade je zaujímavých niekoľko vecí. Hneď na úvod deklarácia smerníka ukazujúceho na pole. To je však len zápis... Je zjavné, že keď nastavím, že tento nový smerník (ktorý ukazuje na nejaký int[10]) má ukazovať tam kde ukazuje aj začiatok poľa desiatich intov, tak obe veci ukazujú na jedno a to isté. Na tomto nie je nič zvláštne...

Prvá zaujímavá vec je, ako sa pristupuje k poľu, prostredníctvom smerníka. Ak som nasmeroval smerník ptr na začiatok poľa a, potom zápis a[n] je ekvivalentný s (*ptr)[n].
Najmä ten zápis pomocou smerníka vyzerá čudne.
ptr je smerník na pole. A teda dereferenciou smerujem na začiatok poľa.
Ak teda napíšem *ptr dostávam smerník smerujúci na prvý prvok poľa.
Toto je dôležité. Nesmerujem na prvok samotný, smerujem na pole (resp. na smerník určujúci začiatok poľa). Ak chcem zistiť obsah 0-tého prvku musím zapísať (*ptr)[0]

Druhá zaujímavá vec, je že operátor [] je rovnocenný s pohybom po poli.
Ak teda napíšem a[2], zápis je ekvivalentný so zápisom *(a+2).
Na pochopenie si treba uvedomiť, čo to je a samotné. Vieme, že ak napíšem meno poľa osamote (teda a samotné) tak to predstavuje, (okrem pár špeciálnych prípadov) smerník na prvý prvok tohto poľa, resp. adresu kde je začiatok poľa. Z tohto logicky vyplýva, že dereferenciou tohoto smerníka dostávam obsah prvého prvku poľa. A naozaj - zápis *a je ekvivalentný so zápisom a[0];
Ak teda smerník a smeruje na prvý prvok poľa, kam smeruje smerník (a+1)? No keďže sa jedná o smerník na int, tak vďaka smerníkovej aritmetike smeruje, práve o jeden int v pamäti ďalej. A čo je uložené o jeden int ďalej? No predsa ďalší prvok poľa :) A ak (a+1) smeruje na ďalší prvok poľa, potom dereferenciou tohoto smerníka dostávam práve ďalší prvok poľa. Povedané inak *(a+1) je to isté ako a[1]

Úplne najzaujímavejšie je však pozorovať, čo sa deje dereferenciou smerníka na pole :) No jeho dereferenciou získam adresu kde začína toto pole. Teda zápis *ptr je ekvivalentný so zápisom &a[0][0] a toto je predsa to isté ako samotné a. Ak *ptr je to isté ako a, tak potom **ptr je to isté ako *a a to je to isté ako a[0].
Ukazovateľ *ptr ukazuje na na prvý prvok v poli (alebo na pole samotné, aj tak sa to dá povedať). Tento je int. Ak teda zvýšim ukazovateľ o jedna, tak bude ukazovať na druhý prvok v poli. Ak *ptr ukazuje na prvok a[0], tak potom *ptr+n ukazuje na prvok a[n]. A keď takto na seba pekne ukazujú, tak predsa musí platiť, že *(*ptr+n) je to isté ako a[n].
Ako vidieť z programu hore, je tomu presne tak :)

#include "stdio.h"

int main(int argc, char* argv[])
{
int a[10];     //pole intov
int *ptr;      //smernik na int
ptr=a;         //smernik na prvy prvok tohto pola

a[2]=7;
printf("\na[2]=%d ptr[2]=%d",a[2],*(ptr+2));
ptr[3]=8;
printf("\na[3]=%d ptr[3]=%d",*(a+3),ptr[3]);

*(a+4)=9;
printf("\na[4]=%d ptr[4]=%d",a[4],*(ptr+4));
*(ptr+5)=10;
printf("\na[5]=%d ptr[5]=%d",*(a+5),ptr[5]);

char pause=getchar();

        return 0;
}
No a na tomto príklade je iba vidieť, že pole intov a smerník na int sú úplne rovnocenné. Samozrejme, že platí smerníková aritmetika a ak ptr ukazuje na nejaký int v pamäti (zhodou okolností prvý prvok poľa intov) tak ptr+1 ukazuje na nasledujúci int v pamäti (zhodou okolností druhý prvok poľa intov)
To že meno poľa a, je zároveň smerníkom na prvý prvok, a možno ho v tomto zmysle používať, je jasné už z predošlého...
#include "stdio.h"

void resetmatrix(int *a){
  for (int i=0;i<10;i++)
        for (int j=0;j<5;j++)
             *a++=0;
                        }

void printmatrix(int *a){
               printf("\n   [0]  [1]  [2]  [3]  [4]");
  for (int i=0;i<10;i++){
               printf("\n[%d]",i);
        for (int j=0;j<5;j++)
             printf("%2d   ",*a++);
                        }
             printf("\n");
                        }

int main(int argc, char* argv[])
{
int a[10][5];      //pole intov
int (((*ptr)[10])[5]);
ptr=&a;

resetmatrix(*a);
a[0][1]=10;
(*ptr)[0][2]=20;
printmatrix(*a);

resetmatrix(*a);
**(a+3)=0;
(*(a+3))[1]=1;
*((*(a+3))+2)=2;
*(a[3]+3)=3;
printmatrix(*a);

resetmatrix(*a);
**(*ptr+4)=5;
/*
        *ptr            POLE
     * (*ptr)           NULTY RIADOK POLA
     *((*ptr)+1)        PRVY RIADOK POLA
*(   *((*ptr)+1)  )     PRVY RIADOK POLA, 0. PRVOK
*((  *((*ptr)+1)  ) +n) PRVY RIADOK POLA, n. PRVOK
*/
*((  *((*ptr)+4)  ) +1)=6 ;
  (  *((*ptr)+4)  ) [2]=7 ;
  (    (*ptr)[4]  ) [3]=8 ;
printmatrix(*a);


char pause=getchar();

        return 0;
}
No a poriadna sranda začína pri dvojrozmerných poliach :) Pristupovať k nim pomocou [][] nie je nič hrozné. Ale ak si urobím smerník na takéto pole, a chcem ho aj rozumne využívať, je potrebné rozlúskať čosi takéto.
Funkcie printmatrix a resetmatrix sú jasné, začnime tým ako pristupovať k prvkom pomocou [][]
...
a[0][1]=10;
(*ptr)[0][2]=20;
...
Čiže nič zložité.
...
**(a+3)=0;
(*(a+3))[1]=1;
*((*(a+3))+2)=2;
*(a[3]+3)=3;
...
Keďže a ako meno poľa predstavuje zároveň smerník, je možné pristupovať k jednotlivým prvkom aj takto. K prvku a[0][0], teda prvku na začiatku poľa pristupujem cez dvojitú dereferenciu ukazovateľa a (pretože práve ten ukazuje na začiatok poľa), zápis a[0][0] je ekvivalentný s **a.
Podľa pravidiel uvedených vyššie zároveň platí, že a[1][0] je ekvivalentné s **(a+1). Pretože keď zväčším smerník a posúvam sa o jeden prvok na ktorý ukazuje.
a ukazuje na nultý prvok poľa, a prvkami poľa a sú riadky (teda ďalšie polia). Ak sú prvkami poľa a riadky, potom zväčšením smerníka o 1 som sa v pamäti pohol práve o jeden riadok.
Ak *a je to isté ako *(a+0) a ukazuje to na nultý riadok, potom *(a+1) musí byť smerník na prvý riadok.
Dereferenciou tohoto smerníka získavam pochopiteľne hodnotu bunky, ktorá sa nachádza nultá na prvom riadku, a preto platí hore spomínané, že *(*(a+1)) resp. **(a+1) je to isté ako a[1][0]

Zápis **a možno zapísať aj ako (*a)[0]
No a zápis **(a+1) možno zapísať zase ako (*(a+1))[0]
Ak sa potrebujem posunúť aj v rámci riadku tak práve prostredníctvom toho čo je uvedené v []
(*(a+3))[1] teda predstavuje prvok na treťom riadku v prvom stĺpci.

Túto hranatú zátvorku však tiež možno prepísať na pohyb pomocou zmeny smerníka. Ak vieme, že (*(a+3))[0] je to isté ako *(*(a+3)) a to je to isté ako *((*(a+3))+0), tak možno ľahko povedať, že *((*(a+3))+2) je prvok na treťom riadku, v druhom stĺpci.

No a teraz možno zase podobným spôsobom prepísať vnútorný pohyb pomocou smerníka na pohyb pomocou hranatých zátvoriek a indexov... Ak a[n] je to isté ako *(a+n) tak je úplne jasné, že v poslednom som to iba aplikoval a teda *(a[3]+3) je to isté ako *((*(a+3))+3) čo ako som si odvodil je prvok v treťom riadku a treťom stĺpci.

...
**(*ptr+4)             =5 ;
*((  *((*ptr)+4)  ) +1)=6 ;
  (  *((*ptr)+4)  ) [2]=7 ;
  (    (*ptr)[4]  ) [3]=8 ;
...
Toto je už obzvlášť zaujímavé, pretože mám vytvorený smerník na pole [10][5]. Hneď prvý zápis vyzerá obzvlášť podozrivo, pretože, keďže smerník ptr ukazuje na celé pole, nemal by som ho priamo zväčšovať, inak sa posuniem v pamäti o celé takéto pole. Toto by bolo zle, pretože ďalšie pole v pamäti už nemám :)
Celá finta **(*ptr+4) však spočíva v tom, že operátor * má vyššiu prioritu a teda tento zápis je vlastne **((*ptr)+4).
Teraz už to je prehľadnejšie. Keďže ptr je smerník na pole a, tak ak si daný smerník dereferencujem, mám priamo prístup k poľu prostredníctvom indexov. (*ptr)[0][0] je teda rovnocenné s a[0][0].
Keďže rozpisovať hranaté zátvorky na pohyb pomocou indexov, už nie je taký problém, rozpíšem najprv tú napravo takto:
*(((*ptr)[0])+0)
Prepísať rovnakým spôsobom aj vnútornú zátovrku nie je opäť problém.
*(( (*ptr)[0] )+0) je ekvivalentné s *(( *((*ptr)+0) )+0)

Priradenia hore využívajú iba rôzne zámeny pohybu pomocou indexov a [] a pohybu pmocou zmeny smerníkov.

#include "stdio.h"

void resetmatrix(int *a){
  for (int i=0;i<10;i++)
        for (int j=0;j<5;j++)
             *a++=0;
                        }

void printmatrix(int *a){
               printf("\n   [0]  [1]  [2]  [3]  [4]");
  for (int i=0;i<10;i++){
               printf("\n[%d]",i);
        for (int j=0;j<5;j++)
             printf("%2d   ",*a++);
                        }
             printf("\n");
                        }

int main(int argc, char* argv[])
{
int a[10][5];      //pole intov
int ((*ptr)[5]);   //smernik na pole 5 int - riadok
ptr=&a[0];

resetmatrix(*a);
**     ptr        =1;
ptr++;
**     ptr        =2;
ptr=&a[0];
*    *(ptr+2)     =3;
*(  (*(ptr+3))+1) =4;
*(  (  ptr[4])+2) =5;
       ptr[5][3]  =6;
    (*(ptr+6))[4] =7;

printmatrix(*a);


char pause=getchar();

        return 0;
}
Ak si zadefinujem ptr ako smerník na pole piatich intov (teda riadok), je ľahké si všimnúť, že to veľmi pripomína samotné a. Áno a je smerník presne takého istého typu ako novo vytvorený ptr. Ako je to možné? Však a má byť smerník na celé dvojrozmerné pole a ptr má byť smerník iba na riadok. Tu len treba dávať pozor čo to a vlastne je. a je adresa prvého prvku (dvojrozmerného) poľa. A čo sú prvky tohto (jednorozmerného) poľa? Zas len polia (teda riadky) No a práve preto, že a udáva adresu kde je začiatok poľa, ktorého prvkami sú polia (riadky), a je zároveň smerníkom na riadok. a teda udáva adresu kde je uložené (dvojrozmerné) pole, ale nie je smerníkom na toto (dvojrozmerné) pole. Je to preto, lebo dvojrozmerné polia neexistujú. a je teda smerníkom na pole, ktorého prvky sú polia (riadky)
Definovať si v takomto prípade smerník na riadok, nemá veľmi zmysel (ak som mal v pláne uľahčiť si pohyb po poli), pretože je to rovnocenné so smerníkom a.

Samozrejme, že si môžem definovať aj smerník na samotný int, a pohybovať sa pomocou neho, ale ani toto nemá nejaký zvláštny význam. (aspoň ma teraz nenapadá) Zväčšovaním tohoto smerníka by som sa totiž posúval po jednotlivých objektoch (dvojrozmerného) poľa, a nemal by som možnosť "skákať" po riadkoch.

Konštantnosť smerníkov na polia

#include "stdio.h"

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

int a[10];
int *ptr;
ptr=a;

*ptr=1;  ptr++;
*ptr=2;  ptr++;
*ptr=3;
printf ("\n %d %d %d",a[0],a[1],a[2]);

*a=4;
// a++;    //CHYBA
*(a+1)=5;
*(a+2)=6;
printf ("\n %d %d %d",a[0],a[1],a[2]);

char pause=getchar();

        return 0;
}
Oplatí sa napísať malú poznámku, že aj keď meno poľa možno používať ako smerník, jedná sa o konštantný smerník. Teda nemožno ho meniť. (čo je pochopiteľné, začiatok poľa sa nemôže posúvať...)

(Troška násilný) Úvod do nesymetrických polí

Pod nesymetrickým poľom si (aspoň ja) predstavujem pole, ktorého prvky nemajú rovnaký typ. Vytvoriť pole povedzme n prvkov, z ktorých prvý bude char, druhý int, tretí float, štvrtý trieda, piaty funkcia... je zjavne chaos, a nie len že sa to nedá (neviem to :), ale ani to podľa mňa nemá význam.
Problém poľa nerovnakých prvkov by sa dal vyriešiť tak, že jednotlivé prvky by som reprezentoval ako smerníky. Teda by som si vytvoril pole smerníkov, pričom smerník1 by ukazoval na char, smerník2 na int, smerník3 na float... Ale to by tiež nešlo :) Pole totiž musí mať všetky svoje prvky rovnakého typu...
Povedzme teda, že všetky prvky poľa budú smerníky na int.
Pri poliach sa ukázalo, že keď definujem pole 10 intov, tak jeho meno predstavuje smerník na (jeden) int. Konkrétne ten, ktorý je v poli uložený ako prvý (teda index nula). Zaujímavé je, že ak definujem pole 20 intov, tak jeho meno predstavuje opäť smerník na (jeden) int. Pri poliach všeobecne platí, že ich meno je zároveň smerníkom na typ prvkov poľa. Počet prvkov poľa pri tom nehrá žiadnu úlohu.
Teda je možné urobiť takto pole, ktorého prvý prvok bude pole x prvkov, jeho druhý riadok pole y prvkov a riadok n bude pole z prvkov. Jediná podmienka je, aby prvky boli rovnakého typu.
#include "stdio.h"

int main(int argc, char* argv[])
{
int Arr1[5]={11,12,13,14,15};
int Arr2[3]={21,22,23};
int Arr3[7]={31,32,33,34,35,36,37};

// a teraz jednotlive smerniky dat do pola
// Budem potrebovat pole 3 smernikov

int *Array[3];
//aj ked maju smerniky smerovat na polia, ja ich nasmerujem len na inty

Array[0]=Arr1;
Array[1]=Arr2;
Array[2]=Arr3;

printf("\nPristup pomocou smernika\n");
for (int i=0;i<5;i++)
        printf("%02d ",*(*(Array)+i));printf("\n");
for (int i=0;i<3;i++)
        printf("%02d ",*(*(Array+1)+i));printf("\n");
for (int i=0;i<7;i++)
        printf("%02d ",*(*(Array+2)+i));printf("\n");
printf("\nPristup pomocou indexov a smernika\n");
for (int i=0;i<5;i++)
        printf("%02d ",*(Array[0]+i));printf("\n");
for (int i=0;i<3;i++)
        printf("%02d ",*(Array[1]+i));printf("\n");
for (int i=0;i<7;i++)
        printf("%02d ",*(Array[2]+i));printf("\n");
printf("\nPristup pomocou indexov\n");
for (int i=0;i<5;i++)
        printf("%02d ",Array[0][i]);printf("\n");
for (int i=0;i<3;i++)
        printf("%02d ",Array[1][i]);printf("\n");
for (int i=0;i<7;i++)
        printf("%02d ",Array[2][i]);printf("\n");

char pause=getchar();

        return 0;
}
Toto síce funguje, ale je to dosť krkolomné. Najhoršie na tomto riešení je to, že to funguje staticky. V podstate sú to len tri statické polia, ktoré som dal dokopy prostredníctvom poľa smerníkov. Ešte aj Array, čo je pole samotné je statické, a dovoľuje uložiť iba 3 ďalšie polia nerovnakej dĺžky. Nič prevratné...
#include "stdio.h"

const int PocetRiadkov=10;

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

int *Array[PocetRiadkov];

for (int i=0;i<PocetRiadkov;i++)
        Array[i]=new int[i+1];

for (int Riadok=0;Riadok<PocetRiadkov;Riadok++)
        for (int i=0;i<Riadok+1;i++)
             Array[Riadok][i]=(Riadok+1)*(i+1);

for (int Riadok=0;Riadok<PocetRiadkov;Riadok++){
        for (int i=0;i<Riadok+1;i++)
           {printf("%02d ",Array[Riadok][i]);}
              printf("\n");}

for (int i=0;i<PocetRiadkov;i++)delete [] Array[i];

char pause=getchar();

        return 0;
}
Tu si (zas len staticky...) vyhradím pamäť pre pole 10 smerníkov. Jednotlivým smerníkom priradím adresy novovytoverných polí - riadkov, pričom každý riadok má toľko prvkov, ktorý je to riadok (teda prvý riadok, má 1 prvok - je tam trošku problém s tým, že prvý riadok má index 0, preto som musel trošku modifikovať rozsahy cyklov)
Na prvý riadok uložím násobky čísla 1 (konkrétne iba prvý násobok čísla jedna, keďže tento prvý riadok má iba jeden stĺpec)
Na druhom riadku sú násobky čísla 2 (keďže riadok má 2 stĺpce, tak 2 takéto násobky)
Na treťom až desiatom riadku sú potom násobky čísel 3 až 10...
No a na konci programu musím jednotlivé veci, ktorým som dynamicky pridelil pamäť zmazať. Ak vytvorím dynamicky smerník na int
int *a=new int;
zmažem ho pomocou
delete a;
Ak vytvorím dynamicky smerník na pole intov
a=new int[10];
zmažem ho pomocou
delete [] a;

Pôvodne som mal v pláne vytvoriť aj samotný smerník Array ukazujúci na pole smerníkov na jednotlivé riadky, dynamicky, ale akosi sa mi to nepodarilo rozbehať, aj keď viaceré zdroje písali že to ide, aj ako to ide... Dokonca sa mi to zdalo aj rozumné, ale nejak to môj kompilátor nepochopil... Zápis
int **Array = new (int*)[PocetRiadkov];
teda neviem prečo nefunguje. Ak to raz vyriešim, dopíšem to aj tu...

(c) Wray 2006