30
STRUKTURE PODATAKA I ALGORITMI 1 Pokazivači i nizovi

05 Pokazivaci i Nizovi

Embed Size (px)

DESCRIPTION

05 Pokazivaci i Nizovi

Citation preview

  • STRUKTURE PODATAKA I ALGORITMI 1Pokazivai i nizovi

  • POKAZIVAI I ADRESEDobijanje adrese nekog objekta (operator &)p = &c;/* p pokazuje na c */

    Operator & se primenjuje samo na objekte u memorijiPristupanje objektu na koji pokaziva pokazuje (operator *, operator dereferenciranja)int x = 1, y = 2, z[10];int *ip;/* ip je pokazivac na int */

    ip = &x;/* ip sada pokazuje na x */y = *ip;/* y je sada 1 */*ip = 0;/* x je sada 0 */ip = &z[3];/* ip sada pokazuje na z[3] */

  • Deklaracija pokazivaaint *ip;double *dp, atof(char *);Ako ip pokazuje na celobrojnu promenljivu, onda se *ip moe koristiti u svakom kontekstu u kome se koristi ceo broj*ip = *ip + 10;Unarni operatori & i * imaju vii prioritet od aritmetikih operatoray = *ip + 1;*ip += 1;++*ip;(*ip)++;Pokazivai su takoe promenljive, pa se mogu koristiti i bez dereferenciranjaq = p; *q=*p;

  • POKAZIVAI I ARGUMENTI FUNKCIJAPozvana funkcija ne moe direktno da promeni promenljivu u funkciji koja je pozivaPrimer: Funkcija koja menja mesta dvema promenljivamaswap(x,y);...void swap(int a, int b) /* POGRESNO*/{int temp;

    temp = a;a = b;b = temp;}

  • Promena se moe postii slanjem pokazivaa na promenljive koje treba promenitiswap(&x, &y);...void swap(int *pa, int *pb) /* zamena *pa i *pb */{int temp;

    temp = *pa;*pa = *pb;*pb = temp;}

    Shematski prikaz prosleivanja pokazivaa funkciji

  • POKAZIVAI I NIZOVIU C-u postoji jaka veza izmeu pokazivaa i nizova Deklaracijaint a[10];definie niz a veliine 10, odnosno niz od 10 uzastopnih celih brojeva [0], a[1], ..., a[9].

    Shematski prikaz niza a u memoriji raunara.

    Notacija a[i] ukazuje na i-ti element niza.

  • Ukoliko je p pokaziva na ceo broj, deklarisan kaoint *p;onda linijap = &a[0];postavlja pokaziva p da pokazuje na nulti element niza a (indeksi nizova u C-u poinju od nule), ili drugaije reeno pokaziva p sadri adresu elementa a[0].

    Pokaziva p pokazuje na nulti element niza a

  • Sada linijax = *p;dodeljuje promenljivoj x vrednost elementa a[0].Ukoliko pokaziva p pokazuje na odreeni element niza, po definiciji p+1 pokazuje na sledei element, p+i pokazuje na i-ti element iza p, a p-i pokazuje na i-ti element ispred p. Tako, ukoliko p pokazuje na a[0], onda*(p+1)predstavlja sadraj elementa a[1], a*(p+i)sadraj elementa a[i].

    Pristupanje elementima niza pomou pokazivaa

  • Indeksiranje nizova i aritmetika pointera su veoma bliski.Po definiciji, naziv niza je upravo adresa nultog elementa niza. Zbog toga nakon izvrenja linijep = &a[0];p i a imaju jednake vrednosti, tako da prethodna linija moe biti napisana i kaop = a;a[i] se moe napisati kao *(a+i)Ukoliko primenimo operator & na oba ova oblika, dobijamo da je &a[i] isto to i a+i, tj. adresa i-tog elementa niza.Slino vai i za pokaziva p, pa je p[i] isto to i *(p+i).Postoji razlika izmeu pokazivaa i nizovap=a i p++ je dozvoljenoa=p i a++ nije dozvoljeno

  • Kada se funkciji prosleuje naziv niza, ono to se zapravo alje je adresa nultog elementa.Unutar pozvane funkcije ovaj argument je lokalna promenljiva, a parametar koji predstavlja niz je pokaziva, odnosno promenljiva koja sadri adresu nultog elementa niza.Posmatrajmo funkciju za odreivanje duine stringa (niza karaktera):/* duzina: vraca duzinu stringa s */int duzina(char *s){int n;

    for(n = 0; *s != '\0'; s++)n++;

    return n;}

    ...

    duzina("Zdravo, drugari!");/* konstantan string */duzina(niz);/* char niz[100]; */duzina(pok);/* char *pok */

  • U definiciji funkcija dozvoljeno je deklarisanje formalnih parametara na oba naina; i kao niza i kao pokazivaa.Deklaracijechar s[]ichar *ssu ekvivalentne.Funkciji je mogue proslediti i deo nekog niza tako to bi joj se prosledio pokaziva na podniz. Tako, ukoliko je a niz, pozivifun(&a[5]);ifun(a+5);prosleuju funkciji fun podniz koji poinje od petog elementa niza a.

  • ADRESNA ARITMETIKAAko je p pokaziva na neki element niza, tada p++ uveava p tako da pokazuje na naredni elementp+=1 uveava p tako da pokazuje na element koji se nalazi i elemenata iza onog na koji trenutno p pokazujeako pokazivai p i q pokazuju na lanove istog niza, onda se mogu primeniti operatori ==, !=, , =p < qje tano ukoliko p pokazuje na element koji je ispred onog na koji pokazuje qp+n pokazuje na n-ti objekat iza onog na koji pokazuje p, bez obzira tip objekata

  • PRIMER: FUNKCIJE ZA ALOKACIJU MEMORIJEalloc(n) obezbeuje memoriju za n uzastopnih znakovnih pozicija i vraa pokaziva na prvi lan tog nizaafree(p) oslobaa memoriju koja je na ovaj nain rezervisana i na koju pokazuje pokaziva pfunkcije afree se moraju pozivati u suprotnom redosledu od onog u kojima je pozivana funkcija alloc

  • #define ALLOCSIZE 10000 /* size of available space */

    static char allocbuf[ALLOCSIZE]; /* storage for alloc */static char *allocp = allocbuf; /* next free position */

    char *alloc(int n) /* return pointer to n characters */{if (allocbuf + ALLOCSIZE - allocp >= n) /* it fits */{ allocp += n;return allocp - n; /* old p */}else /* not enough room */return 0;}

    void afree(char *p) /* free storage pointed to by p */{if (p >= allocbuf && p < allocbuf + ALLOCSIZE)allocp = p;}

  • PRIMER: FUNKCIJA STRLEN/* strlen: return length of string s */int strlen(char *s){char *p = s;

    while (*p != '\0')p++;

    return p - s;}

    Dozvoljene operacije sa pokazivaima:-dodeljivanje pokazivaa istog tipa-sabiranje i oduzimanje pokazivaa i celog broja-oduzimanje i poreenje dva pokazivaa-dodeljivanje nule pokazivau i njegovo poreenje sa nulom

    Nije dozvoljeno:-sabiranje, mnoenje i deljenje dva pokazivaa-pomeranje i maskiranje po bitovima-dodavanje brojeva tipa float i double pokazivaima-dodeljivanje pokazivaa jednog tipa pokazivau drugog tipa bez eksplicitne konverzije(osim za void*)

  • ZNAKOVNI POKAZIVAI I FUNKCIJE"Ja sam string" je string konstantaprintf("hello, world\n");

    char *pmessage;pmessage = "now is the time";

    char amessage[] = "now is the time"; /* niz */char *pmessage = "now is the time"; /* pokaziva */

  • PRIMER: FUNKCIJA STRCPYFunkcija strcpy(s,t) kopira string t u string sVerzija sa nizovima/* strcpy: copy t to s; array subscript version */void strcpy(char *s, char *t){int i;

    i = 0;while ((s[i] = t[i]) != '\0') i++;}Verzija sa pokazivaima/* strcpy: copy t to s; pointer version */void strcpy(char *s, char *t){int i;

    i = 0;while ((*s = *t) != '\0') {s++;t++;}}

  • Iskusni C programeri bi napisali/* strcpy: copy t to s; pointer version 2 */void strcpy(char *s, char *t){while ((*s++ = *t++) != '\0');}

    Ili jo krae/* strcpy: copy t to s; pointer version 3 */void strcpy(char *s, char *t){while (*s++ = *t++);}

  • PRIMER: FUNKCIJA STRCMPFunkcija strcmp(s,t) poredi stringove s i t i vraa negativnu vrednost, nulu ili pozitivnu vrednost u zavisnosti od toga da li je s leksikografski ispred, jednako ili iza tVerzija sa nizovima/* strcmp: return t */int strcmp(char *s, char *t){int i;

    for (i = 0; s[i] == t[i]; i++)if (s[i] == '\0')return 0;

    return s[i] - t[i];}

  • Verzija sa pokazivaima/* strcmp: return t */int strcmp(char *s, char *t){for ( ; *s == *t; s++, t++)if (*s == '\0')return 0;return *s - *t;}

  • NIZOVI POKAZIVAA; POKAZIVAI NA POKAZIVAEPokazivai su promenljive, pa se i oni mogu uvati u nizovima.Primer: Sortiranje redova teksta po abecednom redu

    proitati sve redove ulaznog tekstasortirati ihprikazati ih po redu

  • #include #include

    #define MAXLINES 5000 /* maksimalan broj linija koje se mogu sortirati*/

    char *lineptr[MAXLINES]; /* pokazivai na linije teksta */int readlines(char *lineptr[], int nlines);

    void writelines(char *lineptr[], int nlines);void sort(char *lineptr[], int nlines);

    /* sortiranje linija sa ulaza */main(){int nlines; /* broj uitanih linija */

    if ((nlines = readlines(lineptr, MAXLINES)) >= 0){sort(lineptr, nlines);writelines(lineptr, nlines);return 0;}else{printf("greska: suvise veliki broj linija\n");return 1;}}

  • #define MAXLEN 1000 /* maksimalna duzina linije */

    int getline(char *, int);char *alloc(int);

    /* readlines: ucitava redove sa ulaza */int readlines(char *lineptr[], int maxlines){int len, nlines;char *p, line[MAXLEN];

    nlines = 0;while ((len = getline(line, MAXLEN)) > 0)if (nlines >= maxlines || p = alloc(len) == NULL)return -1;else{line[len-1] = '\0'; /* brisanje znaka za novi red */strcpy(p, line);lineptr[nlines++] = p;}

    return nlines;}

  • /* writelines: ispisivanje linija teksta */void writelines(char *lineptr[], int nlines){int i;

    for (i = 0; i < nlines; i++)printf("%s\n", lineptr[i]);}

    ili ovako

    /* writelines: ispisivanje linija teksta */void writelines(char *lineptr[], int nlines){while (nlines-- > 0)printf("%s\n", *lineptr++);}

  • /* sort: sortira niz v u rastucem redosledu */void sort(char *v[], int nlines){int i, j;char *temp;void swap(char *v[], int i, int j);

    for(i = 0; i < n-1; i++)for(j = i+1; j < n; j++)if( strcmp(v[i],v[j]) > 0 ){temp = v[i];v[i] = v[j];v[j] = temp;}}

  • VIEDIMENZIONALNI NIZOVIPrimer: Konverzija dana u mesecu u dan u godini i obratnofunkcija day_of_year pretvara mesec i dan u dan u godinifunkcija month_day pretvara dan u u godini u mesec i dan

    static char daytab[2][13] = {{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};

    /* day_of_year: set day of year from month & day */int day_of_year(int year, int month, int day){int i, leap;

    leap = year%4 == 0 && year%100 != 0 || year%400 == 0;

    for (i = 1; i < month; i++)day += daytab[leap][i];

    return day;}

  • /* month_day: set month, day from day of year */void month_day(int year, int yearday, int *pmonth, int *pday){int i, leap;

    leap = year%4 == 0 && year%100 != 0 || year%400 == 0;for (i = 1; yearday > daytab[leap][i]; i++)yearday -= daytab[leap][i];

    *pmonth = i;*pday = yearday;}

  • Pisanje indeksadaytab[i][j]/* ispravno */daytab[i,j]/* pogresno */

    Prenoenje viedimenzionalnih nizova funkcijif(int daytab[2][13]) { ... }Ili ovakof(int daytab[][13]) { ... }a poto je broj redova nebitan, moe se napisati i ovakof(int (*daytab)[13]) { ... }to znai da je parametar pokaziva na niz od 13 celih brojeva.Zagrade su neophodne zato to uglaste zagrade [] imaju vei prioritet od operatora *. Bez zagrada bi se dobila sledea deklaracijaint *daytab[13]to bi predstavljalo niz od 13 pokazivaa na tip int.

  • INICIJALIZACIJA NIZOVA POKAZIVAAPrimer: Funkcija koja vraa naziv meseca u godini/* month_name: return name of n-th month */char *month_name(int n){static char *name[] = {"Illegal month","January", "February", "March","April", "May", "June","July", "August", "September","October", "November", "December"};

    return (n < 1 || n > 12) ? name[0] : name[n];}

  • POKAZIVAI ILI VIEDIMENZIONALNI NIZOVI?int a[10][20];int *b[10];

    char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };

    char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };