Uvod u programski jezik C (7. deo)
Autor: Stefan Nožinić
Strukture
Struktura u programskom jeziku C označava kompleksan tip podataka koji u sebi sadrži blok od nekoliko primitivnih tipova podataka kao što su integer i char. Ovde je potrebno napomenuti da struktura može sadržati i pokazivače, što će nam kasnije biti korisno kada budemo videli konkretnu primenu struktura. Ovakvi tipovi se definišu ključnom reči struct na sledeći način:
struct A // A je naziv strukture { int a; bool b; char c; }
Ovde smo definisali strukturu pod nazivom A, koja se sastoji od tri primitivne promenljive: celobrojna promenljiva (integer), promenljiva koja određuje logičko stanje (boolean) i promenljiva koja može sadržati jedan karakter (char).
Ovim primitivnim promenljivama pristupamo na sledeći način:
A.a = 1; A.b = true; A.c = 'h';
Kao što možemo videti, ovde se radi o dodeli vrednosti. Potrebno je napomenuti da ne moraju sve promenljive date strukture da imaju dodeljene vrednosti.
Sledi konkretan primer upotrebe strukture koja predstavlja kompleksan broj. Ovakvi brojevi imaju dva dela: realni i imaginarni deo. U našem primeru ćemo za oba dela koristiti double tip podataka, kako bismo mogli predstaviti brojeve koji nisu celi.
#includestruct Complex { double real; double imaginary; } void main(void) { struct Complex c; c.real = 2.0; c.imaginary = 1.41; // ... ispis vrednosti ide ovde }
Primećujete da prilikom definisanja nove promenljive tipa naše strukture moramo koristiti struct Complex a ne samo Complex. Ovo je moguće prevazići upotrebom typedef naredbe na sledeći način:
typedef struct Complex { double real; double imaginary; } Complex;
Sada je moguće definisati našu promenljivu koja nam predstavlja kompleksan broj na sledeći način:
Complex c;
Liste
Lista je jedna konkretna primena struktura. Lista je struktura podataka koja se razlikuje od niza time što je dinamička. To znači da se njena veličina može menjati tokom izvršavanja programa dok smo kod nizova imali slučaj da prilikom definicije niza moramo odrediti tačnu njegovu dužinu i ne možemo je posle menjati. Lista ovaj problem prevazilazi na sledeći način – svaki element liste je struktura sa dve promenljive: jedna promenljiva je vrednost datog elementa, a druga promenljiva je pokazivač na sledeći element. Ovo omogućava da elementi liste budu razbacani po memoriji a ne jedni do drugih, što nam omogućava dinamičnost. Kada želimo da dodamo novi element ili da obrišemo postojeći, dovoljno je samo da ga uklonimo iz memorije i da pokazivače njegovog prethodnika postavimo da pokazuju na njegovog sledbenika. Ovakve liste se zovu jednostruko povezane liste, jer se sa jednog elementa može ići samo na sledeći element i ne može se ići na prethodni.
Sledi primer definicije strukture koja predstavlja element liste:
typedef struct Element { int value; struct Element* next; } Element;
Po definiciji, vidimo da struktura Element ima dve promenljive, jedna je tipa integer koja predstavlja vrednost elementa (mogu biti i drugi tipovi podataka, prim. aut.), a druga predstavlja pokazivač na strukturu Element koji je zapravo pokazivač na sledeći element.
Sledeće što nam je potrebno, jeste funkcija za ubacivanje novog elementa u listu i funkcija za brisanje.
Element* insert(Element* e, int a) { Element* new = (Element*) malloc(sizeof(Element)); Element* next = e->next; e.next = new; new->next = next; new->value = a; return new; } void delete(Element* e) { if (e.next != NULL) { Element* next = e->next; Element* nextnext = next->next; e->next = nextnext; free(next); } }
Funkcija insert uzima dve vrednosti kao argumente, prva je element posle kog će biti ubačen novi element, a druga je vrednost za novi element. Ovde je potrebno obratiti pažnju na → operator koji se koristi umesto tačke, ako se pristupa elementima strukture na koju pokazivač pokazuje. Ova funkcija vraća pokazivač na novoubačeni element.
Funkcija za brisanje prvo „razmešta” pokazivače, a potom koristi free poziv kako bi oslobodila memoriju od obrisanog elementa.
Prednost ovakve strukture smo već spomenuli – dinamičnost. Mana ovakve strukture je ta da pristup elementima traje mnogo duže nego što je slučaj kod nizova, jer moramo da se „prošetamo” kroz sve prethodnike datog elementa dok ne dođemo do njega, jer nemamo njegovu adresu unapred u memoriji, kao što je to bio slučaj sa nizovima.
U sledećem broju ćemo pisati o još nekim strukturama i pokazati njihove primene.
Naredni deo ovog serijala možete pročitati ovde.
Prethodni deo ovog serijala možete pročitati ovde.