Strukture podataka i algoritmi 1

SPA1 - Vežbe 7

Pokazivač na pokazivač

pokazivac na pokazivac

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).

Matrica i pokazivači

matrica i pokazivaci

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či na funkcije

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:

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.

Argumenti komandne linije i parametri funkcije main

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.

Funkcije atoi i atof

Ove funkcije pretvaraju stringove u brojeve.

atoi zvanična dokumentacija
atof zvanična dokumentacija