Professional Documents
Culture Documents
C++ Nizovi PDF
C++ Nizovi PDF
Nizovi i pokazivai
Naglasci:
Jednodimenzionalni nizovi
Dvodimenzionalni nizovi
Nizovi objekata
Ekvivalentnost pokazivake i indeksne notacije nizova
Operacije s pokazivaima
Pokazivai na funkcije
Dinamiko alociranje nizova
Prihvat iznimki kod alociranja memorije
Kompleksnost deklaracija varijabli i funkcija
8.1 Nizovi
Jednodimenzionalni nizovi
Niz je imenovana i numerirana kolekcija istovrsnih objekata koje zovemo elementi niza. Elementi
niza mogu biti proste skalarne varijable i korisniki definirani objekti . Oznaavaju se imenom niza i
cjelobrojnom izrazom indeksom - koji oznaava poziciju elementa u nizu. Indeks niza se zapisuje u
uglatim zagradama iza imena niza. Primjerice, x[3] oznaava element niza x indeksa 3. Sintaksa
zapisa elementa jednodimenzionalnog niza je
Prvi element niza ima indeks 0, a n-ti element ima indeks n-1. Prema tom pravilu, x[3] oznaava
etvrti element niza.
S elementima niza se manipulira kao s obinim skalarnim varijablama ili objektima, ovisno o nainu
kako je izvrena deklaracija niza. Sintaksa deklaracije jednodimenzionalnog niza je:
deklaracija_niza:
oznaka_tipa ime_niza [ konstantni_izraz ] ;
Primjerice, deklaracijom
int data[9];
definira data kao niz od 9 elementa tipa int.
Elementi niza data su dostupni, ako je indeks definiran izrazom koji rezultira cijelim brojem iz
intervala od 0 do 8, npr.
data[0]
8. Nizovi i pokazivai 1
data[2+3] = data[0];
int x=5;
data[x] = 7;
memorija
adresa sadraj
1000 data[0]
1004 data[1]
1008 data[2]
Elementi niza zauzimaju sukscesivne lokacije u 1012 data[3]
memoriji. 1016 data[4]
1020 data[6]
Vrijedi pravilo
1024 data[5]
adresa(data[n])=adresa(data[0]) + n*sizeof(data[0])) 1028 data[7]
1032 data[8]
Deklaracijom niza se rezervira potrebna memorija, ali se ne vri se i inicijalizacija poetnih vrijednosti
elemenata niza. Za inicijalizaciju niza esto se koristi for petlja, pr.
int i, data[10];
for (i = 0; i < 10; i++)
data[i] = 0;
Niz se moe inicijalizirati i s deklaracijom slijedeeg tipa:
int data[9]= {1,2,23,4,32,5,7,9,6};
gdje se unutar vitiastih zagrada navodi lista konstanti.
Ako se inicijaliziraju svi potrebni elementi niza, tada nije nuno u deklaraciji navesti dimenziju niza.
Primjerice
int data[]= {1,2,23,4,32,5,7,9,6};
je potpuno ekvivalentno prethodnoj deklaraciji. Broj elemenata ovakovog niza uvijek moemo dobiti
naredbom:
int numelements = sizeof(data)/sizeof(int);
Niz se moe i parcijalno inicajalizirati. U deklaraciji
int data[10]= {1,2,23};
prva tri elementa imaju vrijednost 1,2,23, a ostale elemente kompajler postavlja na vrijednost nula.
Primjer: Histogram
2 3 4 5 6 7 2 4 7 8 9 1 3 4 6 9 8 7 2 5 6 7 8 9
3 4 5 1 7 3 4 10 10 9 10 5 7 6 3 8 9 4 5 7 3 4 6 1
2 9 6 7 8 5 4 6 3 2 4 5 6 1 3 4 6 9 10 7 2 10 7 8 1
8. Nizovi i pokazivai 2
Treba izraditi program imena hist.cpp pomou kojeg e se prikazati histogram ocjena u 10 grupa (1,
2,.. 10).
/* datoteka: hist.cpp */
#include <iostream>
using namespace std;
int main(void)
{
int i, counts[10], ocjena;
10 *****
9 *******
8 ******
7 **********
6 *********
5 *******
4 **********
3 ********
2 ******
1 *****
Pazite: Pri pozivu programa u komandnoj liniji je sa hist < ocjene.dat izvreno
preusmjerenje standardnog ulaza. Efekt preusmjeravanja je da se sadraj datoteke
ocjene.dat tretira kao da je unesen sa standardnog ulaza.
8. Nizovi i pokazivai 3
Prvo se deklarira niz count od 10 elemenata
int i, counts[10], ocjena; tipa int.
for (i = 0; i < 10; i++) Pomou for petlje vrijednost elemenata niza
counts[i] = 0; inicijalizira se na vrijednost 0.
while (cin >> ocjena) Oitava se ocjena i inkrementira odgovarajui
{ element niza counts; cin vraa vrijednost EOF
if(ocjena <1 || ocjena >10)
break;
kada se oita znak za kraj datoteke -EOF (ako je
counts[ocjena-1]++; unos s tipkovnice znak EOF se unosi s Ctrl-Z
} <enter>)
// datoteka: histf.cpp
void record( int ocjena, int counts[]) Kada se jednodimenzionalni niz pojavljuje u
{ deklaraciji ili definiciji funkcije, tada se ne
counts[ocjena-1]++;
navodi dimenzija niza.
}
Uoimo de se vrijednost elemenata niza
void printstars(int n) moe mijenjati unutar funkcije. Oito je da se
{ niz ne prenosi po vrijednosti (by value), jer
while (n-- > 0) tada to ne bi bilo mogue.
cout << '*';
cout << '\n'; Pravilo je:
}
Nizovi se u funkciju prenose kao
void printhistogram(int counts[]) memorijske reference (by reference).
{ Kompajler memorijsku referencu (adresu)
for (int i = 10; i > 0; i--) { niza pamti "u njegovom imenu" stoga se
cout << i << '\t'; pri pozivu funkcije navodi samo ime, bez
printstars(counts[i-1]);
}
uglatih zagrada.
}
int main(void)
{
int ocjena;
8. Nizovi i pokazivai 4
int counts[10] = {0};
Viedimenzionalni nizovi
Viedimenzionalnim nizovima se pristupa preko dva ili vie indeksa. Npr. deklaracijom:
int x[3][4];
definira se dvodimenzionalni niz koji ima 3 x 4 = 12 elemenata. Deklaraciju se moe itati i ovako:
definiran je niz kojem su elementi 3 niza od 4 elementa tipa int.
Elementima se pristupa preko dva indeksa. U slijedeem primjeru pokazano je kako se dobije suma
svih elemenata matrice x;
int i, j, num_rows=3, num_cols=4;
int sum=0;
for (i = 0; i < num_rows; i++)
for (j = 0; i < num_cols; j++)
sum += x[i][j];
cout << "suma elemenata matrice = " << sum;
memorija
adresa sadraj
U C jeziku dvodimenzionalni nizovi, koji opisuju matrice, u
memoriji su sloeni po redovima matrice. Najprije prvi 1000 x[ 0][ 0]
redak, zatim drugi, itd.. 1004 x[ 0][ 1]
1008 x[ 0][ 2]
U radu s matricama nije potrebno razmiljati kako je niz
1012 x[ 0][ 3]
sloen u memoriji, jer se elementima pristupa preko dva 1016 x[ 1][ 0]
indeksa: prvi je oznaka redka, a drugi je oznaka stupca 1020 x[ 1][ 1]
matrice. 1024 x[ 1][ 2]
matrini prikaz 1028 x[ 1][ 3]
1032 x[ 2][ 0]
x[0][0] x[0][1] x[0][2] x[0][3] 1036 x[ 2][ 1]
x[1][0] x[1][1] x[1][2] x[1][3] 1040 x[ 2][ 2]
1044 x[ 2][ 3]
x[2][0] x[2][1] x[2][2] x[2][3]
8. Nizovi i pokazivai 5
Pri deklariranju argumenta funkcije koji su viedimenzionalnih nizovi takoer se ne navodi prva
dimenzija, ali ostale dimenzije treba deklarirati, kako bi kompajler znao kojim su redom elementi
sloeni u memoriji.
Primjer, definirajmo funkciju kojom se rauna suma elemenata dvodimenzionalne matrice:
int sum_mat_el(int x[][4], int nrows, int ncols)
{
int i, j, sum=0;
for (i = 0; i < nrows; i++)
for (j = 0; i < ncols; j++)
sum += x[i][j];
return sum;
}
Uoimo, da su u definiciji funkcije navedeni i parametri nrows i ncols koji opisuju broj redaka i
stupaca matrice. Oito je da ovo nije ba najbolji nain za rad s matricama, jer je koritenje ove
funkcije mogue samo za matrice koje imaju 4 stupca. Kasnije emo pokazati kako se moe ova
funkcija modificirati da vrijedi za matrice proizvoljnih dimenzija.
Nizovi objekata
Elementi niza mogu biti bilo kojeg tipa ukljuujui i objekte definirane nekom klasom (strukturom).
Primjerice, deklaracijom
Counter counts[10];
deklarira se niz od 10 objekata tipa Counter. Ovakovi oblik deklaracije podrazumijeva da kompajler
uz rezerviranje potrebne memorije izvri i poziv predodreenog konstruktora za svaki element niza.
lanskim funkcijama objekata pristupa se pomou toka operatora, primjerice s
counts[3].get_count()
dobije se vrijednost izbroja brojaa koji je etvrti u nizu counts. Primjer primjene niza brojaa dan je
u datoteci hist-obj.cpp. Pokazano je da se problem izrade histograma moe elegantno rijeiti
koritenjem klase Counter.
// datoteka: hist-obj.cpp
// realizacija histograma pomou klase Counter
#include <iostream>
#include <counter.h> // specifikacija brojaa
void printstars(int n)
{
while (n-- > 0)
cout << '*';
cout << '\n';
}
8. Nizovi i pokazivai 6
cout << i << '\t';
printstars(counts[i-1].get_count());
}
}
int main(void)
{
int ocjena;
Counter counts[10];
counts[ocjena-1]++; counts[ocjena-1].incr_count();
printstars(counts[i-1]); printstars(counts[i-1].get_count());
Prva je razlika u deklaraciji. Kod niza s primitivnim cjalobrojnim tipom potrebno je eksplicitno
inicirati sve elemente na vrijednost nula, dok primjenom klase brojaa tu funkciju obavlja
predodreeni konstruktor klase. Zatim slijede dvije razlike zbog razliitog naina pristupa elementima
niza. Oito je da e se verzija s klasom Counter neto sporije izvravati, jer se funkcija incr_count()
sporije izvrava od prostog inkrementiranja cjelobrojne varijable. S druge strane gledano, verzija s
klasom Counter je razumljivije napisana, i moe se jasnije, bez posebnih programskih komentara,
shvatiti o emu se radi.
Ovaj posebni sluaj zapravo ukazuje na injenicu da se objektno-zasnovani programi esto sporije
izvravaju nego se to moe postiu programiranjem niske razine u C jeziku. esto se govori da
objektno zasnovani programi imaju overhead odnosno da izvravaju vie instrukcija nego bi se to
moglo postii programiranjem niske razine. Kod veih programa ovaj overhead nije znaajan jer se
poveanjem apstrakcije, koju omoguava objektno programiranje, dobijaju elegantnija i sigurnija
rjeenja, a nerijetko i bre izvrenje programa, nego je to mogue s klasinim proceduralnim
programiranjem.
8. Nizovi i pokazivai 7
esto e se koristiti iskazi oblika:
int a[10], i, x;
int *p, *pi;
1. Ime niza ima se tretira se kao "pokazivaka konstanta" koja predstavlja adresu prvog elementa
niza. Naredba
p = a;
vrijednost pokazivaa p postavlja na adresu elementa a[0]. Ovo je ekvivalentno naredbi:
p = &a[0];
Ime niza napisano bez zagrada predstavlja pokaziva na prvi element. Stoga, ako je deklariran niz
array[], tada izraz *array oznaava prvi element, *(array + 1) oznaava drugi element, itd.
Poopimo li ovo pravilo na cijeli niz array, vrijede slijedei odnosi:
*(array) array[0]
*(array + 1) array[1]
*(array + 2) array[2]
...
*(array + n) array[n]
S pokazivaima se takoer moe koristiti indeksna notacija. Tako, ako je inicijaliziran pokaziva p:
p = array;
tada vrijedi:
p[0] *p array[0]
p[1] *(p + 1) array[1]
p[2] *(p + 2) array[2]
...
p[n] *(p + n) array[n]
8. Nizovi i pokazivai 8
int *p = a;
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++)
cout << *p++ << endl; cout << a[i] << endl;
U oba se sluaja tiska iste vrijednosti niza. Obje petlje su jednako efikasne i prihvatljive u
programiranju.
Primjer: obje funkcije print imaju isto djelovanje i mogu se pozvati s istim argumentima:
void print(int x[], int size) void print( int *x, int size)
{ {
for (int i = 0; i < size; i++) while (size-- > 0)
cout << x[i] << endl; cout << *x++ << endl;
} }
/* poziv funkcije print */
int niz[10], size=10;
. . . . .
print(niz, size);
Ponovimo:
Pokazivai zauzimaju sredinje mjesto u oblikovanju C programa, posebno kada se radi s
nizovima.
Pokazivai i nizovi su u specijalnom odnosu. Ime niza, napisano bez uglatih zagrada
predstavlja pokazivaku konstanu koja predstavlja adresu prvog elementa niza.
Indeksna notacija ima ekvivalentni oblik pokazivake notacije. Uglate zagrade moemo
tretirati kao indeksni operator, jer kada se koriste iza imena pokazivaa, uzrokuju da se tim
pokazivaem moe operirati kao s nizom.
Nizovi se prenose u funkciju na nain da se u funkciju prenosi pokaziva na prvi element niza
(odnosno adresa niza). Poto funkcija zna adresu niza, u njoj se moe koristiti naredbe koje
mijenjaju sadraj elemenata niza bilo u indeksnoj ili u pokazivakoj notaciji.
Funkcija ne raspolae s podatkom o broju elemenata niza. Zadatak je programera da tu
vrijednost, ukoliko je potrebna, predvidi kao parametar funkcije.
Pazi !
Pokazivau se pridjeljuju adrese int *p, i;
p = i; //greka
p = &i; // ispravno
Pokazivau se indirekcijom moe pridijeliti samo int *p;
odgovarajui tip float x;
8. Nizovi i pokazivai 9
p = &x; // greka
Operator indirekcije se primjenjuje samo na pokazivake p = *i; i = *p; ?
varijable
Pokazivai moraju biti inicijalizirani na realnu adresu p = &i;
podataka, u suprotnom moe doi do pisanja po p = 5; //greka
programskoj memoriji
cout << *p;
Pazi da ne koristi NULL pokaziva! Zato? p = NULL; p = &i;
to je upisano na NULL adresi? *p = 6;
sizeof(oznaka_tipa)*izraz
Podrazumijeva sa da izraz mora rezultirati prirodnim brojem. Ako se alokacija izvri uspjeno, adresa
alocirane memorije se pridjeljuje pokazivakoj_varijabli. Ako se ne moe izvriti alokacija uspjeno
pokazivakoj_varijabli se pridjeljuje vrijednost 0 (NULL) ili se vri poziv funkcije za prihvat iznimki
(taj sluaj e biti pojanjen kasnije).
Primjerice, s
int n = 10;
float * A= new float[n];
alocira se memorija za n elemenata tipa float. Adresa te memorije se pridjeljuje pokazivau A.
Pomou tog pokazivaa pristupamo elementima niza na isti nain kako bi to radili sa statiki
alociranim nizovima. Primjerice, petljom
for (int i = 0; i < n; i++)
{
A[i] = i * i;
}
elementi niza dobijaju vrijednost Ai=i2.
Nakon zavrenog rada s nizom, odnosno kada se izlazi iz bloka u kojem je niz alociran, niz treba
dealocirati.
U naem sluaju dealociranje se vri naredbom delete [] A;. Nakon dealokacije vrijednost
pokazivaa je neodreena.
8. Nizovi i pokazivai 10
//datoteka: dynamicArray.cpp
#include <iostream.h>
using namespace std;
int main()
{
int n; // Broj elemenata niza
float *A; // Pokaziva niza
// A[i] = i^2.
for (int i = 0; i < n; i++)
A[i] = i * i;
// Dealokacija niza.
delete [] A;
return 1;
}
Primjer ispisa:
Unesite broj elemenata niza? 7
A[0] == 0
A[1] == 1
A[2] == 4
A[3] == 9
A[4] == 16
A[5] == 25
A[6] == 36
Ime funkcije, napisano bez zagrada predstavlja adresu funkcije, pa se pridjelom vrijednosti:
pF = F;
(*pF)(lista_argumenata);
8. Nizovi i pokazivai 11
ili jo jednostavnije, sa
pF(lista_argumenata);
jer, oble zagrade predstavljaju operator poziva funkcije (kompajler sam vri indirekciju pokazivaa,
ako se iza njega napiu oble zagrade).
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double val=1;
char choice;
double (*pFunc)(double);
8. Nizovi i pokazivai 12
{
case '1': pFunc = Kvadrat; break;
case '2': pFunc = sin; break;
case '3': pFunc = cos; break;
default: return 0;
}
PrintVal (pFunc, val);
return 0;
}
Sada je naredba
x = (*pF[1])(3.14) ekvivalentna naredbi x= cos(3.14).
/* program: niz-pfun.c
* koristenje niza pokazivaca na funkciju
*/
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double val=1;
int izbor;
Promotrimo program:
#include <iostream>
using namespace std;
8. Nizovi i pokazivai 13
int main()
{
char* p = new char[1000000000];
2. Kada se primijeni GNU gcc kompajler (ver.3), izvrenje programa e biti prekinuto ve pri
izvrenju prve naredbe s porukom:
"This application has requested the Runtime to terminate it in an unusual
way."
Nedostatak slobodne memorije, je iznimna situacija, pa je ostavljeno da se taj sluaj obradi posebnim
mehanizmom koji se naziva "exception handler". Njega emo upoznati kasnije.
Prema novom ISO standardu iz 1988. godine, koji je implementiran u gcc kompajleru ver. 3, izraz
alokacije ne pokree mehanizam iznimki (ne prekida se program) ve se vraa NULL pokaziva,
samo u sluaju ako se alokacija izvri tako da se koristi new operator s dodatnim argumentom imena
nothrow, primjerice:
char* p = new (nothrow) char[1000000000];
Argument nothrow je tipa nothrow_t, koji predstavlja praznu klasu, a deklariran je u <new.h>.
C++ run-time sistem osigurava da se aktivira funkcija za prihvat greke koja nastaje pri alokaciji
memorije. Tu funkciju se moe redefinirati na sljedei nain:
1. Funkcija za prihvat greke ima prototip bez parametara i bez povrata vrijednosti, primjerice
moe se koristiti funkcija:
void no_memory()
{
cerr << "operator new: nema slobodne memorije\n";
exit(1);
}
koja e dojaviti da nema slobodne memorije i prekinuti izvrenje programa.
8. Nizovi i pokazivai 14
#include <iostream>
#include <new>
void no_memory()
{
cerr << "operator new: nema slobodne memorije\n";
exit(1);
}
int main()
{
set_new_handler(no_memory);
8. Nizovi i pokazivai 15
S desne strane identifikatora mogu biti uglate ili oble zagrade.
Ako su uglate zagrade itamo : identifikator je niz ,
ako su oble zagrade itamo identifikator je funkcija.
Ukoliko ima vie operatora s desne strane nastavljamo itanje po istom pravilu.
Zatim analiziramo zapis s lijeve strane identifikatora ( tu moe biti operator indirekcije i oznaka tipa).
Ako postoji operator indirekcije itamo: identifikator je (... desna strana) pokaziva na tip.
Ako postoji dvostruki operator indirekcije itamo: identifikator je (... desna strana)
pokaziva na pokaziva tip
Ukoliko je dio deklaracije napisan u zagradama onda se najprije ita znaaj zapisa u zagradama.
Primjerice, u deklaraciji
T (*x[n])(double);
najprije se ita dio deklaracije (*x[n]) koji znai da je x niz pokazivaa. Poto je iza ovog izraza s
desne strane (double) znai da je x niz pokazivaa na funkciju koja prima argument tipa double i
koja vraa tip T.
/* program: niz-pfun1.c
* koristenje niza pokazivaca na funkciju
*/
#include <iostream>
#include <cmath>
using namespace std;
8. Nizovi i pokazivai 16
int main()
{
double val=1;
int izbor;
t_pFdd pF[3] = {Kvadrat, sin, cos};
8. Nizovi i pokazivai 17
8.7 ASCIIZ string
Do sada smo radili s nizovima znakova u obliku tekstualnih konstanti koje smo zvali literalni string
("Hello World!"). Cilj nam je da nizove znakova tretiramo kao varijable. Na taj nain moi emo vriti
obradu tekstualnih zapisa.
Najprije emo upoznati kako se manipulira stringom u C jeziku. Funkcije C- jezika tretiraju string kao
za memorijski objekt koji sadri niz znakova, uz uvjet da posljednji znak u nizu mora biti jednak nuli.
Nula na kraju stringa se koristi kao oznaka kraja stringa. Primjerice, u stringu koji sadri tekst:
Hello, World!, indeks nultog znaka je 13, to je jednako duljini stringa. Ovaj string u memoriji
zauzima 14 bajta.
0 1 2 3 4 5 6 7 8 9 0 1 2 3
'H' 'e' 'l' 'l' 'o' ', ' ' ' 'W' 'o' 'r' 'l' 'd' '!' '\0'
Prema ovoj definiciji ASCIIZ string je svaki niz koji se deklarira kao:
niz znakova (npr. char str[10];) , ili kao
pokaziva na znak (char *str;),
pod uvjetom da se pri inicijalizaciji niza, i kasnije u radu s nizom uvijek vodi rauna o tome da
poljednji element niza mora biti jednak nuli.
//Datoteka; hello2.cpp
//Prvi C++ program - drugi put.
#include <iostream>
#include <cstring> // deklaracija funkcije strlen
using namespace std;
int main()
{
char hello[14] = { 'H', 'e', 'l', 'l', 'o', ',', ' ',
'W', 'o', 'r', 'l', 'd', '!', '\0' };
cout << hello << endl;
cout << "Duljina stringa je " << strlen(hello) << endl;
return 0;
}
Hello, World!
Duljina stringa je 13.
8. Nizovi i pokazivai 18
Ovaj program vri istu funkciju kao i na prvi C-program, tiska poruku: Hello, World!. Prvo je
definirana i inicijalizirana varijabla hello. Ona je tipa znakovnog niza od 14 elemenata.
Inicijalizacijom se u prvih 13 elemenata upisuju znakovi (Hello World), posljednji element se inicira
na nultu vrijednost. Ispis ove varijable . Za ispis duljine stringa koritena je standardna funkcija
size_t strlen(char *s);
koja vraa vrijednost duljine stringa. Kao argument funkcija prihvaa vrijednost pokaziva na char,
odnosno adresu poetnog elementa stringa. (size_t je sinonim za unsigned).
1.verzija:
Primjer:
//Datoteka; hello3.cpp
//Prvi C++ program - drugi put.
#include <iostream>
using namespace std;
int main()
{
char hello[] = "Hello, world!";
cout << hello << endl;
cout << "Duljina stringa je " << strlen(hello) << endl;
cout << "Zauzece memorije je" << sizeof(hello)*sizeof(char)
<< " bajta" << endl;
return 0;
}
8. Nizovi i pokazivai 19
Nakon izvrenja programa, dobije se poruka:
Hello, World!
Duljina stringa je 13
Zauzece memorije je 14 bajta
hello[0] = 'h';
hello[6] = 'w';
Ako se procjenjuje da e trebati vie mjesta za string, nego se to navodi inicijalnim literalnim
stringom, tada treba eksplicitno navesti dimenziju stringa. Deklaracijom,
char hello[50] = "Hello, World!";
kompajler rezervira 50 mjesta u memoriji te inicira prvih 14 elemenata na "Hello, World!", zakljuno s
nultim znakom.
Slijedea dva primjera pokazuju rad s stringovima. Bit e opisano kako se mogu napisati standardne
funkcije za kopiranje stringa (strcpy) i usporedbu dva stringa (strcmp).
Funkcija strcpy kopira znakove stringa src u string dest, a vraa adresu od dest.
1. Verzija s nizovima:
char *strcpy( char dst[], char src[])
{
int i;
for (i = 0; src[i] != \0; i++)
dst[i] = src[i];
dst[i] = \0;
return dst;
}
2. Verzija s pokazivakim varijablama
char *strcpy(char *dest, const char *src)
{
char *dp = dest;
while((*dp++ = *src++) != '\0') // kopira se i \0
; /*prazna naredba*/
return dest;
}
8. Nizovi i pokazivai 20
/*1. verzija*/
int strcmp( char s1[], char s2[])
{
int i = 0;
while(s1[i] == s2[i] && s1[i] != \0)
i++;
if (s1[i] < s2[i])
return -1;
else if (s1[i] > s2[i])
return +1;
else
return 0;
}
Najprije se u for petlji usporeuje da li su znakovi s istim indeksom isti i da li je dostignut kraj niza
(znak '\0'). Kad petlja zavri, ako su oba znaka jednaka, to znai da su i svi prethodni znakovi jednaki.
U tom sluaju funkcija vraa vrijednost 0. U suprotnom funkcija vraa 1 ili 1 ovisno o numerikom
kodu znakova koji se razlikuju.
/*2. verzija*/
int strcmp(char *s1, char *s2)
{
for(; *s1 == *s2; s1++, s2++)
{
if(*s1 == '\0')
return 0;
}
return *s1 - *s2;
}
Verzija s pokazivaima predstavlja optimiranu verziju prethodne funkcije. Uoite da se u u for petlji
ne koristi izraz inicijalizacije petlje. Najprije se usporeuju znakovi na koje pokazuju s1 i s2. Ako su
znakovi isti inkrementira se vrijednost oba pokazivaa. Tijelo petlje e se izvriti samo u sluaju ako
su stringovi isti (tada da s1 i s2 konano pokazuju na znak '\0'). U suprotnom petlja se prekida, a
funkcija vraa numeriku razliku ASCII koda znakova koji se razlikuju.
8. Nizovi i pokazivai 21
Dodaje najvie n znakova stringa t na string s, i znak '\0'; vraa s.
int strcmp(const char *s, const char *t)
Usporeuje string s sa stringom t, vraa <0 ako je s<t, 0 ako je s==t, ili >0 ako je s>t.
Usporedba je leksikografska, prema ASCII "abecedi".
int strncmp(const char *s, const char *t, size_t n)
Usporeuje najvie n znakova stringa s sa stringom t; vraa <0 ako je s<t, 0 ako je s==t,
ili >0 ako je s>t.
char *strchr(const char *s, int c)
Vraa pokaziva na prvu pojavnost znaka c u stringu s, ili NULL znak ako c nije sadran u
stringu s.
char *strrchr(const char *s, int c)
Vraa pokaziva na zadnju pojavnost znaka c u stringu s, ili NULL znak ako c nije sadran u
stringu s.
char *strstr(const char *s, const char *t)
Vraa pokaziva na prvu pojavu stringa t u stringu s, ili NULL ako string s ne sadri string t.
size_t strspn(const char *s, const char *t)
Vraa duljinu prefiksa stringa s koji sadri znakove koji ine string t.
size_t strcspn(const char *s, const char *t)
Vraa duljinu prefiksa stringa s koji sadri znakove koji nisu prisutni u stringu t.
char *strpbrk(const char *s, const char *t)
Vraa pokaziva na prvu pojavu bilo kojeg znaka iz string t u stringu s, ili NULL ako nije
prisutan ni jedan znak iz string t u stringu s.
char *strerror(int n)
Vraa pokaziva na string kojeg interno generira kompajler za dojavu greke u nekim
sistemskim operacijama. Argument je obino globalna varijabla errno, iju vrijednost takoer
postavlja kompajler pri sistemskim operacijama.
char *strtok(char *s, const char *sep)
strtok je funkcija kojom se moe izvriti razlaganje stringa na niz leksema koji su
razdvojeni znakovima-separatorima. Skup znakova-separatora se zadaje u stringu sep.
Funkcija vraa pokaziva na leksem ili NULL ako nema leksema.
Koritenje funkcije strtok je specifino jer u strigu moe biti vie leksema, a ona vraa pokaziva na
jedan leksem. Da bi se dobili sljedei leksemi treba ponovo zvati istu funkciju, ali s prvim
argumentom jednakim NULL. Primjerice, za string
char * s = "Prvi drugi,treci";
ako odaberemo znakove separatore: razmak, tab i zarez, tada sljedeim iskazi daju ispis tri leksema
(Prvi drugi i treci):
char *leksem = strtoken(s, " ,\t"); /* dobavi prvi leksem */
while( leksem != NULL) { /* ukoliko postoji */
printf("", leksem); /* ispii ga i */
lexem = strtok(NULL, " ,\t"); /* dobavi sljedei leksem */
} /* pa ponovi postupak */
8. Nizovi i pokazivai 22