Tražio sam po net-u dosta pa sam našao ove stranice:
Uff, ne znam kako točno da ti ovo jednostavno objasnim. Ampersand tu možeš i izostaviti, jer i sa njime i bez njega dobiješ istu stvar.
Počnimo redom. Što je pokazivač? To je varijabla koja sadrži u sebi neku brojčanu vrijednost. Ta vrijednost je u biti memorijska adresa nečega. Ali kako su memorijske adrese brojčane vrijednosti sa njima možeš vršiti računske operacije kao i sa integerima. A pošto su pokazivači varijable to znači da i oni imaju svoju memorijsku adresu.
Polje je niz nečega u memoriji. To je agregatni tip koji se sastoji od skupa više vrijednosti, baš kao i struktura. No polje se u nekim situacijama ponaša kao pokazivač (za razliku od struktura). Npr. gdje god se ime polja spominje u programu, to ime će biti zamjenjeno adresom prvog elementa tog polja (kao da radiš sa vrijednosti pokazivača). Ako polje pokušaš proslijediti funkciji kao argument, u biti ćeš proslijediti memorijsku adresu prvog elementa tog polja, ako iskoristiš "&" operator, također ćeš dobiti memorijsku adresu prvog elementa tog polja. Strukture su drukčije, ako strukturu proslijediš funkciji kao argument, ti doslovno vrijednosti cijele strukture šalješ toj funkciji (pass by value), a ako upotrijebiš operator "&" onda ćeš funkciji proslijediti samo memorijsku adresu te strukture.
Dinamički alocirana polja su nešto posve drugo. To u biti nisu polja, nego blokovi memorije koji mogu biti tretirani kao polja. Takvim blokovima se pristupa preko pokazivača (tada pokazivač sadrži početnu adresu alociranog bloka memorije).
Gdje se polja i pokazivači susreću (što im je zajedničko)? U aritmetici sa pokazivačima. I na jednima i na drugima možeš koristiti iste operatore kako bi došao do nekih elemenata:
int A[20];
int *B=(int*) malloc(20*sizeof(int));
A[2]=200;
B[2]=200;
printf("%d %d\n", A[2], B[2]);
*(A+2)=66;
*(B+2)=66;
printf("%d %d\n", A[2], B[2]);
U ovom primjeru možeš vidjeti polje od 20 integera nazvano "A", i pokazivač koji pokazuje na alocirani blok memorije velicine 20 integera (20*sizeof(int)), nazvan "B".
I polje i pokazivač možemo tretirati kao polje koristeći operator subskripta elementa "[]", te pomoću tog operatora postavimo vrijednost trećeg elementa na 200 (ovo je primjer gdje se pokazivač tretira kao polje).
I polje i pokazivač možemo tretirati kao memorijske adrese, pa ih dereferencirati kako bi aritmetikom pokazivača postavili vrijednost memorije na određenoj adresi na 66 (ta memorijska adresa se u ovom primjeru poklapa sa adresom drugog elementa polja).
A gdje se polja i pokazivači razilaze?
Hajdemo im obojima pokušati uvećati vrijednost:
A+=2;
B+=2;
Ne može. Kompajler ne želi kompajlirati jer tvrdi da "A" nije varijabla koja ima jednu vrijednost, nego je skup vrijednosti (elemenata). "B" s druge strane ima jednu jedinu vrijednost koju možeš mijenjati kako god ti drago. Dakle naučili smo da elemente polja možemo mijenjati, ali ono što se krije iza tog polja se ne može mijenjati.
Da vidimo u čemu se još razlikuju, hajdemo im ispisati vrijednost i adresu:
printf("0x%x 0x%x\n", A, &A);
printf("0x%x 0x%x\n", B, &B);
Interesantno, "A" u oba načina daje adresu svojeg prvog elementa, "B" je drukčiji. On prvo ispiše svoju vrijednost (to jest memorijsku adresu na koju pokazuje), a pomoću operatora "&" dobijemo adresu same varijable "B".
Pokušati dobiti veličinu:
printf("%d\n", sizeof(A));
printf("%d\n", sizeof(B));
Opa, veličina polja "A" je 80 (20 puta po 4 bajta za svaki integer), ali veličina pokazivača "B" je 4 (na 32 bitnom računalu memorijske adrese su velike 32 bita, odnosno 4 bajta), dakle nismo dobili veličinu alociranog bloka memorije nego veličinu same varijable.
Ukratko, naletio si na jednu malo manje jasnu stranu C jezika (ako se dobro sjećam bila je i velika rasprava baš o tome ovdje na forumu edit: dobro se sjećam).
http://c-faq.com/aryptr/aryptrequiv.html
To je u standardu pokriveno ovom rečenicom:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
Polje iz primjera koji si ti linkao je "pravo" polje, ti u svom programu nemaš polje nego pokazivač na blok memorije koji koristiš kao polje. Polje ti u oba slučaja da adresu prvog elementa polja (praktički ne možeš fulati), dok ti pokazivač ili može dati adresu na koju pokazuje, ili svoju vlastitu adresu.
Nadam se da ti je ovaj post koji se pretvorio u esej objasnio malo u čemu su pokazivači i polja slični, a u čemu se razlikuju. Često o tome ne moraš razmišljati, ali ponekad se opečeš ako ih jednostavno poistovjetiš.
E za ovo moraš malo zabrazditi u C++ i MFC. Frajer stvara objekt "data" klase CArray, koji sadrži polje u kojemu je svaki element pokazivač na foo. Dakle ima polje od kojih je svaki element pokazivač. Njemu funkcija qsort proslijedi pokazivač na taj element, što je u biti pokazivač na pokazivač.
Kod tebe svaki element polja nije pokazivač na strukturu, nego struktura. A funkcija qsort ti onda proslijedi pokazivač na taj element, odnosno dobiješ pokazivač na strukturu.
Kužiš sada razliku?