Upload
tarik-alic
View
230
Download
0
Embed Size (px)
DESCRIPTION
C Program
Citation preview
Osnove računarstva 2015/2016
Čudnovate stvariČudnovate stvari(sve što vam niko nije rekao o (sve što vam niko nije rekao o
pokazivačima i stringovima)pokazivačima i stringovima)
Doc. dr Vedran Ljubović
Univerzitet u SarajevuElektrotehnički fakultet Sarajevo
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 2
Deklaracije stringova
● Koja je razlika između:
char s[10] = "Test";
char s[] = "Test";
char* s = "Test";
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 3
Deklaracije stringova
● Niz od 10 elemenata:
char s[10] = "Test";
... 250 251 252 253 254 255 256 257 258 259 260 ...
... T e s t \0 ...
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 4
Deklaracije stringova
● Niz od 5 elemenata:
char s[] = "Test";
... 250 251 252 253 254 255 256 257 258 259 260 ...
... T e s t \0 ...
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 5
Deklaracije stringova
● Pokazivač na literal:
char* s = "Test";
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 256 T e s t \0 ...
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 6
Deklaracije stringova
● Pokazivač na literal:
char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na
literal.
● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:
printf("%s", spoji(rijec1, spoji(" ", rijec2)));
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 7
Deklaracije stringova
● Pokazivač na literal:
char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na
literal.
● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:
printf("%s", spoji(rijec1, spoji(" ", rijec2)));
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 8
Deklaracije stringova
● Pokazivač na literal:
char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na
literal.
● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:
printf("%s", spoji(rijec1, spoji(" ", rijec2)));
Krahiranje, jerje " " literal
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 9
Deklaracije stringova
● Pokazivač na literal:
char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na
literal.
● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:
printf("%s", spoji(rijec1, spoji(" ", rijec2)));
treba ovako:char razmak[100] = " ";printf("%s", spoji(rijec1, spoji(razmak, rijec2)));
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 10
Višestruki pokazivači
● Dvostruki pokazivač je pokazivač koji pokazuje na pokazivač:
int broj=5;int* p = &broj;int** dp = &p;
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 5 251 254 ...
p dpbroj
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 11
Višestruki pokazivači
● Trostruki pokazivač je pokazivač koji pokazuje na dvostruki pokazivač itd.
int broj=5;int* p = &broj;int** dp = &p;int*** tp = &dp;
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 5 251 259 254 ...
p dpbroj tp
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 12
Da li je niz isto što i pokazivač?
● Ime niza nije isto što i pokazivač na prvi element niza!
● Ali ime niza se po potrebi konvertuje u pokazivač na prvi element niza:
int niz[3];int* p = niz;
● Izuzetak je prototip funkcije gdje int niz[] je zaista isto što i int* niz (samo druga sintaksa).
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 13
Niz pokazivača
● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:
float* niz[10];
● Primjer:
char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 253 257 264 1 9 . \0 J a n u ...
... 261 262 263 264 265 266 267 268 269 270 271 ...
... a r \0 2 0 1 6 . \0 ...
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 14
Niz pokazivača
● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:
float* niz[10];
● Primjer:
char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 253 257 264 1 9 . \0 J a n u ...
... 261 262 263 264 265 266 267 268 269 270 271 ...
... a r \0 2 0 1 6 . \0 ...
Ispisaće: Januar
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 15
Niz pokazivača
● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:
float* niz[10];
● Primjer:
char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 253 257 264 1 9 . \0 J a n u ...
... 261 262 263 264 265 266 267 268 269 270 271 ...
... a r \0 2 0 1 6 . \0 ...
Niz pokazivača "datum"
Ispisaće: Januar
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 16
Niz pokazivača
● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:
float* niz[10];
● Primjer:
char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 253 257 264 1 9 . \0 J a n u ...
... 261 262 263 264 265 266 267 268 269 270 271 ...
... a r \0 2 0 1 6 . \0 ...
Niz pokazivača "datum"
Literali se nalaze"negdje" u memoriji
Ispisaće: Januar
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 17
Niz pokazivača vs. matrica
● Ovako deklarisan niz pokazivača nije isto što i matrica:
char mat[3][10] = {"19.", "Januar", "2016."};printf("%s", mat[1]);
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 1 9 . \0 J ...
... 261 262 263 264 265 266 267 268 269 270 271 ...
... a n u a r \0 2 0 ...
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 18
Niz pokazivača vs. matrica
● Ovako deklarisan niz pokazivača nije isto što i matrica:
char mat[3][10] = {"19.", "Januar", "2016."};printf("%s", mat[1]);
... 250 251 252 253 254 255 256 257 258 259 260 ...
... 1 9 . \0 J ...
... 261 262 263 264 265 266 267 268 269 270 271 ...
... a n u a r \0 2 0 ...
Nema nizapokazivača
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 19
Niz pokazivača vs. matrica
● Ime niza pokazivača konvertuje se u dvostruki pokazivač:
char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);
● Ime matrice se konvertuje u "pokazivač na niz":
char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);
char** dp = mat;
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 20
Niz pokazivača vs. matrica
● Ime niza pokazivača konvertuje se u dvostruki pokazivač:
char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);
● Ime matrice se konvertuje u "pokazivač na niz":
char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);
char** dp = mat;
Upozorenje: initialization from incompatible pointer type
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 21
Niz pokazivača vs. matrica
● Ime niza pokazivača konvertuje se u dvostruki pokazivač:
char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);
● Ime matrice se konvertuje u "pokazivač na niz":
char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);
char** dp = mat;
Upozorenje: initialization from incompatible pointer type
Tip promjenljive ap je"pokazivač na niz od
10 elemenata tipa char"
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 22
Niz pokazivača vs. matrica
● Ime niza pokazivača konvertuje se u dvostruki pokazivač:
char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);
● Ime matrice se konvertuje u "pokazivač na niz":
char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);
char** dp = mat;
Upozorenje: initialization from incompatible pointer type
Tip promjenljive ap je"pokazivač na niz od
10 elemenata tipa char"Takav tip nam je potrebanda bismo znali da je ap+1
za 10 bajta veće od ap
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 23
Niz pokazivača vs. matrica
● Ime niza pokazivača konvertuje se u dvostruki pokazivač:
char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);
● Ime matrice se konvertuje u "pokazivač na niz":
char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);
char** dp = mat;
Upozorenje: initialization from incompatible pointer type
Tip promjenljive ap je"pokazivač na niz od
10 elemenata tipa char"Takav tip nam je potrebanda bismo znali da je ap+1
za 10 bajta veće od ap
Zagrade su potrebnekako bi se razlikovalo
od niza od 10 pokazivača
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 24
Slanje matrice u funkciju
● Kada šaljemo niz u funkciju mi ustvari šaljemo pokazivač na prvi član niza (adresu).
● A kada šaljemo matricu, ustvari šaljemo pokazivač na niz koji predstavlja jedan red matrice.
● Mora se navesti jedna dimenzija matrice!
– Dakle funkcije koje rade sa matricama ne mogu biti potpuno univerzalne.
– Zbog toga radije koristimo nizove pokazivača.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 25
Slanje matrice u funkciju
● Primjer:
#include <stdio.h>int primimatricu(int (*mat)[10], int redova) {
printf("%d", mat[0][0]);}int main() {
int matrica[10][10] = {{15}};primimatricu(matrica, 10);return 0;
}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 26
Parametri funkcije main
● Funkcija main ima dva oblika. Do sada smo uvijek koristili oblik bez parametara. Pored toga postoji oblik sa dva parametra:
int main(int argc, char** argv)
● Svakom programu se mogu poslati parametri putem komandne linije.
● argc je broj parametara, a argv je pokazivač na prvi član niza pokazivača na stringove koji predstavljaju tekst parametara.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 27
Parametri funkcije main
● Primjer:
int main(int argc, char** argv) {int i;printf("Program ima %d parametara.\n", argc);printf("Ti parametri su:\n");for (i=0; i<argc; i++)
printf("%s\n", argv[i]);return 0;
}
● Prvi parametar je uvijek ime samog programa.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 28
Primjer: sortiranje
● Napisati funkciju koja abecedno sortira niz stringova.
– Najprije moramo definisati: da li funkcija prima matricu tipa char ili niz pokazivača tipa char?
– Deklaracija funkcije bi izgledala:void sortiraj(char** niz, int n)
void sortiraj(char(*mat)[100], int n)
● Koristićemo Selection sort koji smo obradili na kraju poglavlja 10.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 29
Primjer: sortiranje
● Selection sort (Predavanje 10):
for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {
if (niz[j] < niz[min])min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 30
Primjer: sortiranje
● Selection sort (Predavanje 10):
for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {
if (niz[j] < niz[min])min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}
Ne možemo ovakoporediti stringove
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 31
Primjer: sortiranje
● Selection sort (Predavanje 10):
for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {
if (niz[j] < niz[min])min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}
Ne možemo ovakoporediti stringove
Dodjela nizova neradi znakom =
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 32
Primjer: sortiranje
● Selection sort (Predavanje 10):
for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {
if (niz[j] < niz[min])min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}
Ne možemo ovakoporediti stringove
Dodjela nizova neradi znakom =
Trebamo koristitifunkcije strcmp
i strcpy
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 33
Primjer: sortiranje
void sortiraj(char** niz, int n) {int i, j, min, temp;for (i=0; i<n; i++) {
min=i;for (j=i+1; j<n; j++) {
if (strcmp(niz[j],niz[min]) < 0)min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 34
Primjer: sortiranje
void sortiraj(char** niz, int n) {int i, j, min, temp;for (i=0; i<n; i++) {
min=i;for (j=i+1; j<n; j++) {
if (strcmp(niz[j],niz[min]) < 0)min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}}
???
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 35
Primjer: sortiranje
● U slučaju niza pokazivača možemo samo razmijeniti pokazivače:
D a n a s \0
j e \0
b i o \0
l i j e p \0
d a n \0
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 36
Primjer: sortiranje
● U slučaju niza pokazivača možemo samo razmijeniti pokazivače:
D a n a s \0
j e \0
b i o \0
l i j e p \0
d a n \0
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 37
Primjer: sortiranje
void sortiraj(char** niz, int n) {int i, j, min; char* temp;for (i=0; i<n; i++) {
min=i;for (j=i+1; j<n; j++) {
if (strcmp(niz[j],niz[min]) < 0)min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 38
Primjer: sortiranje
void sortiraj(char** niz, int n) {int i, j, min; char* temp;for (i=0; i<n; i++) {
min=i;for (j=i+1; j<n; j++) {
if (strcmp(niz[j],niz[min]) < 0)min = j;
}
temp = niz[i];niz[i] = niz[min];niz[min] = temp;
}}
Razmijenili smopokazivače u nizu
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 39
Ključna riječ const
● Pored simboličkih konstanti koje smo deklarisali preprocesorskom direktivom #define postoje i konstante koje se deklarišu tako što prije tipa navede ključna riječ const
const int x=5;● Pošto je x konstantno ne može se mijenjati.
● Ipak treba napomenuti da x iznad ustvari nije konstanta! U programskom jeziku C to je promjenljiva koja se ne može mijenjati direktno (ali može preko pokazivača).
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 40
Usporedba konstanti
● #define konstante se bukvalno zamjenjuju u kodu prije kompajliranja, tako da ne zauzimaju nikakvu memoriju. S druge strane, dobar kompajler će isto napraviti i sa const promjenljivim ako je moguće.
● #define konstante su uvijek globalne, a const imaju opseg.
● #define konstante nemaju eksplicitno definisan tip. Njihov tip ovisi od vrijednosti koja im je dodijeljena.
● #define se ne može promijeniti preko pokazivača.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 41
Konstantni pokazivači
char* const a = s;
● Ovim je deklarisan konstantni pokazivač p koji sada može pokazivati samo na s i ni na šta drugo (ne može se pomjerati).
const char* b = s;
● Pokazivač koji pokazuje na konstantne podatke. Pokazivač se može usmjeriti negdje drugo, ali se ono na šta on pokazuje ne može mijenjati. Primjer:
*a = x; /* Moze */a = &x; /* Ne moze */*b = x; /* Ne moze */b = &x; /* Moze */
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 42
Konstantni pokazivači
const char* const c = s;
● Sa ovakvom deklaracijom ne može se mijenjati ni adresa pohranjena u pokazivaču ni ono što je na toj adresi.
● Pokazivač na konstante podatke se često koristi kada se u funkciju šalje niz ali se želi zabraniti da se niz mijenja u funkciji. Npr.
int dajmax(const int* niz, int vel)
Na ovaj način autori funkcije nas obavještavaju da se u funkciji neće promijeniti članovi niza.
● Ova ograničenja se mogu zaobići konverzijom (cast).
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 43
Konstantni pokazivači
● U nekim kompajlerima možete dobiti upozorenje ako pridružujete string literal pokazivaču koji nije konstantan:
char* s = "Test";
Konkretno ovo se dešava sa C++ kompajlerom. Treba pisati:
const char* s = "Test";
● Također ako očekujete da se funkcija može pozivati sa literalom trebali biste navesti const char* kao tip parametra.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 44
Pokazivači na funkcije
● Moguće je deklarisati pokazivač koji pokazuje na funkciju. To je korisno kako bi se funkciji mogla proslijediti druga funkcija kao parametar.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 45
void pokazivač
● Moguće je definisati pokazivače na sve poznate tipove u C-u, pa i nizove (što smo vidjeli ranije).
● Pored toga moguće je definisati generički pokazivač void* za koji nije poznat tip vrijednosti na koju pokazuje.
void* p;
● Koristi se kada tip nije unaprijed poznat nego će kasnije biti određen.
● Nad void* nije moguće primjenjivati pokazivačku aritmetiku jer se ne može znati za koliko bajta treba pomjeriti pokazivač.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 46
void pokazivač
● Primjer:
void* p;...if (tip == INT_TIP)
printf("%d", *(int*)p);
● Prije upotrebe void* moramo pretvoriti (cast) u neki drugi tip.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 47
void pokazivač
● Primjer:
void* p;...if (tip == INT_TIP)
printf("%d", *(int*)p);
● Prije upotrebe void* moramo pretvoriti (cast) u neki drugi tip.
Konvertujemo upokazivač na int
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 48
void pokazivač
● Primjer:
void* p;...if (tip == INT_TIP)
printf("%d", *(int*)p);
● Prije upotrebe void* moramo pretvoriti (cast) u neki drugi tip.
Tako dobiveni pokazivač dereferenciramo kako bismo
dobili cijeli broj
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 49
Dinamička alokacija memorije
● Kako da dobijemo niz stvarno proizvoljne veličine? Pomoću dinamičke alokacije!
● Funkcija za dinamičku alokaciju je malloc i nalazi se u biblioteci stdlib.h
● Funkcija ima jedan parametar – broj bajta koliko treba zauzeti u memoriji, a vraća void pokazivač na zauzetu memoriju.
– Npr. ako nam treba niz od 10 vrijednosti tipa int, potrebno nam je 40 bajta.
– Da bi kod radio na različitim platformama pišemo 10*sizeof(int)
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 50
sizeof operator
● Jedan od operatora u programskom jeziku C je sizeof unarni operator.
● Daje veličinu u memoriji vrijednosti sa desne strane
int niz[] = { 7, 5, 0, 3, 7, 2 };printf("%d", sizeof niz);
● Ako se u zagradama navede tip, daje veličinu tog tipa
printf("%d", sizeof(double));
● Operator sizeof vraća vrijednost tipa size_t koji je na PC-u ekvivalentan long unsigned int (zbog čega gornje naredbe daju upozorenje).
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 51
sizeof operator
● Jedan od operatora u programskom jeziku C je sizeof unarni operator.
● Daje veličinu u memoriji vrijednosti sa desne strane
int niz[] = { 7, 5, 0, 3, 7, 2 };printf("%d", sizeof niz);
● Ako se u zagradama navede tip, daje veličinu tog tipa
printf("%d", sizeof(double));
● Operator sizeof vraća vrijednost tipa size_t koji je na PC-u ekvivalentan long unsigned int (zbog čega gornje naredbe daju upozorenje).
Ispisaće: 24
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 52
Curenje memorije
● Sva memorija zauzeta funkcijom malloc mora se osloboditi funkcijom free.
● Ako se memorija ne oslobodi dolazi do curenja memorije (eng. memory leak)
– Program radi ispravno ali zauzima sve više i više memorije što izaziva postepeno usporenje računara.
● Po završetku programa memorija se oslobađa, ali treba se vježbati da se sva zauzeta memorija oslobodi zbog programa koji dugo stoje pokrenuti.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 53
Primjer dinamičke alokacije
#include <stdio.h>#include <stdlib.h>int main() {
int vel, i;int* niz;printf("Unesite velicinu niza: ");scanf("%d", &vel);niz = (int*)malloc(vel * sizeof(int));printf("Unesite clanove niza: ");for (i=0; i<vel; i++)
scanf("%d", niz[i]);/* ... radimo kao sa obicnim nizom */free(niz);return 0;
}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 54
Primjer 2
● Zadatak: Program omogućuje korisniku da unese niz od najviše 100 riječi pri čemu svaka riječ ima najviše 99 slova. Unos se završava sa dva minusa "--"...
char rijeci[100][100];
● Deklaracijom iznad smo zauzeli 10000 bajta od čega je većina neiskorišteno.
● Da bismo to izbjegli, koristimo niz pokazivača pri čemu svaki pokazuje na dinamički alocirani string koji je tačno onoliko velik koliko je potrebno.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 55
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 56
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
Niz od 100 pokazivača tipa char
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 57
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
Niz od 100 pokazivača tipa char
Unosimo riječ u nizod 100 elemenata
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 58
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
Niz od 100 pokazivača tipa char
Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko
bajta koliko je dugačka riječ + 1
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 59
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
Niz od 100 pokazivača tipa char
Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko
bajta koliko je dugačka riječ + 1
Dodajemo pokazivač nanovu memoriju u niz
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 60
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
Niz od 100 pokazivača tipa char
Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko
bajta koliko je dugačka riječ + 1
Dodajemo pokazivač nanovu memoriju u niz
Kopiramo riječ iz privremenogstringa u alociranu memoriju
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 61
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
Niz od 100 pokazivača tipa char
Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko
bajta koliko je dugačka riječ + 1
Dodajemo pokazivač nanovu memoriju u niz
Kopiramo riječ iz privremenogstringa u alociranu memoriju
Po završetku rada trebaosloboditi zauzetu memoriju
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 62
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {
char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);
} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);return 0;
}
Niz od 100 pokazivača tipa char
Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko
bajta koliko je dugačka riječ + 1
Dodajemo pokazivač nanovu memoriju u niz
Kopiramo riječ iz privremenogstringa u alociranu memoriju
Po završetku rada trebaosloboditi zauzetu memoriju
Mogli smo dinamički alocirati i sam niz pokazivača!
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 63
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char** rijeci;printf ("Unesite broj rijeci: ");scanf("%d", &vel);rijeci = (char**)malloc(vel * sizeof(char*));printf("Unesite rijeci (-- za kraj): ");/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);free(rijeci);return 0;
}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 64
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char** rijeci;printf ("Unesite broj rijeci: ");scanf("%d", &vel);rijeci = (char**)malloc(vel * sizeof(char*));printf("Unesite rijeci (-- za kraj): ");/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);free(rijeci);return 0;
}
Prvo treba osloboditičlanove niza...
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 65
Primjer 2
#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {
int i, vel=0;char** rijeci;printf ("Unesite broj rijeci: ");scanf("%d", &vel);rijeci = (char**)malloc(vel * sizeof(char*));printf("Unesite rijeci (-- za kraj): ");/* ... */for (i=0; i<vel; i++)
free(rijeci[i]);free(rijeci);return 0;
}
Prvo treba osloboditičlanove niza...
...pa onda i sam niz!
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 66
strncat i strncpy
● Funkcije iz biblioteke string.h strcat i strcpy smatraju se nesigurnim. Primjer:
void funkcija(char* s) {char pomocni[100];strcpy(pomocni, s); /* Primljeni string ce imati
najvise 100 znakova */...
● Šta ako primljeni string bude ipak imao više od 100 znakova???
● U C++ programskom jeziku ove funkcije se smatraju za prevaziđene (deprecated) i dobićete upozorenje ako ih koristite.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 67
strncat i strncpy
● Funkcije iz biblioteke string.h strcat i strcpy smatraju se nesigurnim. Primjer:
void funkcija(char* s) {char pomocni[100];strcpy(pomocni, s); /* Primljeni string ce imati
najvise 100 znakova */...
● Šta ako primljeni string bude ipak imao više od 100 znakova???
● U C++ programskom jeziku ove funkcije se smatraju za prevaziđene (deprecated) i dobićete upozorenje ako ih koristite.
Korisnik koji može funkcijiposlati više od 100 karaktera
može pisati po memoriji šta želi!
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 68
strncat i strncpy
● Umjesto njih koristite strncat i strncpy. Primjer:void funkcija(char* s) {
char pomocni[100];strncpy(pomocni, s, 100);pomocni[99] = '\0';...
Iz stringa s u string pomoćni će biti kopirano najviše 100 karaktera. Primjer strncat:
void funkcija(char* s1, char* s2) {char pomocni[100];strncpy(pomocni, s1, 100);pomocni[99] = '\0';strncat(pomocni, s2, 99-strlen(s1));...
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 69
strtok funkcija
● Još jedna korisna funkcija u biblioteci string.h je strtok (skraćeno od string tokenizer).
● Ova funkcija "sjecka" primljeni string po nekom iz niza karaktera.
● Kada prvi put pozovemo funkciju šaljemo joj string i niz delimitera (razdjelnika). Svaki sljedeći put šaljemo nul-pokazivač kao prvi parametar kako bismo označili da i dalje radimo sa istim stringom, a dobićemo pokazivač na sljedeći podstring.
– Ovo je primjer bibliotečne funkcije koja ne daje uvijek isti rezultat za iste parametre (koristi statičke promjenljive).
– Funkcija strtok uništava polazni string jer ubacuje \0 na mjestu svakog delimitera.
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 70
strtok funkcija
● Primjer:
#include <stdio.h>#include <string.h>int main() {
char tekst[] = " Ovo, za pocetak,, je neki primjer.";
char* p;p = strtok(tekst, " .,");while (p != NULL) {
printf("Rijec: %s\n", p);p = strtok(NULL, " .,");
}return 0;
}
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 71
strtok funkcija
● Primjer:
#include <stdio.h>#include <string.h>int main() {
char tekst[] = " Ovo, za pocetak,, je neki primjer.";
char* p;p = strtok(tekst, " .,");while (p != NULL) {
printf("Rijec: %s\n", p);p = strtok(NULL, " .,");
}return 0;
}
Cjepkamo string po znakovima razmak, tačka i zarez
20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 72
strtok funkcija
● Primjer:
#include <stdio.h>#include <string.h>int main() {
char tekst[] = " Ovo, za pocetak,, je neki primjer.";
char* p;p = strtok(tekst, " .,");while (p != NULL) {
printf("Rijec: %s\n", p);p = strtok(NULL, " .,");
}return 0;
}
Cjepkamo string po znakovima razmak, tačka i zarez
Nakon posljednje riječidobićemo NULL