Strukture podataka i algoritmi 1

SPA1 - Vežbe 8

Pokazivači na strukture

Mogu se definisati pokazivači na strukture, na isti način kao pokazivači na bilo koji drugi tip promenljive.

Na primer, ako imamo strukturu POINT definisanu na sledeći način:

typedef struct point {
    int x, y;
} POINT;

Možemo da definišemo promenljivu point_pok koja predstavlja pokazivač na podatak koji je tipa strukture POINT:

POINT *point_pok;

Pokazivaču na strukturu, kao i svim pokazivačima, se može dodeliti vrednost adrese neke promenljive koja je tipa POINT:

POINT s1;
POINT *point_pok = &s1;

Elementima strukture se može prisupiti preko pokazivača korišćenjem operatora -> na sledeći način:

point_pok->x = 10;

Drugi način za pristup elementu strukture preko pokazivača je (*point_pok).x, ali ovaj način se mnogo ređe koristi.

Primer sa promenom vrednosti

Potrebno je da definišemo funkciju koja će omogućiti korisniku promenu polja strukture tipa POINT, koju ćemo proslediti kao argument funkcije.

Pogrešno:

#include <stdio.h>

typedef struct point {
    int x, y;
} POINT;

void get_point_wrong(POINT p) { // nova lokalna promenljiva vidljiva samo u ovoj funkciji (kopija strukture a)
    printf("x = ");
    scanf("%d", &p.x);  // pristupamo poljima kopije
    printf("y = ");
    scanf("%d", &p.y);
    printf("get_point_wrong:\n"); 
    printf("x = %d, y = %d\n", p.x, p.y);
}

int main() {
    POINT a = {0, 0};
    printf("get_point_wrong\n");
    get_point_wrong(a);     // šaljemo vrednost stukture a
    printf("main:\n"); 
    printf("x = %d, y = %d\n", a.x, a.y);
}

Ispravno:

#include <stdio.h>

typedef struct point {
    int x, y;
} POINT;

void get_point(POINT *p) {  // argument je pokazivač, prosleđujemo adresu
    printf("x = ");
    scanf("%d", &p->x); // direktno pristupamo poljima strukture a
    printf("y = ");
    scanf("%d", &p->y);
    printf("get_point:\n"); 
    printf("x = %d, y = %d\n", p->x, p->y);
}

int main() {
    POINT a = {0, 0};
    printf("get_point\n");
    get_point(&a);      // šaljemo adresu strukture a
    printf("main:\n"); 
    printf("x = %d, y = %d\n", a.x, a.y);
}

Učitavanje strigova sa standardnog ulaza

#include <stdio.h>

int main() {
    char str1[100], str2[100], str3[100];
    
    printf("Unesite string koristeci fgets: ");
    fgets(str1, sizeof(str1), stdin);  // Učitavanje stringa sa standardnog ulaza koristeći fgets
    printf("Uneti string koristeci fgets: %s", str1);
    
    printf("Unesite string koristeci scanf: ");
    scanf("%s", str2);  // Učitavanje stringa sa standardnog ulaza koristeći scanf
    printf("Uneti string koristeci scanf: %s", str2);
    
    printf("Unesite string koristeci gets: ");
    gets(str3);  // Učitavanje stringa sa standardnog ulaza koristeći gets
    printf("Uneti string koristeci gets: %s", str3);
    
    return 0;
}

Potpisi funkcija su:

String.h

String.h je biblioteka za rad sa stringovima u C programskom jeziku. Kako bismo mogli da je koristimo, potrebno je da je uključimo u kod pomoću #include <string.h>.

Neke od važnijih funkcija ove biblioteke su:

*Napomena: Odnosi se na leksikografsko poređenje dva stringa. To je način poređenja nizova gde se redom upoređuju karakteri na istom položaju u nizovima. Ako se naiđe na karaktere koji se razlikuju, a na istoj su poziciji, karakter sa većom ASCII vrednošću smatra se većim stringom.

Ostale funkcije biblioteke možete pogledati ovde.

Unije

Unije su složeni tipovi podataka koji omogućavaju da se u isti memorijski prostor, u različitim trenucima, smeštaju podaci različitih tipova.

Unije se difinišu naredbom union.

Za razliku od struktura, kod kojih sva polja imaju definisanu vrednost, kod unije samo jedno polje u datom trenutku ima definisanu vrednost, polje kome je posljednje dodeljena vrednost.

Svi članovi unije dele istu memorijsku lokaciju. Unija zauzima dovoljno memorije za najveći član unije.

#include <stdio.h>
#include <string.h>

union Data {
    int i;
    float f;
    char str[20];
};

int main() {
    union Data data;

    printf("Union size: %ld bytes\n", sizeof(data));

    data.i = 10;
    printf("Integer value: %d\n", data.i);

    data.f = 220.5;
    printf("Float value: %f\n", data.f);
    //printf("Integer value: %d\n", data.i);    // ako pokušamo da pristupimo polju i, dobićemo neočekivanu vrednost jer unija u jednom trenutku može čuvati vrednost samo jednog polja
    strcpy(data.str, "Hello");
    printf("String value: %s\n", data.str);

    return 0;
}

Veličina strukture i unije

Veličina strukture predstavlja zbir bajtova svih članova strukture.

Veličina unije predstavlja veličinu najvećeg člana unije.

#include <stdio.h>

typedef struct {
    int a,b;
    char *c;
    double d[2];
} STRUKTURA; // velicina ove strukture ce biti 32 bajta
// sizeof(int) = 4
// sizeof(double) = 8
// sizeof(char*) = 8
// 2 * sizeof(int) + sizeof(char*) + 2 * sizeof(double) = 32

typedef union {
    int a,b;
    char *c;
    double d[2];
} UNIJA; // velicina ove strukture ce biti 16 bajta
// max(sizeof(int), sizeof(int), sizeof(char*), 2 * sizeof(double)) = 16
// staticki alociran niz se posmatra kao jedna promenljiva
// velicina unija je maksimalna velicina svih promenljivih

int main() {
    printf("sizeof(STRUKTURA) = %ld\n", sizeof(STRUKTURA));
    printf("sizeof(UNIJA) = %ld\n", sizeof(UNIJA));

    return 0;
}