int main() {
int v = 100;
int *pt1 = &v; // pokazivač na int
int **pt2 = &pt1; // pokazivač na pokazivač na int
printf("v = %d, &v = %p \n", v, &v);
printf("pt1 = %p, &pt1 = %p, *pt1 == v = %d \n", pt1, &pt1, *pt1);
printf("pt2 = %p, &pt2 = %p, *pt2 == pt1 = %p, **pt2 == *pt1 == v = %d", pt2, &pt2, *pt2, **pt2);
return 0;
}
Pokazivač na pokazivač može biti koristan ako je potrebno promeniti vrednost (adresu) nekog pokazivača u nekoj funkciji.
Pokazivač na int (na primer) možemo da koristimo da u nekoj funkciji menjamo vrednost nekog int-a ili niza int-ova iz neke druge funkcije.
Pokazivač na pokazivač na int možemo da koristimo u nekoj funkciji ako je potrebno promeniti vrednost pokazivača na int, niza pokazivača na int ili matrice int-ova (videćete u nastavku).
Matricu možemo da alociramo dinamički tako što ćemo prvo alocirati niz pokazivača, a zatim za svaki član tog niza alocirati npr. niz int-ova. Ako alociramo matricu na ovaj način, onda ne mora da znači da će vrste biti susedni blokovi u memoriji, kao što je to značilo prilikom statičke alokacije matrice.
#include <stdio.h>
#include <stdlib.h>
int** alocirajMatricu(int m, int n) {
// m i n su dimenzije matrice, gde je m broj vrsta a n broj kolona
int **matrix = malloc(m * sizeof(int*)); // niz od m pokazivača na int
for (int i = 0; i < m; i++)
matrix[i] = malloc(n * sizeof(int)); // za svaki clan niza pokazivaca alociamo niz od n int
return matrix;
}
Prilikom alociranja matrice, slično kao i prilikom alociranja niza, je preporučljivo da proveravate da li ste dobili NULL ili neku adresu. Ako ste dobili NULL potrebno je da ispišete neku poruku od grešci i pozovete funkciju exit sa parametrom 1 (ovako: exit(1);), kako bi program završio izvršavanje jer nema potrebe da radi neki posao ako nije uspeo da dobije memoriju koja mu je potrebna za taj posao.
U slučaju da ne proveravate da li ste dobili adresu ili NULL, najverovatnije ćete dobiti adresu jer u skoro svim slučajevima ima dovoljno memorije, a na kolokvijumu nećete skoro nikada da alocirate neku mnogo veliku količinu memorije.
Uvek oslobađajte memoriju koju ste rezervisali kada vam više nije potrebna. Kada oslobađate memoriju koju ste alocirali za matricu, prvo oslobađate sve vrste tj. sve članove niza pokazivača, pa tek na kraju niz pokazivača.
#include <stdio.h>
#include <stdlib.h>
void oslobodiMatricu(int **matrix, int m) {
for (int i = 0; i < m; i++)
free(matrix[i]);
free(matrix);
}
Pokazivač na funkciju u jeziku C je promenljiva koja sadrži adresu neke funkcije. Korišćenjem pokazivača na funkciju možemo dinamički odabrati koja funkcija će se izvršiti u određenom trenutku iz programa. Ovo je korisno u situacijama kada želimo da prosledimo funkciju kao argument drugoj funkciji, da omogućimo dinamičko preusmeravanje poziva funkcija ili implementiramo callback funkcije. Evo osnovnih karakteristika i upotreba pokazivača na funkciju:
Deklaracija: Pokazivač na funkciju se deklariše specifičnim sintaksom koja odgovara potpisu funkcije koju pokazivač može pokazivati. Na primer, int (*ptr)(int, int);
deklariše pokazivač na funkciju koja prima dva argumenta tipa int
i vraća rezultat tipa int
.
Inicijalizacija: Pokazivač na funkciju se može inicijalizovati dodeljivanjem adresi neke funkcije koja ima odgovarajući potpis. Na primer, ptr = &add;
, gde je add
funkcija koja odgovara potpisu int add(int, int);
.
Pozivanje funkcije preko pokazivača: Funkcija se može pozvati korišćenjem pokazivača na funkciju, upotrebljavajući sintaksu kao i poziv standardne funkcije. Na primer, int result = ptr(2, 3);
ili int result = (*ptr)(2, 3);
.
Prosleđivanje kao argument: Pokazivač na funkciju se može proslediti kao argument drugoj funkciji, što omogućava dinamičko preusmeravanje poziva funkcija ili implementiranje callback funkcija. Na primer, void process(int (*func_ptr)(int, int));
.
Pokazivači na funkciju su moćan alat u jeziku C koji omogućava veću fleksibilnost i dinamičko ponašanje programa. Međutim, važno je koristiti ih pažljivo i biti siguran da se pravilno koriste, posebno kada se koriste u kombinaciji sa argumentima funkcija ili callback funkcijama, kako bi se izbegle greške u toku izvršavanja programa.
Do sada ste pisali programe gde je potpis funkcije main bio int main()
. Funkcija main može da ima i sledeći potpis: int main(int argc, char *argv[])
.
argv je niz stringova (nizova karaktera). argc je dužina niza argv.
Kako se prosleđuju ovi parametri funkcije main?
Ako kompajliramo fajl koji se zove test.c
u kome se nalazi kod:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf( "BROJ ARGUMENATA=%d\n\n", argc );
for( int i = 0; i < argc; i++)
printf("%d.ARGUMENT=%s\n", i, argv[i] );
}
koristeći komandu gcc -o test test.c
, dobićemo izvršni fajl test
.
Prilikom pokretanja fajla test
možemo mu proslediti argumente, koji će se čuvati u nizu stringova argv, na sledeći način:
./test argument1 argument2 3 argument4
Ovi argumenti se nazivaju argumentima komandne linije.
Rezultat izvršavanja ove komande je:
BROJ ARGUMENATA=5
0.ARGUMENT=./test
1.ARGUMENT=argument1
2.ARGUMENT=argument2
3.ARGUMENT=3
4.ARGUMENT=argument4
Argument sa indeksom 0 tj. prvi argument će uvek biti naziv izvršnog fajla.
Ove funkcije pretvaraju stringove u brojeve.