Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 30

STRUKTURE PODATAKA I ALGORITMI 1

Pokazivai i nizovi
POKAZIVAI I ADRESE
Dobijanje adrese nekog objekta (operator &)
p = &c; /* p pokazuje na c */



Operator & se primenjuje samo na objekte u memoriji
Pristupanje 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 pokazivaa
int *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 operatora
y = *ip + 1;
*ip += 1;
++*ip;
(*ip)++;
Pokazivai su takoe promenljive, pa se mogu koristiti i bez
dereferenciranja
q = p; *q=*p;
POKAZIVAI I ARGUMENTI FUNKCIJA
Pozvana funkcija ne moe direktno da promeni promenljivu u funkciji
koja je poziva
Primer: Funkcija koja menja mesta dvema promenljivama
swap(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 promeniti
swap(&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 NIZOVI
U C-u postoji jaka veza izmeu pokazivaa i nizova
Deklaracija
int 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 kao
int *p;
onda linija
p = &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 linija
x = *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 linije
p = &a[0];
p i a imaju jednake vrednosti, tako da prethodna linija moe biti
napisana i kao
p = 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 nizova
p=a i p++ je dozvoljeno
a=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.
Deklaracije
char s[]
i
char *s
su ekvivalentne.
Funkciji je mogue proslediti i deo nekog niza tako to bi joj se
prosledio pokaziva na podniz. Tako, ukoliko je a niz, pozivi
fun(&a[5]);
i
fun(a+5);
prosleuju funkciji fun podniz koji poinje od petog elementa niza a.

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

PRIMER: FUNKCIJE ZA ALOKACIJU MEMORIJE
alloc(n) obezbeuje memoriju za n uzastopnih znakovnih pozicija i
vraa pokaziva na prvi lan tog niza
afree(p) oslobaa memoriju koja je na ovaj nain rezervisana i na
koju pokazuje pokaziva p
funkcije 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 konstanta
printf("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 STRCPY
Funkcija strcpy(s,t) kopira string t u string s
Verzija 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 STRCMP
Funkcija 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 t
Verzija sa nizovima
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>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 <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
{
for ( ; *s == *t; s++, t++)
if (*s == '\0')
return 0;

return *s - *t;
}

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





proitati sve redove ulaznog teksta
sortirati ih
prikazati ih po redu
#include <stdio.h>
#include <string.h>

#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 NIZOVI
Primer: Konverzija dana u mesecu u dan u godini i obratno
funkcija day_of_year pretvara mesec i dan u dan u godini
funkcija 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 indeksa
daytab[i][j] /* ispravno */
daytab[i,j] /* pogresno */

Prenoenje viedimenzionalnih nizova funkciji
f(int daytab[2][13]) { ... }
Ili ovako
f(int daytab[][13]) { ... }
a poto je broj redova nebitan, moe se napisati i ovako
f(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 deklaracija
int *daytab[13]
to bi predstavljalo niz od 13 pokazivaa na tip int.


INICIJALIZACIJA NIZOVA POKAZIVAA
Primer: 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" };

You might also like