1
Programski jezik C - 2.deo
(materijal sa predavanja D. Vitasa)
Dalje...
1. Pokazivači2. Pojam funkcije3. Prenos parametara4. Biblioteke 5. Funkcije za ulaz i izlaz6. Funkcije za rad sa niskama7. Složeni tipovi u C-u 8. Algoritmi nad složenim tipovima
Funkcija u C-u
2
Funkcija
Polazna ideja:
Pisati programe kao skup funkcija koje pozivaju jedna drugu - program se gradi poput LEGO-kocaka!!!
Primer#include <stdio.h>void main( void ) {
printf("Dobro jutro!\n"); }
ili void main( void ) { pozdrav(); }
void pozdrav( void ) {printf("Dobro jutro!\n");
}
void pozdrav( void ) {printf("Dobar dan!\n");
}
Funkcije
U matematici: y = F( x1, ..., xn)
U C-u: tip ime( tip x1, ..., tip xn)
Na primer: y = 2 x
int stepen ( int x)
3
Definicija funkcije
int stepen( int n )• Definicija funkcije sadrži
– ime funkcije (npr. stepen)– tip i imena (fiktivnih) parametara
(npr. int n)– tip povratne vrednosti, rezultat (npr. int)– kod funkcije: kako se rezultat dobija na
osnovu parametara
Struktura funkcije
tip ime( tip x1, ..., tip xn) {lista deklaracijalista iskaza}
Primer: int stepen( int x, int n ) { // blokint i, p = 1; // p - stepenfor( i=0; i <n; i++ ) p = p * x; return p;} // kraj bloka
Primer(primer08.c)#include <stdio.h>int zbir( int, int); /* prototipovi funkcija*/int stepen( int, int );main() {
int a = 7, b = 2, z, s;z = zbir( a, b );s = stepen( a, b );printf("zbir = %d stepen = %d\n", z, s ); }
int zbir( int x, int y ) {return x+y; }
int stepen( int x, int y ) {int p = 1, i;for( i = 0; i < y; i++) p = p * x;return p; }
4
Primer bez argumenata1. void pozdrav( void ) {
printf("Dobro jutro!\n"); }
2. float pi( void ) {return 3.141592; }
return izraz - vraća vrednost izraza i zaustavlja izvršavanje funkcije
Tada se može u nekoj drugoj funkciji koristiti npr. 2*pi() u aritmetičkom izrazu.
PromenljiveRazlikujemo:
lokalne promeljive - deklarisane unutar blokaKažemo da je promenljiva lokalna ako ima značenje (definisana je)
samo unutar izvesnog dela programa. U C-u je svaka promenljiva unutar bloka lokalna.
globalne promenljive - deklarisane na istom nivou kao funkcijeKažemo da je promenljiva globalna ako ima značenje (definisana je) u
celom programu.
Primer. float x = 3.141592; // x - globalnovoid main( void ) {int k = 2; // k - lokalnoprintf("%f", k * x ); }
Lokalne promenljive su u bloku!
/* Ako x > y, napraviti razmenu vrednosti */int x= 2, y = 1; printf("Pre x = %d y = %d\n", x, y ); if( x > y ){
int temp; temp = x; x = y; y = temp; }
/* temp više nije definisano */printf("Posle x = %d y = %d\n", x, y );
5
Poziv funkcije• U definiciji funkcije se navode formalni (fiktivni)
parametri• U pozivu funkcije se navode stvarni (aktuelni)
parametri (argumenti)
Primer. int stepen( int n ) {...} // definicija...y = stepen( 8 );
Parametri se moraju slagati po broju ( i po tipu).
Funkcija mora biti definisana pre nego što se upotrebi!
float max(float x, float y ){return (x>y) ? x : y; }void main( void ){
float a;scanf("%f", &a );printf("%f\n",
max(a, a*a) ); }
float max(float x, float y );/* Prototip */
void main( void ){float a;scanf("%f", &a );printf("%f\n",
max(a, a*a) ); }
float max(float x, float y ){return (x>y) ? x : y; }
Primeri: da li je n prost broj?int prost( int n ) {
/* mark = 0 ako je broj prost; 1, inače */int d = 1, mark = 0;
do d = d + 1;
while( n%d >= 1 && d*d <= n ); if( n % d == 0 )
mark = 1; // n deljivo sa dreturn mark; }
6
n!
int faktoriel( int n ) { // n - parametarint i, f = 1; // lokalne promenljive
for( i = 2; i <= n; i++ ) f = f * i; // račun
return f; // povratna vrednost}
Pokazivači
Pokazivači
Dva načina adresiranja: direktno i indirektno
- direktno adresiranje
Adresa
7
PokazivačiIndirektno adresiranje: Ako ne želimo ili ne možemo da
koristimo ime promenljive A, možemo da postavimo adresu te promenljive u posebnu promenljivu P, koju nazivamo pokazivač. Tada vrednost promenljive A možemo da dobijemo posredstvom promenljive P.
Pokazivači• Pokazivač je posebna promenljiva (poseban tip) koja
može da sadrži adresu neke druge promenljive. U C-u, pokazivač je vezan za određeni tip podataka. (Zašto?)
• Ako pokazivač P sadrži adresu promenljive A, kažemo da P pokazuje na A.
• Pokazivači, kao i imena promenljivih, omogućavaju pristup unutrašnjoj memoriji, ali među njima treba praviti razliku: – Pokazivač je promenljiva koja može da "pokazuje" na
različite adrese. – Ime promenljive pokazuje uvek na istu adresu.
Operatori na pokazivačima U radu sa pokazivačima koristimo dva operatora: • operator adresa od (&) da bismo dobili adresu jedne
primenljive (Operator referenciranja)• operator sadržaj od (*) da bismo pristupili sadržaju na
određenoj adresi (Operator dereferenciranja)Sintaksa za deklaraciju pokazivača je sledeća: <Tip> *<ImePok> - deklariše da promenljive <ImePok>
može da primi adresu promenljive tipa <Tip>. Na primer, deklaracija int *p; se interpretira *p je tipa int ili p je pokazivač na int
ili p može sadržati adresu promenljive tipa int.
8
Primer
Neka je celobrojna promenljiva x na adresi 1234 i neka je njena vrednost 22. (int x = 22;)
Neka je p: int *p; Tada• iskaz p = &x; dodeljuje promenljvoj p
vrednost adrese od x, tj. p je 1234. • vrednost izraza *p je 22.
Operatori na pokazivačimaAdresni operator & se koristi u obliku &<ImePromenljive>.
Već smo ga upoznali kod funkcije scanf.
Primer: int N;scanf("%d", &N);
Ovde oprezno! Operator & se može primeniti samo na objekte koji se nalaze u unutrašnjoj memoriji kao što su imena promenljivih, ali ne može da se primeni na konstante i izraze!
Operatori na pokazivačimaShematski prikaz: Neka je P neinicijalizovani
pokazivač, a A promenljiva istog tipa koja sadrži vrednost 10.
Iskaz P = &A; dodeljujepromenljvoj P adresu promenljive A:
9
Operatori na pokazivačimaSintaksa za operator sadržaja * je *<ImePok>
koja označava sadržaj adrese na koju pokazuje promenljiva <ImePok>.
Primer. int A = 10, B; int *P; P = &A; B = *P; // B <-- A
Operatori na pokazivačimaNeka je A promenljiva koja sadrži
broj 10, B promenljiva koja sadrži broj 50, a P neinicijalizovani pokazivač.
Posle iskaza: P = &A; // P pokazuje na A B = *P; // Sadržaj A se dodeljuje B*P = 20; // Sadržaj A postaje 20
Operatori na pokazivačimamain() { short A = 10;short B = 50; short *P;
P = &A; B = *P;*P = 20;
return 0; }
main() { short A, B, *P;
A = 10; B = 50; P = &A; B = *P; *P = 20;
return 0; }
10
Pravila za rad sa pokazivačima
Prioritet * i &
Operatori * i & su istog prioriteta kao ostali unarni operatori (negacija, ++, --). U istom izrazu, unarni operatori *, &, !, ++, -- se izračunavaju sdesna ulevo.
Ako pokazivač P pokazuje na promenljivu A, onda se *P može koristiti umesto same promenljive A.
Pravila za rad sa pokazivačima
Posle iskaza P = &A; sledeći iskazi su ekvivalentni:
Y = *P+1 Y = A+1*P = *P+10 A = A+10*P += 2 A += 2++*P ++A(*P)++ A++
U polsednjem primeru su zagrade obavezne jer, kako se operatori * i ++ izračunavaju sdesna, bez zagrada bi ovaj izraz bio izračunat kao *(P++)!!! (Šta je to?)
Pokazivač NUL
Pokazivač NUL je jedini izuzetak: Numerička vrednost 0(nula) se koristi da ukaže da pokazivač ne pokazuje nigde!
int *P; P = 0;
11
Pokazivači su promenljive
Konačno, kako su pokazivači promenljive, mogu se koristiti u izrazima. Npr. neka su P1 i P2 dva pokazivača na int, tada dodela
P1 = P2;
dodeljuje vrednost P2 pokazivaču P1, pa P1 pokazuje na isti objekat kao P2.
I još jednom...Neka je
int A;int *P;P = &A;
Tada: A označava sadržaj od A &A označava adresu od A P označava adresu od A *P označava sadržaj od A
Ali &P označava adresu pokazivača P *A je nedozvoljeno (jer A nije pokazivač)
Primermain() {
int A=1, B=2, C=3;int *P1, *P2;P1=&A;P2=&C;*P1=(*P2)++;P1=P2;P2=&B;*P1-=*P2;++*P2;*P1*=*P2;A=++*P2**P1;P1=&A;*P2=*P1/=*P2;return 0; }
A B C P1 P21 2 3 / /
1 2 3 &A / 1 2 3 &A &C3 2 4 &A &C3 2 4 &C &C 3 2 4 &C &B3 2 2 &C &B3 3 2 &C &B3 3 6 &C &B24 4 6 &C &B24 4 6 &A &B6 6 6 &A &B
12
Dalje o funkcijama
Još jedan primer - EuklidIzračunavanje NZD brojeva a, b > 0:
• ako a = b, NZD(a, b) = a = b• ako a < b, NZD(a, b) = NZD(a, b-a)• ako a > b, NZD(a, b) = NZD(a-b, b)
Npr. NZD(8,6) = NZD(2,6) = NZD(2,4) = NZD(2,2) = 2
Euklidov algoritam
int euklid( int a, int b) {
while( a != b) if( a > b ) a = a – b; else b = b – a;
return a; }
13
Euklidov algoritamint euklid( int a, int b) {
int t; while( u > 0 ) {
if( u < v ) { t = u; u = v; v = t; } // swap
u = u – v; }return v; }
Euklidov algoritamint euklid( int a, int b) {
while( u > 0 ) { if( u < v ) {
int t;t = u; u = v; v = t; }
u = u – v; }return v; }
Prenos parametara
14
TeorijaPrenos parametara se na “teorijskom” nivou
može izvršiti na više načina:
• prenos po vrednosti• prenos po referenci • prenos po imenu
Kako su ove metode ugrađene u C?
Prenos parametara
1. Prenos po vrednostiPoziv funkcije faktoriel( k ) iz neke funkcije prenosi vrednost parametra k(promenljiva ili izraz) funkciji faktoriel.
...; m = faktoriel(5);...int faktoriel( int n ) { ...; return f; }
Šta se dešava u memoriji?POZIV:
stvarni parametar je 5
formira se lokalna promenljiva n i dodeljuje joj se vrednost stvarnog parametra (n = 5)
POVRATAK:
izračunava se f = 5! = 120
preko return-iskaza ova vrednost se vraća funkciji koja je pozvala faktoriel. Lokalno n nestaje!
15
Prenos parametara
2. Prenos po referenci... omogućava prenos vrednosti preko liste
parametara. Umesto da se prenese vrednost, prenosi se adresa. Nema lokalne kopije!!!
Primer: scanf("%d", &n );scanf čita sa tasture vrednost koja se
postavlja na adresu promenljive n.
PrimerPrenos po vrednosti
int pv( int x ) {x = x + 1; return x; }
void main( void) {int r, i = 1; r = pv( i ); printf("%d %d", i, r ); }/* Rezultat i =1, r = 2 */
Prenos po referenci
int pr( int *x ) {*x = *x + 1; }
void main( void) {int i = 1; pr( &i ); printf("%d", i ); }/* Rezultat i =2 */
Primer - swapPrenos po vrednosti/* x = 1, y = 2 */swap( x, y ); // poziv...void swap( int a, int b ) {
int temp;temp = a; a = b;b = temp; }
/* x = 1, y = 2 */
Prenos po referenci/* x = 1, y = 2 */swap( &x, &y ); // poziv...void swap( int *a, int *b ) {
int temp;temp = *a; *a = *b;*b = temp; }
/* x = 2, y = 1 */
16
Prenos parametara
3. Prenos po imenu
Ideja: ne prenositi ni vrednost promeljive, ni njenu adresu, već samo ime.
Primer: Funkcija izračunava zbir prvih nelemenata niza f(n):
float zbir( int n, ime f )
Primer - pokazivač na funkciju
#include <stdio.h>
void main( void ) {int (*funkcija) ();int i = 1; funkcija = printf;(*funkcija) ("funkcija...%d\n", i ); }
Pokazivač na funkciju kao parametar
#include <stdio.h> void f( void (fun_pok) () ); // prototip
void main( void ) {f(printf);
}void f( void (fun_pok) () ){
(*fun_pok) ("Funkcija!"); }
17
Implementacija poziva funkcije
Svaki poziv neke funkcije zauzima novi prostor u memoriji koji je rezervisan za taj poziv i koji je oblika:
Taj prostor se naziva aktivacioni slog. Kada se izvršavanje funkcije okonča, ovaj prostor se oslobađa - vrednosti koje su bile u njemu tokom izvršavanja funkcije se gube.
lokalne promenljive funkcije (f)povratna adresa (gde nastaviti?)
vrednost parametara (5)povratna vrednost (120)
aktivacioni slog za fakt
Pojam biblioteke
Biblioteke
Kompilirani skupovi funkcija koji se mogu priključiti programu. Prototipovi funcija su zadati u zaglavlju .h
#include <stdio.h> znači da će predprocesor uključiti funkcije koje su deklarisane u ovom zaglavlju. Zaglavlja sadrže jošmakro-definicije, itd.
18
Ulazno-izlazne funkcije
Ulaz i izlaz
stream, engl. = struja
x = 'A' memorija &x
A b C C d e 1 2 3 ....
A b C C d e 1 2 3 ...
A
Funkcije za ulaz i izlaz
• U C-u nema iskaza za ulazne i izlazne operacije. One se obavljaju preko funkcija iz standardne ulazno-izlazne biblioteke
<stdio.h>• <stdio.h> sadrži prototipove U/I-funkcija,
definicije konstanti, itd. • Standardni ulaz - tastatura• Standradni izlaz - ekran
19
Formatirani ulaz scanf
• Za formatirani ulaz, funkcijaint scanf( char *format, <lista elementa>);
Povratna vrednost = broj izvršenih konverzija
1. Argumenti se prenose adrese (&x), Moraju biti pokazivači!
2. Format i tipovi moraju biti saglasni!
scanf
• Razmak i tabulator se zanemaruju u formatu
• Ulaz mora strogo odgovarati redosledu karaktera navedenih u formatu!
• Završava se kada istroši opis u formatu.• %*s - ukazuje da odgovarajući podatak
sa ulaza treba zanemariti
scanf
1. char c; short k; long m; float r; scanf("%c%hd%ld%f", &c, &k, &m, &r );
?ABCD10141hx-sadržajfloatlongshortchartip&r&m&k&cadresa%f%ld%hd%cformat4.243981257Aulaz
20
Česti format u scanf (K&R B1.3)
%d - ceo broj u dekadnom zapisu%o - ceo broj u oktalnom zapisu%u - neoznačeni ceo broj %x - ceo broj u heksadecimalnom zapisu%f, %e - realni broj %p - pokazivač, adresa%[...] - karakterska klasa%[^...] - negativna karakterska klasaModifikatori: h - short l,L - long
Primer klase u scanf
1. while(!scanf("%[DdNn]", &c ) ) printf("Uneti DA ili NE!\n");
Ako sa ulaza ne dolazi element klase [DdNn], ostaje se u petlji.
2. while( scanf("%[^DdNn]", &c ) ) printf("Uneti DA ili NE!\n");
Formatirani izlaz printf (K&R B1.2)
• Za formatirani izlaz, funkcijaint printf( char *format, <lista elementa>);
Format sadrži ili obične karaktere (koji se kopiraju na izlaz), ili specifikaciju konverzije (npr. %d).
Povratna vrednost = broj ispisanih karaktera ili <0 ako se pojavi greška.
Format i tipovi moraju biti saglasni!
21
Specifikacija konverzije u printf
% [+] [-] [n1].[n2] [ h l L ] <konverzija>
+ - ispisivanje znaka- - poravnavaje nalevon1 - minimalna širina polja. - separator polja za preciznostn2 - preciznost (max. broj cifara iza decimalne
tačke kod f ili e-konverzije) h l L - modifikator dužine (kao kod scanf)
PrimerZadatak: Napisati program koji ispisuje tablicu ASCII-
grafičkih karaktera i njihove kodove (dekadno i oktalno). void main( void ){unsigned i, j, k;
for( i = 0; i < 32; i++ ) {for( j = 1; j < 4; j++ ) {
k = i + j * 32;printf(" %c-%3d-%o\t", k, k, k ); }
printf(" \n"); }}
Rezultat: j = 1 j=2 j=3i = 0 - 32-40 @- 64-100 `= 96=140i = 1 !- 33-41 A- 65-101 a= 97=141i = 2 "- 34-42 B- 66-102 b= 98=142 ...
Neformatirani ulaz i izlaz
• Unos karakteraint getchar( void );
omogućava unos jednog karaktera sa standardnog ulaza (stdin, tastatura)
• Ispis karakteraint putchar( char c );
omogućava ispis vrednosti c na standardnom izlazu (stdout, ekran)
22
PrimerZadatak: Odrediti u datom tekstu broj razmaka i
ostalih karaktera do pojave prve tačke.
Na primer, sa ulaza stižu karakteri:Ovo je jedan tekst.
Program treba da ispiše:
U tekstu ima 3 razmaka i 15 drugih karaktera.
Rešenje#include <stdio.h>void main( void ){
int razmak = 0, ostali = 0; // Inicijalizacijachar c;
// c = getchar();while( (c = getchar()) != '.' ) { // Ako tačka, kraj
if( c == ' ' ) razmak++; // Da li je razmak?else ostali++; // Onda, ostali... } // c = getchar();
printf("U tekstu ima %d razmaka i %d ostalih karaktera\n", razmak, ostali );
}
Kako pročitati iza tačke?
EOF (End-Of-File) - označava kraj struje!
while( (c = getchar()) != EOF ) {// Da li je kraj ulaza?if( c == ' ' ) razmak++; // Da li je razmak?else ostali++; // Onda, ostali... }
23
EOFKonstanta EOF je definisana u <stdio.h>Na mojoj mašini: #define EOF (-1)Na drugim mašinama može imati i drugu vrednost
(simboličke konstante zavise od konkretne implementacije!).
Vrednost EOF (K&R, zadatak 1-7): #include <stdio.h>main(){
printf("EOf ima vrednost %d\n", EOF); }
PrimerZadatak: Sastaviti program koji izračunava (a) broj
pročitanih karaktera, (b) broj pročitanih redova i (c) broj pročitanih reči u tekstu koji stiže sa standardnog ulaza.
broj karaktera = nc++ za svaki c pre EOFbroj redova = nr++ za svaki '\n'broj reči? = r++, ali kada?
Reč = niz alfabetskih karaktera između dva separatoraPrimer: tajm-out --> 2 reči
dan i noć --> 3 reči. itd
Rešenje#include <stdio.h> (videti primer06.c)#include <ctype.h> // F-je za konverzijuvoid main( void ){
int nc = 0, nr = 0, r = 0, mark=0; char c; // Deklaracijewhile( ( c = getchar()) != EOF ) { // Ako nije kraj,
if( c == '\n ' ) { nr++; mark=0; } // Kraj reda, nije rečelse { nc++; // Jeste karakter
if( isalpha( c ) && mark == 0 ) { // Da li je rečr++; mark = 1; }
else if( !isalpha( c ) ) mark = 0; }printf("nc = %d, nr = %d, r = %d \n", nc, nr, r );
}
24
Komentar
1. Biblioteka <ctype.h> sadrži različite funkcije za ispitivanje i konverziju karaktera. Funkcija islpha( c ) vraća 0 ako c nije alfabetski karakter, inače ≠ 0.
2. Uloga promenljive mark:mark = 0, ako karakter nije alfabetski, amark = 1, ako je karakter alfabetski. Dok smo unutar reči, mark =1!
int isalpha( int c );(primer15.c) /* Nije uključen <ctype.h> */main() {
char c; while( (c = getchar()) != EOF ) {
if( isalpha( c ) ) printf("%c %d\n", c, isalpha( c ) ); }
int isalpha( int c ){int k = 0; if( (65 < c ) && ( c < 90 ) ||
(97 < c ) && ( c < 122 ) ) k = 1; return k; }
Primeri za <ctype.h>1. islower(c) vraća tačno (≠ 0) ako je c malo slovo.
int islower( int c ) {if( c >= 'a' && c <= 'z' ) return c; else return 0; }
2. isdigit(c) vraća tačno (≠ 0) ako je c cifra. Slično kao 1. 3. toupper(c) pretvara mala slova u velika.
int toupper( int c ) {return ( islower(c) ? (c ^ 0x20) : c ); } // 0x20 = 32
Varijanta: return ( islower(c) ? (c - 32) : c );4. Slično int tolower( int) pretvara velika slova u mala.
25
Primer
char a, b, c, d;a = 65; b = 'A'; c = '\101'; d = '\x41';printf("%d %c %o %x\n", a, b, c, d );printf("H%cH%cH%cH%c!\n", a, b, c, d );a= tolower(a); b= tolower(b); c= tolower(c); d= tolower(d);
printf("H%cH%cH%cH%c!\n", a, b, c, d );printf("%d %c %o %x\n", a, b, c, d ); ...
Dalje...
Složeni tipovi....
Top Related