You are on page 1of 2009

_________________________________________________________

ZBIRKA ZADATAKA
IZ
PROGRAMSKOG JEZIKA C
V 1.0 05/08/2015
_________________________________________________________
ETF Beograd
ETF Podgorica
ETF Sarajevo
FER Zagreb
FSB Split
FTN Kosovska Mitrovica
MAT FAK Beograd
PMF Niš
PMF Srbsko Sarajevo
FTN Čačak
UN Singidunum Beograd
VTŠ Čačak
VTŠ Niš
_____________________________________________________________

Sakupio i obradio:
jjanko2015@gmail.com
SADRŽAJ
_________________________________________________________________
C reference card ANSI
Službeni podsetnik FER Zagreb
1.ETF Beograd
2.ETF Podgorica
3.ETF Sarajevo
4.FER Zagreb
5.FSB Split
6.FTN Kosovska Mitrovica
7.MAT FAK Beograd
8.PMF Niš
9.PMF Srbsko Sarajevo
10.FTN Čačak
11.UN Singidunum Beograd
12.VTŠ Čačak
13.VTŠ Niš
_________________________________________________________________
Napomena:

Zbirka predstavlja skup vežbi iz programskog jezika C


Nedostaju vežbe sa FTN NS i ELFAK Niš
Za brži pristup pojedinoj stavki u sadržaju kliknuti na bukmark
Za bolje razumevanje pogledati predavanja na odgovarajućem fakultetu tj. školi
C Reference Card (ANSI) Constants Flow of Control
long (suffix) L or l statement terminator ;
Program Structure/Functions float (suffix) F or f block delimeters { }
type fnc(type 1 ,. . . ) function declarations exponential form e exit from switch, while, do, for break
type name external variable declarations octal (prefix zero) 0 next iteration of while, do, for continue
main() { main routine hexadecimal (prefix zero-ex) 0x or 0X go to goto label
declarations local variable declarations character constant (char, octal, hex) 'a', '\ooo', '\xhh' label label :
statements newline, cr, tab, backspace \n, \r, \t, \b return value from function return expr
} special characters \\, \?, \', \" Flow Constructions
type fnc(arg 1 ,. . . ) { function definition string constant (ends with '\0') "abc. . . de" if statement if (expr ) statement
declarations local variable declarations else if (expr ) statement
statements Pointers, Arrays & Structures else statement
return value; declare pointer to type type *name while statement while (expr )
} statement
declare function returning pointer to type type *f()
comments for statement for (expr 1 ; expr 2 ; expr 3 )
/* */ declare pointer to function returning type type (*pf)() statement
main(int argc, char *argv[]) main with args generic pointer type void * do statement do statement
exit(arg ) terminate execution null pointer NULL while(expr );
object pointed to by pointer *pointer
C Preprocessor address of object name &name
switch statement switch (expr ) {
case const 1 : statement 1 break;
include library file #include <filename> array name[dim] case const 2 : statement 2 break;
include user file #include "filename" multi-dim array name[dim 1 ][dim 2 ]. . . default: statement
replacement text #define name text Structures }
replacement macro #define name(var ) text struct tag { structure template
Example. #define max(A,B) ((A)>(B) ? (A) : (B)) declarations declaration of members ANSI Standard Libraries
undefine #undef name }; <assert.h> <ctype.h> <errno.h> <float.h> <limits.h>
quoted string in replace # create structure struct tag name <locale.h> <math.h> <setjmp.h> <signal.h> <stdarg.h>
concatenate args and rescan ## member of structure from template name.member <stddef.h> <stdio.h> <stdlib.h> <string.h> <time.h>
conditional execution #if, #else, #elif, #endif member of pointed to structure pointer -> member
is name defined, not defined? #ifdef, #ifndef Example. (*p).x and p->x are the same
Character Class Tests <ctype.h>
name defined? defined(name ) single value, multiple type structure union alphanumeric? isalnum(c)
line continuation char \ bit field with b bits member : b alphabetic? isalpha(c)
control character? iscntrl(c)
Data Types/Declarations Operators (grouped by precedence) decimal digit? isdigit(c)
character (1 byte) char structure member operator name.member printing character (not incl space)? isgraph(c)
integer int structure pointer pointer ->member lower case letter? islower(c)
float (single precision) float printing character (incl space)? isprint(c)
increment, decrement ++, --
float (double precision) double printing char except space, letter, digit? ispunct(c)
plus, minus, logical not, bitwise not +, -, !, ~
short (16 bit integer) short space, formfeed, newline, cr, tab, vtab? isspace(c)
indirection via pointer, address of object *pointer , &name
long (32 bit integer) long upper case letter? isupper(c)
cast expression to type (type) expr
positive and negative signed hexadecimal digit? isxdigit(c)
size of an object sizeof
only positive unsigned convert to lower case? tolower(c)
pointer to int, float,. . . *int, *float,. . . multiply, divide, modulus (remainder) *, /, % convert to upper case? toupper(c)
enumeration constant enum add, subtract +, -
constant (unchanging) value const String Operations <string.h>
declare external variable extern left, right shift [bit ops] <<, >> s,t are strings, cs,ct are constant strings
register variable register comparisons >, >=, <, <= length of s strlen(s)
local to source file static comparisons ==, != copy ct to s strcpy(s,ct)
no value void up to n chars strncpy(s,ct,n)
bitwise and &
structure struct concatenate ct after s strcat(s,ct)
create name by data type typedef typename bitwise exclusive or ^
up to n chars strncat(s,ct,n)
size of an object (type is size_t) sizeof object bitwise or (incl) | compare cs to ct strcmp(cs,ct)
size of a data type (type is size_t) sizeof(type name) logical and && only first n chars strncmp(cs,ct,n)
pointer to first c in cs strchr(cs,c)
Initialization logical or ||
pointer to last c in cs strrchr(cs,c)
initialize variable type name=value conditional expression expr 1 ? expr 2 : expr 3 copy n chars from ct to s memcpy(s,ct,n)
initialize array type name[]={value 1 ,. . . } assignment operators +=, -=, *=, . . . copy n chars from ct to s (may overlap) memmove(s,ct,n)
initialize char string char name[]="string " expression evaluation separator , compare n chars of cs with ct memcmp(cs,ct,n)
pointer to first c in first n chars of cs memchr(cs,c,n)
Unary operators, conditional expression and assignment oper-
put c into first n chars of cs memset(s,c,n)
ators group right to left; all others group left to right.

c 1999 Joseph H. Silverman Permissions on back. v1.3



1 2 3
C Reference Card (ANSI) Standard Utility Functions <stdlib.h> Integer Type Limits <limits.h>
absolute value of int n abs(n) The numbers given in parentheses are typical values for the
Input/Output <stdio.h> absolute value of long n labs(n) constants on a 32-bit Unix system.
quotient and remainder of ints n,d div(n,d) CHAR_BIT bits in char (8)
Standard I/O
retursn structure with div_t.quot and div_t.rem CHAR_MAX max value of char (127 or 255)
standard input stream stdin
quotient and remainder of longs n,d ldiv(n,d) CHAR_MIN min value of char (−128 or 0)
standard output stream stdout
returns structure with ldiv_t.quot and ldiv_t.rem INT_MAX max value of int (+32,767)
standard error stream stderr
pseudo-random integer [0,RAND_MAX] rand() INT_MIN min value of int (−32,768)
end of file EOF
set random seed to n srand(n) LONG_MAX max value of long (+2,147,483,647)
get a character getchar()
terminate program execution exit(status) LONG_MIN min value of long (−2,147,483,648)
print a character putchar(chr )
pass string s to system for execution system(s) SCHAR_MAX max value of signed char (+127)
print formatted data printf("format ",arg 1 ,. . . )
Conversions SCHAR_MIN min value of signed char (−128)
print to string s sprintf(s,"format ",arg 1 ,. . . )
convert string s to double atof(s) SHRT_MAX max value of short (+32,767)
read formatted data scanf("format ",&name 1 ,. . . )
convert string s to integer atoi(s) SHRT_MIN min value of short (−32,768)
read from string s sscanf(s,"format ",&name 1 ,. . . )
convert string s to long atol(s) UCHAR_MAX max value of unsigned char (255)
read line to string s (< max chars) gets(s,max)
convert prefix of s to double strtod(s,endp) UINT_MAX max value of unsigned int (65,535)
print string s puts(s)
convert prefix of s (base b) to long strtol(s,endp,b) ULONG_MAX max value of unsigned long (4,294,967,295)
File I/O
same, but unsigned long strtoul(s,endp,b) USHRT_MAX max value of unsigned short (65,536)
declare file pointer FILE *fp
Storage Allocation
pointer to named file fopen("name ","mode ")
allocate storage malloc(size), calloc(nobj,size) Float Type Limits <float.h>
modes: r (read), w (write), a (append) FLT_RADIX radix of exponent rep (2)
change size of object realloc(pts,size)
get a character getc(fp) FLT_ROUNDS floating point rounding mode
deallocate space free(ptr)
write a character putc(chr ,fp) FLT_DIG decimal digits of precision (6)
Array Functions
write to file fprintf(fp,"format ",arg 1 ,. . . )
search array for key bsearch(key,array,n,size,cmp()) FLT_EPSILON smallest x so 1.0 + x 6= 1.0 (10−5 )
read from file fscanf(fp,"format ",arg 1 ,. . . )
sort array ascending order qsort(array,n,size,cmp()) FLT_MANT_DIG number of digits in mantissa
close file fclose(fp)
FLT_MAX maximum floating point number (1037 )
non-zero if error ferror(fp) Time and Date Functions <time.h> FLT_MAX_EXP maximum exponent
non-zero if EOF feof(fp)
processor time used by program clock() FLT_MIN minimum floating point number (10−37 )
read line to string s (< max chars) fgets(s,max,fp )
Example. clock()/CLOCKS_PER_SEC is time in seconds FLT_MIN_EXP minimum exponent
write string s fputs(s,fp)
current calendar time time() DBL_DIG decimal digits of precision (10)
Codes for Formatted I/O: "%-+ 0w.pmc"
- left justify time2 -time1 in seconds (double) difftime(time2 ,time1 ) DBL_EPSILON smallest x so 1.0 + x 6= 1.0 (10−9 )
+ print with sign arithmetic types representing times clock_t,time_t DBL_MANT_DIG number of digits in mantissa
space print space if no sign structure type for calendar time comps tm DBL_MAX max double floating point number (1037 )
0 pad with leading zeros tm_sec seconds after minute DBL_MAX_EXP maximum exponent
w min field width tm_min minutes after hour DBL_MIN min double floating point number (10−37 )
p precision tm_hour hours since midnight DBL_MIN_EXP minimum exponent
m conversion character: tm_mday day of month
h short, l long, L long double tm_mon months since January
c conversion character: tm_year years since 1900
d,i integer u unsigned tm_wday days since Sunday
c single char s char string tm_yday days since January 1
f double e,E exponential tm_isdst Daylight Savings Time flag
o octal x,X hexadecimal convert local time to calendar time mktime(tp)
p pointer n number of chars written convert time in tp to string asctime(tp)
g,G same as f or e,E depending on exponent convert calendar time in tp to local time ctime(tp)
convert calendar time to GMT gmtime(tp)
Variable Argument Lists <stdarg.h> convert calendar time to local time localtime(tp)
declaration of pointer to arguments va_list name; format date and time info strftime(s,smax,"format ",tp)
initialization of argument pointer va_start(name ,lastarg ) tp is a pointer to a structure of type tm
lastarg is last named parameter of the function
access next unamed arg, update pointer va_arg(name ,type) Mathematical Functions <math.h>
call before exiting function va_end(name ) Arguments and returned values are double
trig functions sin(x), cos(x), tan(x)
inverse trig functions asin(x), acos(x), atan(x)
arctan(y/x) atan2(y,x)
hyperbolic trig functions sinh(x), cosh(x), tanh(x) c 1999 Joseph H. Silverman
May 1999 v1.3. Copyright
exponentials & logs exp(x), log(x), log10(x)
Permission is granted to make and distribute copies of this card pro-
exponentials & logs (2 power) ldexp(x,n), frexp(x,*e) vided the copyright notice and this permission notice are preserved on
division & remainder modf(x,*ip), fmod(x,y) all copies.
powers pow(x,y), sqrt(x) Send comments and corrections to J.H. Silverman, Math. Dept., Brown
rounding ceil(x), floor(x), fabs(x) Univ., Providence, RI 02912 USA. hjhs@math.brown.edui

4 5 6
Programiranje i programsko inženjerstvo – službeni podsjetnik verzija 2013.b

Izvadak iz ASCII tablice Prioritet operatora


Znak Opis Dekadska vrijednost OPERATORI PRIDRUŽIVANJE
LF sljedeći red, novi red 10 poziv funkcije()
Space blank, praznina 32 []
L → D

Viši prioritet
0 znamenka nula 48 referenciranje .
A veliko slovo A 65 postfiks ++ --
a malo slovo a 97 ! ~ ++ -- sizeof & *
prefiks ++ -- D → L
unarni + -
Prikaz realnih brojeva
(cast) D → L
IEEE 754 jednostruka IEEE 754 dvostruka
preciznost preciznost * / % L → D
K = BE + 127 K = BE + 1023 binarni + - L → D
denormalizirani broj: K = 0 denormalizirani broj: K = 0 << >> L → D
± ∞ ili NaN: K = 255 ± ∞ili NaN: K = 2047 < <= > >= L → D

Niži prioritet
najveći pozitivan broj najveći pozitivan broj == != L → D
 3.4 × 1038  1.8 × 10308 & L → D
najmanji pozitivan broj najmanji pozitivan broj ^ L → D
 1.4 × 10-45  4.9 × 10-324
| L → D
ρ  2-24  6 × 10-8 ρ  2-53  1.1 × 10-16 && L → D
|| L → D
math.h ? : D → L
double fabs (double x); x = *= /= %= += -=
double sin (double x); D → L
&= ^= |= <<= >>=
double cos (double x); , L → D
double tan (double x);

double asin (double x); Izgled konverzijskih specifikacija kod


double acos (double x); funkcije printf
double atan (double x);
double sinh (double x); %[znak][širina][.preciznost]tip
double cosh (double x); [znak] Objašnjenje
double tanh (double x);
double exp (double x); ex ništa desno pozicioniranje
double log (double x); ln x tiska - predznak, a umjesto +
praznina
predznaka je praznina
double log10 (double x); log x
- lijevo pozicioniranje
double pow (double x, double y); xy
+ rezultat uvijek počinje s + ili -
double sqrt(double x); x
0 ispisuje vodeće nule
double fmod(double x, double y); x mod y
# konverzija na alternativan način:
double ceil (double x); x  ne utječe na c s d i u
double floor(double x); x  ispisuje vodeću 0 za o
ispisuje vodeće 0x ili 0X za x ili X
stdlib.h ispisuje dec. točku i kad nema
int abs (int x); x decimala za e E F
long labs (long x); x ispisuje prateće 0 za g G
void exit (int status);
void srand (unsigned int seed);
int rand (void); vraća broj iz intervala [0, RAND_MAX]
void *malloc (size_t size); vraća NULL u slučaju pogreške
void free (void *block);
void *realloc(void *block, size_t size); vraća NULL u slučaju pogreške

string.h
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t maxlen);
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t maxlen);
size_t strlen(const char *s);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t maxlen);
char *strchr(const char *s, int c);
Programiranje i programsko inženjerstvo – službeni podsjetnik verzija 2013.b
char *strrchr(const char *s, int c);
char *strstr(const char *string, const char *substring);
char *strpbrk(const char *string, const char *setofcharacters);

ctype.h
int toupper(int ch);
int tolower(int ch);
int isdigit(int c); provjerava je li znak znamenka (0-9)
int isalpha(int c); provjerava je li znak slovo (A-Z ili a-z)
int isalnum(int c); provjerava je li znak slovo (A-Z ili a-z) ili znamenka (0-9)
int isprint(int c); provjerava može li se znak ispisati (0x20-0x7E)
int iscntrl(int c); provjerava je li znak kontrolni (0x7F ili 0x00-0x1F)
int isspace(int c); provjerava je li znak praznina
int islower(int c); provjerava je li znak malo slovo (a-z)
int isupper(int c); provjerava je li znak veliko slovo (A-Z)

stdio.h
int getchar(void); vraća učitani znak ili EOF
int putchar(int ch); vraća ispisani znak ili EOF (kod pogreške)
int scanf(const char *format, arg1, arg2, ...,arg n);
vraća broj učitanih argumenata (0…n) ili EOF (kraj datoteke)

Tipovi formatskih specifikacije za scanf: %d,%i,%o,%u,%x,%c,%s,%e,%f,%g,%p,%[…],%[^…].


Prefiksi: h(za short) l(long, double) L(long double), npr. %hd, %ld, %lf, %Lf

int printf(const char *format, arg1, arg2, ...,arg n); vraća broj ispisanih znakova

Tipovi formatskih specifikacije za printf: %d,%i,%o,%u,%x,%X,%c,%s,%e,%f,%g,%G,%e,%E,%p.

int puts(const char *s); vraća EOF u slučaju pogreške


char *gets(char *string); vraća NULL ako kao prvi znak pročita kraj datoteke (CTRL+Z (windows) ili
CTRL+D(unix)) ili ako je nastupila pogreška

FILE *fopen(const char *filename, const char *mode);

mode: "w","a","r","w+","a+","r+" Napomena: U Windows op. sustavu za binarne datoteke treba na kraj dodati b

int fclose(FILE *fp); vraća 0 ako je operacija uspjela ili EOF u slučaju pogreške
int fgetc(FILE *stream); vraća pročitani znak ili EOF (pogreška ili kraj datoteke)
int fscanf (FILE *stream, const char *format, arg1, arg2, ..., arg n);
vraća broj učitanih argumenata ili EOF(pogreška ili kraj datoteke)
char *fgets(char *s, int n, FILE *stream);
vraća NULL u slučaju pogreške ili kraja datoteke
int fputc(int c, FILE *stream);
vraća ispisani znak ili EOF u slučaju pogreške
int fprintf (FILE *stream, const char *format, arg1, arg2, ..., arg n);
vraća broj ispisanih znakova ili EOF u slučaju pogreške
int fputs(char *s, FILE *stream);
vraća nenegativni broj ili EOF u slučaju pogreške
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
vraća broj učitanih objekata. (0..n)
size_t fwrite(void *ptr, size_t size, size_t n, FILE *stream);
vraća broj ispisanih objekata. U slučaju pogreške taj je broj < n.
int fseek(FILE *stream, long offset, int whence);
vraća 0 ako je pozicioniranje uspjelo ili broj različit od 0 u slučaju pogreške
whence: SEEK_SET – pozicioniranje u odnosu na početak datoteke
SEEK_CUR - pozicioniranje u odnosu na trenutnu poziciju u datoteci
SEEK_END - pozicioniranje u odnosu na kraj datoteke

long ftell(FILE *stream); vraća trenutnu poziciju u datoteci ili -1 u slučaju pogreške
ELEKTROTEHNIČKI FAKULTET
UNIVERZITETA U BEOGRADU

PROGRAMIRANJE 2
MATERIJAL ZA VEŽBE NA TABLI I PRIPREMU ISPITA

verzija: 26.06.2008.

Detaljna objašnjenja vezana za bilo koji deo gradiva vezanog za


teoriju dostupna su u beleškama sa predavanja, kao i u knjizi koja
opisuje jezik C dovoljno precizno:
• Laslo Kraus – Programski jezik C.

Više zadataka se može pronaći u odgovarajućoj zbirci prof. Krausa:


• Laslo Kraus, Zbirka zadataka iz programskog jezika C.

Sve ove knjige su dostupne u skriptarnici ili u biblioteci fakulteta.

Zadaci koji su tipa ispitnih pitanja su priloženi u celosti, uključujući i


obrazloženje rešenja tamo gde je to potrebno.

U materijal je uključeno i nekoliko ispitnih zadataka, koji su rešeni u


potpunosti i komentarisani do odgovarajućeg stepena opširnosti.

Materijal će biti stalno dorađivan. Nove verzije će redovno biti


dodavane na Internet stranicu predmeta:

http://rti.etf.rs/ir1p2

Sugestije, primedbe i uočene greške poslati putem elektronske pošte


na adresu oo1p2@etf.rs.

Ove materijale treba koristiti isključivo kao podsetnik


a nipošto kao jedini izvor znanja.

Nemojte NIKAD učiti programski kod napamet.

Svako ponavljanje bez razumevanja programskog koda


je štetno i na ispitu će biti kažnjavano oduzimanjem poena.
Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

SADRŽAJ
Predstavljanje realnih brojeva 3
Standard za aritmetiku realnih brojeva 3
Zaokruživanje 5
Zadatak Z12 6
Zadatak IZ3 6
Zadatak IZ4 7
Zadatak IZ5 8
Zadatak IZ34A (integralni ispit, 09.10.1998. godine) 9
Zadatak Z14 9
Programski jezik C 10
Zadatak C5 10
Zadatak C10 11
Operatori: prioritet i redosled primene 12
Zadatak C15 13
Zadatak C20 14
Zadatak C25 15
Zadatak C30 16
Zadatak C35 17
Zadatak C40 17
Zadatak C45 18
Zadatak C47 19
Zadatak C48 19
Zadatak C50 20
Zadatak C55 21
Zadatak C57 22
Zadatak C60 22
Zadatak C65 23
Zadatak C70 24
Zadatak C75 25
Zadatak C80b 26
Zadatak C90 27
Zadatak C95 28
Zadatak C100 29
Zadatak C104 30
Zadatak C110 32
Zadatak C115 33
Zadatak C120 34
Zadatak C122 37
Zadatak C125 41
Zadatak CI-2007-Jan-2 42
Zadatak CI-2006-Okt-1 43
Zadatak CI-2007-Okt-2 44
Zadatak CI-2006-Sep-2 45
Zadatak CI-2006-Jan-1 46
Zadatak CI-2006-Jan-2 48
Zadatak CI-2006-Sep-1 49
Zadatak C2008-A1 50
Zadatak C2008-S11 50
Zadatak C2008-S12 51
Zadatak C2008-S21 51
Zadatak C2008-S22 52

Materijal za vežbe na tabli i pripremu ispita Strana 2/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

PREDSTAVLJANJE REALNIH BROJEVA


Standard za aritmetiku realnih brojeva
– Raznolikost predstavljanja realnih brojeva u računarima.
– Problem portabilnosti numeričkog softvera.
– Standard za binarnu aritmetiku realnih brojeva u pokretnom zarezu:
ANSI/IEEE Std 754-1985.
(IEEE – The Institute of Electrical and Electronics Engeneers
ANSI – American National Standard Institute)

Standard specificira:
1. Osnovni i prošireni format realnih brojeva
2. Operacije +, –, *, /, ostatka (rem), kvadratnog korena( ) i komparaciju realnih brojeva
3. Konverzije: celi brojevi ⇔ realni brojevi
4. Konverzije: realni brojevi ⇔ realni brojevi (različiti formati brojeva)
5. Konverzije: osnovni format realnih brojeva ⇔ decimalni niz znakova
6. Rukovanje kodovima grešaka

Osnovna osobina standarda: niz bitova, generisan kao rezultat aritmetičke operacije, može nositi
dvojaku informaciju:
1. ispravno obavljena operacija ⇒ niz bitova je rezultat operacije
2. detektovana je neka greška ⇒ niz bitova je binarno kodirani signal greške
(tzv. NaN = Not a Number)
Postoje dva tipa NaN–a:
1. signalni NaN (signal NaN) – signalizira neispravnu operaciju kad god se pojavi u ulozi
operanda
2. tihi (mirni) NaN (quiet NaN) – za skoro sve aritmetičke operacije ne signalizira neispravnost

U skladu sa IEEE standardom, realni brojevi se u memorijske reči smeštaju na sledeći način:

memorijska reč s eeeeeee mmmmmmmmmmm


broj bita u datom polju 1 k p
smisao polja znak eksponent mantisa

Ukupan broj bita: n = 1 + k + p

Vrednost tako predstavljenog realnog broja se računa na sledeći način:

R = (–1)s⋅2E⋅M

gde vrednosti s, E i M imaju sledeća tumačenja:


• s predstavlja znak datog broja (s=0 ⇒ broj je pozitivan; s=1 ⇒ broj je negativan)
• E predstavlja celobrojni eksponent, čija se vrednost računa u kôdu sa viškom, kao E = e-v,
gde je
o e vrednost neoznačenog celog broja čija se vrednost dobija na osnovu bita eee...e,
polja eksponent
o v se naziva višak, a predstavlja celobrojnu vrednost koja se računa: v=2k-1-1, gde je k
broj bita polja eksponent
• M predstavlja vrednost mantise sa skrivenim bitom (videti objašnjenje u nastavku)

Materijal za vežbe na tabli i pripremu ispita Strana 3/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

U zavisnosti vrednosti bita polja eksponent, postoje četiri različita načina tumačenja sadržaja
memorijske reči u kojoj je smešten realan broj.

1. Kada biti polja eksponent nisu sve 0 ili sve 1 (e≠0000...0 i e≠1111...1), vrednost
eksponenta E se nalazi u opsegu [Emin, Emax] i tada memorijska reč sadrži uobičajen realni
broj sa normalizovanom mantisom. Vrednost mantise M se računa dodavanjem skrivenog
bita vrednosti 1 i decimalnog zareza ispred niza bita polja mantisa: M=1.mmmmm...m.
Skriveni bit se podrazumeva pa zbog toga nije potrebno posebno ga skladištiti u memorijskoj
reči.
2. Kada su biti polja eksponent sve 0 (e=0000...0), ali biti polja mantisa nisu sve 0
(m≠0000...0), tada memorijska reč sadrži realan broj sa nenormalizovanom mantisom.
Vrednost eksponenta E se u ovom specijalnom slučaju računa kao E=e-v+1. Vrednost
mantise M se računa dodavanjem skrivenog bita vrednosti 0 i decimalnog zareza ispred niza
bita polja mantisa: M=0.mmmm...m. Kao i u prethodnom slučaju, ovaj skriveni bit se
podrazumeva. Smisao realnih brojeva sa nenormalizovanom mantisom je proširenje opsega za
realne brojeve veoma male apsolutne vrednosti.
3. Kada su biti polja eksponent i mantisa sve 0 (e=0000...0, m=0000...0), tada memorijska
reč sadrži realan broj čija je vrednost 0. Treba primetiti da zbog znaka (bit s), standard
dozvoljava postojanje pozitivne i negativne nule (+0 i -0) ali između njih ne pravi razliku (tj.
imaju istu vrednost).
4. Kada su biti polja eksponent sve 1 (e=1111...1), vrednost eksponenta E je veća od Emax i
razlikuju se dva slučaja:
a. vrednosti bita polja mantisa su sve 0 (m=0000...0) : realni broj ima vrednost ±∞ (u
zavisnosti od vrednosti bita s)
b. vrednosti bita polja mantisa nisu sve 0 (m≠0000...0) : radi se o NaN-u, koji označava
matematički nedefinisanu vrednost

Pozitivni realni brojevi, manji od najmanjeg realnog broja (minREALl) koji je moguće predstaviti sa
zadatim brojem bita se zaokružuju na vrednost 0 (tzv. potkoračenje, eng. underflow), dok se
pozitivni realni brojevi veći od najvećeg realnog broja (maxREAL) zaokružuju na vrednost +∞ (tzv.
prekoračenje, eng. overflow). Slično važi za negativne realne brojeve.
0
-∞ [ ] | [ ] +∞
-maxREAL -minREAL minREAL maxREAL

Standardni formati realnih brojeva

IEEE Standard uvodi 4 formata realnih brojeva (format se odnosi na broj bitova pojedinih polja):
(1) jednostruki (2) jednostruki prošireni (3) dvostruki (4) dvostruki prošireni

FORMAT w k p v Emax Emin


jednostruki 32 8 23 +127 +127 -126
jednostruki prošireni ≥ 43 ≥ 11 ≥ 32 nedef. ≥ +1023 ≤ -1022
dvostruki 64 11 52 +1023 +1023 -1022
dvostruki prošireni ≥ 79 ≥ 15 ≥ 64 nedef. ≥ +16383 ≤ -16382

Materijal za vežbe na tabli i pripremu ispita Strana 4/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2
Jednostruki format

1 k=8 p = 23
s e e e e e e e e mmmmmmmmmmmmmmmmmmmmmmm
31 30 23 22 0

Opseg brojeva:
1. Najmanji nenormalizovani: e=0 ⇒ R = (–1)s⋅2-126⋅(0.00000…………1)
2. Najveći nenormalizovani: e=0 ⇒ R = (–1)s⋅2-126⋅(0.11111…………1)
3. Najmanji normalizovani: e=1 ⇒ R = (–1)s⋅2-126⋅(1.00000…………0)
4. Najveći realan broj: e=254 ⇒ R = (–1)s⋅2127⋅(1.11111…………1)

minREAL = (–1)s⋅2-126⋅2-23 = (–1)s⋅2-149 ≈ (–1)s⋅1.4⋅10-45

maxREAL = (–1)s 2127⋅(1.111...1) ≈ (–1)s⋅2128 = (–1)s⋅3.4⋅1038

Zaokruživanje
Zbog ograničenog broja bita polja mantisa, najčešće nije moguće prezicno smeštanje realnog broja u
memorijsku reč, već se pristupa zaokruživanju. Podrazumeva se da je posmatrani broj, pre smeštanja
u memorijsku reč, beskonačno precizan, pa se zaokruživanje vrši sa ciljem da se uklopi u odredišni
format. Skoro sve operacije nad realnim brojevima daju najpre “beskonačno precizan” rezultat koji se
potom zaokružuje prema odredišnom formatu.
1. Osnovni način zaokruživanja: prema najbližoj vrednosti.
2. Ako su dve zaokružene vrednosti podjednako udaljene od “beskonačno precizne” vrednosti –
bira se ona vrednost kod koje je bit najmanjeg značaja 0.
3. Ako je apsolutna vrednost “beskonačno precizne” vrednosti:
|R| ≥ 2Emax⋅(2–2–p), vrši se zaokruživanje na (–1)s⋅(∞)
p i Emax se određuju iz odredišnog formata.

U praksi, ovo znači sledeće (desno od vertikalne crte se nalaze biti koji se odbacuju):

1 2 3 4
binarna x.xx | 0zzz...zzz x.xx | 1yyy...yyy x.x0 | 100...00 x.x1 | 100...00
predstava broja (makar jedan y je 1)
vrednost na koju x.xx x.xx + 0.01 x.x0 x.x1 + 0.01
se zaokružuje

Ako se pažljivije pogleda, ovakav način zaokruživanja odgovara uobičajenom načinu zaokruživanja
realnih brojeva.

Gubitak tačnosti ima za posledicu da kod računarskog sabiranja realnih brojeva ne važi uvek zakon
asocijativnosti.

Primer1: decimalni računar sa 4 značajne cifre:


R=123.4, r=0.049 ⇒ R+r=123.449 ≈ 123.4
Z1 = ((R+r)+r)+r = 123.4
Z2 = ((r+r)+r)+R = 123.4+0.147 = 123.547 ≈ 123.5 ≠ Z1

Opšte pravilo: početi sumiranje od brojeva manje apsolutne vrednosti.

Materijal za vežbe na tabli i pripremu ispita Strana 5/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

Zadatak Z12
Za smeštanje realnih brojeva koriste se 8 bitova od kojih 3 bita predstavljaju eksponent u kodu sa
viškom. Mantisa se smešta sa skrivenim bitom. Za brojeve veće od nule odrediti najmanju i najveću
vrednost koja se može predstaviti na gornji način.

Zadatak IZ3
Napomena: ovaj zadatak ilustruje razliku između savremenog IEEE standarda za reprezentaciju
realnih brojeva i standarda VAX koji mu je prethodio.
Format predstave realnih brojeva je seeeemmmmm – s je bit za znak broja, eeee su bitovi za
eksponent broja (kôd sa viškom), a mmmmm su bitovi normalizovane mantise (sa skrivenim bitom).
U računaru A – predstava realnih brojeva je sa viškom 8, a u računaru B – sa viškom 7. U računaru A
– mantisa je 0.5≤MA<1, a u računaru B – mantisa je 1≤MB<2. Izgled jednog broja u računaru B, u
skladu sa opisanim formatom, je 3DF16. Kako je predstavljen realan broj iste vrednosti u računaru A?
A) 3DF16
B) 3FF16
C) 3FE16
Rešenje
Prvi način: Moguće je reći, da je predstava realnih brojeva u računaru B u skladu sa duhom IEEE
standarda, imajući u vidu da je višak 7 = 24-1 -1, a mantisa je oblika MB = 1.mmmmm.
Zbog toga, broj 3DF16 = 1|1110|111112 predstavlja maxREAL, kad je računar B u pitanju.

Moguće je zaključiti, da je predstava realnih brojeva u računaru A – u skladu sa starom (VAX)


predstavom brojeva (8 = 24-1, MA = 0.1mmmmm).

Kako je maxREALIEEE = 2⋅maxREALVAX, može se zaključiti da ovaj broj nije moguće predstaviti u
računaru A, jer je maxREALVAX dva puta manji od posmatranog broja.

Drugi način:
B: 3DF16 = 1|1110|111112 EB = eeeeB – 7 = 7 MB = 1.mmmmmB = 1.111112

XB = –1.111112⋅27 = –111111002 XA = XB = –0.1111112⋅28

MA = 0.1mA mA = 111112

EA = eA + 8 = 1610 = 100002 a to nije moguće predstaviti u polju eA koje je širine 4 bita.

Odgovor: N

Materijal za vežbe na tabli i pripremu ispita Strana 6/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

Zadatak IZ4
Format predstave realnih brojeva pomoću reči širine 10 bita je: bit najveće težine za znak broja,
četiri bita za eksponent u kôdu sa viškom 7, i pet bitova najmanje težine za normalizovanu mantisu
sa skrivenim bitom (1≤M<2). Rezultat sabiranja brojeva čiji je izgled A=16068 i B=05158 je:
A) 16338
B) 15668
C) 17668
Rešenje
A: 1|1100|00110 B: 0|1010|01101
SA=1 ⇒ A <0 SB=0 ⇒ B >0
EA=12–7=5 EB=10–7=3
MA=1.00110 MB=1.01101

EA > EB ⇒ B = MB⋅2EB = MB⋅2EB–EA⋅2EA = MB⋅2–2⋅2EA = MB’⋅2EA; MB’ = MB / 22

MB’ = 0.01011|01 |MA| > |MB’| ⇒ A + B = – (MA – MB’)⋅2EA = –MA+B⋅2EA

MA = 1.00110
–MB’ = 0.01011
––––––––––––––––––
MA+B = 0.11011 ovde se mora izvršiti normalizacija.

MA+B = 1.10110⋅2–1

A + B = –MA+B⋅2EA = –1.10110⋅2–1⋅2EA = –1.10110⋅2EA-1 = –MA+B’⋅2EA+B’

SA+B = 1 MA+B’ = 1.10110 EA+B’ = EA – 1 = 4 eA+B = 4 + 7 = 11

s = 1, eeee = 1011, mmmmm = 10110

(A + B) : 1|1011|10110 = 1|101|110|110 =15668

Odgovor: B

Materijal za vežbe na tabli i pripremu ispita Strana 7/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

Zadatak IZ5
U nekom računaru, celi brojevi su predstavljeni u drugom komplementu pomoću reči širine 10 bita,
a za predstavljanje realnih brojeva je takođe predviđeno 10 bita, i to tako da bit najveće težine
određuje znak broja, sledeća 4 bita su za eksponent broja u kôdu sa viškom 7, a preostalih 5 za
normalizovanu mantisu sa skrivenim bitom (1≤M<2). Ako je izgled realnog broja na lokaciji X: 39716,
a izgled celog broja na lokaciji J: 31016, koji će biti izgled lokacije realne promenljive Y nakon izvršene
operacije Y=X+J? Računanje obavljati upotrebljavajući realne brojeve.
A) 3FA16
B) 3E516
C) 3BA16
Rešenje
X: 1|1100|10111 J: 1100010000
–J = 0011110000 = 1.111⋅27
SX = 1, X<0 SJ = 1, J<0
MX = 1.10111 MJ = 1.11100
EX = 12 – 7 = 5 EJ = 7

EJ > EX
X = – MX⋅2-2⋅27
MX’ = 0.01101|11 ≈ 0.01110

Y = – (MJ + MX’) ⋅ 2Ej

MJ= 1.11100
+MX’= 0.01110
–––––––––––––
MY =10.01010 = 1.00101 ⋅ 21

Y = – MY’ ⋅ 2EY+1 = -1.00101 ⋅ 28

s = 1, e = 8 + 7= 1510 = 11112, eeee = 1111, mmmmm = 00101

Y: 1|1111|00101 = 3E516

Odgovor: B

Materijal za vežbe na tabli i pripremu ispita Strana 8/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

Zadatak IZ34A (integralni ispit, 09.10.1998. godine)


Realni brojevi se predstavljaju sa 11 bita formatom seeeeemmmmm gde je s bit za predznak
broja, eeeee (5) biti eksponenta u kodu sa viškom 8, a mmmmm (5) biti normalizovane mantise sa
skrivenim bitom 0.5<=M<1. Celi brojevi predstavljaju se sa 10 bita u drugom komplementu. Ceo broj
I ima izgled 17716 a ceo broj J ima izgled 32516. Najpre se izvrši celobrojno sabiranje N=I+J. Zatim se
izvrši konverzija brojeva I i J u realne brojeve, i sabiranjem tih realnih brojeva dobije broj B. Kolika će
biti apsolutna vrednost razlike brojeva N i B? (Napomena: Sva zaokruživanja vrše se prema pravilima
IEEE standarda, a svi koraci u sabiranju realnih brojeva vrše se na širini određenoj formatom
mantise.)
A) 4 B) 8 C) 2.125
Rešenje
Prvo ćemo izvršiti celobrojno sabiranje.
I = 17716 = 01 0111 0111
J = 32516 = 11 0010 0101
I+J= 100 1001 1100
Pošto u memoriji imamo samo 10 bita sa predstavljanje celih brojeva, jedanaesti bit koji je generisan
u procesu sabiranja otpada i dobijamo 00100111002 = 9C16 = 15610 kao rešenje.
Realno sabiranje se vrši tako što prvo celobrojne vrednosti konvertujemo u realne, uz potrebna
zaokruživanja, a potom dobijene realne vrednosti saberemo.
I: J: 11 0010 0101, što znači da je J<0.
0101110111 = 0.101110111∙2 ≈ 0.101111∙2 s -J: 00 1101 1011 = 0.11011011∙28 ≈ 0.110111∙28
9 9

Sada je potrebno svesti ova dva broja na isti eksponent i pri tome izvršiti zaokruživanja, ako se za
tim ukaže potreba:
J = (-1)∙0.110111∙28 = (-1)∙0.0110111∙28 ≈ (-1)∙0.011100∙28.
Pošto su brojevi različitog znaka, oduzimamo mantisu manjeg od mantise većeg broja:
MI: 0.101111
-MJ: - 0.011100
MI-MJ: 0.100110
Traženi broj izgleda ovako: 0.100110∙28, što je jednako pozitivnom celom broju 00100110002 = 9816
= 15210.
Odavde se može zaključiti da je apsolutna razlika ova dva zbira jednaka 4.
Napomena: Kada se vrši konverzija iz celobrojnog u realni broj, vrši se zaokruživanje na po
vrednosti najbliži realni broj koji se može predstaviti u memoriji datog računara. Konverzija u
obrnutom smeru podrazumeva ili zaokruživanje početnog realnog broja na po vrednosti najbliži celi
broj ili prosto odsecanje razlomljenog dela realnog broja. Ako nije posebno naglašeno, podrazumeva
se prvi pristup.

Odgovor: A

Zadatak Z14
Brojevi sa pokretnom tačkom u računaru imaju binarni oblik seeeeeemmmmmmmmm, gde je s
bit za znak broja, m su bitovi normalizovane mantise sa skrivenim bitom (0.5≤M<1), e su bitovi
eksponenta u kodu sa viškom 25. Naći zbir brojeva x i y čiji su oblici u računaru zadati u brojnom
sistemu sa osnovom q. Rezultate proveriti pretvaranjem zadatih vrednosti i rezultata u decimalni
brojni sistem.

Materijal za vežbe na tabli i pripremu ispita Strana 9/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

PROGRAMSKI JEZIK C
Zadatak C5
Sledeći program za određivanje rešenja linearne jednačine Ax+B=0, za A<>0, napisan na
programskom jeziku C, sadrži više grešaka. Ispraviti sve greške!
main main predstavlja funkciju – treba da stoji main()
Float _x,a,b C je CaseSensitive jezik (razlikuje mala i velika slova)
deklaracija treba da stoji unutar programskog bloka
{
scanf('%f %f',a,b); niz znakova u jeziku C se ogranicava parom znakova "
scanf zahteva adresu, a ne vrednost; Prevodilac za jezik C ne
prijavljuje ovo kao gresku.
_x=-b/a;
printf('%f',_X) _X nije dobro, jer smo deklarisali _x
}

Rešenje:
Ispravljeni program izgleda ovako:
#include <stdio.h> /* na početku svakog programa dolaze direktive */
main()
{
float _x,a,b; /* _x ne smeta (Promenljiva moze sadrzati znak _ ) */
scanf("%f %f",&a,&b);
_x=-b/a;
printf("%f",_x); /* svaka naredba jeziku C završava se znakom tacka-zarez; */
}

Komentar:
Neispravno napisan program je testiran i kompajliran u programskom paketu Visual Studio.net.
Poruke kompajlera su sledeće:
Compiling...
c5.c
c5.c(5) : error C2061: syntax error : identifier 'Float'
c5.c(5) : error C2059: syntax error : ';'
c5.c(7) : error C2143: syntax error : missing ';' before '{'
c5.c(7) : error C2449: found '{' at file scope (missing function header?)
c5.c(8) : error C2015: too many characters in constant
c5.c(14) : error C2059: syntax error : '}'
Na početku svakog programa koji nešto učitava ili ispisuje mora postojati direktiva include sa
parametrom <stdio.h>. Ovo predstavlja uputstvo prevodiocu da iz datoteke stdio.h treba da
pročita osobine bibliotečkih funkcija za ulaz i izlaz podataka.

Materijal za vežbe na tabli i pripremu ispita Strana 10/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

Zadatak C10
Sastaviti program na programskom jeziku C za ispisivanje tablice ASCII kodova za sve štampajuće
znake.
Rešenje
ASCII kod sa brojem 32 je blanko simbol ili razmak. Prva 32 ASCII koda (od 0 do 31) i svi ASCII
kodovi veći ili jednaki 127 predstavljaju specijalne simbole koji se koriste u različite svrhe i najčešće
nemaju neko jasno slovno značenje. Koristili su se za iscrtavanje DOS prozora, i na taj način simulirali
grafiku u tekstualnom režimu rada. Konkretno, prozori razvojnog okruženja Turbo C su napravljeni na
ovaj način! ASCII kodovi između 32 i 126 su štampajući znaci, i ima ih ukupno 95.
Znaci se prikazuju po kolonama. U jednoj koloni se prikazuje po 19 znakova, a u jednom redu se
prikazuje po 5 znakova (5x19=95). Prikazaćemo sve ASCII kodove od 32 do 126.
Program za prikazivanje tablice ASCII kodova može se realizovati na više načina.
I način
#include <stdio.h>
main()
{
char c;
int i;
printf ("\t\tTablica ASCII kodova \n \n");
for(c = ' '; c < ' ' + 19; c++)
{
for(i = 0; i < 95; i += 19)
printf("%3d%c ", c+i, c+i);
putchar('\n');
}
}

II način – ovako NE TREBA raditi!!!


#include <stdio.h>
main()
{
char c=' ';
int i;

printf ("\t\tTablica ASCII kodova \n \n");


linija:
i=0;
znak:
printf("%3d %c ", c+i, c+i);
i=i+19;
if (i<95) goto znak;
printf("\n");
c=c+1;
if (c<' '+19) goto linija;
}

Komentar:
U drugom rešenju se koristi skok sa proizvoljnim odredištem: goto. Korišćenje naredbe goto treba
izbegavati (bilo koji algoritam koji sadrži goto može se ostvariti na neki drugi način, što i pokazuje prvo
rešenje). Glavni razlog za izbegavanje naredbe goto je taj što ta naredba ima veliki stepen slobode u izboru
odredišta skoka tako da omogućava sastavljanje nestrukturiranih, vrlo nepreglednih programa, koji jako često
sadrže mnogo grešaka uzrokovanih upravo lošom strukturom.

Materijal za vežbe na tabli i pripremu ispita Strana 11/52


Elektrotehnički fakultet Univerziteta u Beogradu Programiranje 2

Operatori: prioritet i redosled primene


SMER
PRIORITET BROJ OPERANADA OPERATORI
GRUPISANJA
15 2 [] () . -> →
14 1 ! - ++ -- + - * & (tip) sizeof ←
13 2 * / % →
12 2 + - →
11 2 << >> →
10 2 < <= > >= →
9 2 == != →
8 2 & →
7 2 ^ →
6 2 | →
5 2 && →
4 2 || →
3 3 ?: ←
2 2 = += -= *= /= %= &= ^= |= <<= >>= ←
1 2 , →

Primeri
Relacijski operatori Operatori za dodelu vrednosti
Izraz Objašnjenje (rezultat) Izraz Objašnjenje
5 > 7 0 y = a * x + b
10 <= 20 1 d *= e + f d = (d*(e+f))
8 == 13 > 5 8==(13>5) -> 8==1 -> 0 d = d * e + f d = ((d*e)+f)
14 > 5 < 3 (14>5)<3 -> 1<3 -> 1 a=b=c=d+5 c=d+5,b=c,a=b
a < b < 5 (a<b)<5 -> (0/1)<5 -> 1 a = b++ + c=d<<3,u=b,b=b+1,a=u+(3*c)
a+5 >= c-1.0/e (a+5)>=(c-(1.0/e)) 3*(c=d<<3)
a = b++ + 3*c greška !
= d<<3

Redosled računanja i bočni efekti


((a<<5)+4/b)*(d-=c-2) * ++e
Standard garantuje da će se pre množenja izračunati vrednosti operanada u zagradama. Standard ne
precizira kojim će se redom računati (prvo levi ili prvo desni operand) – implementaciona zavisnost.
Ako rezultat zavisi od redosleda izračunavanja operanada - loš stil pisanja izraza.
Bočni efekti: uzgredna promena vrednosti jedne ili više promenljivih. Rezultat zavisi od redosleda
izračunavanja operanada ako se bar jedna promenljiva, koja podleže uticaju nekog bočnog efekta,
koristi na više od jednog mesta u izrazu. Operatori koji proizvode bočne efekte su ++, -- i svi
operatori dodele vrednosti.
Izraz Objašnjenje
a=b*c + b++ u=b*c, v=b, b++, a=u+v
v=b, b++, u=b*c, a=u+v
a=b*c+(b=d/e) u=b*c, v=(b=d/e), a=u+v
v=(b=d/e), u=b*c, a=u+v
a[i] = ++i Indeksiranje je bin.op.
u=i, ++i, v=i, a[u]=v
i++, v=i, u=i, a[u]=v

Materijal za vežbe na tabli i pripremu ispita Strana 12/52


Zadatak C15
Odrediti čemu su ekvivalentni sledeći izrazi (koristiti zagrade da bi se eksplicitno odredio redosled
izračunavanja)
1. x+=y-=m
2. n%=y+m
3. m++ - --j
4. x=j * j++
5. ++j==m!=y*2

Odgovor:
1. x=(x+(y=(y-m))
2. n=(n % (y+m))
3. m-(j-1); m=m+1; j=j-1
4. x=j * j++ ; ovo zavisi od toga kojim se redom racuna, sa leva na desno ili obrnuto
Odgovor: implementaciono zavisno
5. ((j+1)==m)!=(y*2); j=j+1

Primer – Bočni efekti (autor: Jelica Protić)


Sledeći primer ilustruje manifestovanje bočnih efekata u 8 različitih izraza, za različite prevodioce
jezika C. Inicijalna vrednost promenljive j je 5.
izraz VS 6.0 VS .NET 2003 TC 2.0 GNU GCC ARM C
1. j * j++ 25 25 30 25 30
2. j++ * j 25 25 30 25 30
3. ++j * j 36 36 36 36 36
4. j * ++j 36 36 36 36 36
5. (j=3) * (j++) 9 9 9 9 9
6. (j=3) * (++j) 16 16 12 12 12
7. (j++) * (j=3) 9 9 15 9 15
8. (++j) * (j=3) 9 9 18 9 18
Pitanje: zašto VS dobija 16 kao rezultat u primeru 6?
Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C20
Sastaviti program na programskom jeziku C koji učitava srednje temperature po mesecima za 12
meseci i na osnovu njih izračuna i ispiše srednju temperaturu za celu godinu.
Rešenje:
#include <stdio.h>
#define BROJ_MESECI 12
main()
{
enum meseci {JAN=1,FEB,NAR,APR,MAJ,JUN,JUL,AVG,SEP,OKT,NOV,DEC};
enum meseci mesec=JAN;
/*
Moguce je umesto gornje dve linije napisati samo jednu:
enum meseci {JAN=1,FEB,NAR,APR,MAJ,JUN,JUL,AVG,SEP,OKT,NOV,DEC} mesec=JAN;
*/
float temperature[BROJ_MESECI];
float srednja_temp=0;

while (1)
{
printf("Temperatura za mesec %2d: ",mesec);
scanf("%f",&temperature[mesec - 1]); /* niz u C-u uvek ide od 0 */
srednja_temp+=temperature[mesec - 1];
if (mesec==DEC) break;
mesec++;
}

srednja_temp/=BROJ_MESECI;
printf("Srednja temperatura je %.2f\n",srednja_temp);
}

/*
Jasno je da nam niz nije potreban za racunanje srednje vrednosti
dovoljno je da mesecnu temperaturu ucitavamo u neku pomocnu (float)
promenljivu i da nju dodajemo na srednja_temp
*/

Komentar
Prikaz nekih vrednosti adresa i niza temperature:
&temperature,p: 22FC(SS):0FCC
&temperature[0],p: 22FC(SS):0FCC - adresa clana 0
&temperature[1],p: 22FC(SS):0FD0 - adresa clana 1
temperature: { 3.0,8.0,12.0,15.0,20.0,26.0,29.0,30.0,26.0,20.0,13.0,7.0 }
- prikaz celog niza
temperature[0]: 3.0 - vrednost clana sa indeksom 0
Ovakav prikaz se može dobiti pomoću Watch prozora razvojnog okruženja Turbo C. Najpre se navodi izraz čija
se vrednost posmatra, a onda način kako ona treba da bude ispisana. Uz pomoć ovog dodatka, može se isti
izraz posmatrati na više načina.
izraz,d – kao broj
izraz,c – kao karakter
izraz,p – kao pokazivač (adresa)

Materijal za vežbe na tabli i pripremu ispita Strana 14 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C25
Sastaviti program na programskom jeziku C za određivanje broja velikih slova, malih slova i cifara
u tekstu koji se iz proizvoljnog broja redova učitava preko glavne ulazne jedinice. Tekst se završava
znakom za kraj datoteke.
Rešenje
#include <stdio.h>
#include <ctype.h> /* treba za funkcije vezane za ispitivanje slova */
main()
{
int znak, vel_sl=0, mal_sl=0,cifra=0;

printf("Unesite zeljeni tekst \n");

while ((znak=getchar())!=EOF)
{
vel_sl += isupper(znak) != 0; /* ctype.h */
mal_sl += islower(znak) != 0; /* ctype.h */
cifra += isdigit(znak) != 0; /* ctype.h */
}
printf("Velikih slova ima %d\n",vel_sl);
printf("Malih slova ima %d\n",mal_sl);
printf("Cifara ima %d\n",cifra);
}

Komentar
U zaglavlju ctype.h se nalaze prototipovi funkcija za ispitivanje znakova. U ovom programu su upotrebljene
sledeće funkcije:
- isupper(znak): ispituje da li je zadovoljen uslov (znak>='A') && (znak<='Z')
- islower(znak) : ispituje da li je zadovoljen uslov (znak>='a') && (znak<='a')
- isdigit(znak) : ispituje da li je zadovoljen uslov (znak>='0')&&(znak<='9')
Sve is_ funkcije vraćaju 0 za logičku neistinu, a različito od 0 (ne obavezno 1) za logičku istinu

Materijal za vežbe na tabli i pripremu ispita Strana 15 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C30
Sastaviti program na programskom jeziku C koji učitava decimalan pozitivan celi broj u obliku niza
znakova i ispisuje njegovu vrednost u binarnom obliku. Pretpostaviti da se za interno predstavljanje
celih brojeva koristi 16 bitova.
Rešenje
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
main()
{
char dec[10];
short int bin, i;

printf("Unesite decimalan broj: ");


scanf("%s",dec); /* ucitava string sa standardnog ulaza (dec=&dec[0]) */
/*
atoi vraca 0 ukoliko nije uspela konverzija.
Ukoliko je strlen(dec)=0 onda se drugi deo USLOVA (iza && operatora)
nece ni proveravati. Po postavci zadatka ocekuje se pozitivan broj,
i takav uslov se jednostavno, ovim putem, moze proveriti.
*/
if (strlen(dec) && (bin=atoi(dec)))
{
printf("Binarni broj: ");
i=-1;
while (++i<16)
{
putchar((bin & 0x8000) ? '1' : '0');
/*
0x8000 ima jedinicu na najvisem 15-om bitu
Gornja naredba ce ispisati 15-i bit broja bin!
Najpre ispisujemo najvise bitove, jer takav prikaz zelimo na ekranu
bit15 bit14 ... bit2 bit1 bit0
*/
bin <<= 1 ; /* bin = bin shl 1 ; pomeramo bin ulevo za 1 bit */
if (i%4 == 3)
putchar(' '); /* prikaz razmaka izmedju svake polovine bajta */
}
printf("\n");
}
else
printf("Neispravan broj ili nula\n");
}

Komentar
16-bitni binarni broj može da ima najveću vrednost 65535, ukoliko se tretira kao unsigned, odnosno 32767,
ukoliko se tretira kao signed. To konkretno znači da je za ovaj 16-bitni prikaz dovoljno koristiti niz brojeva
char dec[6] (5 za cifre i 1 za terminator). Sa druge strane, ako se u ovom zadatku unese neki broj veći od
65535/32767 rezultat neće biti ispravan (biće prikazano samo najnižih 16-bitova zadatog broja ako je short int
na datom računaru duži od 16 bita).
Funkcija atoi se može koristiti i za konverziju negativnih vrednosti.
Treba imati na umu i sledeću činjenicu: ako se unese više od 10 znakova nepredvidiv je ishod izvršavanja
ovog programa, jer niz 'dec' ima dodeljeno svega 10 znakova (bajtova) u memoriji i ništa preko toga! Ostatak
memorije pripada drugim podacima ili drugom programskom kodu, tako da se upisivanjem van granica niza
može izazvati nepredvidivo ponašanje.

Materijal za vežbe na tabli i pripremu ispita Strana 16 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C35
Koja od datih konstrukcija na programskom jeziku C predstavlja ekvivalent iskaza na programskom
jeziku Pascal: if (a>b) then begin a:=1; b:=1 end
A) if (a>b) { a=1; b=1; }
B) if (a>b) a=1, b=1;
C) if (a>b) a=1; b=1;

Komentar
Odgovor će biti A ili V (A i B), zavisno od toga kako se definiše ekvivalentnost dva iskaza.
A) Ovo je upravo prepisana selekcija sa Pascala na C.
B) Ukoliko je ispunjen uslov biće izvršena jedna instrukcija u then grani, pri čemu se ona sastoji od
2 izraza. Efekat izvršavanja ova dva izraza je u ovom slučaju identičan slučaju pod A).
C) b=1 se izvršava u svakom slučaju, što ne važi za originalni segment.

Zadatak C40
Šta ispisuju sledeći programi?
a) b)
#include <stdio.h> #include <stdio.h>
main() main()
{ {
int x; int x=0,i;
for (x=0;x<100;x++) for (i=0;i<5;i++)
{ switch (i)
/* ako x nije deljivo sa dva {
vrati se na pocetak tela ciklusa */ case 1: x+=1;
if (x%2) /* ukoliko je i=1 izvrsava se deo
continue; iza case 1: i case 2: */
/* do ovde dolazi samo ako je case 2: x+=2; break;
x deljivo sa 2 (x mod 2 = 0) */ /* Ako je i=2 izvrsava se samo deo
printf("%d\n",x); iza case 2: (zbog break;) */
} case 4: x+=3;
} /* Ako je i=4 izvrsava se samo deo
A) Sve cele brojeve od 0 .. 99 iza case 4: */
}
B) Sve parne brojeve od 0 .. 99 printf("d=%d\n",x);
C) Sve neparne brojeve od 0 .. 99 }
A) 5
Odgovor
B) 6
B C) 9
Odgovor
N
Komentar
Najpre je x=0;
Za i=0, x se ne menja (x=0);
Za i=1, x+=1; x+=2; => x=3;
Za i=2, x+=2; => x=5;
Za i=3, x se ne menja;
Za i=4, x+=3; => x=8;

Materijal za vežbe na tabli i pripremu ispita Strana 17 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C45
Sastaviti program na programskim jeziku C koji formira slučajan celobrojni niz sastavljen od
jednocifrenih brojeva i izvrši uređivanje niza po neopadajućem redosledu vrednosti brojeva.
Rešenje:
Za sortiranje brojeva postoji niz algoritama. Više detalja o ovoj oblasti se može pronaći u knjizi
“Strukture podataka” profesora Tomaševića. Ovde je predstavljen najjednostavniji algoritam pod
nazivom Selection sort, odnosno sortiranje metodom izbora. Ideja je sledeća: u i-tom prolazu se
odabere i-ti (u ovom slučaju) najmanji broj, pa se smesti na i-to mesto.
#include <stdio.h>
#include <stdlib.h>
#define DIM 50

main()
{
int n,a[DIM],i,j,b;
for (;;)
{
printf("\n\n Duzina niza (max %d): ",DIM); scanf("%d", &n);
if ((n <= 0) || (n > DIM)) break;
/* break prekida for ciklus. Ovo je ciklus sa izlazom u sredini */
printf("\nPocetni niz: \n\n");
for (i=0;i<n;i++)
printf("%d%c", a[i] = rand()/((double)RAND_MAX+1.0)*10,
(i % 30 == 29 || i == n-1) ? ('\n') : (' '));
/* Generisace se slucajni brojevi u intevalu od 0 .. 10.
rand() generise slucajan broj od 0 .. RAND_MAX
(RAND_MAX je u slucaju TurboC-a 32767 ) */

/* sledi sortiranje */
for (i = 0; i < n-1; i++)
for (j = i+1; j < n; j++)
if (a[i] > a[j]) b = a[i],a[i] = a[j],a[j] = b; /* zamena 2 promenljive */

printf("\nSortirani niz:\n\n");
for (i = 0; i < n; i++)
printf("%d%c", a[i], (i % 30 == 29 || i == n-1) ? ('\n') : (' '));

/* Deo (i%30==29 || i==n-1) ? ('\n') : (' ') predstavlja karakter


koji treba da se napise iza broja (Clana) niza. Ukoliko se nalazimo
na kraju niza (poslednji element i==n-1), ispisujemo znak za novi red.
Takodje, radi jasnijeg prikaza posle svakog 30-tog clana niza ispisujemo
isto znak za novi red. U svakom drugom slucaju ispisuje se blanko (razmak).*/
}
}
Primer sortiranja 10 slučajnih brojeva:
Prolaz 1: a: { 2, 4, 1, 6, 5, 0, 1, 8, 6, 7 }
Prolaz 2: a: { 0, 4, 2, 6, 5, 1, 1, 8, 6, 7 }
Prolaz 3: a: { 0, 1, 4, 6, 5, 2, 1, 8, 6, 7 }
Prolaz 4: a: { 0, 1, 1, 6, 5, 4, 2, 8, 6, 7 }
Prolaz 5: a: { 0, 1, 1, 2, 6, 5, 4, 8, 6, 7 }
Prolaz 6: a: { 0, 1, 1, 2, 4, 6, 5, 8, 6, 7 }
Prolaz 7: a: { 0, 1, 1, 2, 4, 5, 6, 8, 6, 7 }
Prolaz 8: a: { 0, 1, 1, 2, 4, 5, 6, 6, 8, 7 }
Prolaz 9: a: { 0, 1, 1, 2, 4, 5, 6, 6, 7, 8 }

Materijal za vežbe na tabli i pripremu ispita Strana 18 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C47
Koji od programskih segmenata na programskom jeziku C daju isti izlaz kao dati programski
segment na programskom jeziku Pascal?
j:= -2;
for i:= -2 to j*j do
begin write(j:3); j:=j+1 end;
A) for (i=j=-1;i<=j*j;i++,j++) printf(" %3d ",j);
B) i=-2; while (printf(" %3d ",i),i++ -4);
C) i=j=-2; while (i++ == 4 ? 0 : 4) printf(" %3d ",j++);

Obrazloženje:
U programskom jeziku Pascal se interval for ciklusa određuje neposredno po ulasku u ciklus i ne
menja se u toku izvršavanja ciklusa, dok se u programskom jeziku C uslov kod for ciklusa računa pre
svakog ponavljanja.
Ovaj programski segment na programskom jeziku Pascal ispisuje -2,-1,0,1,2,3,4.
Programski segment (A) na programskom jeziku C je logički neispravan, jer i nikada neće prestići
vrednost j*j. Dodirna tačka im je za i==0,j==0 i i==1,j==1, ali posle toga zbog obostranog
inkrementiranja i će biti uvek manje od j*j. U realnosti, u nekom trenutku će doći do prekoračenja
opsega celih brojeva, i j*j će postati manje od i, za vrednost j takvu da vrednost izraza j*j
prekoračuje maksimalni celi broj.
Programski segment (B) na programskom jeziku C je logički ispravan i ispisuje iste vrednosti kao i
dati programski segment na programskom jeziku Pascal. Zadnji ispisani broj je 4, tada se ne postiže
uslov za ulaz u petlju (i-4 == 0, što predstavlja logičku neistinu), a kao bočni efekat i=5.
Programski segment (C) na programskom jeziku C je logički ispravan. Međutim, on ne ispisuje iste
vrednosti kao i programski segment na programskom jeziku Pascal. Ispisuje jedan broj manje (tj. sve
od -2 do 3). Iz ciklusa se izlazi kada je i==4. Broj koji se ispisao pre toga je bio 3, a bočni efekat je
bio j=4.

Zadatak C48
Data su tri segmenta programa na programskom jeziku C:
I
for (i=x=y=0; ; ++i)
{x++; if (i==n) break; y++; }
printf(“%ld %ld”,x,y);

II
x=0, y=0;
for (i=0; i<=n; i++)
{x=x+1; if (i<n) continue; y=y+1;}
printf(“%ld %ld”,x,y);

III
x=i=0;
while (i<=n)
{ i++; ++x; y=x>n;}
printf(“%ld %ld”,x,y);
Ako su sve promenljive celi brojevi koja dva segmenta daju isti izlaz za n>0?
A) I i II B) II i III C) I i III
Obrazloženje:
I uvek ispisuje x=n+1, y=n,a II i III uvek ispisuju x=n+1, y=1 (n ne utiče na vrednost y).

Materijal za vežbe na tabli i pripremu ispita Strana 19 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C50
Napisati na programskom jeziku C program koji analizira tekst koji se unosi sa standardnog ulaza,
prepoznaje realne brojeve po formatu cc...c.ddd...d i ispisuje ih po formatu c.ddE+ee, a sve
ostale učitane znake ispisuje bez izmene.
Rešenje
#include <stdio.h>
#include <ctype.h>
#define DECIMALNA_TACKA '.'
#define ZNAK_ZA_KRAJ '!'

main()
{
int c, j, broj_cifara;
double vrednost, decimala;

do
{
/* sve dok se ne pojavi neka cifra, ispisuju se karakteri sa ulaza */
while (! ( isdigit(c = getchar()) || (c==ZNAK_ZA_KRAJ) ) )
putchar(c);
if (c == ZNAK_ZA_KRAJ)
break; /* Ukoliko je nadjen znak ! onda se prekida glavna petlja */

vrednost = 0.;
broj_cifara = 0;
/* sve dok se ne naidje na tacku, dodaje se vrednosti pritisnuta cifra na kraj */
while ( isdigit(c) )
vrednost = vrednost * 10 + (c-'0'), c = getchar();
if (c == DECIMALNA_TACKA)
/* sve dok se unose cifre, dodaju se na kraj decimalnog dela */
{
c=getchar();
while ( isdigit(c) )
{
broj_cifara++;
decimala = c - '0';
for (j=0; j < broj_cifara; j++)
decimala/=10;
vrednost += decimala;
c = getchar();
}
}
ungetc(c,stdin);
printf("%1.2E",vrednost);
} while (c != ZNAK_ZA_KRAJ); /* '!' je trenutno znak za kraj */
}

Obrazloženje
Iz programa se izlazi ukoliko se bilo gde u liniji upiše znak '!'
Od unete cifre, broj koji ona predstavlja dobija se kada se od njenog ASCII koda oduzme ASCII
kod znaka '0'.
Pitanje
Šta će se dobiti na izlazu za sledeći red?
123.123.123
Odgovor:
1.23E+02.1.23E+02

Materijal za vežbe na tabli i pripremu ispita Strana 20 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C55
Šta ispisuje sledeći program?
a)
/*C55a*/
#include <stdio.h>
main()
{
int a[]={1,0}, *p;
p=a;
printf("%d, ", *p++);
printf("%d\n", *p);
}
A) 1, 2 B) 1, 0 C) 0, 0
Komentar
Odgovor je B. Prioritet * i ++ je isti, ali je asocijativnost ove grupe operatora sdesna ulevo.
b)
/*C55b, J.Protic*/ printf("\n");
#include <stdio.h> for (p=&a[0], i=0; p+i<a+4; p++, i++)
main() printf("%d", *(p+i));
{ printf("\n");
int a[]={0, 1, 2, 3, 4}; for (p=a+4, i=0; i<=4; i++)
int i, *p; printf("%d", p[-i]);
for (p=a, i=0; p<=&a[4]; p++) printf("\n");
printf("%d", *p); }

Rešenje
01234
02
43210

c)
/*C55c, L.Kraus, primer, modifikacija J.Protic, I.Tartalja, dopuna A.Bosnjakovic*/
#include <stdio.h>
#include <stdlib.h>
main()
{
int **a, n, i, j;
printf("N="); scanf("%d", &n);
a = calloc(n, sizeof(int*)); /*alocira memoriju za n pokazivaca na vrste*/
for (i=0; i<n; i++)
{
*(a+i)= calloc(n, sizeof(int));
/*alocira memoriju za n elemenata vrste koji su tipa int*/
for (j=0; j<n; j++) *(*(a+i)+j) = rand()/((double)RAND_MAX + 1) * 10;
/* C55c.c(44) : warning C4244: '=' : conversion from 'double ' to 'int ', possible loss
of data */
}
for (i=0; i<n; printf("\n"), i++)
for (j=0; j<n; j++)
printf("%d", *(*(a+i)+j));
for (i=n-1; i>=0; i--) printf("%d", *(*(a+i)+n-1-i));
putchar('\n');
}
A) sadržaj matrice vrstu po vrstu, a potom sporednu dijagonalu, sleva-udesno
B) sadržaj matrice vrstu po vrstu, a potom glavnu dijagonalu, sdesna-ulevo
C) sadržaj matrice vrstu po vrstu, a potom sporednu dijagonalu, sdesna-ulevo
Odgovor:
A
Materijal za vežbe na tabli i pripremu ispita Strana 21 od 52
Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C57
Da bi se učitani znakovni niz (string) precizno ispisao «unatrag» (samo znaci koji su unošeni sa
standardnog ulaza), koja naredba se može staviti umesto ***?
scanf(%s%, string1); a = string1; *** while (a>string1) putchar(*(--a));
A) while (*a) a++;
B) for (; *a; a++);
C) while (*a++);
Odgovor
V (A i B)
Komentar
Umesto *** mora da stoji naredba koja će postaviti pointer a tako da pokazuje na NULL (‘\0’)
karakter pointera string1, jer se u narednoj while petlji pointer a najpre dekrementira pa se tek
tada ispisuje odgovarajući znak. Odgovor C nije dobar jer postavlja (zbog bočnog efekta) pointer a
na znak iza ‘\0’ karaktera.

Zadatak C60
Napisati program na programskom jeziku C koji učitava jedan znakovni niz (string) S1 i jedan ceo
broj M, a zatim formira novi znakovni niz S2 samo od onih znakova na čijim su pozicijama
odgovarajući bitovi broja M jednaki 1. Smatrati da se ceo broj predstavlja u 16-bitnoj lokaciji, a da
znakovni niz može imati najviše 16 znakova. Na kraju, program ispisuje novi znakovni niz S2.

Rešenje
/* C60.c, 9.4.1994., II parcijalni ispit */
#include <stdio.h>

main()
{
short int M, maska;
char S1[17], *s1, S2[17], *s2;

printf("Unesi string S1 i broj M:\n");


scanf("%s%d", S1, &M);
s1 = S1;
s2 = S2;
maska = 1;
while (maska && *s1)
{
if (M & maska) {*s2 = *s1; s2++; };
s1++; maska<<=1;
}
*s2 = '\0';
printf("Novi string S2: %s\n", S2);
}

Komentar
U ovom programu promenjiva maska služi da ispitamo gde se nalaze jedinice u broju M koji zadaje korisnik.
Broj bitova broja M (16) odgovara broju znakova stringa S1. Na osnovu pozicije tih jedinica određuju se
znakovi koji će biti u stringu S2. Svaki od stringova S1 i S2 zauzima ukupno 17 bajtova u memoriji – 16 za
same znakove i 1 za završni nulti znak.
Uslov (maska && *s1) je neophodan da bi se dobio ispravan niz s2.

Materijal za vežbe na tabli i pripremu ispita Strana 22 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C65
Koji od sledećih izraza je ekvivalentan izrazu ar[1][2], ako je data sledeća deklaracija:
int ar[][3]={{0,1,2}, {3,4,5}}
A) *(int*) ( ((char*)ar + (1*3*4)) + (2*4) )
B) *(ar[1]+2)
C) *((*ar+1)+2)

Odgovor
B
Obrazloženje

A) zavisi od implementacije tipa int, u prikazanom slučaju je u redu


C) bilo bi ispravno da stoji *(*(ar+1)+2), ovako je u pitanju *(ar[0]+3)
Materijal za vežbe na tabli i pripremu ispita Strana 23 od 52
Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C70
Napisati program na programskom jeziku C koji učitava dva znakovna niza, izvrši nadovezivanje
drugog na prvi, okrene “naopako“ dobijeni niz i ispiše ga na standardnom izlaznom uređaju.
Rešenje
#include <stdio.h>
#include <string.h>
main()
{
int n;
char c, *d, *p, *prvi, *drugi;
printf(“Maksimalna duzina: “);
scanf(“%d\n”, &n);
p = calloc(2*n+1, sizeof(char)) ;
d = calloc(n+1, sizeof(char));
if ((NULL == d) || (NULL == p))
printf(“Nije moguca alokacija!\n”);
else
{
prvi = p; drugi = d;
while ((*p = getchar()) != ‘\n’) p++;
*p = ‘\0’;
while ((*d = getchar()) != ‘\n’) d++;
*d = ‘\0’;
p = prvi; d = drugi;
/* konkatenacija */
while (*p) p++;
while (*p++=*d++);
/* okretanje */
p = prvi;
for (d=p+(strlen(p)-1); p < d; p++, d--)
c=*p, *p=*d, *d=c;
printf(“%s\n”, prvi);

free(p); free(d);
}

Komentar
Za string p se alocira dvostruko više memorije zbog nadovezivanja nizova. OBAVEZNO treba proveriti da li je
uspela alokacija memorije.
Nakon alokacije memorije, vrši se učitavanje stringova, znak po znak, korišćenjem bibliotečke funkcije
getchar(). Zatim se vrši konkatenacija, tako što se drugi string nadoveže na prvi.
Okretanje dobijenog niza u datom rešenju radi se tako što prvi član menja mesto sa poslednjim, drugi sa
pretposlednjim, itd.
S obzirom na to da postoji dinamička alokacija memorije, svu alociranu memoriju OBAVEZNO treba osloboditi
kada ona više nije potrebna (u ovom slučaju pre završetka programa).

Materijal za vežbe na tabli i pripremu ispita Strana 24 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C75
Napisati program na programskom jeziku C koji ponavlja sledeću sekvencu operacija:
1. učitava informaciju o tipu podataka sa kojim će raditi (ceo broj ili znak);
2. učitava dužinu niza podataka;
3. učitava niz podataka zadatog tipa i dužine u dinamički alociranu memoriju;
4. ispisuje u heksadecimalnom obliku sadržaj učitanih podataka, bajt po bajt.
Rešenje
#include <stdio.h>
#include <stdlib.h>

main()
{
void *blok_p, *bajt_p;
int lnt, n;
char o, *format_p;

while(1)
{
o = 0;
while (o != 'c' && o != 'Z' && o != 'k')
{
printf("Tip brojeva: (c)eli/(z)naci, ili (k)raj?");
scanf("%c", &o);
switch(o)
{
case 'c' :
lnt = sizeof(int);
format_p = "%d";
break ;
case 'z' :
lnt = sizeof(char) ;
format_p = "%c" ;
break ;
case 'k' :
break ;
default: printf("Neispravan unos! Ponovite.\n");
}
}

if (o == 'k') break ;
printf("Broj podataka?");
scanf("%d", &n);
blok_p = malloc(lnt*n) ;
printf("Podaci:\n");
for (bajt_p=blok_p; bajt_p<(char*)blok_p+n*lnt; (char*)bajt_p+=lnt)
/*konverzija tipa, pretvaramo generički pokazivac u pokazivač na char */
{ printf("?"); scanf(format_p, bajt_p); }
printf("Bajtovi:\n");
for (bajt_p = blok_p; bajt_p<(char*)blok_p+n*lnt; ((char*)bajt_p)++)
printf("%x", *(char *)bajt_p);
printf("\n");
free(blok_p);
}
}

Komentar
Bajt_p i blok_p su generički pokazivači; pošto kod njih nije određen tip pokazivanih podataka, takav
pokazivač ne može se koristiti za pristup podacima, već samo za čuvanje informacije o adresi nekog podatka.
Pre pristupa nekom podatku, neophodno je generički pokazivač, upotrebom operatora za konverziju tipa,
pretvoriti u pokazivač na željeni tip podataka. Posledice su nepredvidive ako pokazivani podatak nije tipa koji
je naznačen u operatoru za konverziju tipa.

Materijal za vežbe na tabli i pripremu ispita Strana 25 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C80b
Sastaviti program na jeziku C za učitavanje imena gradova uz njihovo uređivanje po abecednom
redosledu i ispisivanje rezultata. U svakom redu se učitava po jedno ime sve dok se ne učita prazan
red.
/* program za sortiranje imena gradova */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_GRAD 100


#define MAX_DUZ 30

main()
{
char *adrese[MAX_GRAD], *adresa;
int znak, br_grad = 0, duz, i;

do
{
adresa = calloc(MAX_DUZ, sizeof(char));
for (duz = 0; duz < MAX_DUZ - 1; duz++)
if ((znak = getchar()) != '\n')
*(adresa + duz) = znak;
else
break;
*(adresa + duz) = '\0';
if (!duz)
{
free(adresa); break;
}
adresa = realloc(adresa, duz + 1);
for (i = br_grad - 1; i >= 0; i--)
if (strcmp(adrese[i], adresa) > 0)
adrese[i + 1] = adrese[i];
else
break;
adrese[i+1] = adresa;
} while (br_grad++ < MAX_GRAD);

for (i = 0; i < br_grad; i++)


printf("%s\n", adrese[i]);
}

Komentar:
Ova tema je detaljno obrađena u knjizi profesora Krausa. Savetuje se studentima da detaljno prouče primere
iz knjige.

Materijal za vežbe na tabli i pripremu ispita Strana 26 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C90
Napisati program koji ispisuje redom binarne vrednosti brojeva koji su zadati putem komandne
linije. Glavnu obradu izdvojiti u potprogram, a potprogram smestiti u posebnu datoteku.
raspak.h
/* limits.h - implementation dependent values
limits.h sadrzi vrednosti koje se ticu maksimalnih i minimalnih velicina podataka,
kao i broja bitova koriscenih za neke tipove podataka, a koje su zavisne od konkretnog
ostvarenja programskog jezika C */

#include <limits.h>

#define NUM_BITS( Type ) ( sizeof( Type ) * CHAR_BIT )

void raspak( unsigned, int [] );

raspak.c
#include "raspak.h"
void raspak( unsigned k, int bit[] )
{
int i = NUM_BITS( unsigned );
while ( i ) bit [ --i ] = k & 1, k >>= 1;
}

c90.c
/*
Napisati program koji ispisuje binarne vrednosti brojeva koji
su zadati na komandnoj liniji. Glavnu obradu izdvojiti u potprogram
*/

#include <stdio.h>
#include <stdlib.h>
#include "raspak.h"

static const BITS_IN_GROUP =4;

int main ( int argc, char *argv[] )


{
int i, j;
int niz[ NUM_BITS( unsigned ) ];
for( i = 1;i < argc; i++ )
{
raspak( atoi( argv[ i ] ), niz );
printf("Bitovi broja %s: ", argv[i]);
for( j =0; j < NUM_BITS( unsigned ); j++ )
{
printf( "%d", niz[ j ] );
if ( j % BITS_IN_GROUP == BITS_IN_GROUP -1 )
putchar ( ' ' );
}
putchar( '\n' );
}
return 0;
}

Komentar
raspak.h – definiciona datoteka u kojoj su deklarisani svi potrebni tipovi podataka, simboličke konstante,
definicije makroa, kao i prototipovi korišćenih funkcija.
raspak.c – sadrži funkciju za rad sa binarnim brojevima (to je ono što se traži u zadatku).
c90.c – ovde je smešten je glavni program, koji koristi definicije iz raspak.h i poziva funkciju čija je
implementacija u raspak.c

Materijal za vežbe na tabli i pripremu ispita Strana 27 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C95
Navesti tip identifikatora x u sledećim definicijama:

char **x; - pokazivač na… pokazivač na… char


int (*x)[10]; - (pokazivač na…) niz od 10… int
int *x[10]; - niz od 10… pokazivača na… int
int *x(); - funkcija koja vraća… pokazivač na… int
int (*x)(); - (pokazivač na…) funkciju koja vraća… int
char ( * ( * x() )[] ) ();
___
funkcija koja vraća
____________
pokazivač na
_______________________
niz
_____________________________
pokazivača na
_______________________________________
funkciju koja vraća
______________________________________________
char
char ( * ( * x[3] )() ) [5];
____
niz od tri
______________
pokazivača na
________________________
funkciju koja vraća
________________________________
pokazivač na
________________________________________
niz od 5
________________________________________________
char
Obrazloženje
Deklaracije se čitaju počev od identifikatora ka spoljašnjosti. Operatori () i [] imaju prioritet 15 i smer
grupisanja s leva udesno, dok operator * ima prioritet 14 i smer grupisanja s desna ulevo (videti tablicu
prioriteta). Zbog toga, kada se deklariše (definiše) pokazivač na niz ili funkciju, moraju da se upotrebe
zagrade. Ovo znači da se prvo uoči identifikator, a zatim se, ako postoje obuhvatajuće zagrade, unutar tih
zagrada čita po sledećem pravilu: prvo se čitaju modifikatori desno od identifikatora, i to redom s leva udesno;
zatim se čitaju modifikatori levo od identifikatora, i to redom sdesna ulevo. Postupak se ponavlja dok se ne
obrade sve obuhvatajuće zagrade, ako postoje. Na kraju se čita tip podatka koji stoji na početku deklaracije.
char *((*x)[](char **));
pokazivač na niz funkcija koje kao argument primaju pokazivač na pokazivač na karakter, a vraćaju pokazivač
na karakter. Ova definicija NIJE VALJANA jer u C-u nije dozvoljeno praviti niz funkcija, pa samim
tim ni pokazivač na niz funkcija.

Materijal za vežbe na tabli i pripremu ispita Strana 28 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C100
Napisati funkciju na programskom jeziku C koja realizuje algoritam QuickSort. Funkcija treba da
sortira niz podataka proizvoljnog tipa. Kriterijum sortiranja definisan je funkcijskim parametrom.
Rešenje
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void swap( void **p1, void **p2 )
{
void *temp = *p1;
*p1 = *p2;
*p2 = temp;
}
/* rekurzivna varijanta */
void quicksort(void *v[], int left, int right, int (*comp)(const void *, const void * ))
{
int i, last;
if( left >= right ) return;
last = left;
for ( i = left + 1; i <= right; i++ )
if ( ( *comp )( v[ i ], v[ left ] ) < 0)
swap( &v[ ++last ],&v[ i ] );
swap( &v[ left ], &v[ last ] );
quicksort( v, left, last - 1, comp );
quicksort( v, last + 1, right, comp );
}
#define MAX_STR 20
#define MAX_DIM 10

void main()
{
char *niz[ MAX_DIM ];
int i,n;
for ( i = 0; i< MAX_DIM; i++ )
{
niz[ i] = calloc( MAX_STR, 1 );
if ( ( niz[ i ] == NULL )
|| ( fgets( niz[ i ], MAX_STR, stdin ) == NULL )
|| ( *( niz[ i ] ) == '\n' )
) break;
}
n = i - 1;
quicksort( niz, 0, n, strcmp );
for ( i = 0; i <= n; i++ ) fputs( niz[ i ], stdout );
}

Komentar
Funkcija swap ima dva argumenta; ovom funkcijom se postiže da **p1 pokazuje tamo gde je pokazivao
**p2 i obrnuto. Funkcija quicksort se zasniva na algoritmu particijskog sortiranja, realizovana je
rekurzivno, i treba da uredi neuređen niz.
Deklaracijom int (*comp)(const void*, const void*) definiše se pokazivač na funkcije čija je
povratna vrednost tipa int i koje imaju dva argumenta tipa const void*. Tamo gde se u programskom
kodu nalazi (*comp)(v[i], v[left]) imamo indirektno adresiranje koje se primenjuje na promenljivu
comp, što je praktično poziv funkcije koja se u memoriji nalazi na adresi na koju pokazuje pokazivač comp. Da
bi ovo bilo ispravno, funkcija na koju comp pokazuje se mora slagati po tipu/tipovima argumenata navedenim
pored (*comp).

Materijal za vežbe na tabli i pripremu ispita Strana 29 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C104
Napisati program u programskom jeziku C za rad sa kompleksnim brojevima. Preko argumenata
programa zadaju se dva kompleksna broja i to tako da se prvo navodi realan deo prvog broja, zatim
imaginarni deo prvog broja, zatim realni i imaginarni deo drugog kompleksnog broja, respektivno.
Ako korisnik ne unese tačan broj argumenata potrebno je prekinuti izvršavanje programa. Takođe
treba napisati potprogram koji proverava da li znakovni niz sadrži broj i pomoću tog potprograma
treba ispitati da li su svi navedeni argumenti zaista brojevi. Ako bar jedan argument nije broj,
potrebno je prekinuti izvršavanje programa. Program treba da sadrži i potprogram za sabiranje dva
kompleksna broja koji vraća kompleksni broj kao rezultat kao i potprogram za konjugovanje
kompleksnog broja koji nema povratnu vrednost. Glavni program treba da na standardnom izlazu
ispiše sve argumente programa, zbir kompleksnih brojeva i konjugovane vrednosti oba kompleksna
broja. Ispis treba vršiti pozivom odgovarajućeg potprograma koji takođe treba napisati. Kompleksne
brojeve predstaviti strukturom.
Rešenje
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0

/* istovremeno definisemo i strukturu sa imenom (SComplex) i tip podatka (TComplex) */


typedef struct SComplex
{
double Re, Im;
} TComplex;

/* parsiramo string da bismo utvrdili da li predstavlja realni broj */


int DaLiJeBroj(const char *pstr)
{
int bTacka = FALSE;
if (*pstr=='+' || *pstr=='-')
++pstr;

while(*pstr)
{
if (!isdigit(*pstr) && *pstr!='.')
return FALSE;
if (*pstr == '.')
{
if (bTacka)
return FALSE;
bTacka = TRUE;
}
pstr++;
}
return TRUE;
}

/* sabiramo dva broja i zbir vracamo kao rezultat funkcije */


TComplex Zbir(TComplex z1, TComplex z2)
{
TComplex cplx;
cplx.Re = z1.Re + z2.Re;
cplx.Im = z1.Im + z2.Im;
return cplx;
}

Materijal za vežbe na tabli i pripremu ispita Strana 30 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C
/* konjugujemo kompleksni broj, operacija se obavlja na samom primerku strukture */
void Konjug(TComplex *pZ)
{
pZ->Im = - pZ->Im;
}

/* ispisujemo broj, u formatu x + jy */


void Ispis(TComplex z)
{
if (z.Im >= 0)
printf("%5.4f + j%5.4f", z.Re, z.Im);
else
printf("%5.4f - j%5.4f", z.Re, -z.Im);
}

/* glavni program, ulazne podatke zadajemo putem komandne linije */


int main(int argc, char *argv[])
{
TComplex z1, z2, zbir;
int i;

if (argc != 5)
{
printf("Unesite tacno cetiri argumenata pri startu programa!\n");
return -1;
}

printf("Uneli ste sledece argumente preko komandne linije:\n");


for (i=1; i < argc; i++)
printf("%d %s\n", i, argv[i]);

for (i=1; i < argc; i++)


{
if (!DaLiJeBroj(argv[i]))
{
printf("Uneli ste argument koji nije broj!\n");
return -1;
}
}

z1.Re = atof(argv[1]);
z1.Im = atof(argv[2]);

z2.Re = atof(argv[3]);
z2.Im = atof(argv[4]);

printf("\nPrvi broj: "); Ispis(z1);


printf("\nDrugi broj: "); Ispis(z2);
zbir = Zbir(z1, z2);
Konjug(&z1); Konjug(&z2);

printf("\nZbir: "); Ispis(zbir);


printf("\nKonjug(z1): "); Ispis(z1);
printf("\nKonjug(z2): "); Ispis(z2);
printf("\n\nHvala na paznji!\n");

return 0;
}

Komentar
Zadavanje argumenta putem komandne linije znači da glavni program ima dva argumenta. Argumenti
komandne linije su stringovi, te ih moramo konvertovati pre korišćenja. Ti argumenti omogućavaju prenošenje
parametara glavnom programu koji se zadaju u sastavu komande operativnog sistema za izvršavanje
programa.

Materijal za vežbe na tabli i pripremu ispita Strana 31 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C110
Date su sledeće deklaracije:
typedef int CeoBroj;
typedef int *PokazivacNaCeoBroj;
typedef int NizCelihBrojeva[100];
CeoBroj *pokazA;
PokazivacNaCeoBroj pokazB;
NizCelihBrojeva niz;

struct {
int x,y;
} zapisA;

struct {
int x,y;
} zapisB, zapisC;
Koje od sledećih naredbi dodele su semantički ispravne?
pokazA = pokazB; /* OK */
pokazA = niz; /* OK */
niz = pokazA; /* GREŠKA */

zapisB = zapisC; /* OK */
zapisA = zapisB; /* GREŠKA */

Obrazloženje
Prvi primer je ispravan zato što je moguća dodela između dve promenljive koje su istog tipa –
pokazA i pokazB su pokazivači na int. Drugi primer je ispravan jer pokazA sada pokazuje tamo
gde pokazuje niz. Tip imena niza je tip nepromenljivog pokazivača na nulti član, zato je treći primer
pogrešan, jer se ne može nepromenljivom pokazivaču dodeliti nova vrednost.
U programskom jeziku C se koristi strukturna ekvivalencija tipova (typedef imena se pri tome
zamenjuju odgovarajućim tipom) osim u slučaju struktura i unija. Za strukture i unije koristi se
ekvivalencija po imenu. Svaka neimenovana struktura je poseban tip, čak i u slučaju da su sva polja
neke dve strukture međusobno identična.

Materijal za vežbe na tabli i pripremu ispita Strana 32 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C115
Sastaviti program na programskom jeziku C za spajanje sadržaja nekoliko sekvencijalnih tekst
datoteka u jednu izlaznu datoteku. Imena datoteka se zadaju kao parametri u komandnoj liniji. Ime
izlazne datoteke je prvi parametar. Ukoliko je prvi parametar "-", izlazna datoteka je stdout.
Rešenje
#include <stdio.h>
#include <string.h>
main (int argc, char *argv[])
{
void prepis (FILE *, FILE*);
FILE *ulaz, *izlaz;
char *prog = argv[0];

izlaz = stdout;
if (argc > 1)
{
argc--;
if (strcmp(*++argv, "-") != 0)
if ((izlaz = fopen(*argv, "w")) == NULL)
{
fprintf(stderr,"%s:greska u otvaranju datoteke %s\n",prog,*argv);
exit(1);
}
}
while(--argc > 0)
if ((ulaz = fopen(*++argv, "r")) != NULL)
prepis(ulaz, izlaz), fclose(ulaz);
else
{
fprintf(stderr,"%s: ne postoji datoteka %s\n", progr, *argv);
exit(2);
}

fclose(izlaz);
exit (0);
}

void prepis(FILE *ulaz, FILE *izlaz)


{
int c;
while((c=getc(ulaz)) != EOF) putc(c, izlaz);
}

Komentar
Elementi char *argv[] (niz pod imenom argv čiji su elementi pokazivači na char, gde operativni sistem
smešta stringove iz komandne linije) se mogu tretirati u kodu sa *argv zbog promocije – niz se ne može
inkrementirati kao što se to radi u datom primeru, ali ako se kao parametar funkcije navede neki niz, C to
automatski tretira kao pokazivač na tip podataka kome pripadaju elementi niza, a za pokazivače je
inkrementiranje dozvoljeno.

Materijal za vežbe na tabli i pripremu ispita Strana 33 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C120
U binarnoj datoteci se nalaze zapisi o automobilima i vozačima. Svaki zapis sadrži podatak o tipu
entiteta, samom entitetu i celobrojnu vrednost sledećeg zapisa u logički organizovanoj listi. Prvi zapis
u datoteci je i prvi zapis liste, a poslednji zapis liste je zapis u čijem polju ukazatelja na sledeći zapis
stoji 0. Svaki zapis u datoteci ima polje koje sadrži broj logički sledećeg zapisa u datoteci.
Napisati:
1. potprogram koji čita navedenu datoteku i formira listu zapisa u dinamički dodeljenoj memoriji,
pri čemu zapise povezuje u suprotnom smeru od smera u datoteci;
2. potprogram koji ispisuje na standardnom izlazu listu iz tačke a) i
3. glavni program koji poziva gornje potprograme
cz120.h
#include <stdio.h>

enum tip {AUTO=1, VOZAC};

struct automobil {enum tip t; char reg_br[10], boja[10], model[10]; };


struct vozac {enum tip t; char pol[2], br_dozvole[10], ime[10], prezime[10]; };

union zapis {struct automobil a; struct vozac v; };

struct element_dat {union zapis z; int b; };


struct element_lis {union zapis z; struct element_lis * s; };

void pisi_auto( struct element_lis *);


void pisi_vozac( struct element_lis *);
void formiraj_listu( FILE*, struct element_lis **);
void pisi_listu( struct element_lis *);
void kreiraj_datoteku(char*);

cz120.c
#include <stdio.h>
#include "cz120.h"

void main(int argc, char *argv[]) {


FILE *av_bin;
struct element_lis *lista;

if (argc > 2)
kreiraj_datoteku(argv[1]);
if (av_bin = fopen(argv[1],"rb"))
{
formiraj_listu(av_bin,&lista);
pisi_listu(lista);
}
}

pisi_av.c
#include <stdio.h>
#include "cz120.h"

void pisi_auto(struct element_lis *e)


{
printf("Registarski broj: %s; Boja: %s; Model: %s\n",
e->z.a.reg_br, e->z.a.boja, e->z.a.model);
}

void pisi_vozac(struct element_lis *e)


{
printf("Pol: %s; Ime i prezime: %s %s; Broj dozvole: %s\n",
e->z.v.pol, e->z.v.ime, e->z.v.prezime, e->z.v.br_dozvole);
}

Materijal za vežbe na tabli i pripremu ispita Strana 34 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C
formlist.c
#include <stdlib.h>
#include <stdio.h>
#include "cz120.h"
void formiraj_listu(FILE *av_bin, struct element_lis **ppLista)
{
struct element_lis *preth=NULL;
struct element_dat bafer;
*ppLista = NULL;
bafer.b = 1;
while (bafer.b > 0)
{
fread(&bafer, sizeof(bafer), 1, av_bin);
fseek(av_bin, sizeof(bafer)*(bafer.b-1), SEEK_SET);
*ppLista = calloc(sizeof(struct element_lis), 1);
(*ppLista)->z=bafer.z;
(*ppLista)->s=preth;
preth = *ppLista;
};
}

pisilist.c
#include "cz120.h"
void pisi_listu(struct element_lis *lista)
{
while(lista)
{
switch (lista->z.a.t)
{
case AUTO: pisi_auto(lista); break;
case VOZAC: pisi_vozac(lista); break;
default: printf("Neispravan element liste!\n");
}
lista = lista->s;
}
}

kr_dat.c
#include "cz120.h"
void kreiraj_datoteku(char* filename)
{
struct element_dat bafer;
int izbor = 1;
FILE *file = fopen(filename, "wb");
while(izbor)
{
printf("Auto[1] ili vozac[2] ili kraj unosa[bilo sta]? \n");
scanf("%d", &izbor);
switch(izbor)
{
case AUTO:
printf("Unesite redom sledece podatke: boja, model, registarski broj, KLJUC: \n");
scanf("%s%s%s%d", bafer.z.a.boja, bafer.z.a.model, bafer.z.a.reg_br, &bafer.b);
bafer.z.a.t = AUTO; break;
case VOZAC:
printf("Unesite redom sledece podatke: ime, prezime, pol, broj dozvole: \n");
scanf("%s%s%s%s%d", bafer.z.v.ime, bafer.z.v.prezime, bafer.z.v.pol,
bafer.z.v.br_dozvole, &bafer.b);
bafer.z.v.t = VOZAC; break;
default: izbor = 0;
}
if (izbor)
fwrite(&bafer, sizeof(struct element_dat), 1, file);
}
fclose(file);}

Materijal za vežbe na tabli i pripremu ispita Strana 35 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C
Komentar
Ovaj zadatak ilustruje korišćenje struktura i unija, kao i konstrukciju programskog sistema iz više datoteka.
Shodno logičkom ustrojstvu celog programskog sistema, programer treba da odluči koje će funkcije imati u
sistemu i kako će ih rasporediti po datotekama.
cz120.h – definiciona datoteka u kojoj su deklarisani svi potrebni tipovi podataka, simboličke konstante,
definicije makroa, kao i prototipovi korišćenih funkcija.
cz120.c – ovde se nalazi glavni program, koji poziva odgovarajuće potprograme. U slučaju da datoteka sa
podacima ne postoji, glavni program poziva funkciju koja će je napraviti, a potom čita iz te datoteke u listu
zapisa, koju na kraju na standardnom izlazu.
pisi_av.c – ovde su smeštene funkcije pisi_auto() i pisi_vozac(), koje služe za ispis podataka o
automobilima i o vozačima.
formlist.c – sadrži funkciju koja izvršava čitanje datoteke, koju smo formirali pozivom funkcije
kreiraj_datoteku(), i formiranje lista zapisa u dinamički dodeljenoj memoriji.
pisilist.c – ovde se nalazi funkcija za ispis već formirane liste zapisa, koja zavisno od tipa zapisa poziva
jednu od funkcija pisi_auto() i pisi_vozac().
kr_dat.c – ovde se nalazi funkcija kreiraj_datoteku() koja kreira binarnu datoteku u kojoj će se
nalaziti zapisi o automobilima i vozačima.

Materijal za vežbe na tabli i pripremu ispita Strana 36 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C122
Potrebno je realizovati u programskom jeziku C skup funkcija za rad sa listom čije je ponašanje
isto kao ponašanje podatka tipa liste iz pseudojezika. Funkcije za rad sa listom treba da se zovu isto
kao u pseudojeziku (find_bolp, insert, move_forward...) i treba da budu realizovane u zasebnoj
implementacionoj .c datoteci. Takođe je potrebno napraviti odgovarajuću definicionu .h (header)
datoteku u kojoj će biti deklarisani svi potrebni tipovi podataka i prototipovi korišćenih funkcija.
Podaci se u listi skladište preko generičkog pokazivača (void *), a potrebno je obezbediti brisanje
podataka sadržanih u listi kroz call-back mehanizam. Napraviti inicializacionu funkciju koja inicijalizuje
listu i koja postavlja odgovarajuću funkciju koja se poziva kroz call-back mehanizam pri uništavanju
liste. Pointer na ovu funkciju se prosleđuje kao argument funkcije za inicijalizaciju liste. U listu je iz
tekstualne datoteke potrebno pročitati podatke o studentima. Podaci su u fajl složeni tako da je u
jednom redu ime i prezime studenta, u drugom broj indeksa u formatu Broj/GodinaUpisa i u trećem
prosek studenta. Nakon čitanja iz datoteke, upisati sve podatke o studentima iz liste u novu binarnu
datoteku i to tako da se upisuju samo podaci o studentima sa prosekom većim od 8.5.
pj_lista.h
#define TRUE 1
#define FALSE 0

typedef enum { lsBOLP = 0, lsEOLP, lsCURRENT } TListStatus;

struct SListElement /* element liste */


{
void *pData; /* pointer u kome se skladisti adresa podatka */
struct SListElement *pNext; /* pokazivac na sledeci element u listi */
};

struct SList
{
TListStatus lsStatus; /* status - trenutni polzaj u listi */
struct SListElement *pHead; /* pokazivac na glavu liste */
struct SListElement *pCurrent; /* pokazivac na tekuci element */
void (*destructor)(void *); /* pokazivac na funkciju koja ima argument tipa void* */
};

typedef struct SListElement TListElement;


typedef struct SList TList;

void initialize_list(TList *pList, void (*destructor)(void *));


void find_bolp(TList *pList);
int move_forward(TList *pList);
int insert(TList *pList, void *pData);
void *get(TList *pList);
void destroy_list(TList *pList);
int eolp(TList *pList);

pj_lista.c
#include <stdlib.h>
#include "pj_lista.h"

/* Argumenti: pList - pointer na promenljivau tipa Tlist, destructor - pointer na


funkciju koja se poziva u toku unistavanja liste za svaki njen podatak */
void initialize_list(TList *pList, void (*destructor)(void *))
{
pList->pHead = NULL;
pList->lsStatus = lsBOLP;
pList->pCurrent = NULL;
pList->destructor = destructor;
}

Materijal za vežbe na tabli i pripremu ispita Strana 37 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

void find_bolp(TList *pList)


{
pList->lsStatus = lsBOLP;
pList->pCurrent = NULL;
}

int move_forward(TList *pList)


{
if (pList->lsStatus == lsEOLP)
return FALSE;

if (pList->lsStatus == lsBOLP)
{
pList->pCurrent = pList->pHead;
if (pList->pCurrent == NULL)
pList->lsStatus = lsEOLP;
else
pList->lsStatus = lsCURRENT;
}
else
{
pList->pCurrent = pList->pCurrent->pNext;

if (pList->pCurrent == NULL)
pList->lsStatus = lsEOLP;
}

return TRUE;
}

/* pList - pokazivac na tip Tlist, pData - podatak koji ce biti ubacen u listu. */
int insert(TList *pList, void *pData)
{
TListElement *pNewElem;

if (pList->lsStatus == lsEOLP)
return FALSE;

pNewElem = (TListElement *)calloc(1, sizeof(TListElement));

if (pNewElem == NULL)
return FALSE;

pNewElem->pData = pData;
pNewElem->pNext = NULL;

if (pList->lsStatus == lsBOLP)
{
pNewElem->pNext = pList->pHead;
pList->pHead = pNewElem;
pList->pCurrent = pNewElem;
pList->lsStatus = lsCURRENT;
}
else
{
pNewElem->pNext = pList->pCurrent->pNext;
pList->pCurrent->pNext = pNewElem;
pList->pCurrent = pNewElem;
}
return TRUE;
}

void *get(TList *pList)


{
if (pList->lsStatus == lsCURRENT)
return pList->pCurrent->pData;

Materijal za vežbe na tabli i pripremu ispita Strana 38 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

return NULL;
}
void destroy_list(TList *pList)
{
TListElement *pElem, *pHelpElem;
for (pElem = pList->pHead; pElem != NULL; )
{
pHelpElem = pElem->pNext;
if (pList->destructor)
(*pList->destructor)(pElem->pData); /* na ovom mestu pointer na funkciju */
/* se dereferencira i zatim se poziva ta funkcija */
/* sa argumentom pElem->pData */
free(pElem);
pElem = pHelpElem;
}
}

int eolp(TList *pList)


{
return pList->lsStatus == lsEOLP;
}

cz122.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "pj_lista.h"

typedef struct { /* struktura u kojoj se cuvaju podaci o */


char strIme[256]; /* studentu */
int nGodUpisa;
int nBroj;
float fProsek;
} TStudent;

void UnistiStudenta(void *pStudent) /* funkcija neophodna za call-back */


{ /* pri unistavanju liste */
if (pStudent != NULL)
{
printf("UnistiStudenta %s\n", ((TStudent*)pStudent)->strIme);
free(pStudent);
}
}

void main()
{
FILE *f1, *f2;
TList list;
TStudent *pStudent;
char *pKrajLinije;

f1 = fopen("studenti.txt", "r"); /* otvaramo tekstualnu datoteku za citanje */


if (f1 == NULL)
{
printf("Datoteka ne postoji!\n"); /* otvaramo binarnu datoteku za upis */
return;
}

f2 = fopen("studenti.bin", "wb");
if (f2 == NULL)
{
printf("Datoteka za upis nece da se otovori!\n");
fclose(f1);
return;
}

Materijal za vežbe na tabli i pripremu ispita Strana 39 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C
initialize_list(&list, UnistiStudenta);
/* identifikator funkcije je ujedno i pokazivac na funkciju */

while (!feof(f1))
{
pStudent = (TStudent *)calloc(sizeof(TStudent), 1);
fgets(pStudent->strIme, 255, f1);
/*
Funkcija fgets cita string sve do kraja linije, ali ukljucuje i kraj linije u string!
Zato cemo koristiti strchr funkciju koja vraca adresu prvog karaktera koji se zadaje kao
drugi argument funkcije u okviru stringa koji se zadaje kao prvi argument funkcije.
Ako karakter nije pronadjen strchr vraca NULL. Kada pronadjemo karakter za kraj linije,
prosto cemo ga izbaciti postavljajuci ga na '\0' sto oznacava kraj stringa.
*/
if ((pKrajLinije = strchr(pStudent->strIme, '\n')) != NULL)
*pKrajLinije = '\0';

fscanf(f1, "%d/%d \n", &pStudent->nBroj, &pStudent->nGodUpisa);


fscanf(f1, "%f \n", &pStudent->fProsek);
if (!insert(&list, (void *)pStudent))
{
destroy_list(&list);
printf("Greska pri ubacivanju u listu!\nProgram prekinut!\n");
return;
}
}

fclose(f1);
find_bolp(&list);
while (TRUE)
{
move_forward(&list);
if (eolp(&list))
break;
pStudent = (TStudent*)get(&list);
printf("Ime i prezime: %s\n", pStudent->strIme);
printf("Broj indeksa: %d/%02d\n", pStudent->nBroj, pStudent->nGodUpisa);
printf("Prosek: %4.2f\n", pStudent->fProsek);
if (pStudent->fProsek > 8.5)
{
if (fwrite(pStudent, sizeof(TStudent), 1, f2) == 1)
printf("Kandidat uspesno upisan u novi fajl...\n\n");
else
{
printf("Greska pri upisu! Program prekinut.\n");
break;
}
}
else
printf("Kandidat nije zadovoljio uslove za upis u novi fajl!\n\n");
}

fclose(f2);
destroy_list(&list);
printf("** KRAJ **\n");
}

Materijal za vežbe na tabli i pripremu ispita Strana 40 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C125
Pod pretpostavkom da su zapisi u datoteci uređeni u leksikografski uređeno stablo, šta ispisuje
dati program za zadatu datoteku (prvi argument komandne linije) i zadati ključ (drugi argument)?
#include <stdio.h>
#include <string.h>
struct tree_elem
{
char key[7];
unsigned long left, right;
};
void create(char* filename)
{
struct tree_elem buffer;
FILE *file = fopen(filename, "wb");
while (!ferror(file))
{
printf("\nKEY LEFT RIGHT: ");
scanf("%6s %lu %lu", buffer.key, &buffer.left, &buffer.right);
if (strcmp(buffer.key, "END") == 0) break;
fwrite(&buffer, sizeof(struct tree_elem), 1, file);
}
fclose(file);
}
void traverse( FILE *file, char key[], unsigned long node)
{
struct tree_elem buffer;
static int ukupno_aktivacija = 0;
int ova_akt;
printf("Pocetak aktivacije %d\n", ova_akt = ++ukupno_aktivacija);
if ( node == 0 )
{ printf("Kraj aktivacije %d\n", ova_akt); return; }
fseek( file, ( node - 1 ) * sizeof( struct tree_elem ), SEEK_SET);
fread( &buffer, sizeof(struct tree_elem ), 1, file );
if ( ferror( file ) ) return;
traverse( file, key, buffer.left );
if ( strcmp( key, buffer.key ) >= 0)
{
printf( "%s\n", buffer.key );
traverse( file, key, buffer.right );
}
printf("Kraj aktivacije %d\n", ova_akt);
}
void main( int argc, char *argv[] )
{
FILE *file; /* ovako odredjujemo da li kreiramo datoteku ili */
if (argc > 3) create(argv[1]); /* koristimo vec napravljenu nekom ranijom prilikom */
if ( ( file = fopen( argv[1], "rb" ) ) == NULL )
fprintf( stderr, "Greska pri otvaranju datoteke %s\n", argv[1] );
else
traverse( file, argv[2], 1 );
}
A) ključeve svih zapisa u datoteci u leksikografskom poretku
B) ključeve svih zapisa manjih do jednakih zadatom, u leksikografskom poretku
C) ključeve svih zapisa manjih do jednakih zadatom, u obrnutom leksikografskom poretku
Odgovor
B
Komentar
Promenljive ukupno_aktivacija i ova_akt služe za pojašnjavanje rednog broja aktivacije posmatrane
rekurzivne funkcije traverse, i nemaju uticaja na suštinu zadatka.

Materijal za vežbe na tabli i pripremu ispita Strana 41 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C
Zadatak CI-2007-Jan-2
Napisati potprogram unsigned in zbir (char *a, char *b) na programskom jeziku C
koji određuje decimalnu vrednost zbira brojeva a i b. Odgovarajući stvarni argumenti su znakovni
nizovi (stringovi) od maksimalno 3 znaka i predstavljaju pozitivne cele brojeve u heksadecimalnom
brojnom sistemu. Pri tome, znak koji predstavlja cifru najveće težine je prvi u znakovnom nizu.
Napisati glavni program na programskom jeziku C koji sa standardnog ulaza učitava dva niza od po 3
znaka koji treba da predstavljaju heksadecimalne cifre, potom poziva potprogram zbir i na
standardnom izlazu ispisuje rezultat zbira ta dva broja.
#include <stdio.h>
unsigned int zbir (char *a, char *b)
{
Nemojte NIKAD
unsigned int vred_a = 0, vred_b = 0; programski kod
učiti napamet.
while (*a)
{
vred_a *= 16;
if (*a >= '0' && *a <= '9') vred_a += (*a - '0');
else if (*a >= 'a' && *a <= 'f') vred_a += (*a - 'a' + 10);
else if (*a >= 'A' && *a <= 'F') vred_a += (*a - 'A' + 10);
a++;
}
sscanf(b, "%x", &vred_b);
printf("%d\t%x\n", vred_a, vred_a); /* nije traženo u postavci */
printf("%d\t%x\n", vred_b, vred_b); /* nije traženo u postavci */
return vred_a + vred_b;
} Svako ponavljanje bez
razumevanja programskog koda
je štetno i na ispitu će biti
main()
{
char a[4], b[4];
printf("Unesite brojeve: ");
kažnjavano oduzimanjem poena.
scanf("%s%s", a, b);
printf("Zbir ovih brojeva je %d\n", zbir(a, b));
}

Komentar
U funkciji zbir() su prikazana dva različita pristupa dobijanja vrednosti broja zapisanog u heksadecimalnom
brojnom sistemu. Najpre se vrši konverzija broja a, tako što se u ciklusu analizira znak po znak, sve dok se ne
dođe do kraja znakovnog niza. Primetiti da nigde nije pretpostavljena dužina nizova a i b, pa je ovo rešenje
univerzalno (u onoj meri u kojoj opseg predstavljanja celih brojeva dozvoljava). Za praktične primene, ovom
rešenju nedostaje provera da li znakovni nizovi a i b zaista predstavljaju cele brojeve u heksadecimalnom
zapisu. To se, međutim, nije tražilo - pa nije ni prikazano u rešenju. Nakon ciklusa za konverziju broja a, vrši
se konverzija broja b pozivom funkcije sscanf(). Ova funkcija se ponaša slično scanf() odnosno fscanf(), s
tim što je izvor koji treba čitati u datom formatu zadat znakovnim nizom koji se zadaje kao prvi argument. U
ovom slučaju radi se o nizu b. Naziv sscanf() zapravo potiče string scanf. U ostalim aspektima, može se
smatrati da se ova funkcija ponaša kao scanf().

Materijal za vežbe na tabli i pripremu ispita Strana 42 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak CI-2006-Okt-1
Napisati program na programskom jeziku C koji izračunava broj osvojenih bodova na šampionatu
trka Formule 1. Podaci o vozačima i timovima se nalaze u tekst datoteci vozaci.txt prema sledećem
formatu: u svakom redu datoteke redom su zapisani prezime i ime vozača i naziv tima za koji vozač
vozi (svako polje po 30 karaktera najviše). Poznato je da ima tačno 28 vozača koji učestvuju u
trkama i da se na šampionatu vozi 20 trka. Podaci o rezultatima trka smešteni su tekst datoteci
trke.txt tako da se u svakom redu datoteke nalaze redni brojevi pozicija jednog vozača po završetku
svake trke (20 pozicija, za svaku trku po jedna). U slučaju da vozač ne prođe cilj (odustane od trke),
broj pozicije za tu trku je 0. Podaci u prvom redu datoteke trke.txt odgovaraju vozaču iz prvog reda
datoteke vozaci.txt, itd. Bodovi za vozače za jednu trku se računaju na sledeći način: prvih 8 vozača
dobija 10, 8, 6, 5, 4, 3, 2 i 1 bod respektivno, ostali 0 bodova. Program treba da izračuna i na
standardnom izlazu ispiše osvojene bodove tako da u jednom redu stoje prezime i ime vozača,
osvojen broj bodova i naziv tima.
#include <stdio.h>
main() {
FILE *vozaci, *trke; Nemojte NIKAD
char prezime[31], ime[31], tim[31];
int v,p,pozicija,poena; programski kod
vozaci = fopen("vozaci.txt", "r"); učiti napamet.
trke = fopen("trke.txt", "r");
if( ! vozaci || ! trke ) {
if( ! vozaci ) printf("Neuspelo otvaranje datoteke vozaci.txt\n");
else fclose(vozaci);
if( ! trke ) printf("Neuspelo otvaranje datoteke vozaci.txt\n");
else fclose(trke);
exit(0);
}
for(v=0; v<28; v++) {
fscanf(vozaci, "%s %s %s", prezime, ime, tim);
poena = 0;
for(p=0; p < 20; p++) {
fscanf(trke, "%d", &pozicija);
switch(pozicija) {
case 1: poena += 10; break;
case 2: poena += 8; break;
case 3: poena += 6; break;
case 4: poena += 5; break;
case 5: poena += 4; break;
case 6: poena += 3; break;
case 7: poena += 2; break;
case 8: poena += 1; break;
}
}
printf("%s %s %d %s\n", prezime, ime, poena, tim);
}
Svako ponavljanje bez
fclose(vozaci);
fclose(trke);
} razumevanja programskog koda
je štetno i na ispitu će biti
kažnjavano oduzimanjem poena.
Komentar
Provera da li su datoteke uspešno otvorene nije najjezgrovitije zapisana, ali je verovatno najpribližnija načinu
na koji se razmišlja prilikom donošenja odluke. Najpre je izvršeno otvaranje obe datoteke. Ako bilo koja od
njih nije uspešno otvorena, potrebno je prekinuti program, a prethodno prethodno ispisati koja zapravo nije
uspešno otvorena (moguće – obe). Za onu koja je uspešno otvorena se ne vrši ispisivanje već njeno
zatvaranje. Iako obaveštenje o nastalim greškama pri radu nije traženo u postavci, ovde je to prikazano iz
edukativnih razloga.

Materijal za vežbe na tabli i pripremu ispita Strana 43 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak CI-2007-Okt-2
Napraviti program na programskom jeziku C koji obrađuje datoteku koja sadrži izvorni program na
programskom jeziku C. Potrebno je datoteku prepisati u novu datoteku, tako da se izostave svi
komentari i očuva uređenost teksta po redovima. Primer:
Ulazna datoteka Odgovarajuća izlazna datoteka
#include <stdio.h> #include <stdio.h>
/* ispis proizvoda i kolicnika dva broja main()
*/ {
main() int a, b;
{ scanf("%d%d", &a, &b);
int a, b; printf("%d", a*b);
scanf("%d%d", &a, &b); printf("%d", a/b);
printf("%d", a*b); /* ispis a*b */ }
/* ispis a/b */ printf("%d", a/b);
}
Imena ulazne i izlazne datoteke se zadaju kao prvi i drugi parametar komandne linije i imaju
najviše 30 znakova. U slučaju da dođe do greške pri otvaranju neke od datoteka, ispisati poruku o
greški i prekinuti izvršavanje programa.
#include <stdio.h>
int main(int argc, char *argv[]) {
char znak;
enum StanjeObrade { VAN_K, POC_K, UNUTAR_K, KRAJ_K } stanje = VAN_K;
FILE *ul, *izl;
if (NULL == (ul = fopen(argv[1], "r"))) {
fprintf(stderr, "Doslo je do greske pri otvaranju %s\n", argv[1]);
return 1;
}
if (NULL == (izl = fopen(argv[2], "w"))) {
fclose(ul);
fprintf(stderr, "Doslo je do greske pri otvaranju %s\n", argv[2]);
return 2;
}

Nemojte NIKAD
while ((znak = fgetc(ul)) != EOF) {
switch(stanje) {

programski kod
case VAN_K:
if ('/' == znak) stanje = POC_K;

učiti napamet.
else fputc (znak, izl);
break;
case POC_K:
if ('*' == znak) stanje = UNUTAR_K;
else stanje = VAN_K, fputc('/', izl), fputc(znak, izl);
break;
case UNUTAR_K:
if ('*' == znak) stanje = KRAJ_K;
break;
case KRAJ_K:
if ('/' == znak) stanje = VAN_K;
else stanje = UNUTAR_K;
break;

}
}
Svako ponavljanje bez
fclose(ul);
fclose(izl);
razumevanja programskog koda
}
return 0; je štetno i na ispitu će biti
kažnjavano oduzimanjem poena.
Komentar
Zadatak se bavi nešto složenijom obradom ulazne datoteke u odnosu na jednostavno prepisivanje podataka. U
programu se uvodi pojam "stanja" na osnovu kojeg se odlučuje kako treba tretirati ulazni tekst. Na primer,
ako se trenutna obrada vrši unutar komentara, ništa se ne prepisuje u izlaznu datoteku i obrnuto. S obzirom
na to da se početak i kraj komentara označava pomoću dva karaktera (/ i *), uvodi se četiri stanja: van
komentara, početak komentara, unutar komentara i kraj komentara. U stanju van komentara,
svi znaci se prepisuju, osim kada se pojavi znak /. Tada je potrebno pročitati naredni znak i utvrditi da li je on
* (počinje komentar) ili nije (treba / poslati u izlaznu datoteku). Dakle, kada u stanju van komentara naiđe
znak /, potrebno je preći u novo stanje, u kojem se očekuje dolazak znaka *. Slično se vrši izlazak iz
komentara.
stderr je izlazni uređaj koji se automatski stvara i koji služi kao "kanal" za ispis grešaka. Njegovo korišćenje
nije zahtevano u postavci zadatka – njegova uloga u ovom rešenju je edukativna.

Materijal za vežbe na tabli i pripremu ispita Strana 44 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak CI-2006-Sep-2
Napisati program koji jednu tekst datoteku prepisuje u drugu tekst datoteku, uz očuvanje
uređenosti teksta po linijama. Linije u kojima postoji neparan broj znakova razmaka se prepisuju tako
da sva slova budu mala, a ostale tako da sva slova budu velika. Linije ne mogu biti duže od 80
znakova. Imena tekst datoteka se zadaju putem standardnog ulaza; ne mogu biti duža od 30
znakova. U slučaju da ne uspe otvaranje neke od datoteka, ispisati poruku korisniku u kojoj se
navodi sa kojom datotekom je došlo do problema i prekinuti izvršenje programa.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
main() {
char ime_ul_dat[30+1], ime_izl_dat[30+1], linija[80+1+1];
FILE *ul_dat, *izl_dat;
Nemojte NIKAD
int duz_lin, i, br_raz; programski kod
scanf("%s", ime_ul_dat); učiti napamet.
scanf("%s", ime_izl_dat);
ul_dat = fopen(ime_ul_dat, "r");
if (NULL == ul_dat) {
fprintf(stderr, "Doslo je do greske pri radu sa %s\n", ime_ul_dat);
exit(EXIT_FAILURE);
}
izl_dat = fopen(ime_izl_dat, "w");
if (NULL == izl_dat) {
fclose(ul_dat);
fprintf(stderr, "Doslo je do greske pri radu sa %s\n", ime_izl_dat);
exit(EXIT_FAILURE);
}
while (fgets(linija, 82, ul_dat) != NULL) {
duz_lin = strlen(linija);
br_raz = 0;
for (i = 0; i < duz_lin; i++)
br_raz += isspace(linija[i]) != 0;
for (i = 0; i < duz_lin; i++)
if (br_raz % 2)
linija[i] = tolower(linija[i]);
else
linija[i] = toupper(linija[i]);
fputs(linija, izl_dat);
}
fclose(ul_dat);
Svako ponavljanje bez
fclose(izl_dat); razumevanja programskog koda
je štetno i na ispitu će biti
}

kažnjavano oduzimanjem poena.


Komentar
U postavci je rečeno da imena datoteka nisu duža od 30 znakova. Zbog toga se kreiraju dva niza dužine 31
znak, gde je namerno naglašeno da se rezerviše prostor za jedan znak više od maksimalne dužine zbog znaka
za kraj znakovnog niza ('\0'). Za liniju se rezerviše jedno mesto više: pod pretpostavkom da niz može imati
najviše 80 znakova, potrebno je još jedno mesto za kraj znakovnog niza i još jedno mesto za eventualni
znak za novi red koji će funkcija fgets() smestiti u niz linija. Kasnije u programu se funkciji fgets() zadaje
vrednost 82 kao jedan od argumenata. To je uputstvo da je za čitanje rezervisano tačno 82 znaka, od kojih
jedan mora biti znak za kraj znakovnog niza.
Simbol EXIT_FAILURE je definisan u zaglavlju stdlib.h i služi kao argument funkciji exit() za označavanje
prekida programa zbog greške. U postavci se to nije tražilo, ali je u rešenju prikazano iz edukativnih razloga.
Funkcija isspace() određuje da li je dati znak razmak, a funkcije tolower() i toupper() konvertuju dati znak
u malo odnosno veliko slovo respektivno. Ni njihova upotreba nije tražena u postavci. Osim iz edukativnih
razloga, ovde su prikazane jer povećavaju čitljivost programa, pa se njihova upotreba preporučuje.

Materijal za vežbe na tabli i pripremu ispita Strana 45 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak CI-2006-Jan-1
U cilju proglašenja najboljeg igrača(MVP) na odbojkaškom turniru, organizacioni odbor turnira je
doneo sledeću odluku o načinu bodovanja učinka igrača: poen iz servisa vredi 1 poen, poen iz smeča
vredi 0.5 poena, a blokada 0.2 poena. Podaci o učinku svih igrača za vreme celog turnira nalaze se u
tekstualnoj datoteci odbojka.txt. U jednom redu datoteke nalaze se podaci za jednog igrača. Za
svakog igrača se pamti njegovo ime i prezime (niz od tačno 30 karaktera), visina (ceo broj), težina
(ceo broj), broj ostvarenih poena iz servisa na turniru (ceo broj), broj poena iz smeča (ceo broj) i
broj blokada (ceo broj). Napisati program na programskom jeziku C koji iz datoteke odbojka.txt
čita podatke o igračima i pronalazi prvog igrača sa najvećim brojem ostvarenih poena i na
standardnom izlazu ispisuje ime tog igrača i broj ostvarenih poena.
Rešenje sa fgets
#include<stdio.h>
#include<string.h>
main() {

Nemojte NIKAD
double poen_serv = 1.0, poen_smec = 0.5, poen_blok = 0.2;
double max_poeni = 0.0, poeni;

programski kod
char ime_i_prez[31], max_ime_i_prez[31];
unsigned visina, tezina, br_serv, br_smec, br_blok;
FILE *ul_dat = fopen("odbojka.txt", "r");
učiti napamet.
if( ul_dat == NULL )
exit(0);

while (fgets(ime_i_prez, 31, ul_dat) != NULL) {


fscanf(ul_dat, "%d%d%d%d%d", &visina, &tezina, &br_serv, &br_smec, &br_blok);
poeni = poen_serv * br_serv + poen_smec * br_smec + poen_blok * br_blok;
if (max_poeni < poeni) {
max_poeni = poeni;
strcpy(max_ime_i_prez, ime_i_prez);
}
}
Svako ponavljanje bez
razumevanja programskog koda
je štetno i na ispitu će biti
fclose(ul_dat);
kažnjavano oduzimanjem poena.
if (max_poeni > 0.0)
printf("MVP je %s, sa ostvarenih %lf poena\n", max_ime_i_prez, max_poeni);
}

Komentar
Ovaj zadatak je rešen na dva veoma slična načina. U rešenju prikazanom na ovoj strani koristi se funkcija
fgets() da pročita ime i prezime igrača kao jednu celinu (tj. kao jedan red teksta) i smesti ih u znakovni niz
ime_i_prez.
Drugo rešenje, prikazano na sledećoj strani, koristi funkciju fscanf() za čitanje imena i prezimena kao dva
nezavisna znakovna niza, zbog čega je naknadno potrebno izvršiti njihovo spajanje u jedan znakovni niz:
najpre se pročita ime i smesti u znakovni niz ime_i_prez. Nakon toga se u poseban niz prezime smešta
pročitano prezime. Zatim se na ranije pročitano ime dodaje jedan znak razmaka a posle toga i pročitano
prezime. Dodavanje jednog znakovnog niza na kraj drugog se vrši funkcijom strcat().
Treba primetiti sledeće. Očekivano da oba rešenja daju isti rezultat u smislu čitanja imena i prezimena. Ipak,
ne mora biti tako: ako ulazna datoteka sadrži više od jednog razmaka između imena i prezimena, ti razmaci će
ostati nakon čitanja kada se koristi funkcija fgets(). To se neće desiti kada se za čitanje imena i prezimena
koristi funkcija fscanf() jer ona automatski ignoriše sve razmake koji razdvajaju dva niza znakova.

Materijal za vežbe na tabli i pripremu ispita Strana 46 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C
Resenje sa fscanf
#include<stdio.h>
#include<string.h>
main() {
double poen_serv = 1.0, poen_smec = 0.5, poen_blok = 0.2;
double max_poeni = 0.0, poeni;
char ime_i_prez[31], prezime[31], max_ime_i_prez[31]; Nemojte NIKAD
unsigned visina, tezina, br_serv, br_smec, br_blok;
FILE *ul_dat = fopen("odbojka.txt", "r"); programski kod
if( ul_dat == NULL ) učiti napamet.
exit(0);

while( fscanf(ul_dat, "%s", ime_i_prez) != EOF) {


fscanf(ul_dat, "%s", prezime);
strcat(ime_i_prez, " ");
strcat(ime_i_prez, prezime);
fscanf(ul_dat, "%d%d%d%d%d", &visina, &tezina, &br_serv, &br_smec, &br_blok);
poeni = poen_serv * br_serv + poen_smec * br_smec + poen_blok * br_blok;
if (max_poeni < poeni) {
max_poeni = poeni;
strcpy(max_ime_i_prez, ime_i_prez);
}
}

fclose(ul_dat);

if (max_poeni > 0.0)


printf("MVP je %s, sa ostvarenih %lf poena\n", max_ime_i_prez, max_poeni);
}

Komentar Svako ponavljanje bez


Videti komentar dat uz prethodno rešenje zadatka. razumevanja programskog koda
je štetno i na ispitu će biti
kažnjavano oduzimanjem poena.

Materijal za vežbe na tabli i pripremu ispita Strana 47 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak CI-2006-Jan-2
Napisati potprogram double bin2dbl(char * num) na programskom jeziku C koji na osnovu
znakovnog niza (stringa) num koji predstavlja binarnu reprezentaciju realnog broja izračunava i kao
rezultat vraća brojnu vrednost tipa double, koja će se ispisati u decimalnom brojnom sistemu. String
num ima najviše 10 binarnih cifara uključujući i decimalnu tačku koja može a ne mora postojati.
Napisati glavni program na programskom jeziku C koji sa standardnog ulaza učitava string num,
poziva potprograma bin2dbl i na standardnom izlazu ispisuje dobijeni rezultat. (npr. za unos
“1011.101” program treba da ispiše rezultat 11.625).
#include <stdio.h>
#include <string.h>
double bin2dbl(char *num) {
unsigned num_length = strlen(num), i = 0;
double celi_deo = 0, razl_deo = 0;

/* ako prvi znak nije decimalna tacka, računa se celi deo broja */
if (num[i] != '.') {
celi_deo = num[0] - '0';
/* dok se ne stigne do kraja broja ili do decimalne tacke */
while (++i < num_length && num[i] != '.')
celi_deo = celi_deo * 2 + (num[i] - '0');
}
Nemojte NIKAD
/* ako postoji razlomljeni deo, kreće se od kraja */
if (i < num_length) programski kod
učiti napamet.
/* dok se ne stigne do decimalne tacke */
while (i < --num_length)
razl_deo = (razl_deo + num[num_length] - '0')/2;

return celi_deo + razl_deo;


}

main() {
char ul_num[11];
printf("Unesite binarni broj koji treba prevesti u decimalni brojni sistem: ");
scanf("%s", ul_num);
printf("%7.3lf\n", bin2dbl(ul_num));
} Svako ponavljanje bez
razumevanja programskog koda
je štetno i na ispitu će biti
kažnjavano oduzimanjem poena.
Komentar
Tražena funkcija izračunava vrednost realnog broja zapisanog u binarnom brojnom sistemu i od dobijene
vrednosti pravi podatak tipa double. Obrada se vrši na sledeći način: ako niz ne počinje znakom '.', onda je u
pitanju celobrojni deo tog realnog broja. Pravi se ciklus koji se ponavlja sve dok se ne obrade svi znakovi u
nizu (slučaj kada je zadat ceo broj) ili dok se ne naiđe na decimalnu tačku (realni broj sa razlomljenim delom).
Do nastavka funkcije se dakle stiže u tri situacije: niz je počeo decimalnom tačkom ili obrada niza je završena
ili tokom obrade celobrojnog dela se stiglo do decimalne tačke. S obzirom na to da se u slučaju prve i treće
situacije postupa isto (određuje se razlomljeni deo), najpre se eliminiše druga situacija (završena obrada)
proverom da li je i manje od num_length. Ako je taj uslov ispunjen, u novom ciklusu se određuje vrednost
razlomljenog dela, s tim što obrada ide od kraja niza, zbog prirode problema (krajnje desna pozicija je pozicija
cifre najmanje težine).
Ova funkcija nije prilagođena praktičnoj upotrebi, jer bi to zahtevalo da se pre određivanja vrednosti broja
izvrši provera da li se dati znakovni niz zaista sastoji od cifara 0 i 1 i najviše jednog decimalnog zareza.
Preporučuje se pisanje funkcije koja to utvrđuje za samostalnu vežbu.

Materijal za vežbe na tabli i pripremu ispita Strana 48 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak CI-2006-Sep-1
Na programskom jeziku C napisati potprograme i glavni program koji vrše obradu niza realnih
brojeva. Unos podataka, obrada, ispis rezultata i oslobađanje memorije se vrši u potprogramima.
Potprogram za unos sa standardnog ulaza učitava broj elemenata niza realnih brojeva tipa float,
alocira potrebnu dinamičku memoriju sa smeštanje tog niza i učitava elemente niza. Ovaj potprogram
treba da proveri uspešnost poziva funkcije za dodelu dinamičke memorije i u slučaju neuspeha
prekida izvršavanje programa. Potprogram za obradu, ispis i oslobađanje memorije štampa sve
brojeve iz unetog niza koji su u opsegu +/- 10% od vrednosti aritmetičke sredine niza. Nakon ispisa,
potprogram oslobađa dinamički alociranu memoriju. Napisati glavni program koji redom poziva
opisane potprograme. Potprogrami sa glavnim programom smeju razmenjivati podatke samo preko
liste argumenata i povratne vrednosti.
#include <stdio.h>
#include <stdlib.h>
#define FAILURE 0
#define SUCCESS 1
int Unos(float **niz_Adr, int *br_el_Adr) {
float *niz;
int i, br_el;
printf("Unesite broj elemenata: "); Nemojte NIKAD
scanf("%d", &br_el);
niz = calloc(br_el, sizeof(float));
programski kod
if (NULL == niz) return FAILURE;
for (i = 0; i < br_el; i++)
učiti napamet.
scanf("%f", &niz[i]);
*niz_Adr = niz;
*br_el_Adr = br_el;
return SUCCESS;
}
void ObradaIspisDealociranje(float *niz, int br_el) {
float arit_sred = 0.0;
int i;
for(i = 0; i < br_el; i++) arit_sred += niz[i];
if (0 != br_el) arit_sred /= br_el;
printf("%f\n", arit_sred);
for(i = 0; i < br_el; i++)
if (niz[i] >= 0.9 * arit_sred && niz[i] <= 1.1 * arit_sred)
printf("%f\t", niz[i]);
printf("\n");
free(niz);
}
main() {
Svako ponavljanje bez
float *niz = 0; razumevanja programskog koda
int br_el;
if (Unos(&niz, &br_el)) je štetno i na ispitu će biti
else
ObradaIspisDealociranje(niz, br_el);
kažnjavano oduzimanjem poena.
printf("Greska pri unosu\n");
niz = 0;
}

Komentar
U postavci se eksplicitno traži da glavni program komunicira sa potprogramima putem argumenata i povratnih
vrednosti. Takav pristup u pisanju programa se preporučuje čak i ako se posebno ne naglasi. Takođe, nije
navedeno - ali bi trebalo podrazumevati, međusobna komunikacija potprograma treba da se odvija na isti
način.
Funkcija za unos i alokaciju memorije vraća vrednost celobrojnu vrednost - FAILURE odnosno SUCCES u
zavisnosti od uspeha. S obzirom na to da ta funkcija alocira memoriju za niz koji treba učitati – dakle menja
vrednost pokazivača, u potprogram se prenosi adresa pokazivača na dati niz brojeva. U suprotnom nikakva
izmena ne bi bila vidljiva van potprograma. Kod dealokacije memorije, ne prosleđuje se adresa pokazivača jer
se ne očekuje da se promena vrednosti tog pokazivača vidi sa mesta poziva (u ovom slučaju iz glavnog
programa). Ipak, u toj situaciji programer treba da vodi računa da nakon poziva funkcije za dealokaciju
memorije postavi vrednost to pokazivača na 0. U ovom zadatku to nije neophodno jer se taj pokazivač više ne
koristi (kraj programa), ali je dobra praksa.

Materijal za vežbe na tabli i pripremu ispita Strana 49 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C
Zadatak C2008-A1
Šta ispisuje sledeći program na programskom jeziku C, ukoliko je pozvan sa prog 3 5 7 8 ?
#include <stdio.h>
#include <stdlib.h>
union { struct { int a,b;} c; struct { int a,b,c;} d; } e;
void main(int argc, char* argv[])
{
int s=atoi(argv[1]), br = atoi(argv[2]);

for(e.c.a=0;e.c.a<br;e.c.a++)
for(e.d.a=0;e.d.a<5;e.d.a++)
for(e.c.a=0;e.c.a<5;e.c.a++)
for(e.c.b=0;e.c.b<5;e.c.b++) s++;

printf("%d", s);
}

A) 30 (B) 28 C) 628
Komentar
S obzirom na to da je kod elemenata unije memorijski prostor deljen, polja a i b strukture c dele iste lokacije
sa poljima a i b strukture d. Drugim rečima, svaka promena nad poljima a i b strukture c istovremeno
predstavlja i promenu nad poljima a i b strukture d i obrnuto.
Na početku promenljiva s dobija vrednost 3 a br 5. Dakle, spoljni ciklus (e.c.a) se na prvi pogled ponavlja 5
puta. Medjutim, vec naredni unutrašnji ciklus (e.d.a) se vrši nad istim podatkom, tako da kada on bude
završen, e.d.a će imati vrednost 5, a to automatski važi i za e.c.a. Sledeći for ciklus se odvija ponovo nad
e.c.a. Na osnovu prethodnog zaključka, kada on bude završen, automatski će biti ispunjen uslov za prekid
prva dva ciklusa. Prema tome, "koristan efekat" u programu imaju naredna dva ugneždena ciklusa. Ukupan
broj izvršavanja operacije s++ je zbog toga 25. Kako je početna vrednost s bila 3, konačna vrednost u
trenutku ispisivanja će biti 28.

Zadatak C2008-S11
Napisati program na programskom jeziku C koji sa standardnog ulaza čita znak po znak do kraja
linije. Znakovi se čitaju jedan po jedan. U početku se dinamički alocira niz od 10 elemenata. Nadalje,
svaki put kada u nizu treba više mesta, niz se proširi za još 10 znakova.
#include<stdlib.h>
#include<stdio.h>

void main(){
char *p=NULL, c;
int i = 0;
while( (c=getchar()) != '\n') {
if (i%10 == 0) p = realloc( p, (i+10) * sizeof(char) );
p[i++] = c;
}
if (i%10 == 0) p = realloc( p, (i+1) * sizeof(char) );
p[i++] = '\0';
printf("%s\n",p);
free(p); Svako ponavljanje bez
} razumevanja programskog koda
je štetno i na ispitu će biti
kažnjavano oduzimanjem poena.

Materijal za vežbe na tabli i pripremu ispita Strana 50 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C2008-S12
Napisati segment programa na programskom jeziku C koji menja dimenziju kvadratne matrice sa
staroN na N. Ako se matrica smanji, tada elementi koji ostanu u novoj matrici treba da budu
neizmenjeni u odnosu na staru matricu. Ako se matrica poveća, elementi koji su postojali u staroj
matrici treba da ostanu neizmenjeni.
if (N < staroN) {
for (j = 1; j < N; j++)
for (i = 0; i < N; i++) m[j*N+i] = m[j*staroN+i];
}
if (N != staroN) m = realloc(m,N*N*sizeof(unsigned int));
if (N > staroN){
for (j = staroN-1; j > 0; j--)
for (i = staroN-1; i >= 0; i--)
m[j*N+i] = m[j*staroN+i];
}

Zadatak C2008-S21
Napisati program na programskom jeziku C koji sa standardnog ulaza čita znak po znak do kraja
linije. Znakovi se čitaju jedan po jedan. U početku se dinamički alocira niz od 10 elemenata. Nadalje,
svaki put kada u nizu više nema mesta, niz se proširi za još 10 znakova. U slučaju da realokacija
bude neuspešna, završiti čitanje i ispisati ono što može da stane u već alocirani prostor.
Rešenje
#include<stdlib.h>
#include<stdio.h>
Nemojte NIKAD
void main(){ programski kod
char *staro_p=NULL, *novo_p, c;
int i = 0; učiti napamet.
while( (c=getchar()) != '\n') {
if (i%10 == 0) {
novo_p = realloc( staro_p, (i+10) * sizeof(char) );
if (novo_p == NULL) {
printf("Neuspesno realociranje\n");
break;
}
else staro_p = novo_p;
};
staro_p[i++] = c;
}
if (i%10 == 0) {
novo_p = realloc( staro_p, (i+1) * sizeof(char) );
if (novo_p == NULL) {
printf("Neuspesno realociranje\n");
i--;
}
else staro_p = novo_p;
};
staro_p[i] = '\0';
printf("%s\n",staro_p);
Svako ponavljanje bez
free(staro_p); razumevanja programskog koda
} je štetno i na ispitu će biti
kažnjavano oduzimanjem poena.

Materijal za vežbe na tabli i pripremu ispita Strana 51 od 52


Elektrotehnički fakultet Univerziteta u Beogradu Programski jezik C

Zadatak C2008-S22
Napisati program na programskom jeziku C koji učita broj vrsta i broj kolona i potom učita matricu
tih dimenzija. Program potom učita broj kolone koju treba izbaciti i izbacuje tu kolonu iz matrice.
Zatim čita redni broj vrste na koji umeće vrstu koju će učitati sa standardnog ulaza.
Rešenje
#include<stdlib.h>
#include<stdio.h>

void main(){
unsigned int **m, **novo_m;
int M, N, i, j, k;
scanf("%d %d", &M, &N);
m = malloc(M * sizeof(unsigned int*));
for (j = 0; j < M; j++){
m[j] = malloc( N * sizeof(unsigned int) );
for (i = 0; i < N; i++)scanf("%u", &m[j][i] );
}

printf("Unesite broj kolone koju izbacujete: ");


scanf("%d", &k);
if ( k >= 0 && k < N) {
for (j = 0; j < M; j++){
for (i = k+1; i < N; i++)
m[j][i-1] = m[j][i];
m[j] = realloc( m[j], (N-1) * sizeof(unsigned int) );
}
N--;
}
Nemojte NIKAD
for (j = 0; j < M; j++){
for (i = 0; i < N; i++) programski kod
printf("%d ",m[j][i]);
printf("\n"); učiti napamet.
}
printf("\n\n");

printf("Unesite red broj na koji umecete vrstu: ");


scanf("%d", &k);
if ( k >= 0 && k < M) {
m = realloc( m, (M+1) * sizeof(unsigned int*) );
M++;
for( j = M-1; j > k; j--)
m[j] = m[j-1];
m[k] = malloc( N * sizeof(unsigned int) );
for( i = 0; i < N; i++)
scanf("%u", &m[k][i]);
}

Svako ponavljanje bez


for (j = 0; j < M; j++){
for (i = 0; i < N; i++)
printf("%u ",m[j][i]); razumevanja programskog koda
je štetno i na ispitu će biti
free(m[j]);
printf("\n");
} kažnjavano oduzimanjem poena.
printf("\n\n");
free(m);
}

Komentar
Zbog čitljivosti programa, u ovom rešenju su izostavljene provere da li je alokacija (realokacija) uspešno
izvršena. Pri pisanju bilo kakvog programa ove provere NE SMEJU biti izostavljene. Izostavljanjem tih provera,
ponašanje programa u slučaju nedostatka prostora nije predvidivo i može dovesti do katastrofalnih posledica.

Materijal za vežbe na tabli i pripremu ispita Strana 52 od 52


Prvi čas računskih vežbi iz Programiranja I

1. Koji od navedenih identifikatora nisu ispravni i zašto?

aaa _1_
a12 Windows
12a vece-manje
_12a north&south

2. Koju vrijednost ima promenljiva b poslije izvršavanja navedenih naredbi?

short int a=32767, b;


b=a+1; /* b = -32768 */

3. Koju će vrijednost imati realna promjenljiva B poslije datog niza naredbi? Na koji način se u tu
promjenljivu može upisati tačan rezultat date operacije?

int A;
float B;
A=5;
B=5*A/7; /* B = 3 */

4. Koju će vrijednost uzeti promenljive s1 i s2 nakon izvršenja svake od datih naredbi? Koju će vrijednost
uzeti promenljiva s2 ako se u poslednjem izrazu izostavi spoljašnji par zagrada u drugom sabirku?

int s1, s2, q=8;


s1=1;
s2=++s1+5; /* s1=2, s2 = 7 */
s1=!s2; /* s1 = 0, s2 = 7 */
s2+=(q%3)+((q<10)||(s1--)); /* s2 = 10, s1 = 0 */

5. Odrediti vrijednost promenljivih posle izvršenja svake od datih naredbi.

int t, a=3, b=7, i, j;


t=a&b; /* t = 3 */
i=(t==3); /* i = 1 */
j=(i==0) ? i : t; /* j = 3 */
Drugi čas računskih vežbi iz Programiranja I

1. Napisati program koji za uneti prirodni broj računa zbir njegovih cifara.

#include<stdio.h>
main()
{
int s=0,broj;
printf("Unesi prirodan broj\n");
scanf("%i",&broj);
while (broj!=0){
s+=broj%10;
broj/=10;
}
printf("Suma cifara prirodnog broja je: %d\n",s);
}

2. (Sa I kolokvijuma) Napisati program u programskom jeziku C koji učitava prirodan broj N i koji ispituje
da li je taj broj savršen broj. Prirodan broj je savršen ukoliko je jednak sumi svih svojih djelilaca koji su
manji od njega. Na izlazu štampati odgovarajuću poruku. Primjer: Broj 28 je djeljiv sa 1,2,4,7,14 i 28,
pa je zbir djelilaca manjih od njega 1+2+4+7+14=28, a to znači da je broj 28 savršen.

#include<stdio.h>
main()
{
int N,i,suma=0;
printf("Uneti broj N: ");
scanf("%d",&N);
for(i=1; i<N; i++){
if(N%i==0){
suma+=i;
}
}
if(suma==N)
printf("Broj %d jeste savrsen broj\n",N);
else
printf("Broj %d nije savrsen broj\n",N);
}

3. Napisati program koji približno računa sumu reda:



1
n
n 1
2

Sumiranje vršiti sve dok je opšti član sume veći od 10-4.

#include<stdio.h>
main()
{
int N=1;
float suma=0,op;
op=1.0/(N*N);
while(op>1e-4){
suma=suma+op;
N=N+1;
op=1.0/(N*N);
}
printf("Suma je %f",suma);
}
4. Napisati program koji računa najveći zajednički delilac (NZD) brojeva a i b pomoću Euklidovog
algortima:
1. Ako je a=b, tada je NZD=a i to je kraj algoritma.
2. Od većeg broja oduzmemo manji i vraćamo se na prvi korak.

#include<stdio.h>
void main()
{
int a, b;
puts("Unesi cijele brojeve");
scanf("%d %d",&a,&b);
while(a!=b) {
if (a>b)
a-=b;
else
b-=a;
}
printf("NZD je: %d\n",a);
}
Treći čas računskih vežbi iz Programiranja I

1. Napisati program koji formira podniz datog niza koji se sastoji od onih elemenata koji su veći od datog
cijelog broja.

#define MAX 20
#include <stdio.h>
main()
{
int N,C,k=0,i,a[MAX],b[MAX];
printf("Unesi broj clanova niza:");
scanf("%d",&N);
printf("Unesi cijeli broj:"); scanf("%d",&C);
printf("Unesi clanove niza:");
for(i=0;i<N;i++){
scanf("%d",a+i);
if(a[i]>C)
b[k++]=a[i];
}
if(k>0){
printf("Elementi niza koji su veci od datog cijelog broja
su:\n");
for(i=0;i<k;i++) printf("%d ",b[i]);
}
}

2. Napisati program koji definiše niz cijelih brojeva X i koji vrši sumiranje elemenata tog niza korišćenjem
pomoćne pokazivačke promjenljive. Prilagoditi program tako da eventualna izmjena broja elemenata
niza u njegovoj inicijalizaciji ne zahtijeva intervenciju na programu.

#include<stdio.h>
main(){
int X[]={-3,4,2,7,11,-9};
int *p, i, suma=0;
for(i=0; i < sizeof(X)/sizeof(X[0]); i++) {
p=&(X[i]); suma+=*(p+i); ili suma+=*p++, pri čemu
suma+=*p; pre petlje mora p=&(X[0]); ili p=X.
}
printf("Dobijena suma je: %d\n",suma);
}
3. Napisati program koji učitava matricu cijelih brojeva A, dimenzija NxM, i koji tu matricu štampati
prateći strelice prikazane na slici. Npr., za matricu:

1 2 3 4
11 12 13 14 
A 
 21 22 23 24 
 
31 32 33 34 
redosljed štampanja treba da bude: 1,11,21,31,32,22,12,2,3,13,23,33,34,24,14,4.

#include <stdio.h>
main(){
int i,j,n,m, a[20][20];
printf("Unesi dimenzije matrice a: ");
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
scanf("%d",&a[i][j]);
for(j=0;j<m;j++)
if(j%2==0)
for(i=0;i<n;i++)
printf("%d ",a[i][j]);
else
for(i=n-1;i>=0;i--)
printf("%d ",a[i][j]);
}
Četvrti čas računskih vježbi iz Programiranja I

1. Učitati string koji sadrži manje od 20 karaktera sa tastature i sva mala slova u tom stringu
konvertovati u velika, a ostale karaktere ne menjati.

#include<stdio.h>
#include<string.h>
main()
{ char niz[20];
int i;
puts("Unesi neku rec");
scanf("%s",niz);
for (i=0;i<strlen(niz);i++){
if (niz[i]>='a' && niz[i]<='z')
niz[i]-='a'-'A';
}
printf("Novi string je: %s",niz);
}

2. Napisati program koji učitava string, koji predstavlja rečenicu, i koji koristeći funkciju
proverava da li je rečenica ispravno zadata. Ispravno zadata rečenica zadovoljava sljedeće:
a) Rečenica mora početi velikim slovom i završiti se tačkom.
b) Riječi su proizvoljni podstringovi koji mogu sadržati samo mala slova.
c) Riječi mogu biti razdvojeni jednim razmakom (SPACE), zarezom ili tačka-zarezom.
U glavnom programu učitati string, pozvati funkciju i na izlazu ispisati obavještenje da li je
rečenica ispravno zadata.

#include <stdio.h>
#include <string.h>

int recenica(char *);

main(){
int p;
char s[20];
printf("\nUnesi string ");
gets(s);

p=recenica(s);

if(p==1)
printf("Nije");
else
printf("Jeste");
}
int recenica(char *s){

int i, duz, ind=0;

duz=strlen(s);

if ((s[0]<'A' || s[0]>'Z') || s[duz-1]!='.')


ind=1;

if(ind==0)
{
for(i=1;i<duz-1;i++){

if((s[i]<'a' || s[i]>'z') && s[i]!=' ' && s[i]!=',' && s[i]!=';')


ind=1;

if((s[i]==' '||s[i]==','||s[i]==';') && (s[i+1]==' '|| s[i+1]==','


|| s[i+1]==';'))
ind=1;
}
}

return ind;

3. Napisati program koji sadrži funkciju koja određuje i štampa srednju vrednost niza realnih
brojeva. Broj članova, kao i članovi niza se zadaju po startovanju programa.

#include<stdio.h>

float sred_niz(int,float *);

main()
{
int n,i;
float a[20];
puts("Uneti broj clanova niza");
scanf("%d",&n);
puts("Uneti elemente niza");
for(i=0;i<n;i++)
scanf("%f",a+i);
printf("Srednja vrednost ovog niza je: %f\n",sred_niz(n,a));
}

float sred_niz(int duzina,float *a)


{
int i;
float sum=0.0;
for(i=0;i<duzina;i++)
sum+=a[i];
return sum/duzina;
}
4. Napisati program u programskom jeziku C koji učitava prirodan broj N i koji štampa prvih N
savršenih brojeva. Prirodan broj je savršen ukoliko je jednak sumi svih svojih djelilaca koji
su manji od njega. Program sadrži funkciju koja određuje da li je broj koji joj se prosleđuje
kao argument savršen.
Primjer: Broj 28 je djeljiv sa 1,2,4,7,14 i 28, pa je zbir djelilaca manjih od njega
1+2+4+7+14=28, a to znači da je broj 28 savršen.

#include<stdio.h>

main(){
int N,k=0;
long i=1;
printf("Uneti N ");
scanf("%d",&N);
while(k<N){
if(savrsen(i)==1){
k=k+1;
printf("%d\n",i);
}
i=i+1;
}
}

int savrsen(long M){


long suma=0,i=1;
while(i<=M/2){
if(M%i==0)
suma+=i;
i+=1;
}
if(suma==M)
return 1;
else
return 0;
}
Peti čas računskih vežbi iz Programiranja I

1. Napisati program koji na zadatom sortiranom nizu primjenjuje binarno pretraživanje uz pomoć
odgovarajuće rekurzivne funkcije.

#include <stdio.h>
#include <conio.h>

int binarno(int [], int, int, int);


int K;

main(){
int A[30], N, i, poz;
printf("Uneti duzinu niza");
scanf("%d",&N);
printf("Uneti elemente niza");
for(i=0;i<N;i++)
scanf("%d",A+i);
printf("Uneti element koji se trazi: ");
scanf("%d",&K);
poz = binarno(A,0,N-1,N/2);
if (poz == -1)
printf("Nema takvog elementa");
else
printf("Element se nalazi na poziciji %d!",poz);
getch();
}

int binarno(int X[], int fir, int last, int mid){


if (fir > last)
return -1;
else if (fir == last || fir == last-1) {
if (X[fir] == K || X[last] == K)
return (X[fir] == K) ? fir : last;
else
return -1;
}
if (X[mid] == K)
return mid;
else if (X[mid] < K)
return binarno(X,mid+1,last,(mid+1+last)/2);
else
return binarno(X,fir,mid-1,(fir+mid-1)/2);
}
2. Sortirati elemente niza celih brojeva u rastući poredak koristeći sortiranje sa spajanjem (merge sort).

#include <stdio.h>
#include <conio.h>

void merge_sort(int [], int, int, int);


void combine(int [], int, int, int);
void swap(int [], int, int);

main(){
int A[30], N, i;
printf("Uneti duzinu niza");
scanf("%d",&N);
printf("Uneti elemente niza");
for(i=0;i<N;i++)
scanf("%d",A+i);
merge_sort(A,0,N-1,N/2);
printf("Sortirani niz je: ");
for(i=0;i<N;i++)
printf("%d ",A[i]);
getch();
}

void merge_sort(int X[], int fir, int last, int mid){


if (fir == last)
return;
else {
merge_sort(X,fir,mid,(fir+mid)/2);
merge_sort(X,mid+1,last,(mid+1+last)/2);
}
combine(X,fir,last,mid);
}

void combine(int X[], int fir, int last, int mid){


int i=mid+1,j;
while (i<=last){
j = i;
while (X[j]<X[j-1] && j>fir){
swap(X,j,j-1);
j--;
}
i++;
}
}

void swap(int X[], int p, int q){


int temp;
temp = X[p];
X[p] = X[q];
X[q] = temp;
}

Napomena: Slika uz ovaj program je preuzeta sa internet stranice http://en.wikipedia.org/wiki/Merge_sort


Šesti čas računskih vježbi iz Programiranja I

1. Sastaviti program koji od elemenata dinamičkog niza formira druga dva dinamička niza, niz
nenegativnih i niz negativnih brojeva. Prikazati elemente tako dobijenih nizova.
#include<stdio.h>
#include<stdlib.h>
main()
{
int *a,*b,*c,i,j=0,k=0,duz,duz1=0;
puts("Uneti duzinu niza");
scanf("%d",&duz);
a=(int *)malloc(duz*sizeof(int));
if(a==NULL){
puts("Nema memorije"); exit(1);
}
puts("Elementi niza");
for(i=0;i<duz;i++){
scanf("%d",a+i);
if(a[i]>=0)
duz1++;
}
b=(int *)malloc(duz1*sizeof(int));
c=(int *)malloc((duz-duz1)*sizeof(int));
if((b==NULL)||(c==NULL)){
puts("Nema memorije"); exit(1);
}
for(i=0;i<duz;i++)
if(a[i]>=0)
b[j++]=a[i];
else
c[k++]=a[i];
free(a);
puts("Pozitivni brojevi su:");
for(i=0;i<duz1;i++)
printf("%d ",b[i]);
puts("Negativni brojevi su:");
for(i=0;i<duz-duz1;i++)
printf("%d ",c[i]);
free(b);
free(c);
}

2. Napisati program kojim se unose dva cijela broja a i b (a<b, ne treba provjeravati). Program treba da
generiše niz svih slučajno raspoređenih brojeva iz intervala [a,b], pri čemu se elementi niza ne smiju
ponavljati. Niz dinamički alocirati.
#include <stdio.h>
#include <stdlib.h>
void generisi(int *, int, int);
int main()
{
int *X, a,b,i;
// ovom naredbog podešavamo generator slučajnih brojeva
srand (time(NULL));
printf("Unesite a i b:");
scanf("%d%d",&a,&b);
X=(int *)malloc((b-a+1)*sizeof(int));
if (X==NULL)
{
printf("Nema memorije!");
exit(1);
}
generisi(X,a,b);
printf("Generisani niz slucajnih brojeva je: ");
for (i=0;i<b-a+1;i++)
printf("%d ",X[i]);
free(X);

}
// I varijanta
void generisi(int *X, int a, int b)
{
int i, k=0, broj,ind;
while (k<b-a+1)
{
broj=a+rand()%(b-a+1);
ind=1;
for (i=0;i<k;i++)
if (X[i]==broj)
{
ind=0;
break;
}
if (ind)
X[k++]=broj;
}
}
// II varijanta
void generisi(int *X, int a, int b)
{
int i, t, poz;
for (i=0;i<b-a+1;i++)
X[i]=a+i;
for (i=0;i<b-a+1;i++)
{
poz=rand()%(b-a+1);
t=X[i];
X[i]=X[poz];
X[poz]=t;
}
}
Sedmi čas računskih vježbi iz Programiranja I

1. Svaki red fajla c:\broj.txt sadrži po jedan cijeli broj. Sastaviti program koji štampa najmanji i najveći cijeli broj u
tom fajlu.

#include<stdio.h>
main()
{
FILE *fp;
int najmanji, najveci, broj;
fp=fopen("c:\\broj.txt","r");
if(fp==NULL){
printf("Greska pri otvaranju fajla");
exit(1);
}
fscanf(fp,"%d",&broj);
najmanji=broj;
najveci=broj;
while(fscanf(fp,"%d",&broj)!=EOF){
if(broj<najmanji)
najmanji=broj;
if(broj>najveci)
najveci=broj;}
fclose(fp);
printf("Najmanji je broj %d, a najveci %d\n", najmanji, najveci);
}

2. Svaki red fajla Brojevi.txt sadrži po jedan prirodan broj. Napisati program koji formira fajl 2_9.txt prepisujući
samo one brojeve iz fajla Brojevi.txt koji nemaju drugih cifara osim 2 i 9. Primjeri takvih brojeva su 2, 9, 22, 29,
229 itd. Nakon datih obrada zatvoriti predmetne fajlove. Vodite računa da li su fajlovi korektno otvoreni.

#include<stdio.h>
void main()
{
int broj, pom, cif, ind;
FILE *a, *b;
if((a=fopen("c:\\Brojevi.txt","r"))==NULL) {
puts("Greska pri otvaranju fajla"); exit(1); }
if((b=fopen("c:\\2_9.txt","w"))==NULL) {
puts("Greska pri otvaranju fajla"); exit(1); }
while(fscanf(a,"%d",&broj)!=EOF) {
ind=1; pom=broj;
while(pom!=0){
cif=pom%10;
if(cif!=2 && cif!=9)
ind=0;
pom/=10;
}
if(ind && broj!=0)
fprintf(b,"%d\n",broj);
}
fclose(a); fclose(b);
}
Osmi čas računskih vježbi iz Programiranja I

1. Elementi liste su celi brojevi. Sastaviti program koji vrši sumiranje brojeva upisanih u čvorovima liste
korišćenjem rekurzivne funkcije.

#include<alloc.h>

struct str {
int a;
struct str *sled; };

int sabiranje(struct str *);

main()
{
struct str *elem, *pom, *glava;
int i, n;
puts("Uneti broj elemenata liste");
scanf("%d",&n);
puts("Elementi liste");
for(i=0;i<n;i++){
elem=(struct str *) malloc(sizeof(struct str));
scanf("%d",&(elem->a));
elem->sled=NULL;
if(i==0){
pom=elem;
glava=elem;
}
else {
pom->sled=elem;
pom=elem;
}
}
printf("Zbir je %d ",sabiranje(glava));
}

int sabiranje(struct str *lista){


if(lista->sled==NULL)
return lista->a;
else
return lista->a + sabiranje(lista->sled);
}

2. Elementi liste su sortirani celi brojevi. Sastaviti program koji učitava ceo broj i smešta ga u sortiranu listu tako da
se ne naruši sortiranost. Umetanje tog broja izvršiti pomoću funkcije, a ne u okviru glavnog programa.

#include<stdio.h>
#include<alloc.h>

struct str {
int a;
struct str *sled;
};

struct str *umetanje(struct str *,int);

main()
{
struct str *elem, *pom, *glava;
int i, n, broj;
puts("Uneti broj elemenata liste");
scanf("%d",&n);
puts("Elementi liste");
for(i=0;i<n;i++){
elem=(struct str *) malloc(sizeof(struct str));
scanf("%d",&(elem->a));
elem->sled=NULL;
if(i==0){
pom=elem;
glava=elem;
}
else {
pom->sled=elem;
pom=elem;
}
}
printf("Uneti neki broj ");
scanf("%d",&broj);
pom=umetanje(glava,broj);
for(i=0;i<=n;i++){
printf("%d ",pom->a);
pom=pom->sled;
}
}

struct str *umetanje(struct str *lista,int broj)


{
struct str *umet,*poc,*pom;
poc=lista;
umet=(struct str *)malloc(sizeof(struct str));
umet->a=broj;
if(broj<=lista->a){
umet->sled=lista;
return umet;
}
pom=lista;
lista=lista->sled;
while(lista!=NULL){
if(broj<=lista->a){
umet->sled=lista;
pom->sled=umet;
return poc;
}
else{
pom=lista;
lista=lista->sled;
}
}
umet->sled=NULL;
pom->sled=umet;
return poc;
}
Deveti čas računskih vježbi iz Programiranja I

1. Elementi liste su parovi; prvi u paru je cio broj k, a drugi je realan broj a, što znači da taj element liste
definiše član polinoma axk. Dakle, cijela lista zadaje jedan polinom p(x). Napisati program koji formira
datu listu, zatim učitava realan broj x, argument polinoma, a nakon toga računa vrijednost polinoma p(x)
korišćenjem rekurzivne funkcije. Štampati dobijenu vrijednost.

struct lista {
int k;
float a;
struct lista *next;
};

float polinom(struct lista *p, float x)


{
if(p->next==NULL)
return p->a*pow(x,p->k);
return p->a*pow(x,p->k)+polinom(p->next,x);
}

2. Elementi liste su riječi. Napisati funkciju koja određuje da li su te riječi leksikografski uređene u rastući
poredak.

struct lista {
char rijec[20];
struct lista *next;
};

int uredjene(struct lista *p)


{
if(p->next==NULL)
return 1;
else {
if (strcmp(p->rijec,p->next->rijec)>0)
return 0;
else
return uredjene(p->next);
}
}

3. Elementi liste su cijeli brojevi. Napisati program kojim se od početne liste formiraju dvije nove liste, lista
sa parnim i lista sa neparnim elementima. Štampati dobijene liste.

#include <stdio.h>
#include <stdlib.h>

struct str
{
int a;
struct str *sled;
};

int main()
{
int n,i;
struct str *el, *pre, *glava, *lista, *glPar=NULL, *glNep=NULL, *prePar=NULL,
*preNep=NULL;
puts("Unijeti broj elemenata liste:");
scanf("%d",&n);

puts("Unesi elemente liste:");


for(i=0;i<n;i++)
{
el=(struct str *)malloc(sizeof(struct str));
scanf("%d",&(el->a));
el->sled=NULL;

if(i==0) glava=el;
else pre->sled=el;

pre=el;
}

lista=glava;

while(lista!=NULL){
if((lista->a)%2 == 0){
if(glPar==NULL) glPar=lista;
else prePar->sled=lista;
prePar=lista;
}
else{
if(glNep==NULL) glNep=lista;
else preNep->sled=lista;
preNep=lista;
}
lista=lista->sled;
}

if(prePar) prePar->sled=NULL;
if(preNep) preNep->sled=NULL;

puts("Lista sa parnim elementima:");


while(glPar!=NULL)
{
printf("%d ", glPar->a);
glPar=glPar->sled;
}

puts("\nLista sa neparnim elementima:");


while(glNep!=NULL)
{
printf("%d ", glNep->a);
glNep=glNep->sled;
}

}
4. Na osnovu unešene matrice susjedstva grafa sa 5 čvorova provjeriti da li je taj graf usmjeren ili
neusmjeren.

#include <stdio.h>
void main()
{
int ms[5][5];
int i, j, ind=1;
puts("Uneti matricu susedstva grafa ");
for(i=0;i<5;i++)
for(j=0;j<5;j++)
scanf("%d",&ms[i][j]);
for(i=0;i<5;i++)
if(ms[i][i]==1)
ind=0;
if(ind)
for(i=0;i<5;i++) {
for(j=0;j<5;j++) /* for(j=i+1;j<5;j++) */
if(ms[i][j]!=ms[j][i])
ind=0;
if(ind==0)
break;
}
if(ind)
printf("\nNeusmjeren!\n");
else
printf("\nUsmjeren!\n");
}
Deseti čas računskih vježbi iz Programiranja I

1. Napisati funkciju koja određuje broj čvorova drveta (težinu drveta).

struct drvo {
int a;
struct drvo *left;
struct drvo *right;
};

int tezina(struct drvo *root)


{
if(root->left!=NULL && root->right!=NULL)
return 1 + tezina(root->left) + tezina(root->right);
else if(root->left!=NULL && root->right==NULL)
return 1 + tezina(root->left);
else if(root->left==NULL && root->right!=NULL)
return 1 + tezina(root->right);
else
return 1;
}

2. Napisati funkciju koja određuje broj listova drveta.

int listovi(struct drvo *root)


{
if(root->left!=NULL && root->right!=NULL)
return listovi(root->left) + listovi(root->right);
else if(root->left!=NULL)
return listovi(root->left);
else if(root->right!=NULL)
return listovi(root->right);
else
return 1;
}

3. Svakom vrhu pridružena je jedna riječ dužine manje od 12 karaktera. Sastaviti potprogram koji određuje
koliko puta se pojavljuje data riječ.

struct drvo {
char rijec[12];
struct drvo *left;
struct drvo *right;
};

int brojrijeci(struct drvo *root, char *s)


{
int ind=0;
if(strcmp(root->rijec,s)==0)
ind=1;
if(root->left!=NULL && root->right!=NULL)
return ind + brojrijeci(root->right,s) + brojrijeci(root->left,s);
else if(root->left!=NULL)
return ind + brojrijeci(root->left,s);
else if(root->right!=NULL)
return ind + brojrijeci(root->right,s);
else
return ind;
}
4. Vrši se obilazak binarnog drveta od korijena ka listovima i sabiraju se cijeli brojevi upisani u čvorovima
drveta. Sastaviti potprogram koji pronalazi najveću takvu putanju.

struct drvo {
int n;
struct drvo *left;
struct drvo *right;
};

int max_path(struct drvo *root)


{
if(root->left==NULL && root->right==NULL)
return root->n;
else if(root->left!=NULL && root->right!=NULL)
return root->n + max(max_path(root->left),max_path(root->right));
else if(root->left!=NULL)
return root->n + max_path(root->left);
else
return root->n + max_path(root->right);
}

int max(int a, int b)


{
return (a > b) ? a : b;
}

5. Dato je binarno drvo u čijim su čvorovima upisani cijeli brojevi. Odrediti redosljed štampanja tih brojeva
ukoliko koristimo:
a) Inorder obilazak (lijevo poddrvo, korijen, desno poddrvo);
b) Preorder obilazak (korijen, lijevo poddrvo, desno poddrvo);
c) Postorder obilazak (lijevo poddrvo, desno poddrvo, korijen).

a) 11, 4, 9, 7, 6, 2, 5, 3, 1
b) 2, 7, 4, 11, 9, 6, 5, 3, 1
c) 11, 9, 4, 6, 7, 1, 3, 5, 2
LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

... Zadaci iz C-a ...

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

1. Napraviti program koji ucitava koordinate dvije tacke u


trodimenzionalnom prostoru:
Tacke t i t su definirane kao trojke:
1 2

- t =(x , y , z ) ,
1 1 1 1
- t =(x , y , z ).
2 2 2 2
Kao izlaz program daje udaljenost izmedju tih tacki.

NAPOMENA: Za drugi korijen koristiti funkciju sqrt() koja je


definirana u datoteci math.h. Na primjer, naredba a=sqrt(9); ce
izracunati drugi korijen iz 9 i pridruziti izracunatu vrijednost
varijabli a.

RJEŠENJE:

// Ukljucujemo datoteke u kojima se nalaze funkcije koje cemo koristiti.


# include <stdio.h>
# include <math.h>
// Definisanje glavne funkcije main()
int main () {
// Definisanje potrebnih varijabli
float x1,y1,z1,x2,y2,z2,d;
// Unos kordinata x1,y1,z1 (printf - ispis poruke; scanf - unos varijabli)
printf("Unesi tacku a(x1,y1,z1): ");
scanf("%f,%f,%f", &x1, &y1, &z1);
// Unos kordinata x2,y2,z2
printf("Unesi tacku b(x2,y2,z2): ");
scanf("%f,%f,%f", &x2, &y2, &z2);
// Racunanje udaljenosti po formuli (sqrt - funkcija koja racuna drugi korjen)
d=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
// Ispis udaljenosti d
printf("Udaljenost izmedju tacki a i b je: %f", d);
// Kraj programa (getch() - stavljamo da bi zadrzali poruku u kojoj je
// rezultat. U suprotnom nam se nece prikazati poruka na ekranu, iako je
// program uspjesno izvrsen
getch();
// Return 0; - (umjesto 0 mozemo staviti bilo koji cio broj, jednostavno
// nekako je potrebno zavrsiti funkciju main() pa se obicno stavlja return 0;
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

2. Napravite C-program koji ucitava potrošnju elektricne


energije u KWh (velika tarifa(VT) i mala tarifa(MT)) i
pripadajuce cijene po KWh (cijena za malu tarifu i cijena za
veliku tarifu).
Kao izlaz program daje:
- ukupnu potrošnju u KWh;
- novcani iznos racuna;
- udio velike tarife i male tarife u ukupnoj potrošnji.
Na primjer, izlaz iz programa treba biti sljedeceg formata:
Ukupna potrosnja je 234.25 KWh.
Udio velike tarife u ukupnoj potrosnji je 25 %.
Udio male tarife u ukupnoj potrosnji je 75%.
Iznos racuna je 25.45 KM.

RJEŠENJE:

# include <stdio.h>
int main () {
// Definisanje potrebnih varijabli
float VT,MT,CV,CM,UKUPNO,RACUN,UDIOM,UDIOV;
// Unos male tarife, velike tarife, cijene male tarife i cijene velike tarife
printf("\n Unesi potrosnju po velikoj tarifi (KWh): ");
scanf("%f", &VT);
printf("\n Unesi potrosnju po maloj tarifi (KWh): ");
scanf("%f", &MT);
printf("\n Cijena za veliku tarifu po jednom Kwh: ");
scanf("%f", &CV);
printf("\n Cijena za malu tarifu po jednom Kwh: ");
scanf("%f", &CM);
// Racunanje ukupne potrosnje
UKUPNO=VT+MT;
// Racunanje cijene ukupne potrosnje (cijena po maloj tarifi + cijena po
// velikoj tarifi)
RACUN=VT*CV+MT*CM;
// Izracunava udio velike i male tarife u ukupnoj potrosnji (procenat)
UDIOM=(MT/UKUPNO)*100;
UDIOV=(VT/UKUPNO)*100;
// Ispis rezultata
printf ("\n Ukupna potrosnja elektricne energije je: %.f KWh", UKUPNO);
printf ("\n Ukupna cijena elektricne energije je: %.f KM", RACUN);
printf ("\n Udio velike tarife u potrosnji je: %.f procenata", UDIOV);
printf ("\n Udio male tarife u potrosnji je: %.f procenata", UDIOM);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

3. Napisati program koji ce izracunati presjek skupova S1 i S2.


Skupovi S1 i S2 definirani su intervalima realnih brojeva:
S1=[A, B]
S2=[C, D].
Na primjer, za slijedeci ulaz: A=3, B=9, C=7, D=11
program kao izlaz treba dati:

Rezultantni interval je REZ=[7, 9].

RJEŠENJE:

#include <stdio.h>
main() {
// Definisanje varijabli
float A,B,C,D,MAX,MIN;
// Unos skupova
printf("\n Unesi prvi skup X[A,B] A>B: ");
scanf("%f,%f", &A,&B);
printf("\n Unesi drugi skup Y[C,D] C>D: ");
scanf("%f,%f", &C,&D);

/* Logika zadatka je sljedeca: Prvo moramo pretpostaviti da je prvi broj


intervala veci ili jednak drugom, A>=B i C>=D, jer ako ovo ne vrijedi interval
nije matematicki ispravan (taj uslov nismo ispitivali da nebi komplikovali
zadatak). Presjek skupa ce biti neki interval [MIN,MAX].
Uslov da zadatak ima RJEŠENJE je da je B < C kao i D < A sto je i logicno jer
u suprotnom presjeka nema!
Broj MIN je ustvari jedan od brojeva A ili C (manji broj od ova 2 broja),
a MAX je manji broj od brojeva B i D. Ako je A=C ili B=D uzima se vrijednost
pod ELSE ali tada nam je svakako svejedno koja ce se uzeti vrijednost kao MIN
ili MAX jer je tada A=C odnosno B=D */

if (A>C) MAX=A; else MAX=C;


if (B<D) MIN=B; else MIN=D;
if ((B<C)||(A>D)) printf("\n Nema presjeka!"); else {
printf ("\n Presjek je: [%.f,%.f]", MAX, MIN); }
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

4. Napisati program koji ucitava koeficijente a, b i c realnog


tipa. Ti koeficijenti definiraju funkciju f(x):
2
f(x)=ax +bx+c
Program zatim provjerava da li su ti keficijenti u rasponu -10 do
10. Ako nisu, program ispisuje poruku:
Koeficijenti a, b i c nisu u zadanom rasponu.
Ako koeficijenti a, b i c jesu u zadanom rasponu, program kao
izlaz daje vrijednost prve derivacije u tacki x. Tacka x se
takodjer unosi sa standardnog ulaza.
Na primjer, ako je ulaz a=1, b=2, c=1, x=1 program kao izlaz
daje: Prva derivacija u tacki x=1 je 4.

RJEŠENJE:

# include <stdio.h>
int main () {
// Definisanje varijabli
float a,b,c,x,izvod;
// Unos koeficijenata a,b,c
printf ("Unesi koef. (a,b,c) funkcije f(x)=ax2+bx+c (-10<(a,b,c)<10):");
scanf("%f,%f,%f", &a,&b,&c);
// Unos vrijednosti x
printf ("Unesi vrijednost x");
scanf("%f", &x);
// Ispit uslova
if (a>-10&&a<10&&b>-10&&b<10&&c>-10&&c<10){
// Izracunavanje izvoda po odredjenoj matematickoj formuli
izvod=2*a*x+b;
// Ispis izvoda
printf("Prva derivacija u tacki x=%.f je %.f", x, izvod);
// Ispis odgovarajuce poruke ukoliko uslov nije zadovoljen
} else printf ("Koeficijenti nisu iz odgovarajuceg intervala!");
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

5. Napisati program koji ucitava tri cijela broja iz intervala


od 50 do 200. Ako svi uneseni brojevi nisu iz tog intervala,
program treba ispisati poruku "Svi brojevi nisu iz intervala 50
do 200” i završiti program. Ako su brojevi unutar tog intervala
program treba ispisati ucitane brojeve po velicini od najmanjeg
prema najvecem.

RJEŠENJE:

#include <stdio.h>
main() {
// Definisanje varijabli
int x[3], i, j, p;
// Unos brojeva
printf("\n Unesi tri broja u rasponu od 50 do 200 (U formatu: a, b, c): ");
scanf("%d, %d, %d", &x[0], &x[1], &x[2]);
// Provjera jesu li brojevi iz odgovarajuceg intervala
if (x[0]>50&&x[1]>50&&x[2]>50&&x[0]<200&&x[1]<200&&x[2]<200) {
/* Sortiranje brojeva
Potrebne su nam dvije for petlje koje ce „listati“ brojeve koji se nalaze u
nekom nizu. Ovaj tip sortiranja se uglavnom svodi na provjeru da li je prvi
broj manji od drugog ili treceg, i ako jeste, onda mijenja mjesto sa tim
brojem. Medjutim nakon ovoga nije zavrseno sortiranje. Ako npr. Unesemo
brojeve 3, 2, 1, nakon prvog prolaska imamo 2, 3, 1 nakon drugog 2, 1, 3 ali
jos uvijek nije zavrseno sortiranje, i zbog toga i postoji prva for petlja
koja ce to ponoviti jos jednom i dobivamo 1, 2, 3 i niz je sortiran, i sada ga
samo jos treba ispisati na ekran. */
for (i=0;i<2;i++)
for (j=0;j<2;j++)
if (x[j]>x[i]) {
p=x[i];
x[i]=x[j];
x[j]=p;
}
// Ispis sortiranih brojeva
printf("\n Sortirani brojevi: %d, %d, %d ", x[0], x[1], x[2]);
// Ako brojevi nisu iz intervala, ispis odgovarajuce poruke
} else { printf("\n Svi brojevi nisu iz intervala 50 do 200!!!");
}
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

6. Napisati program koji ce ispisati brojeve djeljive sa 5, 7


ili 11, a manje ili jednake od nekog ucitanog broja n sa
tastature. Brojeve treba ispisati od najveceg prema najmanjem.
Obavezno koristiti for petlju. Na primjer, ako je korisnik za n
unio broj 20 onda program treba ispisati:
20
15
14
11
10
7
5

RJEŠENJE:

#include <stdio.h>
int main()
{
// Definisanje varijabli
int n, i;
// Unos nekog prirodnog broja
printf("Unesite broj: ");
scanf("%d", &n);
/* For petlja postavlja brojac „i“ na vrijednost unesenog broja, i provjerava
se da li je taj broj djeljiv sa 5, 7 ili 11, i ako jeste printa ga na ekran i
umanjuje brojac za jedan, ako broj nije djeljiv sa ovim brojevima, onda se
samo brojac umanji na kraju for petlje bez printanja broja na ekranu. Isti se
postupak ponavlja i za broj manji za jedan, kao i broj manji za dva... sve
tako do broja 1 (mogli smo staviti i 4 jer brojevi ispod 5 svakako nisu
djeljivi sa ovim brojevima! */
for(i=n;i>0;i--)
{
if ((i % 5 == 0)||(i % 7 == 0)||(i % 11 == 0)) printf("\n Broj: %d", i);
}
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

7. Napisati program koji ce izracunavati sumu prema slijedecoj


formuli: suma=1-1/2+1/3-1/4+...+1/n
Broj n se unosi sa tastature(standardnog ulaza). Program treba
ispisati vrijednost sume na standardnom izlazu (monitoru)
koristeci slijedecu poruku:
Koristeci <n> clanova suma je <suma>.
(Na mjestu <n> se treba nalaziti konkretno uneseni broj n, a na
mjestu <suma> se treba nalaziti konkretno izracunata suma.)
Zadatak riješite koristeci while petlju.

RJEŠENJE:

#include <stdio.h>
int main()
{
// Definisanje varijabli
float i=1,n,suma=0;
// Unos prirodnog broja
printf ("\n Unesi broj n:");
scanf("%f", &n);
/* Racunanje sume
While petlja vrti podprogam u okviru while petlje sve dok je brojac „i“ koji
je na pocetku 1, manji od unesenog broja n. Ako je uneseni broj 1 ne ulazi se
u petlju i na izlazu se ispisuje Suma je:1. Ako je broj veci od 1 onda se
racuna suma prema matematickoj formuli. Grupisali smo formulu datu u zadatku
tako da trazimo sume po dva broja (odnosno razlike), i zatim te razlike
brojeva sabiramo, ali moramo paziti jer moramo brojac „i“ uvecati za 2 jer smo
u formuli ukljucili odmah 2 broja.
Ovaj nacin ima i dobru i losu stranu. Dobra strana je jer nemoramo uvoditi
nikakvu pomocnu varijablu i citav kod za racunanje sume se sastoji od dva
izraza, a losa strana je kad unesemo neparne brojeve sto necemo dobiti tacnu
sumu i tako kad unesemo broj 3 program ce izracunati 1-1/2+1/3=0.5 sto nije
tacno, a to smo dobili jer program nemoze grupisati clanove po 2 jer ih imamo
tri i zadnji ostaje sam i ne racuna se. Ali ovaj mali nedostatak mozemo
zanemariti jer se u ovakvim zadacima obicno unose veliki brojevi da se sve
svodi na preciznost nalazenja broja 0.69 pa nam je svejedno da li je zadnji
clan uracunat ili ne, ali eto ako zelimo ipak 100% precizno uraditi, zadatak
moze se uraditi i bez grupisanja sa mijenjanjem predznaka sume, ali to uradite
sami :) */
while ((i<n)&&(n>1)) {
suma=suma+(1/i-1/(i+1));
i=i+2;
}
// Ispis sume
if (n>1) printf ("\n Suma je: %f", suma); else if (n=1) printf ("Suma je: 1");
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

8. Napraviti program koji sa standardnog ulaza ucitava cijeli


broj m koji predstavlja redni broj mjeseca u godini, te ucitava i
broj g koji predstavlja godinu, a na monitoru ispisuje naziv tog
mjeseca i broj dana u tom mjesecu. Pretpostaviti da je prestupna
svaka cetvrta godina, iako je pravilo o racunanju prestupnih
godina nešto slozenije. Na primjer, ako su ulazne vrijednosti
m=2, g=2000 program treba ispisati:

februar, 2000. g., broj dana:29

Ili ako su ulazne vrijednosti m=5, g=2005 program treba ispisati:


maj, 2005. g., broj dana: 31

RJEŠENJE:

#include <stdio.h>
main() {
/* Deklarisanje varijabli
Definisanje dvodimenzionalne matrice 12 sa 9 (12 mjeseci, a broj 9 je ustvari
broj slova od kojih se sastoje mjeseci, najvise ima semptembar (9 slova). */
int m,g,d,i;
char mj[12][9]={{"Januar"},{"Februar"},{"Mart"},{"April"},
{"Maj"},{"Juni"},{"Juli"},{"August"},{"Septembar"},
{"Oktobar"},{"Novembar"},{"Decembar"}};
// U programu se uvodi i naredba „goto“ koja „skace“ sa linije na liniju
// programa.
pocetak:
// Unos mjeseca i godine
printf ("\n Unesi mjesec i godinu (m,g):"); scanf ("%d,%d", &m,&g);
// Ako se unese 1,3,5,7,8,10 ili 12 mjesec onda ima d=31 dan
if ((m==1)||(m==3)||(m==5)||(m==7)||(m==8)||(m==10)||(m==12)) d=31; else
// Ako se ipak unese 4,6,9 ili 11 mjesec onda ima d=30 dana
if ((m==4)||(m==6)||(m==9)||(m==11)) d=30; else
/* Ili ako se ipak unese mjesec 2 onda se provjerava jos i prijestupna godina
(svaka godina djeljiva sa 4), i u zavisnosti da li je prijestupna ili ne d=29
odnosno d=29 dana. Ako broj nije od 1 do 12 vraca se na pocetak programa*/
if ((m==2)) if ((g%4==0)) d=29; else d=28; else goto pocetak;
// Ispis mjeseca koji se nalazi zapisan u mj[] (m-1 jer nam je januar pod
brojem 0)
printf("%s , %d. g., broj dana: %d", mj[m-1], g, d);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

9. Napisati program koji ucitava realnu matricu dimenzija 10x10


te pronalazi najmanji element na glavnoj dijagonali.

RJEŠENJE:

#include <stdio.h>
main (){
// Deklarisanje varijabli
float A[10][10], MIN;
int i,j;
/* Unos matrice (koristimo 2 for petlje pri unosu (i su redovi a j su kolone).
Brojevi se unose po redovima.
*/
printf("\n Unesi matricu A[10][10]: \n");
for (i=0;i<10;i++)
for (j=0;j<10;j++)
{
printf(" [%d,%d]:", i+1, j+1);
scanf("%f", &A[i][j]);
}
/* Trazenje najmanjeg elementa na dijagonali!
Postupak je sljedeci. Elementi na dijagonali su tipa [i,j] gdje su i,j
jednaki. Tako dijagonalni elementi matrice 3x3 su [1,1], [2,2], [3,3]. Posto
nam trebaju samo elementi kada su (i,j) jednaki koristimo jednu for petlju. Na
pocetku stavimo da je najmanji element prvi element na poziciji [1,1], u C-u
je pozicija (0,0) ustvari pozicija (1,1) u realnom svijetu. I ulazimo u for
petlju. Ispituju se redom brojevi kod kojih su brojaci „i“ i „j“ jednaki. Ako
je neki od brojeva koji se ispitaju manji od MIN onda se taj broj pridruzi
varijabli MIN. */
MIN=A[0][0];
for (i=1,j=1;i<10;i++,j++) if (A[i][j]<MIN) MIN=A[i][j];
// Ispis najmanjeg broja na dijagonali
printf("\nNajmanji element na glavnoj dijagonali je: %.f", MIN);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

10. Napišite funkciju faktor () koja izracunava n! pri cemu je


prototip funkcije faktor (): double faktor (int n)
Zatim, napisati glavni program koji ucitava neki prirodni broj
n,1<n<10; a zatim izracunava n! pozivom funkcije faktor() i
rezultat ispisuje na standardni izlaz.

RJEŠENJE:

#include <stdio.h>
main (){
// Deklarisanje varijabli
int N;
double F;
// Deklarisanje prototipa funkcije
double faktor (int n);
//Unos prirodnog broja
printf("\nUnesi prirodan broj N: ");
scanf("%d", &N);
/* Pozivanje funkcije faktor() i pridruzivanje vrijednosti koju funkcija
izracuna varijabli F */
F=faktor(N);
// Ispis faktorijele
printf("Faktorijela od %d je: %g", N, F);
// Kraj programa
getch();
return 0;
}

/* Funkcija koja racuna vrijednost faktorijele. Funkcija prima prirodan broj N


a vraca realan broj (double) kao rezultat. */
double faktor (int n) {
int i;
double fak=1;
/* Racunanje faktorijele se vrsi tako da se broj od kojeg trazimo faktorijelu
pomnozi sa svakim cijelim brojem manjim od sebe a koji je veci od 1. Na
pocetku je fak=1 jer ako bi bilo 0 dobili bi uzastopno mnozenje sa 0 i nebi
dobili ispravan rezultat */
for (i=n;i>1;i--) fak=fak*i;
// Vracanje izracunate faktorijele
return fak;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

11. Napisati program koji ucitava broj elemenata (n) nekog


cjelobrojnog polja (Polje) a zatim i elemente tog polja
(maksimalno 100). Program nakon toga pronalazi maksimalni element
unesenog polja i ispisuje ga na standardni izlaz.
Na primjer, ako su ulazni podaci: n=4, Polje=(2,5,20,4) program
ce ispisati vrijednost broja 20.

RJEŠENJE:

# include <stdio.h>
main (){
// Definisanje varijabli
int n, i, niz[100], max;
// Unos broja elemenata
printf("\nUnesi broj elemenata: ");
scanf("%d", &n);
// Unos niza od N elemenata (pomocu for petlje)
for (i=0;i<n;i++)
{
printf ("\nUnesi elemenat broj %d: ", i+1);
scanf("%d", &niz[i]);
}
// Postavljanje vrijednosti max na vrijednost prvog clana niza
max=niz[0];
/* For petlja vrti brojeve od 2 broja (prvi je ukljucen u liniju iznad) i
provjerava se da li je i-ti broj veci od max i ako jeste varijabli max se
pridruzuje vrijednost tog elementa*/
for (i=1;i<n;i++)
if (max<niz[i]) max=niz[i];
// Ispis najveceg elementa niza
printf("Najveci element niza je: %d", max);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

12. Napisati program koji ucitava 5 realnih elemenata dva polja


A i B a zatim izracunava elemente treceg polja C (koji takodjer
ima 5 elemenata) pri cemu se i-ti element polja C dobiva prema
slijedecoj formuli:
C[i]=2*A[i]+B[i], i=1,2,…n
Na kraju program na standardni izlaz ispisuje elemente sva tri
polja: A, B i C.

RJEŠENJE:

# include <stdio.h>
main (){
// Definisanje varijabli
float A[5], B[5], C[5];
int i;
/* Unos elemenata prvog polja (pomocu for petlje, i+1 zbog realnosti, da nam
ne ispisuje se na ekranu "Unesi element 0") */
for (i=0;i<5;i++){
printf("\nUnesi %d element prvog polja: ",i+1);
scanf("%f", &A[i]);
}
// Unos elemenata drugog polja
for (i=0;i<5;i++){
printf("\nUnesi %d element drugog polja: ",i+1);
scanf("%f", &B[i]);
}
// Racunanje clanova matrice C po formuli C=2*A+B (pomocu jedne for petlje).
for (i=0;i<5;i++) C[i]=2*A[i]+B[i];
// Ispis elemenata polja A
printf("\nElementi prvog polja A: ");
for (i=0;i<5;i++) printf("%.f ", A[i]);
// Ispis elemenata polja B
printf("\nElementi drugog polja B: ");
for (i=0;i<5;i++) printf("%.f ", B[i]);
// Ispis elemenata polja C
printf("\nElementi treceg polja C: ");
for (i=0;i<5;i++) printf("%.f ", C[i]);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

13. Napisati program koji ucitava broj elemenata nekog polja


(maksimalno 100) a zatim i elemente tog polja. Program zatim
pronalazi najmanji element i na standardni izlaz ispisuje sve
elemente koji su manji od dvostruke vrijednosti pronadjenog
najmanjeg elementa.

RJEŠENJE:

# include <stdio.h>
main (){
// Definisanje varijabli
int n, i, niz[100], min;
// Unos broja elemenata
printf("\nUnesi broj elemenata: ");
scanf("%d", &n);
// Unos niza od N elemenata (pomocu for petlje)
for (i=0;i<n;i++){
printf ("\nUnesi elemenat broj %d: ", i+1);
scanf("%d", &niz[i]);
}
// Postavljanje vrijednosti min na vrijednost prvog clana niza
min=niz[0];
/* For petlja vrti brojeve od drugog broja (prvi je ukljucen u liniju iznad) i
provjerava se da li je i-ti broj manji od min i ako jeste varijabli min se
pridruzuje vrijednost tog elementa. */
for (i=1;i<n;i++)
if (min>niz[i]) min=niz[i];
/* For petlja vrti sve brojeve i za svaki broj se vrsi provjera da li je manji
od dvostruke vrijednosti nadjenog najmanjeg broja, i ako je taj broj zaista
manji od 2*min ispisuje se na ekran, a ako nije ide se na iduci broj. */
for (i=0;i<n;i++)
if (niz[i]<min*2) printf("\n %d", niz[i]);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

14. Napisati funkciju koja kao argument prima cijeli broj a


vraca broj koji se dobije tako da se iz argumenta izbace cifre
2,3,8 i 9.
Prototip funkcije je: int izbaci2389(int x)
Nakon toga, napišite glavni program koji ucitava neki cjeli broj,
poziva funkciju izbaci2389 i ispisuje rezultat na standardnom
izlazu.

RJEŠENJE:

# include <stdio.h>
main (){
// Definisanje prototipa funkcije
int izbaci2389(int x);
// Definisanje varijabli
int N, X;
// unos prirodnog broja
printf("\nUnesi prirodan broj: ");
scanf("%d", &N);
// Poziv funkcije i pridruzivanje rezultata varijabli X
X=izbaci2389(N);
// Ispis prepravljenog broja
printf("\nPrepravljeni broj: %d", X);
// Kraj programa
getch();
return 0;
}

// Funkcija za izbacivanje cifri 2,3,8,9 iz prirodnog broja


int izbaci2389(int x)
{
int t=1, y=0, ost;
/* While petlja se izvrsava dok je x>0. Uzima se ostatak dijeljenja broja sa
10 (npr. od broja 129, ostatak je 9), zatim se varijabli x odbije zadnja cifra
dijeljenjem sa 10 (do odbijanja dolazi jer radimo sa int brojevima pa nema
decimalnog zareza (npr 129/10=12). Zatim provjerimo dali je dobijeni ostatak
ost jednak 2,3,8 ili 9 i ako jest vracamo se na pocetak petlje i vrsimo isti
postupak za broj koji smo dobili odbijanjem zadnje cifre (i sve tako dok ne
odbijemo sve cifre, tj. dok ne dobijemo broj 0). Ako varijabla ost ipak je
razlicita od 2,4,8,9 onda se varijabli y doda vrijednost ost pomnozena sa t. U
programu varijabla t nam ustvari broji koja je decimala u pitanju. Kad je t=1
radimo sa jedinicama, kad je t=10 radimo sa deseticama... Tako npr. broj 1234
mozemo rastaviti kao 4*1+3*10+2*100+1*1000 gdje su nam brojevi 1,10,100,1000
ustvari nase t. */
while (x>0){
ost=x%10;
x=x/10;
if ((ost==2)||(ost==3)||(ost==8)||(ost==9)) continue;
y=y+ost*t;
t=t*10;
}
return y;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

15. Napisati funkciju koja kao argument uzima potrošnju u KWh


za veliku i malu tarifu te na standardnom izlazu ispisuje racun
za utrošenu elektricnu energiju.
Pretpostaviti da je cijena za veliku tarifu po utrošenom KWh 0.10
KM, a cijena za malu tarifu po utrošenom KWh je 0.05 KWh.
Prototip funkcije je: void racun(float vt, float mt) gdje :
* vt oznacava potrošnju za veliku tarifu
* mt oznacava potrošnju za malu tarifu
Nakon toga, napišite glavni program koji ucitava potrošnju za
veliku tarifu i malu tarifu, te na standardnom izlazu ispisuje
racun za tu potrošnju.

RJEŠENJE:

# include <stdio.h>
main (){
// Definisanje prototipa funkcije
void racun(float vt, float mt);
// Definisanje varijabli
float vt, mt;
// Unos potrosnje po velikoj i maloj tarifi
printf("Unesi potrosnju za veliku tarifu: ");
scanf("%f", &vt);
printf("Unesi potrosnju za malu tarifu: ");
scanf("%f", &mt);
// Poziv void funkcije (funkcija ne vraca rezultat), sa argumentima vt i mt
racun(vt, mt);
// Kraj programa
getch();
return 0;
}
// Funkcija koja kreira racun za utrosak energije na osnovu argumenata vt i mt
void racun(float vt, float mt)
{
float cijena;
// Racunanje ukupne cijene na osnovu argumenata vt i mt i zadatih cijena
cijena=vt*0.10+mt*0.05;
// Ispis rezultata
printf("\n--------------RACUN ZA UTROSENU EL. ENERGIJU-------------------- ");
printf("\nPotrosnja VT: %f KWh", vt);
printf("\nPotrosnja MT: %f KWh", mt);
printf("\n**************************************************************** ");
printf("\nUkupno: %f KM", cijena);
printf("\n**************************************************************** ");
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

16. Napisati funkciju koja kao argument uzima tri cijela broja
a, p i c. Funkcija vraca cijeli broj koji se dobije tako da se u
broju a iza p-te cifre s desne strane umetne cifra c.
Ako je p veci od ukupnog broja cifri izlaz iz funkcije treba biti
jednak ulazu. Ako se broj c sastoji od više cifri onda se umece
samo zadnja cifra iz tog broja.
Prototip funkcije je: int umetni(int a, int p, int c)
Nakon toga, napišite program koji ucitava neki pozitivan cijeli
broj a, poziciju umetanja cifre p i broj koji definira cifru koja
se umece c, te poziva funkciju umetni() i ispisuje na standardnom
izlazu rezultirajuci broj.

RJEŠENJE:

# include <stdio.h>
main (){
// Definisanje prototipa funkcije
int umetni(int a, int p, int c);
// Definisanje varijabli
int a, p, c, rez;
// Unos brojeva a,p,c
printf("Unesi brojeve a, p, c: ");
scanf("%d,%d,%d", &a,&p,&c);
// Poziv funkcije umetni() i pridruzivanje rezultata varijabli rez
rez=umetni(a,p,c);
// Ispis rezultata
printf("Rezultat: %d", rez);
// Kraj programa
getch();
return 0;
}

// Funkcija koja umece broj c na p-tu poziciju u broju a s desna


int umetni(int a, int p, int c)
{
int t=1, ost, x=0,br=0;
// Broju c pridruzuje se samo njegova zadnja cifra
c=c%10;
/* Racuna se ostatak dijeljenja sa 10 (ost), broju a se "otkida" zadnja cifra.
Ukoliko su brojevi p i br (brojac) identicni na to mjesto treba ubaciti broj
c. t nam broji decimale (vidi 14. zadatak).
Varijabli x se dodaje ostatak ost pomnozen sa t.
X je trazeni broj koji funkcija vraca u glavni program. */
while (a>0){
ost=a%10;
a=a/10;
if (p==br) {x=x+c*t; t=t*10; p=1000;}
x=x+ost*t;
t=t*10;
br++;
}
return x;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

17. Napraviti program koji ce na monitoru ispisati prvih N


cijelih brojeva i njihove kvadrate u formatu:
1 na kvadrat je 1
2 na kvadrat je 4
3 na kvadrat je 9
..........................
Broj N se unosi sa tastature. Koristiti for petlju.

RJEŠENJE:

#include <stdio.h>

int main() {
// Definisanje varijabli
int n,i;

/* Unos broja n sa tastature */

printf("\nUnesi broj n: ");


scanf("%d", &n);

/* Ispis prvih n brojeva i njihovih kvadrata, krenuvsi od broja 1, i znaci


krece od 1 i ide sve do broja za jedan manji od unesenog */

for ( i = 1 ; i < n ; i++ )


printf("\n %d na kvadrat je %d \n", i, i*i);

// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

18. Napraviti program koji izracunava rješenja sistema


linearnih jednadzbi:

a x + a x = b
11 1 12 2 1
a x + a x = b
21 1 22 2 2
(nepoznate su x i x )
1 2

Koeficijenti a , a , b , a , a , b se unose sa tastature. Ako


11 12 1 21 22 2
sistem jednadzbi nema rješenje program ispisuje poruku «RJEŠENJE
ne postoji».

RJEŠENJE:
#include <stdio.h>
int main() {
// Definisanje varijabli
float a11,a21,a12,a22,x1,x2,b1,b2;
/* Unos podataka (U dijelu %fx1%fx2=%f izmedju %fx1 i %fx2 nema plusa, u
suprotnom bi morali pri unosu operacije - (minus) upisivati +-) */
printf("\n Unesite 1 linearnu jednacinu a11x1+a12x2=b1 (x1, x2 nepoznate): ");
scanf("%fx1%fx2=%f", &a11, &a12, &b1);
printf("\n Unesite 2 linearnu jednacinu a21x1+a22x2=b2 (x1, x2 nepoznate): ");
scanf("%fx1%fx2=%f", &a21, &a22, &b2);
/* Izracunavanje x2 metodom supstitucije */
x2=(b2 * a11 - a21 * b1) / (a22 * a11-a21 * a12);
/* Izracunavanje x1 metodom uvrstavanja x2 u prvu jednacinu */
x1=(b1 - a12 * x2) / a11;
/* Provjerava se da li je sistem odredjen */
/* Ukoliko je sistem odredjen ispisuju se rjesenja, u suprotnom se ispisuje
poruka: RJEŠENJE ne postoji */
if ((a11*a22)==(a12*a21)) printf("\nRJEŠENJE ne postoji!!!");
else printf("\nRezultat je: x1=%.2f i x2=%.2f", x1, x2);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

19. Napisati program koji ucitava 4 cijela broja, a kao izlaz


daje dva najveca broja. Na primjer, ako korisnik kao ulaz unese
slijedece cijele brojeve:
23 5 45 33
rezultat izvodjenja programa treba biti:
Najveci broj je 45.
Drugi broj po velicini je 33.

Napomena: Tekstualne poruke vašeg programa trebaju biti iste kao


gore navedene.

RJEŠENJE:

#include <stdio.h>

int main() {
// Definisanje varijabli
int i,j,p,niz[4];
/* Unos brojeva niza (4 broja), pomocu for petlje koja ide od 1 do 4. */
printf("\n Unesite 4 cijela broja!");
for(i=1;i<=4;i++){
printf("\n %d broj: ", i);
scanf("%d",&niz[i]);
}

/* Proces sortiranja
Koristena je metoda bubblesort (spomenuta u jednom od zadataka ranije), to je
metoda „preljevanja“, provjerava se da li je j-ti clan manji od j+1-vog i ako
jeste mijenjaju se mjesta.
Npr. Unesemo 1,2,3,4. Nakon prvog prolaska imamo 2,1,3,4. Nakon drugog
prolaska 2,3,1,4. Nakon treceg prolaska imamo 2,3,4,1. I onda prva for petlja
proces ponavlja jos jednom. Pa imamo 3,2,4,1 zatim i 3,4,2,1 pa onda ostaje
isto jer je 2 vec vece od 1. Ali niz nije sortiran! Prva for petlja jos jednom
pokrece postupak i imamo 4,3,2,1. Proci ce se onako bezveze jos 2 puta kroz
petlju „j“ i zatim se izlazi iz petlje, i ispisuju se rezultati*/

for(i=1;i<=3;i++)
for(j=1;j<=3;j++)
if (niz[j+1]>niz[j]) {
p=niz[j];
niz[j]=niz[j+1];
niz[j+1]=p;
}

/*Ispis rjesenja zadatka*/

printf("\n Najveci broj je %d", niz[1]);


printf("\n Drugi broj po velicini je %d", niz[2]);

// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

20. Napisati program koji ce sa tastature ucitati prirodan


broj, te ispitati da li je broj prost. Ako se unese broj koji
nije prirodan (n<=0), program ispisuje poruku „Broj nije
prirodan“ i završava. Ako je broj prost program ispisuje poruku „
Uneseni broj je prost“. Ako broj n nije prost program ispisuje
poruku „Uneseni broj je slozen“. Ako je unesen broj n=1 program
ispisuje poruku: „Broj 1 nije niti prost niti slozen“.

Napomena:Pod prostim brojem podrazumijevamo prirodan broj koji se


ne moze napisati kao umnozak dvaju prirodnih brojeva manjih od
tog broja. Broj 1 nije niti prost niti slozen.

RJEŠENJE:
#include <stdio.h>

main () {

// Definisanje varijabli
int i,br, ispit;
// Unos jednog prirodnog broja
printf ("\n Unesi prirodan broj: ");
scanf ("%d", &br);
// Provjera da li je broj prirodan, i ako nije ispisuje
// se poruka da broj nije prirodan
if (br<=0) printf("\n Broj nije prirodan"); else
// Provjera da li je uneseni broj, broj 1, i ako jeste,
// ispisuje se odgovarajuca poruka
if (br==1) printf("\n Broj 1 nije ni prost ni slozen"); else
/* Ako je unesen prirodan broj veci od 1, provjerava se da li je broj prost
ili slozen, varijabla "ispit" kao rezultat. Djelimo broj „br“ sa svakim brojem
manjim od polovine unesenog broja. Na pocetku je „ispit=0“ sto nam govori da
je broj neparan. Ulazi se u petlju i pocinje dijeljenje sa brojevima 2,3,4...
Ako se broj „br“ uspije podijeliti sa nekim od brojeva varijabla ispit ce
automatski poprimiti vrijednost 1. U zavisnosti da li je broj „br“ uspio se
podijeliti sa nekim brojem bez ostatka, zavisiti ce i cinjenica da li je broj
prost ili slozen. */
{
ispit=0; i=2;
while (i<br/2) {
if ((br % i == 0)) ispit=1;
i++;
}
// Ispis odgovarajuce poruke na izlazu (PROST ILI SLOZEN)
if (ispit) printf("\n Broj je slozen"); else printf("\n Broj je prost");}
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

21. Napraviti program koji izracunava n! (n faktorijela). Broj n


se unosi sa tastature i treba biti u rasponu [1,20]. Ako broj n
nije u datom rasponu, program ispisuje poruku „Uneseni broj nije
u datom rasponu“ i završava se program.
Napomena: n! je definirano kao n! = n⋅ (n-1) ⋅ (n-2) ⋅....3⋅2⋅1.

RJEŠENJE:

#include <stdio.h>

main () {

// Definisanje varijabli
int i;
float n,f;

// Unos prirodnog broja


printf("\n Unesi broj N u rasponu od [1,20]: ");
scanf("%f", &n);

/* Racunanje faktorijele, ukoliko je broj u rasponu [1,20]. Faktorijela se


racuna tako sto se uneseni broj pomnozi sa svakim brojem manjim od sebe, i sve
se to pridruzuje varijabli „f“. */
f=1;
if ((n>0) && (n<21)) {
for (i=0;i<n;i++) f=f*(n-i);

// Ispis rezultata
printf("\n Faktorijela od broja %.0f je: %0.f", n, f);

// Ispis poruke ukoliko broj n nije u odgovarajucem rasponu


} else printf ("\n Uneseni broj nije u datom rasponu!");

// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

22. Napisati program koji ce izracunati sumu kvadrata prvih n


prirodnih brojeva. Broj n se unosi sa tastature i treba biti u
intervalu [2,100]. Ako broj n nije u tom intervalu program
ispisuje poruku „Broj nije u zadanom intervalu“ i završava. Na
primjer, ako se unese n=3, program ce izracunati sumu:
suma=12+22+32=14.

RJEŠENJE:
#include <stdio.h>
main () {
// Definisanje varijabli
int i,broj,suma;
// Unosenje prirodnog broja sa tastature u rasponu od [2,100]
printf("\n ULAZ: Broj \"N\" u rasponu od [2,100]: ");
scanf("%d", &broj);

/* Ukoliko se unese broj u tacnom intervalu [1,100] racunanje sume kvadrata.


Imamo varijablu suma (na pocetku 0), koja se krece sabirati redom sa:
1*1 + 2*2 + 3*3 + 4*4 ... I sve do unesenog broja.*/
suma=0;
if ((broj>1) && (broj<101)) {
for (i=1;i<=broj;i++) suma=suma+(i*i);

// Ispis sume kvadrata prvih n brojeva


printf("\n Suma kvadrata prvih %d brojeva: %d", broj, suma);

// Ispis odgovarajuce poruke ukoliko broj n nije u odgovarajucem rasponu


} else printf ("\n Uneseni broj nije u datom rasponu!");

// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

23. Napraviti program koji ce na ekranu ispisivati broj PI


prema formuli PI=1-1/3+1/5-1/7...1/i, a vrijednost eps unosimo sa
tastature i mora biti u intervalu 0.1 do 0.0001. Suma se racuna
sve dok je 1/i vece od eps.

RJEŠENJE:

#include <stdio.h>

main () {

// Definisanje varijabli
float eps,pi,n;

// Unos broja koji oznacava preciznost


printf("\n Unesi broj eps u rasponu od [0.0001,0.1]: ");
scanf("\n %f", &eps);

/* Provjera da li je broj „eps“ iz odredjenog intervala, i ako jeste racunanje


broja „pi“. Radi lakseg sastavljanja formule (jer imamo – i + naizmjenicno)
grupisacemo clanove po 2. i onda sve svodimo na operaciju sabiranja razlika 2
broja. Na kraju se brojac uvecava za 4 jer smo odmah po dva clana u formuli
koristili */
n=1; pi=0;
if ((eps>0.0001) && (eps<0.1)) {
while (1/n>eps) {
pi=pi+(4/n-4/(n+2));
n=n+4;
}

// Ispis broja PI
printf ("PI je: %f", pi);

// Ispis poruke ukoliko broj eps nije u odgovarajucem rasponu


} else printf ("\n Broj nije u trazenom rasponu!");
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

24. Napisati C program koji ce ucitati dimenzije (RA x KA)


realne matrice A (maksimalno 10 x 10) , dimenzije (RB x KB)
realne matrice B (maksimalno 10 x 10), te ucitati elemente tih
matrica. Program zatim treba izracunati matricu C koja je
proizvod matrica A i B. Na kraju program treba ispisati sve tri
matrice: A, B i C.
* RA, RB oznacavaju broj redova matrica A i B, respektivno;
* KA, KB oznacavaju broj kolona matrica A i B, respektivno.
Prilikom unosa dimenzija matrica program treba provjeriti da li
su unesene dimenzije u dozvoljenim granicama, tj. da li je
RA<=10, RB<=10, KA<=10, KB<=10, te isto tako program treba
provjeriti da li se matrice mogu mnoziti, tj. da li je ispunjeno:
KA=RB

RJEŠENJE:
#include <stdio.h>
main(){
float A[10][10], B[10][10], C[10][10];
int RA, RB, KA, KB, i, j, k;
// Unos dimenzija prve i druge matrice
printf("\nUnos dim. matrica A[RA,KA], B[RB,KB], u obliku \"RA,KA,RB,KB\": ");
scanf("%d,%d,%d,%d", &RA, &KA, &RB, &KB);

// Ispit uslova: da li su dimenzije u intervalu od 1 do 10.


if ((RA<=10)&&(RA>0)&&(RB<=10)&&(RB>0)&&(KA<=10)&&(KA>0)&&(KB<=10)&&(KB>0)) {
// Ispit uslova: da li je broj kolona prve matrice i broj redova druge isti.
if (KA==RB){

/* Unos elemenata prve matrice A (pomocu 2 for petlje, objasnjeno u jednom od


prethodnih zadataka. */
printf("\nUnesi elemente matrice A[%d,%d]: \n", RA, KA);
for (i=0;i<RA;i++)
for (j=0;j<KA;j++){
printf("Unesi element [%d,%d]: ", i+1, j+1);
scanf("%f", &A[i][j]); }

// Unos elemenata druge matrice B


printf("\nUnesi elemente matrice B[%d,%d]: \n", RB, KB);
for (i=0;i<RB;i++)
for (j=0;j<KB;j++){
printf("Unesi element [%d,%d]: ", i+1, j+1);
scanf("%f", &B[i][j]); }

/* Racunanje matrice C po formuli C=A*B. Dvije for petlje identicne for


petljama pri unosu matrice ili ispisu, koje „setaju“ po redovima i kolonama
matrica A,B,C. Prema matematickom postupku proizvod matrica A i B je:
C[1][1]=A[0][0] * B[0][0] + A[0][1] * B[1][0] + ... + A[0][n] * B[n][0] sto je
primjenjeno na formulu koja se nalazi unutar for petlje sa argumentom „k“.
Argument „k“ se krece od 1 do broja kolona prve matrice, i predstavlja broj
sabiraka u formuli iznad. C[i][j] = 0; je uvedeno jer vrijednost C[i][j] nije
definisana, a moramo je koristiti u formuli unutar for petlje po „k“. */

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

for (i=0;i<RA;i++)
for (j=0;j<KB;j++) {
C[i][j]=0;
for (k=0;k<KA;k++) C[i][j]=C[i][j]+A[i][k]*B[k][j]; }
// Ispis matrice A
printf("\nMatrica A[%d,%d]: \n", RA, KA);
for (i=0;i<RA;i++){
printf("\n");
for (j=0;j<KA;j++) printf("%4.f ", A[i][j]); }
// Ispis matrice B
printf("\nMatrica B[%d,%d]: \n", RB, KB);
for (i=0;i<RB;i++){
printf("\n");
for (j=0;j<KB;j++) printf("%4.f ", B[i][j]); }
// Ispis matrice C
printf("\nMatrica C[%d,%d]: \n", RA, KB);
for (i=0;i<RA;i++){
printf("\n");
for (j=0;j<KB;j++) printf("%4.f ", C[i][j]); }
// Ispis poruka ukoliko podaci nisu regularni
} else printf("\n Matrice se nemogu pomnoziti!");
} else printf("\n Matrice nisu u odgovarajucem intervalu!");
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

25. Napisati C program koji sa standardnog ulaza ucitava


elemente realne matrice dimenzija 5 x 5, te izracunava sumu
elemenata svake kolone i sumu elemenata svakog reda.
Za unos i pohranjivanje matrice koristite dvodimenzionalno polje,
dok za pohranjivanje suma po redovima i kolonama trebate
koristiti jednodimenzionalno polje.
Program takodjer treba pronaci:
* u kojoj koloni je najmanja suma,
* u kojem redu je najveca suma,
te ispisati na standardni izlaz unesenu matricu, redne brojeve i
sume pronadjene kolone, odnosno, reda.

RJEŠENJE:

#include <stdio.h>
main(){

// Definisanje varijabli
float MATRIX[5][5], SUMA[5], sumaR, sumaK;
int i,j, Kolona, Red;

// Unos elemenata matrice


printf("\nUnesi elemente matrice MATRIX[5,5]: \n");
for (i=0;i<5;i++)
for (j=0;j<5;j++){
printf("[%d,%d]: ", i+1, j+1);
scanf("%f", &MATRIX[i][j]); }

/* Postavljanje vrijednosti elemenata niza SUMA na 0 (jer vrijednosti niza


SUMA[] nisu definisane. */
for (i=0;i<5;i++) SUMA[i]=0;

/* Racunanje suma po redovima. Sabiramo sve brojeve prvog reda, znaci „i“ se
ne mijenja, a „j“ se uvecava za 1 sve do 5. I kada se sabere tih 5 brojeva, to
je suma prvog reda i zapisuje se u SUMA[0], zatim se isto ponavlja za ostale
redove, tako sto se samo „i“ uvecava za 1 i prelazi time na iduci red. */
for (i=0;i<5;i++)
for (j=0;j<5;j++)
SUMA[i]=SUMA[i]+MATRIX[i][j];

/* Nalazenje najvece od izracunatih suma. Postavlja se da je prva suma


najveca, i zatim se provjerava da li od preostalih ima neka koja je veca, i
ako je veca, onda se ta suma postavlja da je najveca. Vrijednost „i+1“ nam
predstavlja broj reda u kojem je ta suma (na pocetku stavili smo da je „i=1“
jer ispred stoji da je „sumaR=SUMA[0]“. */
sumaR=SUMA[0]; Red=1;
for (i=1;i<5;i++) if (sumaR<SUMA[i]) {sumaR=SUMA[i]; Red=i+1;}

// Postavljanje vrijednosti elemenata niza SUMA na 0


for (i=0;i<5;i++) SUMA[i]=0;

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

/* Racunanje suma po kolonama... ista procedura, samo smo zamijenili mjesta


brojaca „i, j“ unutar „MATRIX[i][j]“. */
for (i=0;i<5;i++)
for (j=0;j<5;j++)
SUMA[i]=SUMA[i]+MATRIX[j][i];

// Pronalazenje najmanje od izracunatih suma


sumaK=SUMA[0]; Kolona=1;
for (i=1;i<5;i++) if (sumaK>SUMA[i]) {sumaK=SUMA[i]; Kolona=i+1;}

// Ispis matrice MATRIX


printf("\nMatrica MATRIX[5,5]: \n");
for (i=0;i<5;i++){
printf("\n");
for (j=0;j<5;j++) printf("%.f ", MATRIX[i][j]); }

// Ispis rjesenja
printf("\nU %d koloni je najmanja suma koja iznosi %.f", Kolona, sumaK);
printf("\nU %d redu je najveca suma koja iznosi %.f", Red, sumaR);

// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

26. Program ucitava jednu rijec a i znak c koji se treba


prebrojati u toj rijeci. Nakon toga program poziva funkcije
duzina() i izbroji () i samogl(), te ispisuje duzinu unesene
rijeci a i broj pojavljivanja znaka c u toj rijeci, kao i broj
samoglasnika u rijeci.

RJEŠENJE:

#include <stdio.h>
// Funkcije „duzina“, „izbroji“ i „samogl“
// Funkcija duzina prima pokazivac na prvo slovo nekog stringa, a zatim u
while petlji provjerava se koliko znakova ima rijec, kada se dodje do nultog
znaka, izlazi se iz petlje, rezultet je varijabla „d“ koja se vraca iz
funkcije.
int duzina(char *string)
{
int d=0;
while (*string++!='\0') d++;
return d;
}

/* Slicno prvoj funkciji, samo funkcija pored pokazivaca na prvi znak stringa
prima i znak koji se broji. I umjesto da broji se broj clanova, umjesto d++
ide uslov (ako je slovo na koje pokazuje pokazivac nase slovo), „b“ se uveca
za 1. Kada „dodje“ while petlja do nultog znaka, izlazi se iz petlje a
varijabla „b“ se vraca kao rezultat.
NAPOMENA: U gornjoj funkciji stoji u uslovu *string++ sto prebaca pokazivac na
iduci clan nakon sto while petlja napravi jedan „krug“, dok u drugoj funkciji
stoji u uslovu samo *string ali je poslije if petlje uvecan pokazivac za „1“,
sto nam daje opet isti efekat. */
int izbroji(char *string, char c)
{
int b=0;
while (*string!='\0')
{
if (*string==c) b++;
string++;
}
return b;
}

/* Identicno funkciji izbroji() samo umjesto provjere „*string==c“ ide uslov


da li je „*string“ neki od samoglasnika, a ne znak koji unosimo. Funkcija
prima samo pokazivac bez znaka. */
int samogl (char *string)
{
int b=0;
while(*string!='\0')
{
if (*string=='a'||*string=='A'||*string=='E'||*string=='e'||*string=='I'||
*string=='i'||*string=='O'||*string=='o'||*string=='U'||*string=='u') b++;
string++;
}
return b;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

int main()
{
// Definisanje varijabli
char a[80],c;
// Unos rijeci bez razmaka i jednog slova koje ce se prebrojavati
printf("\nUnesite jednu rijec do 20 znakova (bez razmaka):");
scanf("%s",a);
printf("\nKoji znak treba prebrojati:");
scanf("\n%c",&c);
// Ispis rjesenja
printf("\nUnesena rijec sadrzi %d znakova!",duzina(a));
printf("\nBroj znakova %c je: %d",c,izbroji(a,c));
printf("\nBroj samoglasnika je: %d", samogl(a));
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

27. Napisati program koji u realno polje temp ucitava 10


realnih vrijednosti koje predstavljaju temperature u 10
razlicitih dnevnih termina. Program zatim poziva funkcije
maxtemp() i prtemp() koje izracunavaju maksimalnu dnevnu
temperaturu i prosjecnu dnevnu temperaturu i ispisuje na
standardnom izlazu te vrijednosti.

RJEŠENJE:
#include <stdio.h>
main ()
{
// Definisanje varijabli
float temp[10], *p;
int i;
// Definisanje prototipa funkcija
float maxtemp(float *p);
float prtemp(float *p);
// Unos 10 temperatura u niz temp[];
for (i=0;i<10;i++)
{
printf("\nUnesi temperaturu br.%d: ",i+1);
scanf("%f", &temp[i]);
}
// Postavljanje pokazivaca p na prvi clan niza temp[];
p=temp;
// Isipis rezultata uz poziv funkcija
printf("\nMaksimalna temperatura je: %.1f", maxtemp(p));
printf("\nProsjecna temperatura je: %.1f", prtemp(p));
// Kraj programa
getch();
return 0;
}
/* Funkcija maxtemp() prima pokazivac na realan niz i pomocu for petlje (vidi
11. zadatak) pronalazi se najveci broj (temperatura i vraca se iz funkcije */
float maxtemp(float *p)
{
float max=*p;
int i;
for (i=0;i<10;i++) { if (max<*p) max=*p; p++; }
return max;
}
/* Funkcija prtemp() prima pokazivac na realan niz i pomocu for petlje se
saberu svi clanovi niza i na kraju (poslije for petlje) se podijeli sve sa 10
(broj temperatura), tj. vraca se vrijednost (pr/10) kao rezultat */

float prtemp(float *p)


{
float pr=0;
int i;
for (i=0;i<10;i++) { pr=pr+*p; p++; }
return (pr/10);
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

28. Modificirati prethodni program (27) tako da program ucitava


cijeli broj n a zatim se sa tastature unosi n vrijednosti za
temperature u polje temp. Pretpostaviti da je n<=10. U skladu s
tim potrebno je modificirati funkcije maxtemp() i prtemp() tako
da imaju slijedece prototipove:

float maxtemp(int n, float *p);


float prtemp(int n, float *p);

RJEŠENJE:

# include <stdio.h>
main ()
{
// Definisanje varijabli
float temp[10], *p;
int i, n;
// Definisanje prototipa funkcija
float maxtemp(int n, float *p);
float prtemp(int n, float *p);
// Unos broja n
printf("\nUnesi broj temperatura: ");
scanf("%d", &n);
// Unos n temperatura u niz temp[];
for (i=0;i<n;i++)
{
printf("\nUnesi temperaturu br.%d: ",i+1);
scanf("%f", &temp[i]);
}
// Postavljanje pokazivaca p na prvi clan niza temp[];
p=temp;
// Isipis rezultata uz poziv funkcija
printf("\nMaksimalna temperatura je: %.1f", maxtemp(n, p));
printf("\nProsjecna temperatura je: %.1f", prtemp(n, p));
// Kraj programa
getch();
return 0; }

/* Funkcija prima pokazivac na realan niz, i broj n i pomocu for petlje (vidi
11. zadatak) pronalazi se najveci broj (temperatura i vraca se iz funkcije */
float maxtemp(int n, float *p) {
float max=*p;
int i;
for (i=0;i<n;i++) { if (max<*p) max=*p; p++; }
return max; }
/* Funkcija prima pokazivac na realan niz i broj „n“ i pomocu for petlje se
saberu svi clanovi niza i na kraju (poslije for petlje) se podijeli sve sa
brojem „n“ (broj temperatura), tj. vraca se vrijednost (pr/n) kao rezultat */
float prtemp(int n, float *p){
float pr=0;
int i;
for (i=0;i<n;i++) { pr=pr+*p; p++; }
return (pr/n); }

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

29. Napisati funkciju s imenom adresa() koja kao argument uzima


dva stringa koji predstavljaju ime i prezime a kao rezultat vraca
se novi string koji se dobije tako da se string koji predstavlja
prezime promijeni u string koji predstavlja e-mail adresu
slijedeceg oblika: [prezime].[ime]@etf.unsa.ba
Prototip funkcije je: char *adresa(char *ime, char *prezime)
Na primjer, ako su argumenti ime=“Marko“, prezime=“Markovic“
funkcija adresa() vraca pokazivac na rezultirajuci string prezime
koji je promijenjen u novi string oblika:
Markovic.Marko@etf.unsa.ba.

Nakon toga, napisati glavni program koji ucitava ime i prezime


neke osobe i na standardnom izlazu ispisuje toj osobi pridruzenu
e-mail adresu koja se dobije pozivom funkcije adresa().

RJEŠENJE:
#include <stdio.h>
// Funkcija adresa()
char *adresa(char *ime, char *prezime)
{
// Definisanje varijabli potrebnih za rad u funkciji
char *p, POMOC[]="@etf.unsa.ba", *POM;
/* Pointer „p“ pokazuje na pocetak prezimena, a „POM“ pokazuje na pomocni niz
“POMOC“ u kojem se nalazi string „@etf.unsa.ba.“ */
p=prezime; POM=POMOC;

// Generisanje email adrese


// Ova while petlja pokazivac postavi iza zadnjeg znaka, tj. Na nulti znak.
while (*p!='\0') p++;
// Umjesto nultog znaka upise se „.“ i predje se na iduci znak
*p='.'; p++;
// Poslije tacke se ubacaju karakteri iz niza na koji pokazuje pokazivac „ime“
while (*ime!='\0') { *p=*ime; ime++; p++; }
// Poslije imena se doda string na koji pokazuje pokazivac „POM“
while (*POM!='\0') { *p=*POM; POM++; p++; }
// Vracanje pokazivaca iz funkcije
return p;
}

// Glavni program
int main(){
// Definisanje varijabli
char *ime, *prezime, *c;
char U1[100], U2[100];
// Unos podataka ime i prezime
printf("\nUnesi ime:");
scanf("%s", &U1);
printf("\nUnesi prezime:");
scanf("%s", &U2);
// Postavljanje pokazivaca „c“ na pocetak prezimena
c=U2;
// Postavljanje pokazivaca ime i prezime na stringove U1 i U2

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

ime=U1;
prezime=U2;
// Poziv funkcije „adresa()“ i slanje pokazivaca „ime“ i „prezime“ u funkciju
prezime=adresa(ime, prezime);
// Ispis Email adrese
printf("\nGenerirana korisnikova Email adresa: %s", c);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

30. Napisati funkciju koja kao argument uzima znakovno polje


jmbg (jedinstveni maticni broj gradjanina) a kao izlaz vraca
strukturnu varijablu koja predstavlja datum rodjenja doticne
osobe. Prototip funkcije je: struct datum fdatum(char *jmbg) gdje
struct datum predstavlja strukturu definiranu kao:

struct datum
{
int dan;
int mjesec;
int godina;
};

Na primjer, ako je strukturna varijala drodj definirana kao:


struct datum drodj; te ako je ulaz u funkciju
jmbg=“2405978234567“ poziv funkcije drodj=fdatum(jmbg); treba
vratiti strukturnu varijablu koja predstavlja datum 24.05.1978.,
tj. funkcija vraca slijedece podatke strukturne varijable tipa
datum:

drodj.dan=24;
drodj.mjesec=5;
drodj.godina=1978;

Nakon toga napišite glavni program koji sa standardnog ulaza


ucitava jmbg kao znakovno polje a nakon poziva funkcije fdatum()
ispisuje datum rodjeja osobe sa doticnim jedinstvenim maticnim
brojem.

RJEŠENJE:
# include <stdio.h>

// Definisanje strukture datum


struct datum {
int dan;
int mjesec;
int godina;
};

/* Funkcija koja vraca datum kreiran od znakovnog polja u koje je upisan


maticni broj */

struct datum fdatum(char *jmbg){

// Definisanje varijable drodj kao strukturne varijable od datum


struct datum drodj;

// Definisanje pokazivaca koji pokazuje na strukturnu varijablu


struct datum *pd;
int i;

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

// Racunanje varijabli strukturne varijable


// Pretpostavka je da je korisnik ciji maticni broj unesete rodjen 1xxx godine
drodj.dan=0; drodj.mjesec=0; drodj.godina=1000;
// Racunanje jedinice dana
for (i=0;i<10;i++) if (*jmbg==49+i) drodj.dan=10*(1+i);
// Racunanje desetice dana i sabiranje sa jedinicom
for (i=0;i<10;i++) if (*(jmbg+1)==49+i) drodj.dan+=(1+i);
// Racunanje jedinice mjeseca
for (i=0;i<10;i++) if (*(jmbg+2)==49+i) drodj.mjesec=10*(1+i);
// Racunanje desetice mjeseca i sabiranje sa jedinicom
for (i=0;i<10;i++) if (*(jmbg+3)==49+i) drodj.mjesec+=(1+i);
// Racunanje stotice godine i sabiranje sa 1000
for (i=0;i<10;i++) if (*(jmbg+4)==49+i) drodj.godina+=100*(1+i);
// Racunanje desetice godine i sabiranje sa stoticom
for (i=0;i<10;i++) if (*(jmbg+5)==49+i) drodj.godina+=10*(1+i);
// Racunanje jedinice godine i sabiranje sa deseticom
for (i=0;i<10;i++) if (*(jmbg+6)==49+i) drodj.godina+=(1+i);
// Postavljanje pokazivaca na prvi znak strukturne varijable „drodj“
pd=&drodj;
// Funkcija vraca objekat koji se nalazi na adresi na koju pokazuje „pd“
return *pd;
}

// Glavni dio programa


main () {
struct datum drodj;
char jmbg[40], *p;

// Pretpostavka je da je uneseni maticni broj odgovarajuci


printf("Unesi maticni broj: ");
scanf("%s", &jmbg);

// Poziv funkcije fdatum i pridruzivanje rezultata strukturnoj varijabli drodj


drodj=fdatum(jmbg);

// Ispis rjesenja
printf("\nDatum rodjenja: %d.%d.%d", drodj.dan, drodj.mjesec, drodj.godina);

// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

31. Napisati program koji broji rijeci koje imaju n znakova u


tekstualnoj datoteci cije ime se unosi sa tastature. Na primjer,
ako u direktoriju(folderu) T11 na disku C: postoji datoteka
pismo.txt sa slijedecim sadrzajem:
Lijep pozdrav!
Sretnu i uspjesnu Novu godinu zeli Vam kompanija BHKOM.
Isto tako se nadamo da ce se dosadasnja uspjesna saradnja
nastaviti i u novoj 2006. godini.
Direktor: IVIC IVICA
program treba nakon unosa imena sa tastature i broja n:
Unesite broj znakova: 5
Unesite ime datoteke: C:\T11\pismo.txt
dati slijedeci izlaz:
Datoteka pismo.txt sadrzi 4 rijeci sa 5 znakova.
Napomene:
Rijeci sa pet znakova za gore navedenu datoteku su:
{Lijep, BHKOM, novoj, IVICA}.
Prilikom brojanja znakova ne uzimaju se u obzir znakovi
interpunkcije: tacka (.), zarez (,), usklicnik (!) i sl.
Prilikom rješavanja zadatka obavezno napravite testnu datoteku
pismo.txt i pohranite je u direktorij T11, te tu datoteku
koristite za testiranje vašeg rješenja.

RJEŠENJE:

# include <stdio.h>
main() {
// Definisanje varijabli
FILE *datoteka;
char dat[60], znak;
int znakovi, br=0, rez=0;
// Unos putanje do datoteke
printf("Unesi putanju do datoteke: ");
scanf("%s", &dat);
// Ispituje se da li datoteka postoji, ako postoji, ide se dalje u program u
// suprotnom se ispisuje error poruka i izlazi iz programa
if ( (datoteka = fopen (dat, "r")) == NULL) {
printf("Greska kod otvaranja datoteke %s !\n", dat);
getch();
exit(1); }
// Unos broja znakova
printf("Unesi broj znakova: ");
scanf("%d", &znakovi);

/* While petlja vrti se i uzima se znak po znak iz datoteke sve dok ne dodje
se do kraja datoteke i kada stignemo na kraj izlazi se iz programa. Ukoliko je
uneseni karakter razlicit od znakova ? ! . \n , \t i blanko znaka onda se
varijabla br uveca za jedan, u suprotnom se provjeri da li je broj br jednak
broju znakova koji smo unjeli, i ako jeste varijabla rez se uveca za jedan, i
onda se br postavi na 0. Kada stignemo do kraja datoteke izlazi se iz
petlje.*/

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

while((znak=fgetc(datoteka))!=EOF){
if ((znak=='?')||(znak=='!')||(znak==' ')
||(znak=='.')||(znak=='\n')||(znak==',')||(znak=='\t')) {
if (br==znakovi) rez++; br=0;} else br++;
}
/* Ukoliko zadnja rijec se sastoji od trazenog broja znakova, ona nece biti
uracunata jer smo izasli iz petlje, pa je potrebno dodati ovaj uslov iza
petlje da bi smo imali 100% tacan program*/
if (br==znakovi) rez++;
//Zatvaranje datoteke
fclose(datoteka);
// Izlaz iz programa
printf("Datoteka %s sadrzi %d rijeci sa %d znakova.", dat, rez, znakovi);
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

32. Napravite tekstualnu datoteku “ORPodaci.txt“ (pomocu


programa Notepad ili slicnog) slijedeceg formata:
[prezime ]· · · · · ·[ime] · · · · ·[brbod1] · · · · · ·[brbod2]
gdje :
- kolona [prezime] zauzima 15 mjesta;
- kolona [ime] zauzima 10 mjesta;
- kolona [brbod1] zauzima 4 mjesta i predstavlja broj bodova na
prvom parcijalnom ispitu
- kolona [brbod2] zauzima 4 mjesta i predstavlja broj bodova na
drugom parcijalnom ispitu
- U datoteku “ORPodaci.txt“ unesite podatke za 15 studenata.
- Spasite datoteku “ORPodaci.txt“ u direktorij C:\T12.
- VAZNO: Prilikom kreiranja datoteke “ORPodaci.txt“ budite
precizni u zauzimanju mjesta za pojedine kolone.

Zatim, napisati program koji ucitava sadrzaj tekstualne datoteke


“ORPodaci.txt” i na temelju te datoteke kreira novu datoteku pod
imenom “Polozili.txt” u kojoj se treba nalaziti sortiran (od
veceg prema manjem) spisak onih studenata koji su polozili oba
parcijalna ispita (to su oni studenti koji imaju na oba
parcijalna 10 ili više bodova).
Datoteka “Polozili.txt” je slijedeceg formata:
[prezime ]· · · · · · · ·[ime] · · · · · · ·[ukupno]
gdje :
- kolona [prezime] zauzima 15 mjesta;
- kolona [ime] zauzima 10 mjesta;
- kolona [ukupno] zauzima 4 mjesta i predstavlja ukupan broj
bodova sa oba parcijalna ispita.

RJEŠENJE:
#include <stdio.h>
#include <stdlib.h>

/* Definisanje strukture forma koja se sastoji iz varijabli prezime i ime tipa


char i prvi i drugi tipa integer */
struct forma {
char prezime[15];
char ime[10];
int prvi;
int drugi;
};

main(){

/* Definisanje varijabli:
Neo - pokazivac na fajl koji se cita
Trinity - pokazivac na fajl u koji se pise

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

podaci[15] - strukturni niz podaci u koji ce se upisati svi podaci koji se


ucitaju iz fajla, maksimalno 15...
Love - pomocna strukturna varijabla
i,j,k - potrebni projaci za sortiranje, i jos ponesta :) */
FILE *Neo, *Trinity;
struct forma podaci[15];
struct forma Love;
int i=0, j=0, k=0;

/* Otvaranje datoteke ORPodaci.txt i pridruzivanje pokazivacu Neo, ako ne


postoji datoteka izlazi se iz programa */
if ((Neo=fopen("C:\\T12\\ORPodaci.txt","r"))==NULL)
{
printf("Greska pri otvaranju datoteke");
exit(1);
}

/* Datoteka polozili.txt se kreira i pridruzuje pokazivacu Trinity */


Trinity = fopen ("c:\\T12\\Polozili.txt", "w");

/* Citanje podataka iz datoteke i upisivanje istih u strukturu podaci.


Varijabla i se vraca kao broj koji oznacava broj studenata koji su polozili
obe parcijale. podaci[i].prvi se automatski sabira sa podaci[i].drugi i ukupna
vrijednost postaje ustvari podaci[i].prvi!*/
while(fscanf(Neo,"%15s%10s%4d%4d",&podaci[i].prezime,&podaci[i].ime,&podaci[i]
.prvi,&podaci[i].drugi) != EOF )
{
if ((podaci[i].prvi>=10)&&(podaci[i].drugi>=10))
podaci[i].prvi+=podaci[i].drugi; else i--;
i++;
}

// Proces sortiranja... objasnjen u jednom od zadataka ranije...


for(j=0;j<i-1;j++)
for(k=j+1;k<i;k++)
if (podaci[k].prvi>podaci[j].prvi)
{
Love=podaci[j];
podaci[j]=podaci[k];
podaci[k]=Love;
}

// Upis podataka u datoteku na koju pokazuje pokazivac Trinity (Polozili.txt)


for (j=0; j<i; j++)
fprintf(Trinity,"%-15s%-10s%-4d\n",
podaci[j].prezime,podaci[j].ime,podaci[j].prvi);

// Zatvaranje datoteka...
fclose(Neo);
fclose(Trinity);

// Kraj programa...
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

33. Napisati funkciju okreni() koja kao argument uzima neki


string i okrece sadrzaj tog stringa naopako. Prototip funkcije
okreni() treba biti:
void okreni(char* p)
Zatim napravite glavni program koji sa standardnog ulaza ucitava
neki string, te ga ispisuje naopako.
Primjer:
Unesite string: Sarajevo
Naopako: ovejaraS

RJEŠENJE:
#include <stdio.h>
// Funkcija okreni
void okreni(char *p){
// Definisanje pomocnih varijabli
char pom;
int i=0, j=0, br=0;
// Brojanje slova rijeci, pointer „odlazi“ na kraj rijeci.
while (*p!='\0') {br++; p++;}
/* Pointer je „otisao“ na kraj rijeci, a nama treba u nastavku da je na
pocetku, pa cemo ga vratiti na pocetak tako sto ga pomaknemo za isti broj
mjesta nazad, za koji smo ga while petljom pomjerili naprijed! */
p=p-br;
// Glavni dio programa, ALGORITAM.
/* Recimo da smo unjeli rijec LOVE. Rijec koju trebamo dobiti kao rezultat je
EVOL. Znaci potrebno je zamjeniti zadnje slovo sa prvim, i drugo sa
predzadnjim. Brojac „i“ nam predstavlja znak do kojeg smo dosli sprijeda, a
brojac „j“ straga. Na pocetku ce biti i=0, j=3 (jer je br=3, nemojte se
zbuniti sto je 3 a ne 4, tu su ipak cetiri clana 0,1,2,3). Znaci nakon sto se
for petlja jednom izvrsi „i“ se uveca za 1 i postaje 1, a j se umanji za 1 i
postane 2. Znaci u prvom slucaju pomocu pomocne varijable „pom“ mijenjamo
znakove na 0 i 3 poziciji, drugi put ce se zamjeniti znakovi na 1 i 2
poziciji. I dobili smo trazenu rijec. Mozda zbunjuje uslov i<br/2; ali je
neophodan, broj permutacija je jednak polovini duzine rijeci, nacrtajte sebi
neki primjer i zakljucite to :). Ukoliko se uzme rijec sa neparnim brojem
slova onda se srednji clan ne pomjera nigdje, ostaje, sto je i logicno. Dok se
clanovi oko njega izmjenjaju simetricno. Funkcija nevraca nikakvu vrijednost,
ali promjene ostaju zapamcene zbog pristupa vrijednostima preko pointera! */
for (i=0,j=br-1;i<br/2;i++,j--){
pom=*(p+i);
*(p+i)=*(p+j);
*(p+j)=pom;
}
}
// Glavni program
main(){
// Definisanje varijabli i pointera
char NIZ[100];
char *t;
// Unos neke rijeci i zapisivanje iste u NIZ
printf("Unesi neku rijec: ");
scanf("%s", &NIZ);

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

// Postavljanje pokazivaca „t“ na „NIZ“


t=NIZ;
// Pozivanje funkcije i slanje pokazivaca „t“ u funkciju
okreni(t);
/* Ispis stringa NIZ preuredjenog funkcijom (printa se „t“, a „t“ nam pokazuje
na „NIZ“). */
printf("%s", t);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

34. Napisati funkciju ubaci5() koja kao argument uzima neki


prirodni broj n i dva broja a i b, a zatim vraca se broj koji bi
nastao zamjenom cifri na mjestu a i b cifrom 5 (gledano s desne
strane). Funkcija ne treba ništa ispisivati. Funkcija ubaci5()
treba imati prototip:
int ubaci5(int n,int a,int b);
Pretpostaviti da su a i b valjano unesene vrijednosti koje imaju
smisla. Primjeri ulaznih argumenata i vracenih vrijednosti:
Primjer1: za ulazne argumente n=123321, a=2, b=3 funkcija vraca
broj 123551.
Primjer 2: za ulazne argumente n=23455, a=3, b=5 funkcija vraca
broj 53555.

RJEŠENJE:

#include <stdio.h>
// Funkcija ubaci5();
int ubaci5(int n,int a,int b) {
// Definisanje varijabli
int c=0,t=1,o,i;
/* Brojac „i“ krece od 1(prvi znak straga) i ide dok broj „n“ koji smo primili
u funkciju ne postane 0. Svaki put kada for petlja se izvrsava ponovo, uzima
se ostatak dijeljenja sa 10, odnosno uzima se zadnja cifra broja „n“, i
pridruzuje varijabli „o“. Zatim se broj „n“ podijeli sa 10, cime mu se odbije
zadnja cifra. Suma „c“ se uvecava za „t*o“ gdje t se mijenja kao
1,10,100,1000. Kada i bude jednako „a“ ili „b“ onda se umjesto „t*o“ doda
„t*5“ i time se na „a-to/b-to“ mjesto doda broj 5 umjesto broja koji je bio na
toj poziciji. Naredba „continue;“ ce vratiti na pocetak for petlje kako se
nebi izvrsile i linije ispod, jer bi time dobili ubacivanje brojeva, a ne
zamjenu!!! Savjet: Probajte napisati recimo petocifren broj, i skontajte malo
na papiru prvo kako biste te zamjene uradili, skontajte ulogu varijabli „o“ i
„t“!!! */
for (i=1;n>0;i++){
o=n%10;
n=n/10;
if (i==a) {c=c+t*5; t=t*10; continue;}
if (i==b) {c=c+t*5; t=t*10; continue;}
c=c+t*o;
t=t*10;}
return c;}
main(){
// Definisanje varijabli a,b,n
int n, a, b;
// Unos brojeva a,b,n
printf("Unesi prirodan bron n:"); scanf("%d", &n);
printf("Unesi brojeve a,b:"); scanf("%d,%d", &a, &b);
/* Poziv funkcije, slanje n,a,b u funkciju, a rezultat se
pridruzuje varijabli n, koja se printa u iducoj liniji. */
n=ubaci5(n,a,b);
printf("%d", n);
// Kraj programa.
getch();
return 0; }

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

35. Napisati program koji ucitava podatke iz ulazne formatirane


tekstualne datoteke „gradovi.txt“ i kreira izlaznu datoteku
„prosjeci.txt“ koja sadrzi spisak gradova s prosjecnom
temperaturom za prva tri mjeseca. Datoteka „gradovi.txt“ je
sljedeceg formata:
[grad] [JAN] [FEB] [MAR]
gdje je:
[grad] kolona u kojoj su zapisani nazivi gradova i koja zauzima
15 mjesta;
[JAN], [FEB], [MAR] kolona u kojoj su zapisane cjelobrojne
prosjecne temperature za mjesec januar, februar i mart,
respektivno. Ove kolone zauzimaju po 10 mjesta.
Datoteka „prosjeci.txt“ je slijedeceg formata:
[grad] [PRTEMP]
gdje je:
[grad] kolona u kojoj su zapisani nazivi gradova i koja zauzima
15 mjesta;
[PRTEMP] kolona u kojoj su zapisane prosjecne temperature
koristeci dva decimalna mjesta i maksimalno dva mjesta prije
decimalne tacke.
Primjer sadrzaja datoteke „gradovi.txt“:
TRAVNIK 0 1 2
ZENICA 2 3 4
TUZLA 2 5 5
SARAJEVO 0 3 1
Primjer sadrzaja datoteke „prosjeci.txt“:
TRAVNIK 1.00
ZENICA 3.00
TUZLA 4.00
SARAJEVO 1.33

RJEŠENJE:

#include <stdio.h>
main(){
// Definisanje varijabli
FILE *Neo, *Trinity;
char grad[15];
float JAN, FEB, MAR, PRO;
/* Provjera da li postoji datoteka gradovi.txt i ako ne postoji ispis greske,
u suprotnom se nastavlja program */
if ((Neo=fopen("C:\\gradovi.txt","r"))==NULL)
{
printf("Greska pri otvaranju datoteke");
return 0;
}
// Otvaranje datoteke prosjeci.txt
Trinity=fopen("C:\\prosjeci.txt","w");
/* Citanje podataka iz datoteke gradovi.txt izracunavanje prosjecne
temperature PRO i printanje u datoteku prosjeci.txt */

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

while(fscanf(Neo,"%15s%10f%10f%10f", &grad, &JAN, &FEB, &MAR) != EOF ) {


PRO=(JAN+FEB+MAR)/3;
fprintf(Trinity,"%-15s%2.2f\n", grad, PRO);
}
// Kraj programa
close(Neo);
close(Trinity);
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

36. Napisati funkciju izbacip() koja kao argument uzima neki


prirodni broj n, a zatim vraca broj koji bi nastao izbacivanjem
parnih cifri iz tog broja. Funkcija ne treba ništa ispisivati.
Funkcija izbacip() treba imati prototip:
int izbacip(int n);
Na primjer, za argument 123420 funkcija treba vratiti broj 13.

RJEŠENJE:

// Funkcija izbacip() prima neki integer broj


int izbacip(int n){
/* Definisanje varijabli, „t“ je tezisnica koja se svaki put kada dodajemo
neku cifru pomnozi sa 10, „o“ je ostatak, „i“ je brojac, a „c“ je broj koji ce
funkcija vratiti kao rezultat */
int c=0,t=1,o,i;
/* „i“ se uvecava za 1 i for petlja se vrti sve dok broj „n“ bude jednak 0 */
for (i=1;n>0;i++){
/* Uzima se ostatak dijeljenja sa 10, odnosno zadnja cifra broja */
o=n%10;
// „Odbije“ se zadnja cifra broja „n“ dijeljenjem sa 10
n=n/10;
/* Ako je broj paran, vraca se na pocetak petlje i time se izbacaju parne
cifre */
if (o%2==0) continue;
// Dodavanje cifre na broj „c“
c=c+t*o;
// Mnozenje tezisnice sa 10
t=t*10;
}
// Vracanje varijable c
return c;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

37. Napisati funkciju ispis_preko_a() koja kao argment uzima


neko cjelobrojno polje i dva prirodna broja a i d, a zatim
ispisuje sve elemente polja koji su veci od broja a. Broj d
predstavlja broj elemenata polja. Funkcija treba imati slijedeci
prototip:
void ispis_preko_a(int *polje, int a, int d)
Na primjer, za ulazne argumente
int polje[]={4,5,7,20,8,10,2,-2}, a=6, d=8
trebaju se ispisati brojevi: 7, 20, 8, 10

RJEŠENJE:

// Funkcija prima pokazivac na polje, i dva cijela broja „a“,“d“


void ispis_preko_a(int *polje, int a, int d)
{
// Definisanje brojaca „i“
int i;
/* For petlja se „vrti“ sve dok brojac i koji krece od 0 ne bude veci od broja
„d“ koji je funkcija primila. */
for (i=0; i<d; i++){
/* Ako je broj „a“ koji je primljen u funkciju manji od broja u polju do kojeg
smo dosli on se ispisuje na ekran.*/
if (a<polje[i]) printf("%d, ", polje[i]);
}
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

38. Napisati funkciju zamijeni() koja ce u jednodimenzionalnom


polju A velicine d zamijeniti i-ti element sa minimalnim
elementom u polju A. Elementi polja A su vec definirani u glavnom
programu. Funkcija treba imati prototip:
void zamijeni(int *A, int i, int d)
Na primjer, ako su elementi polja A:
int A[]={3, 7, 10, 20, 18, 4,10, 2, 20], a argumenti i i d imaju
slijedece vrijednosti i=3, d=9 funkcija zamijeni() promjeni polje
A u polje sa slijedecim elementima: 3, 7, 2, 20, 18, 4, 10, 2, 20
(na trece mjesto se stavlja minimalni element iz polja a to je 2)

RJEŠENJE:

// U funkciju se prima niz brojeva „A“, broj „i“, broj „d“.


void zamijeni(int *A, int i, int d)
{
// Definisanje brojaca „j“ i varijable „min“
int j,min;
// Postavljanje vrijednosti „min“ na prvi clan niza
min=A[0];
/* Trazenje najmanjeg elementa u nizu. Pretpostavili smo da je to prvi broj, i
sada trebamo ispitati da li postoji neki broj krenuvsi od drugog (j=1 umjesto
j=0 u for petlji) i ako postoji neki manji postavi se da je taj broj „min“. */
for (j=1; j<d; j++) if (min>A[j]) min=A[j];
/* Postavljanje na i-tu poziciju vrijednosti „min“ (i=1 ide jer nam je i-ti
clan ustvari broj za jedan manje, jer nam je prvi clan nulti clan! */
A[i-1]=min;
// Ispis niza
for (j=0; j<d; j++) printf("%d ", A[j]);
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

39. Data je tekstualna datoteka c:\pismo.txt.


Napisati funkcije za:
a) ispis datoteke na standardni izlaz zadrzavajuci strukturu po
redovima;
b) prepis datoteke u novu mijenjajuci mala i velika slova;
c) ispisati datoteku u obrnutom redosljedu na izlaz (prva
postaje zadnja, druga postaje pretposljednja rijec...)
d) ispitati da li je neka rijeè palindrom (isto znacenje kada se
cita i u obrnutom smjeru)

RJEŠENJE:

# include <stdio.h>
// Ispis datoteke na standardni izlaz zadrzavajuci strukturu po redovima...
void ispis(FILE *datoteka){
char znak;
printf("\nSadrzaj datoteke je: \n\n");
while(fscanf(datoteka,"%c", &znak)!=EOF){
printf("%c", znak);
}
}

/* Ispitati da li je neka rijec palindrom (isto znacenje kada se cita i u


obrnutom smjeru) */
void palindrom(FILE *datoteka){
char znak[100];
char *p, *t;
int i, br=0, ispit=0;
printf("\n\nProvjera palindroma: \n");
while(fscanf(datoteka,"%s", &znak)!=EOF){
p=znak;
t=znak;
br=0;
while(*p!='\0') {p++; br++;} p--;
ispit=1;
for(i=0;i<(br/2);i++) if (*(p-i)!=*(t+i)) {ispit=0; break;}
if (ispit==1) {printf("\nPalindrom je: %s", znak); ispit=0;}
}
}

// Prepis datoteke u novu mijenjajuci mala i velika slova


void ispisunovu(FILE *datoteka){
FILE *datoteka1;
char znak;
datoteka1=fopen("c:\\pismo1.txt","w");
while(fscanf(datoteka,"%c", &znak)!=EOF){
if ((znak>64)&&(znak<91)) znak=znak+32; else
if ((znak>96)&&(znak<122)) znak=znak-32;
fprintf(datoteka1, "%c", znak);
}
fclose(datoteka1);
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

/* Ispisati datoteku u obrnutom redosljedu na izlaz (prva postaje zadnja,


druga postaje pretposljednja rijec...) */
void ispisobrnuto(FILE *datoteka){
char znak, matrix[1000][1000], pok[1000];
int i=0, j=0, br=0, k=0, niz[100];
printf("\n\nSadrzaj datoteke je (naopako): \n");
while(fscanf(datoteka,"%c", &znak)!=EOF){
if (znak==' ') {br++; j++; i=0; continue;}
if (znak=='\n') {br++; niz[k]=j; j++; k++; i=0; continue;}
matrix[j][i]=znak;
i++;
}
niz[k]=j;
j=0;
for (i=br;i>=0;i--) {
if((i==niz[k-j])&&(k-j!=-1)) { printf("\n"); j++;}
printf("%s ", matrix[i]);
}
}

main() {
// Definisanje pokazivaca na datoteku
FILE *datoteka;
// Otvaranje datoteke za citanje
datoteka=fopen("c:\\pismo.txt","r");
// Poziv funkcije za ispis datoteke na ekran...
ispis(datoteka);
fclose(datoteka);
// Otvaranje datoteke za citanje
datoteka=fopen("c:\\pismo.txt","r");
// Poziv funkcije za prepis datoteke u novu mijenjajuci mala i velika slova.
ispisunovu(datoteka);
fclose(datoteka);
// Otvaranje datoteke za citanje
datoteka=fopen("c:\\pismo.txt","r");
/* Poziv funkcije za ispis datoteke u obrnutom redosljedu na izlaz (prva
postaje zadnja, druga postaje pretposljednja rijec...) */
ispisobrnuto(datoteka);
fclose(datoteka);
// Otvaranje datoteke za citanje
datoteka=fopen("c:\\pismo.txt","r");
/* Poziv funkcije za ispitivanje da li je neka rijec palindrom (isto znacenje
kada se cita i u obrnutom smjeru) */
palindrom(datoteka);
fclose(datoteka);
// Kraj programa...
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

40. Napisati program koji cita više linija teksta sa ulaza i


štampa koliko rijeci je duzine 2 3 4 i više slova. Štampu
realizovati pomocu funkcije STAM_REZ u datoteku ili na ekranu. Iz
datoteke rezultata dati izvještaj o ukupnom broju rijeci i
prosjecnoj duzini rijeci.

RJEŠENJE:

#include <stdio.h>

// Funkcija koja kreira datoteku sa rezultatima


void STAM_REZ(char *tekst, int br){

// Definisanje pokazivaca na fajl


FILE *rezultati;

// Definisanje varijabli
int i,b=0,dva=0,tri=0,cetiri=0,vise=0, brojslova=0, prosjek=0;

// Otvaranje datoteke u koju cemo pisati podatke


rezultati=fopen("c:\\rezultati.txt","w");

// For petlja vrti se "br" puta...


for (i=0;i<br;i++){

/* Ukoliko znak do kojeg smo dosli nije „?“ „!“ „.“ „\n“ , „\t“ ili „blanko“
brojac „b“ se uvecava za 1, brojac „b“ nam pokazuje koliko slova je u rijeci
izbrojano. */
if ((tekst[i]=='?')||(tekst[i]=='!')||(tekst[i]==' ')
||(tekst[i]=='.')||(tekst[i]=='\n')||(tekst[i]==',')||(tekst[i]=='\t')) {

/* Nakon sto naidjemo na neki od ovih znakova u uslovu ulazimo u petlju... i


imamo... ako je b>1 broj slova ce se sabrati sa brojem slova rijeci koja se
trenutno obradjuje, ako je b=2 onda se varijabla dva koja broji rijeci sa 2
slova uveca za 1. Ako je tri onda se varijabla tri uveca za 1... ako je preko
4 onda se varijabla vise uveca za 1... primjetite da se brojac vraca na 0
izlaskom iz uslova, nebitno da li je bilo b=0 ili 1 ili 2 ili ... */
if (b>1) brojslova=brojslova+b;
if (b==2) {dva++; b=0;} else
if (b==3) {tri++; b=0;} else
if (b==4) {cetiri++; b=0;} else
if (b>4) {vise++; b=0;} else b=0;
} else b++;
}

// Upis podataka u datoteku...


fprintf(rezultati,"Rijeci sa 2 slova: %d\n", dva);
fprintf(rezultati,"Rijeci sa 3 slova: %d\n", tri);
fprintf(rezultati,"Rijeci sa 4 slova: %d\n", cetiri);
fprintf(rezultati,"Rijeci sa preko 4 slova: %d\n", vise);
prosjek=brojslova/(dva+tri+cetiri+vise);
fprintf(rezultati,"PROSJEK: %d\n", prosjek);

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

/* Zatvaranje datoteke i izlaz iz funkcije... „void“ funkcija ne vraca


nista!!! Izlaskom je sve sto se u njoj desavalo zaboravljeno, ali zato imamo
sve rezultate pohranjene u datoteci iz koje cemo po povratku u program citati
podatke.*/
fclose(rezultati);
}

// Glavni program
main(){

// Definisanje varijabli
int br=0, i=0, p=0, dva, tri, cetiri, vise, prosjek;
char tekst[1000];

// Definisanje pokazivaca na fajl


FILE *izvjestaj;

/* Unos teksta (koristio sam while petlju koja upisuje znak po znak, a ne %s
koja upisuje cijeli string odjednom, a zasto? pa jednostavno jos uvijek neznam
drugi nacin da izbjegnem situaciju kad upisete prvi razmak, a program to
shvati kao kraj stringa i racuna samo da je string prva rijec, a ostalo kao da
niste unjeli. Ovako se ucita sve sto unesete sa tastature, sto nam i treba. U
zadatku nije naznaceno sta ce biti prekid unosa, pa sam ja stavio tacku :) )*/
printf("Unesi tekst[i], (Tacka za kraj unosa!):");
while (tekst[i-1]!='.') { scanf("%c", &tekst[i]); i++; br++;}

/* Poziv funkcije u koju saljemo tekst koji smo unijeli kao i brojac „br“ koji
je prebrojao broj unesenih karaktera, mogli smo i bez njega, al eto ja nekako
vise volim for petlje od while petlji :) */
STAM_REZ(tekst, br);

// Otvaranje datoteke za citanje i pridruzivanje pokazivacu izvjestaj.


izvjestaj=fopen("c:\\rezultati.txt","r");

// Citanje podataka iz datoteke... formati isti kao pri upisu :)


fscanf(izvjestaj,"Rijeci sa 2 slova: %d\n", &dva);
fscanf(izvjestaj,"Rijeci sa 3 slova: %d\n", &tri);
fscanf(izvjestaj,"Rijeci sa 4 slova: %d\n", &cetiri);
fscanf(izvjestaj,"Rijeci sa preko 4 slova: %d\n", &vise);
fscanf(izvjestaj,"PROSJEK: %d", &prosjek);

// Ispis izvjestaja na ekranu.


printf("\n\nIZVJESTAJ: ");
printf("\n\nUkupno rijeci: %d", dva+tri+cetiri+vise);
printf("\nProsjecna duzina rijeci: %d", prosjek);

// Zatvaranje datoteke i kraj programa


fclose(izvjestaj);
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

41. Program treba unjeti 2 broja i ispisati NZD... najveci


zajednicki djeljilac...

RJEŠENJE:

#include <stdio.h>
main() {
// Definicija varijabli
int i,a,b,min,nzd=1;
// Unos dva prirodna broja
printf("Unesi dva broja: ");
scanf("%d,%d", &a, &b);
// Pridruzuje se varijabli min manji od unesena 2 broja
if (a<=b) min=a; else min=b;
// I se stavlja da je jednako min, i umanjuje se sve do 1... prvi broj
// sa kojem uspiju podijeliti se oba broja je i NZD... izlazi se iz petlje kad
// se oba broja uspiju bodijeliti...
for (i=min;i>0;i--){
if (((a%i)==0)&&((b%i)==0)) {nzd=i; break;}
}
// Ispis NZD-a
printf("\nNajveci zajednicki sadrzilac je: %d" , nzd);
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

42. Ispis sljedeceg znaka na ekranu...


+++++-+++++
++++---++++
+++-----+++
++-------++
+---------+
++-------++
+++-----+++
++++---++++
+++++-+++++
#include <stdio.h>
main() {
int k,i,j,a=11; // a predstavlja dimenzije znaka
for (k=0;k<a;k++) printf("+");
printf("-");
for (k=0;k<a;k++) printf("+");
printf("\n");
for (i=1;i<a;i++){
for (k=0;k<a-i;k++) printf("+");
for (k=a;k>a-i;k--) printf("-");
printf("-");
for (k=a;k>a-i;k--) printf("-");
for (k=0;k<a-i;k++) printf("+");
printf("\n");
}
for (i=2;i<a;i++){
for (k=a;k>a-i;k--) printf("+");
for (k=0;k<a-i;k++) printf("-");
printf("-");
for (k=0;k<a-i;k++) printf("-");
for (k=a;k>a-i;k--) printf("+");
printf("\n");
}
for (k=0;k<a;k++) printf("+");
printf("-");
for (k=0;k<a;k++) printf("+");
printf("\n");
// Svaki pokusaj pojasnjenja ovog zadatka je suvisan... ovo cete ili skontat
ili necete :) jednostavna igra sa for petljama... pokusajte uraditi preko
funkcija :)
// Kraj programa
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

43. Unesite broj clanova niza cijelih brojeva, a zatim i


clanove niza a zatim ih sortirajte od najveceg ka najmanjem i
ispisite sortirano na ekran.

RJEŠENJE:

# include <stdio.h>
main(){
// Definisanje varijabli
int n,i,j,niz[100],pom;
// Unos broja clanova niza
printf("\n Unesite broj clanova: "); scanf("%d", &n);
/* Unos niza */
for (i=0;i<n;i++){
printf("\n Unesi clan %d :", i+1);
scanf("%d", &niz[i]); }
/* Znaci imamo neki niz, recimo od 5 clanova: [1,3,4,2,5] i trebamo ga
sortirati od veceg ka manjem broju... na kraju treba izgledati [5,4,3,2,1].
Pri koristenju ove metode, koristimo dvije for petlje, od kojih je jedna (po
„i“ brojacu, tu samo onako radi reda) :) dok druga petlja obavlja vecinu
posla. Mozete primjetiti da u uslovu stoji „i<(n-1)“ kao i „j<(n-1)“. Ako
pogledamo jedan niz od 5 clanova i ako bi mijenjali brojeve tako da mijanjamo,
prvi i drugi clan, zatim drugi i treci, pa 3 i 4, pa 4 i 5. Znaci imamo 4
izmjene iako imamo 5 clanova, i zbog toga u uslovu ide „n-1“ umjesto „n“!
Znaci program radi tako da se vanjska for petlja izvrsi „n-1“ puta a
unutrasnja se izvrsi „(n-1)*(n-1)“ puta... u nasem slucaju od 5 clanova, znaci
16 puta. Mozda je ova metoda spora dosta jer se okrece 16 puta, sto bi se
moglo smanjiti, ali zbog jednostavnosti izgleda, prvo sam uzeo ovu metodu.
Dalje imamo uslov u unutrasnjoj petlji „niz[j]<niz[j+1]“ koji bi u prijevodu
znacio, ako je j-ti clan manji od iduceg (j+1) onda im mijenja mjesta...
Graficki desavanja pri sortiranju naseg niza izgledaju ovako (uspravno
citajte).
1 - 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5
3 - 1 4 4 4 3 3 3 3 3 5 5 5 4 4 4 4
4 - 4 1 2 2 2 2 5 5 5 3 3 3 3 3 3 3
2 - 2 2 1 5 5 5 2 2 2 2 2 2 2 2 2 2
5 - 5 5 5 1 1 1 1 1 1 1 1 1 1 1 1 1
I na kraju smo dobili soritran niz... znaci 16 puta se vrtila unutrasnja
petlja po 4 puta je kretala od prvog do cetvrtog clana i vrsila izmjene po
uslovu u if petlji, i na kraju rezultat mora biti sortiran niz! Da smo htjeli
obrnuto da sortiramo od najmanjeg ka najvecem samo bi se promjenio znak < u
uslovu u if petlji u znak > ... :) */
for (i=0;i<(n-1);i++)
for (j=0;j<(n-1);j++)
if (niz[j]<niz[j+1]) {
pom=niz[j+1];
niz[j+1]=niz[j];
niz[j]=pom;
}
// Ispis niza i kraj programa...
printf("\n Ispis niza: ");
for (i=0;i<n;i++) printf("[%d]", niz[i]);
getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

44. Zadatak br. 43. (prethodni) na drugi nacin...

RJEŠENJE:

# include <stdio.h>
main(){
// Definisanje varijabli
int n,i,j,niz[100],pom;
// Unos broja clanova niza
printf("\n Unesite broj clanova: "); scanf("%d", &n);
/* Unos niza */
for (i=0;i<n;i++){
printf("\n Unesi clan %d :", i+1);
scanf("%d", &niz[i]); }

/* U prethodnom primjeru sam uradio zadatak metodom bubblesort, a ovaj sam


uradio koristeci metodu NALAZENJA NAJVECEG U NIZU/PODNIZU i stavljanje na
"vrh". Znaci samo se ove for petlje razlikuju u odnosu na prethodni zadatak :)
Imamo vanjsku petlju koja je identicna onoj iz prethodnog zadatka, i ona vrti
unutrasnju petlju n-1 puta. Sad, ako pogledate prethodni primjer primjetiti
cete na grafickom prikazu da nekoliko puta su se vrtile for petlje ali je niz
ostajao isti. Ovom metodom cemo izbjeci to, i uciniti da program radi jos
brze. Znaci svakim novim prolaskom kroz vanjsku petlju se PODNIZ unutar
unutrasnje petlje umanji za 1, i time dobijamo na vremenu. Ovo je malo teze
objasniti :) pa pogledajte graficki prikaz:

1 - 3 4 4 5 5 5 5 5 5 5
3 - 1 1 1 1 3 3 4 4 4 4
4 - 4 3 3 3 1 1 1 2 3 3
2 - 2 2 2 2 2 2 2 1 1 2
5 - 5 5 5 4 4 4 3 3 2 1

Vidite kako smo dosli do rezultata uz samo 11 permutacija, naspram onih 16 iz


prvog primjera. Znaci u prvom dijelu ovog grafickog prikaza, nadjen je najveci
broj niza i stavljen na vrh (broj 5). U drugom dijelu (primjetite da smo
smanjili broj okretanja sa 4 na 3 jer nas vise broj na vrhu ne interesuje, i
samo od preostalog niza od 4 clana trazimo najveci i stavljamo na vrh... i
tako do kraja. */

for (i=0;i<(n-1);i++)
for (j=i+1;j<n;j++)
if (niz[j]>niz[i])
{
pom=niz[i];
niz[i]=niz[j];
niz[j]=pom;
}

// Ispis niza i kraj programa...


printf("\n Ispis niza: ");
for (i=0;i<n;i++) printf("[%d]", niz[i]);

getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


LoVe dOts... ForEver... Autor: Murtic Nirmel
ETF - 2005/2006 www.etf.ba

45. Unosi se sa ulaza broj clanova. Zatim se unese IME, PREZIME


i broj bodova svakog clana. Na izlazu treba ispisati clanove
sortirane po broju bodova.

RJEŠENJE:

# include <stdio.h>
// Definisanje strukture
struct struktura {
char ime[100];
char prezime[100];
int bodovi;
};

main(){
// Definisanje varijabli
int n,i,j;
struct struktura spisak[100];
struct struktura pom;
// Unos broja clanova niza
printf("\n Unesite broj imena: "); scanf("%d", &n);
/* Unos imena, prezimena, bodova i direktan upis u strukturu*/
for (i=0;i<n;i++){
printf("\n Unesi %d ime:", i+1);
scanf("%s", &spisak[i].ime);
printf(" i prezime:");
scanf("%s", &spisak[i].prezime);
printf(" i bodove:");
scanf("%d", &spisak[i].bodovi);
}
/* Proces sortiranja */
for(i=0;i<(n-1);i++)
for(j=0;j<(n-1);j++)
if (spisak[j].bodovi<spisak[j+1].bodovi)
{
pom=spisak[j];
spisak[j]=spisak[j+1];
spisak[j+1]=pom;
}
// Ispis niza i kraj programa...
for (i=0;i<n;i++) printf("\n%d. [%s %s]: %d", i+1, spisak[i].prezime,
spisak[i].ime, spisak[i].bodovi);

getch();
return 0;
}

Email: matrix.bih@gmail.com ; MSN: nirmel_m@hotmail.com


Programiranje i programsko inženjerstvo, FER
Upute za rad s razvojnom okolinom M S Visual Studio 2008 - Pisanje i pokretanje programa pisanih u programskom jeziku C

Upute za rad s razvojnom okolinom MS Visual Studio 2008


Pisanje i pokretanje programa pisanih u programskom jeziku C

1.Instalacija razvojne okoline:

Preuzeti instalaciju razvojne okoline MS Visual Studio .NET 2008 Professional sa stranica
http://msdnaa.fer.hr/ i instalirati ga na vlastito računalo. Dozvoljene su i verzije 2005 i 2010.

2.Pokretanje razvojne okoline:

Start → Programs → Microsoft Visual Studio 2008 → Microsoft Visual Studio 2008
Prilikom pokretanja sučelja obično se pojavi tzv. Start Page na koje se vidi lista nekoliko
zadnje kreiranih projekata, što se inače koristi za brzi pristup prethodno kreiranim projektima.

3. Stvaranje projekta (preduvjet za početak pisanja programa)

Iz izbornika File, odaberite opciju New Project (slika 1).

Slika 1.

Odabirom opcije New Project pojavit će se dijalog kao na slici 2. U ovom dijalogu
odaberite:
 tip projekta: Visual C++ → Win32 Console Application
 ime projekta: u polje Name umjesto <Enter name> upišite željeno ime

1
Programiranje i programsko inženjerstvo, FER
Upute za rad s razvojnom okolinom M S Visual Studio 2008 - Pisanje i pokretanje programa pisanih u programskom jeziku C

 lokaciju projekta: za polje Location odaberite kazalo u kojem će projekt biti


smješten pritiskom na gumb Browse. Kazalo ispod kojeg će vaš novi projekt biti
kreiran mora postojati.
 Ostale podatke nemojte mijenjati te pritisnite gumb OK.

Slika 2

Nakon toga pojavit će se dijalog kao na slici 3. Odaberite opciju Application


Settings.

Slika 3

2
Programiranje i programsko inženjerstvo, FER
Upute za rad s razvojnom okolinom M S Visual Studio 2008 - Pisanje i pokretanje programa pisanih u programskom jeziku C

Na dijalogu kao na slici 4 potrebno je uključiti opciju Empty project.


Nakon toga odaberite gumb Finish i novi projekt će biti kreiran.

Slika 4

U ovom je trenutku stvoren projekt koji još uvijek ne sadrži niti jednu datoteku s
programskim kodom.

4. Pisanje programa

Dodavanje programske datoteke u projekt:


 pozicionirati se u tzv. Solution Explorera (u slučaju da nije vidljiv odabrati opciju
izbornika View → Solution Explorer). Unutar Solution Explorera pod
nazivom projekta (u ovo primjeru smo projekt nazvali Vjezba1) nalaze se 3 stavke:
Source Files, Header Files i Resource Files.
 desnim klikom miša na Source Files pojavit će se dijalog kao na slici 5 čime nam
je omogućeno dodavanje nove datoteke u projekt. Potrebno je odabrati opciju Add →
New item.

3
Programiranje i programsko inženjerstvo, FER
Upute za rad s razvojnom okolinom M S Visual Studio 2008 - Pisanje i pokretanje programa pisanih u programskom jeziku C

Slika 5
 Nakon toga potrebno je odabrati da želite dodati C++ datoteku (slika 6) i dati joj ime
koje mora završavati s ekstenzijom .c (u ovom primjeru tu ćemo datoteku nazvati
vjezba.c). Pritisnite gumb Open i datoteka će se stvoriti i postati dijelom projekta.

Slika 6
 U novodobiveni prostor za pisanje programa koji je dobiven dodavanjem datoteke
vjezba.c potrebno je upisati program. Za vježbu upišite program sa slajda 21 prvog
predavanja (02-UvodProgramiranje).

4
Programiranje i programsko inženjerstvo, FER
Upute za rad s razvojnom okolinom M S Visual Studio 2008 - Pisanje i pokretanje programa pisanih u programskom jeziku C

Slika 7

5. Prevođenje programa

Potrebno je izvesti izgradnju izvršne datoteke odabirom opcije izbornika Build → Build
ImeVašegProjekta (na slici 7 to je opcija Build Vjezba1)

Slika 8
U slučaju da vaš program nema grešaka pojavit će se poruka kao na slici 8. U slučaju da se
Output prozor ne vidi, pokrenite opciju izbornika View → Output.

5
Programiranje i programsko inženjerstvo, FER
Upute za rad s razvojnom okolinom M S Visual Studio 2008 - Pisanje i pokretanje programa pisanih u programskom jeziku C

Ako je program imao grešaka na ovom prozoru će se pojaviti lista grešaka gdje se dvoklikom
miša na pojedinu od njih možete pozicionirati na redak u kojem se ta pogreška nalazi.

Slika 9

6. Pokretanje programa

Ako je program bio bez grešaka možete ga pokrenuti odabirom opcije Start Without
Debugging iz izbornika Debug (slika 9).

Slika 10

7. Rad na drugom programu

Želite li testirati neki drugi program, a da pri tome sačuvate već napisani program,
možete koristiti jednu od ovih metoda:
 zatvorite projekt korištenjem opcije File → Close Solution, te
cjelokupni opisani postupak ponoviti s nekim drugim imenom
 u već postojeće rješenje koje sadrži jedan projekt dodati još jedan tako da
u Solution Exploreru desnom tipkom miša kliknete na Solution
ImeRješenja (u ovom primjeru Solution 'Vjezba1') i odaberete
opciju Add → New Project. Postupak dodavanja novog projekta je
sličan već opisanom postupku.

Ako imate više otvorenih projekata, odabir koji projekt (program) želite pokrenuti obavlja se
tako da se na željeni projekt klikne desnom tipkom miša i odaberete Set as
StartUpProject (slika 10).

6
Programiranje i programsko inženjerstvo, FER
Upute za rad s razvojnom okolinom M S Visual Studio 2008 - Pisanje i pokretanje programa pisanih u programskom jeziku C

Slika 11

7
Programiranje i programsko inženjerstvo
 Sveučilište u Zagrebu - Fakultet elektrotehnike i računarstva -Zavod za primijenjeno računarstvo

Upute za instalaciju paketa MinGW i rad s prevodiocem GCC


Pisanje i izvršavanje programa pisanih u programskom jeziku C

1. Instalacija paketa MinGW

Preuzeti i instalirati MinGW Installer alat sa stranica


http://sourceforge.net/projects/mingw/files/latest/download?source=files

Pokrenuti MinGW Installer alat te putem njega instalirati osnovne komponente paketa MinGW. U
lijevom polju potrebno je odabrati Basic Setup i zatim u desnom polju označiti stavku mingw32-base.

Nakon toga u izborniku odaberite Installation -> Apply Changes te u novootvorenom prozoru kliknite
na gumb Apply.

Nakon provedene instalacije potrebno je podesiti sistemsku varijablu PATH dodavanjem putanje do
direktorija bin paketa MinGW. Ako ste MinGW instalirali s inicijalnim (default) postavkama,
direktorij bin paketa MinGW će biti C:\MinGW\bin.

Sistemska varijabla PATH može se podesiti u Control Panel-u:

1
Control Panel -> System and Security -> System
Potrebno je kliknuti na link koji se nalazi s lijeve strane -> Advanced system settings

U novootvorenom prozoru odabrati karticu (tab) Advanced te zatim kliknuti na gumb Environment
Variables… kako je prikazano na slici:

2
Nakon toga potrebno je u listi System variables odabrati varijablu Path i kliknuti na gumb Edit

U novootvorenom prozoru, u polje Variable value, na kraj postojećeg teksta dodati

;C:\MinGW\bin\

3
Obratite pažnju na znak ; na početku teksta koji se dodaje u varijablu Path.

Napomena:
Ako ste MinGW instalirali u drugom direktoriju (umjesto u C:\MinGW) tada u tekstu kojim se
dopunjava varijabla Path, zamijeniti C:\MinGW s putanjom do tog direktorija.
Navedeni tekst dodajte na kraj postojećeg sadržaja varijable Path, vodeći računa o tome da
postojeći sadržaj varijable ne obrišete!

Alternativni način instalacije

Studenti koji imaju problema sa instalacijom najnovije inačice MinGW kolekcije na svoje Windows
računalo mogu pokušati ovu alternativnu metodu:

1. Na računalu kreirati direktorij u koji će se smjestiti MinGW datoteke (npr. C:\MinGW\)


2. Iz repozitorija datoteka preuzeti arhivu MinGW.zip i raspakirati je u gore kreirani direktorij
3. Postaviti PATH sistemsku varijablu kao što piše u uputama (ako se MinGW nalazi u
"C:\MinGW\" onda je u PATH potrebno nadodati ;C:\MinGW\bin\ )

4
2. Pisanje i pokretanje programa

Nakon što ste instalirali paket MinGW, u direktoriju C:\PPI (ili neki drugi direktorij po vašem
izboru) stvorite znakovnu datoteku (npr. koristeći uređivač teksta Notepad) „ppi.c“. U znakovnu
datoteku upišite sljedeći kod:

#include<stdio.h>

int main(void){
printf("Programiranje i programsko inzenjerstvo");
return 0;
}

Program ćete prevesti pomoću prevodioca GCC na sljedeći način:

1. Pokrenite command prompt (npr. Start menu -> Run pa upišite „cmd“) i pozicionirajte se u
direktorij C:\PPI.
2. Pokrenite prevodilac GCC naredbom
cc -ansi -pedantic-errors -Wall -o ppi.exe ppi.c
Prvo se navodi naziv programa koji obavlja prevođenje – „cc“. Nakon toga navode se
parametri:
-ansi – parametar kojim osiguravamo prevođenje sukladno ANSI standardu
-pedantic-errors – parametar kojime zahtijevamo detaljno ispisivanje grešaka u
programu
-Wall – parametar kojime zahtijevamo detaljan ispis upozorenja
Zatim slijedi parametar „–o“ kojim se određuje kako će se zvati izvršna datoteka, u našem
slučaju to je „ppi.exe“. Na kraju je naveden naziv datoteke s izvornim kodom, „ppi.c“.

Nakon prevođenja programa ppi.c, pokrenite izvršnu datoteku „ppi.exe“. Na zaslonu će se ispisati
tekst „Programiranje i programsko inzenjerstvo“.

5
Napomena:

Ako vam prilikom pokretanja prevodioca GCC sustav javi sljedeću grešku

'cc' is not recognized as an internal or external command, operable program or batch file.

znači da sistemska varijabla Path nije ispravno podešena. Ako niste u mogućnosti podesiti varijablu
Path, možete napraviti sljedeće:s

1. Pozicionirajte se u direktorij bin unutar direktorija u kojeg ste instalirali MinGW. Ako ste
ostavili inicijalne postavke tada se to direktorij nalazi u C:\MinGW\bin
2. Sada možete pokrenuti GCC prevodilac, ali za naziv datoteke s izvornim kodom morate unijeti
cijelu putanju do te datoteke. Isto vrijedi i za naziv izvršne datoteke

Ako se datoteka s izvornim kodom nalazi u C:\PPI\ppi.c te ako u istom direktoriju (C:\PPI)
želimo stvoriti i datoteku s izvršnim kodom, GCC prevodilac treba pokrenuti :

cc -ansi -pedantic-errors -Wall -o C:\PPI\ppi.exe C:\PPI\ppi.c

Kao naziv datoteke s izvornim kodom naveden je C:\PPI\ppi.c, a kao naziv izlazne datoteke
navedena je datoteka C:\PPI\ppi.exe.
Program se pokreće navođenjem apsolutnog ili relativnog puta do datoteke s izvršnim kodom, u
našem primjeru:

C:\PPI\ppi.exe

6
Programiranje i programsko inženjerstvo
 Sveučilište u Zagrebu - Fakultet elektrotehnike i računarstva -Zavod za primijenjeno računarstvo

Korištenje znakovnog sučelja u operacijskom sustavu Windows


Windows operacijski sustav za komunikaciju s korisnikom, osim grafičkog korisničkog sučelja (GUI -
graphical user interface), omogućava korištenje znakovnog (tekstualnog) korisničkog sučelja (CLI -
command-line interface, command-line user interface, console user interface, CUI-character user
interface) u kojem se računalom upravlja upisivanjem naredbe u naredbenom retku (command line).
Kod takvog načina komunikacije, računalo prvo korisniku ispisuje obavijest (prompt) da je spremno
od njega prihvatiti naredbu, nakon čega korisnik koristeći tipkovnicu upisuje naredbu. Znakovno
korisničko sučelje vrlo je često u upotrebi u znanosti, inženjerstvu i industriji, a podržano je od svih
danas važnih operacijskih sustava, kao što su Unix, Linux, Windows, itd.
U sklopu kolegija Programiranje i programsko inženjerstvo, znakovno sučelje koristit će se prilikom
rada s datotekama u koje su pohranjeni izvorni i izvršni kodovi C programa, te radi prevođenja i
izvršavanja C programa.

1 Pokretanje znakovnog sučelja


Postoji više mogućnosti za pokretanje znakovnog sučelja (tj. otvaranja prozora s znakovnim
sučeljem). U nastavku je navedeno nekoliko mogućnosti:
a) Start  Svi programi (All Programs)  Pomagala (Accessories) Naredbeni redak
(Command Prompt)
b) Start  Svi programi (All Programs)  Pomagala (Accessories)  Pokreni (Run)
nakon čega se otvara prikazani
prozor u kojem je u okvir
potrebno upisati naredbu cmd te
pritisnuti gumb OK:

c) Start  u okvir za pretraživanje (Search) upisati cmd, nakon čega se otvara prozor
prikazan pod b)
d) istovremeni pritisak tipki Windows i R (Win+R), nakon čega se otvara prozor prikazan pod b)
Nakon toga otvara se prozor s znakovnim sučeljem:

1
2 Izvođenje programa i naredbi
Pokretanje naredbe ili programa obavlja se upisivanjem njegovog imena, argumenata (npr. naziv
datoteke) i opcija (parametri koji modificiraju djelovanje naredbe, a navode se iza znaka /), te
pritiskom na tipku Enter. Ne razlikuju se velika i mala slova u nazivima datoteka, naredbi i opcija.
Dakle, sasvim je svejedno je li upisano npr. HELP ili help.
Naredba se upisuje iza prompta, koji se pojavljuje kada je sučelje spremno od korisnika prihvatiti
naredbu. Prompt obično završava znakom >.
U nastavku su navedeni primjeri korištenja pojedinih naredbi u njihovom osnovnom obliku. Popis
uobičajenih naredbi moguće je dobiti upisivanjem naredbe help. Za prikaz dodatnih informacija o
pojedinoj naredbi, potrebno je upisati help naziv_naredbe.
Program koji se izvodi može biti prekinut istovremenim pritiskom na tipke Ctrl i C (Ctrl+C).
Izvođenje programa može biti privremeno zaustavljeno pritiskom na tipku Pause ili kombinacijom tipki
Ctrl+S. Nastavak izvođenja na ovaj način zaustavljenog programa obavlja se pritiskom na bilo koju
tipku, na primjer Enter.
Naredbom exit završava se rad s znakovnim sučeljem i zatvara pripadni prozor.
Primjer:
help help (dobivanje uputa o radu programa help)

help tree (dobivanje uputa o radu programa tree; uz kratki opis naredbe dan je i opis
dozvoljenih opcija: /F i /A, pa je moguće, na primjer, zadati naredbu: tree /f)

3 Rad s datotekama i direktorijima

3.1 Datotečni sustav operacijskog sustava Windows


Podaci pohranjeni u vanjskoj (postojanoj) memoriji (npr. disk, CD, memory stick, ...) logički su
organizirani u datoteke. Datoteka je imenovani skup podataka koji sačinjavaju logičku cjelinu.
Datoteke su logički grupirane u direktorije (mape, kazala), koji mogu sadržavati proizvoljan broj
datoteka i drugih direktorija (poddirektorija). Direktoriji su organizirani hijerarhijski, u strukturu nalik
na stablo. Direktorij je zapravo datoteka koja sadrži popis i podatke o karakteristikama drugih
datoteka.

2
Datotečni sustav računala je dio operacijskog sustava koji služi za organiziranje, upravljanje i pristup
datotekama. Upravljanje datotekama jedna je od osnovnih zadaća operacijskog sustava. Operacijski
sustav, između ostalog, vodi evidenciju o fizičkom smještaju datoteka na mediju za pohranu te nudi
sučelje za otvaranje postojećih, stvaranje novih datoteka, čitanje iz datoteke, pisanje u datoteku,
premještanje, preimenovanje te brisanje datoteka i direktorija.

Datoteka je određena (identificirana) imenom i apsolutnim putem (path) do direktorija u koji je


upisana. Ime datoteke/direktorija sastoji se od osnovnog dijela i nastavka, međusobno odvojenih
točkom. Nastavak nije obavezan dio imena datoteke/direktorija, ali se obično navodi uz ime datoteke
kako bi se njime sugerirao njezin tip i namjena. Na primjer, uobičajeno je datoteci koja sadrži samo
tekst dodijeliti nastavak txt, datoteci koja sadrži izvorni kod napisan u programskom jeziku C
dodijeliti nastavak c, a datoteci koja predstavlja izvršni program dodijeliti nastavak exe. Osim naziva,
datoteka ima i ostala svojstva kao što je npr. veličina, vrijeme nastanka i izmjene itd.
Datotečni sustav može uključivati više vanjskih jedinica za pohranu (najčešće tvrdih diskova). U
operacijskom sustavu Windows one mogu biti podijeljene u više logičkih jedinica (particija), obično
označenih slovima C:, D:, itd. U nastavku se pod pojmom disk misli na logičku jedinicu.

Svaki disk sadrži jedan izvorni ili osnovni direktorij (root) koji je označen znakom \. Kako broj izvornih
direktorija ovisi o broju diskova, da bi se znalo o kojem se izvornom direktoriju radi, ispred znaka \
navodi se i oznaka diska, npr. C:\, D:\, itd. U nekim operacijskim sustavima (npr. Unix), postoji samo
jedan izvorni direktorij te se ne navodi oznaka diska.
Na slici je, u grafičkom sučelju operacijskog sustava Windows (pomoću programa Windows Explorer),
prikazana stablasta struktura direktorija na disku C te, na desnoj strani, sadržaj (direktoriji i datoteke)
direktorija \cygwin\lib:

3
Prikaz stablaste strukture direktorija u
znakovnom sučelju omogućava naredba tree.
Ako je naredba zadana bez opcija, ispisuju se
samo nazivi direktorija. Navođenjem opcije /f,
biti će prikazane i datoteke (slika desno).
Operacijski sustav prati trenutnu poziciju
korisnika unutar datotečnog sustava za vrijeme
dok koristi znakovno korisničko sučelje. Ta se
trenutna pozicija naziva radni (working, current)
disk i radni direktorij. Informacija o radnom disku i
radnom direktoriju sastavni je dio prompta. Na
slici desno prompt predstavlja tekst
C:\cygwin\lib>, što znači da je radni disk C, a
radni direktorij je direktorij lib, koji je
poddirektorij direktorija cygwin smještenog u
izvornom direktoriju.

Datoteci/direktoriju moguće je pristupiti


navođenjem puta do te datoteke/direktorija, tj.
navođenjem naziva direktorija kroz koje je
potrebno proći da bi se došlo do te
datoteke/direktorija, odvojene znakom \. Put
može biti apsolutan ili relativan.

Apsolutni put započinje oznakom diska i izvornim


direktorijem, nakon čega se navode svi direktoriji
do direktorija u koji je smještena datoteka. Na
primjer, ako se datoteka popis.txt nalazi u
direktoriju \users\ana na disku C, apsolutni put
do nje je C:\users\ana\popis.txt.

Relativni put ovisi o radnom direktoriju. Prilikom navođenja relativnog puta do datoteke moguće je
koristiti i posebne oznake:
. označava radni direktorij
.. označava direktorij nadređen radnom direktoriju
Na primjer, ako je radni direktorij C:\users\hrvoje (apsolutni put do tog direktorija), oznaka .
predstavlja oznaku za direktorij C:\users\hrvoje, oznaka .. predstavlja oznaku za direktorij C:\users, a
..\.. je oznaka za izvorni direktorij C:\. Relativni put do datoteke čije je ime popis.txt, a nalazi se u
direktoriju C:\users\ana je ..\ana\zivotopis.txt.
Većina naredbi kao argument prihvaća naziv jedne ili više datoteka, odnosno direktorija. Ako se kod
navođenja naziva izostavi ime direktorija ili diska, podrazumijeva se da se radi o trenutno radnom
direktoriju i disku.
Kod nekih naredbi nije potrebno pisati puno ime datoteka ili direktorija, već je moguće koristiti i
posebne znakove (tzv. metaznakove, wildcard):
* zamjenjuje neodređeni niz, bilo koju kombinaciju znakova
? zamjenjuje samo jedan, bilo koji znak.
Na primjer, niz ?.txt određuje sve datoteke koje imaju ime duljine jednog znaka i nastavak txt.

4
Primjer:
tree \ (prikaz stablaste strukture direktorija radnog diska, počevši od izvornog direktorija,
bez prikaza datoteka)

3.2 Pregled sadržaja direktorija (dir)


Naredbom dir ispisuje se sadržaj direktorija. Imena koja u ispisu imaju oznaku <DIR> su direktoriji, a
ostalo su datoteke.
Primjer:
dir (pregled svih datoteka i direktorija u radnom direktoriju)

dir ppi (pregled direktorija ppi koji se nalazi u radnom direktoriju)


dir c:\tmp (pregled direktorija tmp na disku C:, navođenjem apsolutnog puta)
dir \tmp (pregled direktorija tmp na radnom disku, navođenjem apsolutnog puta)
dir c:\t*.* (pregled svih datoteka čiji naziv počinje slovom t i imaju neki nastavak)

3.3 Promjena radnog direktorija (cd)


Za promjenu radnog direktorija koristi se naredba cd. Izvođenjem naredbe cd, navedeni direktorij
proglašava se radnim direktorijem. Direktorij čije je ime navedeno uz naredbu mora postojati. Ako se
naziv direktorija iza naredbe cd izostavi, naredba ispisuje apsolutni put do radnog direktorija.
Dozvoljeno je koristiti apsolutni i relativni put do direktorija.
Naredbom cd nije moguće promijeniti radni disk. Promjena radnog diska obavlja se navođenjem
naziva diska i dvotočke.
Primjer:
cd \users (direktorij users na radnom disku postaje radni direktorij)
cd .. (direktorij nadređen radnom postaje radni direktorij)
cd ..\ana (radni direktorij postaje direktorij ana, koji se nalazi u direktoriju
nadređenom radnom)
cd users (direktorij users, koji se nalazi u radnom direktoriju, postaje radni direktorij)
cd (ispis apsolutnog puta do radnog direktorija)
D: (disk D postaje radni disk)

3.4 Kreiranje direktorija (mkdir)


Naredbom mkdir stvara se novi direktorij, čiji je naziv obavezno navesti. Stvaranjem direktorija on
ne postaje radnim. Da bi postao radni, potrebno je upotrijebiti naredbu cd.
Primjer:

5
mkdir c:\tmp (stvaranje direktorija tmp u izvornom direktoriju na disku C)
mkdir tmp (stvaranje direktorija tmp u radnom direktoriju)

3.5 Kopiranje datoteka (copy)


Naredbom copy obavlja se kopiranje datoteke (datoteka) u neku drugu datoteku unutar istog ili
nekog drugog direktorija. Naredba copy u jednostavnijem obliku ima dva argumenta: prvi argument
predstavlja ime datoteke čiji se sadržaj kopira (izvor), a drugi argument je ime kopije. U drugom
obliku, copy naredbi se može predati više datoteka kao izvor, a kao zadnji argument navodi se ime
jednog direktorija u koji se kopiraju sve navedene datoteke.
Primjer:
copy ppi.c ppi1.c (kopiranje datoteke ppi.c u datoteku ppi1.c u radnom direktoriju)
copy ppi.c \tmp (kopiranje datoteke ppi.c iz radnog direktorija u direktorij tmp na radnom
disku)
copy C:\*.* . (kopiranje svih datoteka izvornog direktorija u radni direktorij)

3.6 Promjena imena i premještanje datoteka i direktorija (move)


Naredbom move obavlja se promjena imena jedne datoteke ili direktorija, odnosno premještanje
direktorija ili datoteka u druge direktorije. Ako se kao izvor navedu nazivi više datoteka ili koriste
posebni znakovi, za ciljno ime treba navesti naziv direktorija (slično kao kod naredbe cp) u koji će biti
premještene izvorne datoteke.
Primjer:
move ana hrvoje (promjena naziva direktorija ana u hrvoje)
move ppi.c ppi.save (promjena naziva datoteke ppi.c u ppi.save)
move ppi* tmp (premještanje datoteka čije ime počinje s ppi.c u direktorij tmp)

3.7 Ispis sadržaja datoteke na zaslon (type)


Naredba type prikazuje na zaslonu sadržaj datoteke (obično datoteke s nastavkom txt). Pokušaj
ispisa sadržaja datoteke koja ne sadrži samo tekst (npr. datoteke s nastavkom exe), rezultira ispisom
nerazumljivog niza znakova.
Primjer:
type ppi.c (ispisivanje sadržaja datoteke ppi.c na zaslon)

3.8 Brisanje datoteke (del)


Naredbom del moguće je obrisati jednu ili više datoteka (dozvoljena je upotreba posebnih znakova *
i ?). Ako se kao argument naredbe navede ime direktorija, obrisat će se sve datoteke u tom
direktoriju.
Primjer:
del ppi.exe (brisanje datoteke ppi.exe)
del x.* (brisanje svih datoteka s imenom x i bilo kojim nastavkom u radnom
direktoriju)
del \tmp (brisanje svih datoteka u direktoriju tmp)
del . (brisanje svih datoteka u radnom direktoriju)

6
3.9 Brisanje direktorija (rmdir)
Naredbom rmdir briše se navedeni direktorij. Ako nisu navedene dodatne opcije, direktorij je
moguće obrisati samo ako je prazan, tj. ako u njemu nema niti jedne datoteke ili direktorija.
Korištenjem opcije /s moguće je obrisati i direktorij koja nije prazan.
Primjer:
rmdir C:\tmp (brisanje praznog direktorija tmp u izvornom direktoriju)
rmdir /s vjezba (brisanje direktorija vjezba koji se nalazi u radnom direktoriju,
direktorij će biti obrisan i ako nije prazan)

4 Preusmjeravanje (redirekcija)
Prilikom izvođenja naredbi u znakovnom sučelju podrazumijeva se da se ulazni podaci prihvaćaju s
tipkovnice, a izlazni ispisuju na zaslonu. Tipkovnica predstavlja standardni ulaz, a zaslon standardni
izlaz. Međutim, ponekad je potrebno izlazne podatke preusmjeriti u datoteku, ili pak ulazne podatke,
umjesto s tipkovnice, preuzeti iz datoteke. To se postiže korištenjem znakova za preusmjeravanje:
> preusmjerava izlaz u datoteku; ako datoteka već postoji, briše se njen dotadašnji sadržaj
< preuzima ulazne podatke iz datoteke
>> preusmjerava izlaz u datoteku; ako datoteka već postoji, podaci se dodaju na kraj datoteke

4.1 Preusmjeravanje izlaznih podataka u datoteku


Naredbom
dir C:\tmp > dir_tmp.txt
rezultat naredbe dir C:\tmp, koji bi se standardno pojavio na zaslonu, bit će zapisan u datoteku
dir_tmp.txt u radnom direktoriju. Ako datoteka nije postojala prije izvođenja naredbe, naredbom
će biti kreirana. Ako je datoteka postojala, njen stari sadržaj će se izgubiti.
Naredbom
dir . >> dir_tmp.txt
rezultat naredbe dir . bit će nadodan na kraj datoteke dir_tmp.txt.

4.2 Preusmjeravanje ulaznih podataka iz datoteke


Preusmjeravanje ulaznih podataka naročito je korisno prilikom testiranja programa koji zahtijeva
puno ulaznih podataka, jer je umjesto njihovog stalnog upisivanja pomoću tipkovnice moguće
koristiti podatke koji su unaprijed pripremljeni i pohranjeni u datoteku.
Naredbom
izracunaj.exe < podaci.txt
standardni ulaz usmjeren je iz datoteke podaci.txt, pa će program izracunaj.exe iz te
datoteke, umjesto s tipkovnice, učitati potrebne podatke. Ako program ispisuje rezultate, oni će biti
ispisani na zaslonu monitora.

4.3 Preusmjeravanje ulaznih i izlaznih podataka


Naredbom
izracunaj.exe < podaci.txt > rezultati.txt
postiže se da se ulaz u program izracunaj.exe preusmjeri iz datoteke podaci.txt, a izlaz se
preusmjeri u datoteku rezultati.txt.

7
5 Editori teksta
Editori teksta su programi namijenjeni pisanju teksta u kojem nema posebnih znakova za
formatiranje (tzv. kontrolnih kôdova). Za razliku od editora, programi za uređivanje teksta, osim slova
i uobičajenih znakova, ubacuju posebne znakove koji služe za formatiranje konačnog teksta
(određivanje rubova, određivanje tipa i veličine slova i sl.). Za pisanje programa koriste se isključivo
editori.
Na vježbama se koristi editor Notepad. Editor je moguće pokrenuti na dva načina:
 navođenjem samo naredbe notepad,
 navođenjem naredbe notepad iza koje slijedi ime datoteke koju je potrebno editirati (notepad
ime_datoteke).
Ako je editor pokrenut na prvi način, potrebno je naknadno navesti ime datoteke u koju se želi
spremiti upisani tekst. Međutim, kako je txt ponuđeni nastavak za naziv datoteke, često se dogodi
da datoteka dobije dodatni nastavak txt, a treba paziti i na direktorij u koji će biti smještena. Na
primjer, ako je datoteku potrebno nazvati ppi.c, moguće je da zapravo bude nazvana ppi.c.txt.
Zato je preporuka pokretati editor uz navođenje naziva datoteke (uz mogućnost navođenja
apsolutnog ili relativnog puta):
notepad ppi.c (editorom se otvara datoteka ppi.c koja je smještena u radnom
direktoriju)
notepad d:\vjezbe\p.c (editorom se otvara datoteka p.c koja je smještena u direktoriju
\vjezbe na disku D)

8
Zadaci za vježbu
1) Obaviti sljedeće:
1. Izvorni direktorij na disku C proglasiti radnim direktorijem (u nastavku vježbe radni disk i
direktorij promijeniti samo kada je to traženo u zadatku).
2. Na disku C u izvornom direktoriju kreirati direktorij vjezba.
3. Unutar direktorija vjezba, ne mijenjajući radni direktorij, kreirati direktorije osobno i ppi.
4. Uz korištenje relativnog puta proglasiti direktorij C:\vjezba\osobno radnim direktorijem,
te unutar njega kreirati direktorije txt i slike.
5. Uz korištenje apsolutnog puta proglasiti direktorij slike radnim direktorijem, a zatim u taj
direktorij kopirati nekoliko slika (možete ih prethodno potražiti korištenjem npr. programa
Windows Explorer). Prilikom kopiranja slika navesti apsolutni put do direktorija u kojem se
nalaze slike, a relativni put do direktorija u koji je potrebno kopirati slike.
6. Jednom naredbom proglasiti direktorij C:\vjezba\osobno\txt radnim direktorijem, uz
korištenje relativnog puta.
7. Provjeriti postoji li u radnom direktoriju datoteka nema.me.
8. Editorom Notepad u datoteku zivot.txt upisati neki tekst.
9. Kopirati datoteku zivot.txt u datoteke pom.txt i pom1.txt u radnom direktoriju.
10. Ispisati stablastu strukturu direktorija (bez datoteka) na disku C počevši od izvornog
direktorija. Privremeno zaustaviti te nakon toga nastaviti ispisivanje te strukture na zaslon.
11. Ispisati stablastu strukturu direktorija, uključujući datoteke, počevši od direktorija vjezba uz
korištenje relativnog puta. Usporediti dobivenu strukturu sa strukturom prikazanom u
grafičkom sučelju, koristeći program Windows Explorer.
12. Pozvati program help bez argumenata, a izlaz programa preusmjeriti u datoteku
help.txt.
13. Ispisati sadržaj radnog direktorija.
14. Prebaciti datoteku help.txt u nadređeni direktorij.
15. Ispisom sadržaja radnog, a zatim i nadređenog direktorija, provjeriti je li kopiranje uspješno
obavljeno.
16. Bez promjene radnog direktorija, na zaslon ispisati sadržaj datoteke help.txt.
17. U radnom direktoriju obrisati sve datoteke čije ime započinje slovom p.
18. Proglasiti izvorni direktorij radnim direktorijem navođenjem relativnog puta.
19. Obrisati direktorij C:\vjezba\osobno\txt (navesti apsolutni put do direktorija).
20. Obrisati sve datoteke u direktoriju C:\vjezba\osobno\slike (navesti relativni put do
direktorija).
21. Obrisati direktorij osobno.

2) Napisati program koji će pročitati dva cijela broja i ispisati veći broj. Izvorni kod pohraniti u
datoteci proba.c u direktoriju ppi kreiranom u 1. zadatku. Za editiranje koristiti editor Notepad
(naziv datoteke navesti prilikom pokretanja editora). Prevesti program pomoću prevodioca GCC,
a izvršnu datoteku nazvati proba.exe. Izvesti program tako da se:
1) brojevi čitaju s tipkovnice, a rezultat ispisuje na zaslon monitora
2) brojevi čitaju s tipkovnice, a rezultat ispisuje u datoteku izlaz.txt
3) brojevi čitaju iz datoteke ulaz.txt koja je prethodno pripremljena pomoću editora, a
rezultat ispisuje na kraj datoteke izlaz.txt, bez uništavanja njenog prethodnog sadržaja

9
Rješenja
1)
1. cd c:\
2. mkdir vjezba
3. mkdir vjezba\osobno
mkdir vjezba\ppi
4. cd vjezba\osobno
mkdir txt
mkdir slike
5. cd c:\vjezba\osobno\slike
npr: copy c:\users\hrvoje\slike\*2013*.jpg .
6. cd ..\txt
7. dir nema.me
8. notepad zivot.txt
9. copy zivot.txt pom.txt
copy zivot.txt pom1.txt
10. tree \
privremeno zaustavljanje izvođenja: Pause (ili Ctrl+S)
nastavak izvođenja: bilo koja tipka
11. tree /f ..\..
12. help > help.txt
13. dir
14. move help.txt ..
15. dir .
dir ..
16. type ..\help.txt
17. del p*
18. cd ..\..\..
19. rmdir /s C:\vjezba\osobno\txt
20. del C:\vjezba\osobno\slike
21. rmdir /s C:\vjezba\osobno

2) cd c:\vjezba\ppi
notepad proba.c
U znakovnu datoteku proba.c upisati sljedeći kod:
#include <stdio.h>
int main(void) {
int x,y;
printf("Upisite dva cijela broja: ");
scanf("%d %d", &x, &y);
if (x>y) {
printf("%d\n", x);
} else {
printf("%d\n", y);
}
return 0;
}

10
cc -ansi -pedantic-errors -Wall -o proba.exe proba.c
1) proba.exe
2) proba.exe > izlaz.txt
type izlaz.txt
3) notepad ulaz.txt
U znakovnu datoteku proba.c upisati dva cijela broja, npr:
10 5

proba.exe < ulaz.txt >> izlaz.txt


type izlaz.txt

11
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 25

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

1. vježbe uz predavanja

1. Napišite program koji na zaslon ispisuje poruku


Upisite jedan pozitivni cijeli broj:
i nakon toga preko tipkovnice učita jedan cijeli broj. Ako je broj ispravno upisan (tj.
učitan je pozitivan broj), na zaslon treba ispisati:
Zadnja znamenka broja xxxxx je x
inače, ako je učitan negativan broj ili nula, na zaslon ispisati
Broj xxxxx nije pozitivan broj

Uputa: kojim brojem n treba podijeliti broj m da bi se kao ostatak dijeljenja dobila zadnja
(krajnje desna) znamenka broja m? Postoji li u programskom jeziku C aritmetička
operacija kojom se izračunava ostatak cjelobrojnog djeljenja?

2. S tipkovnice učitati polumjer kruga (realni broj). Ako je učitani broj pozitivan, izračunati
opseg i površinu kruga, te na zaslon ispisati:
zadani polumjer je: xxxxxx.xxxx
opseg kruga je: xxxxxx.xxxx
povrsina kruga je: xxxxxx.xxxx
inače (ako učitani broj nije pozitivan) na zaslon treba ispisati:
broj xxxxxx.xxxx nije ispravan polumjer kruga

3. S tipkovnice učitati cijeli broj i zatim na zaslon ispisati poruku:


ucitan je broj xxxxx
Ako je učitan negativan broj, ispisati:
broj je negativan
Nakon toga (bez obzira je li učitani broj negativan) ispitati parnost učitanog broja i
ispisati odgovarajuću poruku:
broj je paran
ili
broj je neparan

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 25

Rješenja

1.
#include <stdio.h>
int main (void) {
int broj, zadnjaZnamenka;
printf("Upisite jedan pozitivan cijeli broj: ");
scanf("%d", &broj);

if (broj > 0) {
zadnjaZnamenka = broj % 10;

/* Druga mogucnost izracunavanja zadnje znamenke jest:


zadnjaZnamenka = broj - broj / 10 * 10;
U prethodnoj naredbi uocite cjelobrojno dijeljenje!
*/

printf("Zadnja znamenka broja %5d je %d\n", broj, zadnjaZnamenka);

} else {
printf("Broj %5d nije pozitivan broj\n", broj);
}

return 0;
}

2.
#include <stdio.h>
int main (void) {
float polumjer, opseg, povrsina;
scanf("%f", &polumjer);

if (polumjer > 0) {
opseg = 2 * polumjer * 3.14159;
povrsina = polumjer * polumjer * 3.14159;
printf("zadani polumjer je: %11.4f\n", polumjer);
printf("opseg kruga je: %11.4f\n", opseg);
printf("povrsina kruga je: %11.4f\n", povrsina);
} else {
printf("broj %11.4f nije ispravan polumjer kruga\n", polumjer);
}

return 0;
}

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 25

3.
#include <stdio.h>
int main (void) {
int broj, ostatak;
scanf("%d", &broj);
printf("ucitan je broj: %5d\n", broj);

if (broj < 0) {
printf("broj je negativan\n");
}

ostatak = broj % 2;
if (ostatak == 0) {
printf("broj je paran\n");
} else {
printf("broj je neparan\n");
}

return 0;
}

ili

#include <stdio.h>
int main (void) {
int broj;
scanf("%d", &broj);
printf("ucitan je broj: %5d\n", broj);

if (broj < 0) {
printf("broj je negativan\n");
}

if (broj % 2 == 0) {
printf("broj je paran\n");
} else {
printf("broj je neparan\n");
}

return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 47

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

2. vježbe uz predavanja

1. Pročitajte i zaključite što bi sljedeći program (kada bi bio ispravan) trebao raditi.

#include <stdio.h>;
int mein (void) {
integer xa; ya; xb; yb; xc; yc;
printf("Upisite koordinate vrha trokuta A >");
scan("%d %d", &xa, &ya);
printf("Upisite koordinate vrha trokuta B >");
scan("%d %d", &xb, &yb);
printf("Upisite koordinate vrha trokuta C >");
scan("%d %d", &xc, &yc);
xTezista = xa + xb + xc / 3;
yTezista = ya + yb + yc / 3;
printf("Teziste trokuta A(%d, %d), B(%d, %d), C(%d, %d) jest T(%d, %d)"
, xa, ya, xb, yb, xc, yc, xTezista, yTezista);
return 0
}
Zatim pomoću copy-paste upišite program u datoteku na svom računalu i pokušajte ga
prevesti. Prvo ispravite isključivo sintaktičke pogreške. Nakon toga ispravite pogreške
povezivanja. Kada se program uspješno prevede, testirajte program s različitim ulaznim
podacima:
- za vrhove trokuta s koordinatama (0, 0), (3, 3) i (6, 0)
- za vrhove trokuta s koordinatama (0, 0), (1, 1) i (2, 0)
- za vrhove trokuta s koordinatama (0, 0), (1.5, 1.5) i (3, 0)
Ispravite sve logičke pogreške.
Uputa: pri rješavanju ovog zadatka korisno je poslužiti se C prevodiocem, koji će otkriti
one sintaktičke pogreške i pogreške povezivanja koje sami možda ne uspijete uočiti.

2. Napisati C program kojim će se s tipkovnice učitati pozitivni cijeli broj koji ima 5
znamenaka. Nije potrebno provjeravati je li korisnik upisao ispravan broj. Program treba
na zaslon ispisati prvu i posljednju znamenku učitanog broja.

3. Napisati C program kojim će se s tipkovnice učitati pozitivni cijeli broj koji ima 5
znamenaka. Nije potrebno provjeravati je li korisnik upisao ispravan broj. Program treba
na zaslon ispisati drugu i četvrtu znamenku.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 47

Rješenja

1. Sintaktičke pogreške:
− točka-zarez se ne smije stavljati iza pretprocesorskih naredbi
− definicija varijabli xa, ya, xb, yb, itd. je neispravna. Varijable koje se odjednom
definiraju međusobno se odjeljuju zarezom, a ne točkom-zarezom. Tip integer ne
postoji.
− varijable xTezista i yTezista nisu definirane
− nedostaje točka-zarez iza naredbe return.

Pogreške povezivanja:
− u stdio.h ne postoji funkcija scan (postoji scanf)
− program mora sadržavati funkciju main (a ne mein)

Logičke pogreške:
− koordinate težišta se neispravno izračunavaju. X koordinate triju vrhova treba prvo
zbrojiti, a tek tada podijeliti s 3 (trenutno se na kvocijent z/3 dodaje vrijednost za x i y.
Isto vrijedi i za y koordinate.
− nakon dodavanja zagrada program će ispravno raditi za koordinate vrhova (0, 0), (3,
3) i (6, 0), ali ne i za koordinate (0, 0), (1, 1) i (2, 0). Razlog je u cjelobrojnom
dijeljenju i tipu rezultata: 0+1+0 cjelobrojno podijeljeno s 3 daje 0, a ne 0.33333.
Potrebno je promijeniti tip svih varijabli: koordinate vrhova trokuta i težišta trebaju biti
realni, a ne cijeli brojevi.

Program nakon ispravljanja svih pogrešaka:


#include <stdio.h>
int main (void) {
float xa, ya, xb, yb, xc, yc;
float xTezista, yTezista;
printf("Upisite koordinate vrha trokuta A >");
scanf("%f %f", &xa, &ya);
printf("Upisite koordinate vrha trokuta B >");
scanf("%f %f", &xb, &yb);
printf("Upisite koordinate vrha trokuta C >");
scanf("%f %f", &xc, &yc);
xTezista = (xa + xb + xc) / 3;
yTezista = (ya + yb + yc) / 3;
printf("Teziste trokuta A(%f, %f), B(%f, %f), C(%f, %f) jest T(%f, %f)"
, xa, ya, xb, yb, xc, yc, xTezista, yTezista);
return 0;
}

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 47

2.
#include <stdio.h>
int main (void) {
int broj;
printf("Upisite 5-znamenkasti pozitivni cijeli broj: ");
scanf("%d", &broj);
printf("Prva znamenka: %d\n", broj/10000);
printf("Posljednja znamenka: %d\n", broj%10);
return 0;
}

3.
#include <stdio.h>
int main (void) {
int broj;
printf("Upisite 5-znamenkasti pozitivni cijeli broj: ");
scanf("%d", &broj);
printf("Druga znamenka: %d\n", broj%10000/1000);
printf("Cetvrta znamenka: %d\n", broj%100/10);
return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 84

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

3. vježbe uz predavanja

1. Pročitajte i zaključite što bi sljedeći program (kada bi bio ispravan) trebao raditi.
Napišite tekst programskog zadatka koji bi odgovarao programu. Nacrtajte dijagram toka.
Zatim pomoću copy-paste upišite program u datoteku na svom računalu i pokušajte ga
prevesti. Ispravite sve vrste pogrešaka i testirajte s različitim ulaznim podacima.

#definiraj PI 3,1415926
float main (void) {
int a;
float b;
printf("Upisite duljinu velike poluosi a>");
scanf("%f", &a);
printf("Upisite duljinu male poluosi b>");
scanf("%f", &b);
if (a > 0) {
if (b > 0) {
povrsina = A x B x pi;
printf("Povrsina elipse s poluosima a=%f i b=%f je %f", povrsina);
scanf("%f", &b);
} else {
printf("Duljina male poluosi mora biti veca od nule.\nKraj. ");
}
} else {
printf("Duljina velike poluosi mora biti veca od nule.\nKraj. ");
}
return O;
}

2. Napisati C program za pretvaranje vrijednosti temperature izražene u različitim mjernim


jedinicama. Na početku program treba ispisati poruku:
Program za konverziju Fahrenheit - Celsius i obrnuto.
Za F u C upisite 1, a za C u F bilo koji drugi cijeli broj >

Ako korisnik upiše broj 1, tada ispisati poruku


Upisite temperaturu izrazenu u stupnjevima Fahrenheit >

te s tipkovnice učitati realni broj koji predstavlja temperaturu izraženu u stupnjevima


Fahrenheit, izračunati ekvivalentnu temperaturu izraženu u stupnjevima Celsius te ispisati
temperaturu izraženu u obje jedinice
xxxx.xxx st. F = xxxx.xxx st. C

Ako korisnik upiše bilo koji drugi cijeli broj, tada ispisati poruku
Upisite temperaturu izrazenu u stupnjevima Celsius >

te s tipkovnice učitati jedan realni broj koji predstavlja temperaturu izraženu u stupnjevima
Celsius, izračunati ekvivalentnu temperaturu izraženu u stupnjevima Fahrenheit te ispisati
temperaturu izraženu u obje jedinice
xxxx.xxx st. C = xxxx.xxx st. F
1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 84

3. Nacrtati dijagram toka i napisati C program za zbrajanje ili množenje realnih brojeva. Na
početku program treba ispisati poruku
Program za zbrajanje ili mnozenje.
Upisite dva realna broja >

i učitati dva realna broja koji predstavljaju operande.


Nakon toga program treba ispisati poruku
Upisite vrstu operacije (1-zbrajanje, 2-mnozenje) >

i učitati cijeli broj kojim se određuje vrsta operacije. Ako je korisnik upisao broj 1, tada treba
izračunati i ispisati zbroj operanada, a ako je upisao broj 2, tada izračunati i ispisati
umnožak operanada. Ako za odabir vrste operacije korisnik nije upisan niti broj 1 niti broj 2,
tada treba ispisati poruku
Neispravan odabir operacije.

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 84

Rješenja
1. Programski zadatak: napisati program kojim će se učitati duljine velike i male poluosi elipse.
Nakon učitavanja duljina obje osi, ispitati ispravnost unesenih podataka. Ako je velika poluos
neispravno zadana, ispisati poruku "Duljina velike poluosi mora biti veca od nule.", u sljedećem
retku na zaslonu ispisati "Kraj", te završiti s izvršavanjem programa. Ako je mala poluos
neispravno zadana, ispisati poruku "Duljina male poluosi mora biti veca od nule.", u sljedećem
retku na zaslonu ispisati "Kraj", te završiti s izvršavanjem programa.
Ako su duljine obje osi ispravno zadane, izračunati površinu elipse i ispisati poruku " Povrsina
elipse s poluosima a=x.xxxxxx i b=x.xxxxxx je x.xxxxxx.
Dijagram toka:

učitaj a, b

Da
a>0

Ne
Da
ispiši "neispravna
b>0
velika os, kraj"
Ne
ispiši "neispravna izračunaj i ispiši
mala os, kraj" površinu elipse

Program nakon ispravljanja svih pogrešaka:


#include <stdio.h>
#define PI 3.1415926
int main (void) {
float a;
float b;
float povrsina;
printf("Upisite duljinu velike poluosi a> ");
scanf("%f", &a);
printf("Upisite duljinu male poluosi b> ");
scanf("%f", &b);
if (a > 0) {
if (b > 0) {
povrsina = a * b * PI;
printf("Povrsina elipse s poluosima a=%f i b=%f je %f", a, b, povrsina);
} else {
printf("Duljina male poluosi mora biti veca od nule.\nKraj");
}
} else {
printf("Duljina velike poluosi mora biti veca od nule.\nKraj");
}
return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 02-UvodProgramiranje.pdf - do stranice: 84

2.
#include <stdio.h>
int main (void) {
float cels, fahr;
int izbor;
printf("Program za konverziju Fahrenheit - Celsius i obrnuto.\n");
printf("Za F u C upisite 1, a za C u F bilo koji drugi cijeli broj >");
scanf("%d", &izbor);
if (izbor == 1) {
printf("Upisite temperaturu izrazenu u stupnjevima Fahrenheit >");
scanf("%f", &fahr);
cels = (fahr - 32.) * 5. / 9.;
printf("%8.3f st. F = %8.3f st. C\n", fahr, cels);
} else {
printf("Upisite temperaturu izrazenu u stupnjevima Celsius >");
scanf("%f", &cels);
fahr = cels * 9. / 5. + 32.;
printf("%8.3f st. C = %8.3f st. F\n", cels, fahr);
}
return 0;
}

3. U ovom rješenju je prikazan samo dio dijagrama toka:

Ne
op = 1

Da
Ne
ispiši zbroj op = 2

Da
ispiši "neispravna
ispiši umnožak
operacija"

#include <stdio.h>
int main (void) {
float x, y;
int operacija;
printf("Program za zbrajanje ili mnozenje.\nUpisite dva realna broja >");
scanf("%f %f", &x, &y);
printf("Upisite vrstu operacije (1-zbrajanje, 2-mnozenje) >");
scanf("%d", &operacija);
if (operacija == 1)
printf("Zbroj je %f\n", x + y);
else
if (operacija == 2)
printf("Umnozak je %f\n", x * y);
else
printf("Neispravan odabir operacije.\n");
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 30

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

4. vježbe uz predavanja

1. Dekadski broj 29 prikažite u obliku binarnog broja


2. Binarni broj 10011011 prikažite u obliku dekadskog broja (za prikaz ovog binarnog broja nije
korištena tehnika dvojnog komplementa)
3. Registar od 8 bitova koristi se za prikaz brojeva tehnikom dvojnog komplementa. Koja
dekadska vrijednost je prikazana u registru, ako je sadržaj registra 00011011.
4. Registar od 8 bitova koristi se za prikaz brojeva tehnikom dvojnog komplementa. Koja
dekadska vrijednost je prikazana u registru, ako je sadržaj registra 10011011.
5. Dekadski broj -14 prikazati kao binarni broj u registru od 5 bitova, korištenjem tehnike
dvojnog komplementa
6. Dekadski broj -14 prikazati kao binarni broj u registru od 10 bitova, korištenjem tehnike
dvojnog komplementa
7. Koji se najveći i najmanji broj (izraziti u dekadskom obliku) može pohraniti u registru od 12
bita
a. ako se ne koristi tehnika dvojnog komplementa
b. ako se koristi tehnika dvojnog komplementa
8. Koliko najmanje bitova treba imati registar ako je u njega potrebno pohraniti dekadski broj 38
a. ako se ne koristi tehnika dvojnog komplementa
b. ako se koristi tehnika dvojnog komplementa
9. U binarnom brojevnom sustavu, uz primjenu tehnike dvojnog komplementa, koristeći
registre veličine 5 bitova, obavite operacije:
a. 410 + 710
b. 1210 - 510
c. 710 + 1110
d. 1210 - 1610
Rezultate provjerite pretvorbom dobivenih binarnih rezultata u dekadske brojeve
10. Dekadski broj 110 pretvoriti u oktalni broj:
a. direktno (uzastopnim dijeljenjem s 8)
b. indirektno, grupiranjem znamenaka binarnog broja
11. Dekadski broj 94 pretvoriti u heksadekadski broj:
a. direktno (uzastopnim dijeljenjem sa 16)
b. indirektno, grupiranjem znamenaka binarnog broja
12. Heksadekadske brojeve F2C i 4E napisati u obliku binarnih i oktalnih brojeva
13. Oktalni broj 76431 napisati u obliku heksadekadskog broja

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 30

14. Dekadski broj -9 pohraniti u registar od 5 bitova (tehnikom dvojnog komplementa). Rezultat
prikazati kao
a. binarni broj
b. heksadekadski broj
c. oktalni broj

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 30

Rješenja

1. 29 : 2 = 14 ostatak 1
14 : 2 = 7 ostatak 0
7 : 2 = 3 ostatak 1
3 : 2 = 1 ostatak 1
1 : 2 = 0 ostatak 1

Broj 29 je pozitivan, stoga nije potrebno izračunavati dvojni komplement.


Rješenje: 11101
Provjera: 1⋅24 + 1⋅23 + 1⋅22 + 0⋅21 + 1⋅20 = 29

2. Prva znamenka jest jedinica, ali u zadatku piše da nije korištena tehnika dvojnog
komplementa. To znači da se radi o pozitivnom broju:
1⋅27 + 0⋅26 + 0⋅25 + 1⋅24 + 1⋅23 + 0⋅22 + 1⋅21 + 1⋅20 = 155

3. U zadatku piše da se za prikaz broja koristi tehnika dvojnog komplementa, ali prvi bit u
registru nije jedinica. To znači da je u registru prikazan pozitivan broj. Vrijednost određujemo
na isti način kao da se tehnika dvojnog komplementa uopće ne koristi:
1⋅24 + 1⋅23 + 0⋅22 + 1⋅21 + 1⋅20 = 27

4. Za prikaz broja se koristi tehnika dvojnog komplementa, a prvi bit u registru jest jedinica.
To znači da je u registru prikazan neki negativan broj x. Izračunavanjem dvojnog
komplementa dobit će se broj koji je jednak po apsolutnoj vrijednosti, ali suprotnog
predznaka (dakle, pozitivan broj):

10011011 -> x
01100100 -> jedinični komplement
+ 1 dodaje se jedan kako bi se dobio dvojni komplement
= 01100101 -> -x
Dobiveni broj -x je pozitivan broj (prvi bit mu nije jedinica), stoga se lako može odrediti o
kojem se dekadskom broju radi:
1⋅26 + 1⋅25 + 0⋅24 + 0⋅23 + 1⋅22 + 0⋅21 + 1⋅20 = 10110
Ako je -x=10110, onda je x=-10110.
Konačno rješenje jest: u registru je pohranjen dekadski broj -101

5. Negativni cijeli brojevi prikazuju se tehnikom dvojnog komplementa. Nije moguće direktno
odrediti binarni prikaz broja -14, stoga se prvo određuje binarni prikaz pozitivnog broja 14
(uzastopnim dijeljenjem s 2). Voditi računa o tome da registar ima 5 bitova!
+1410 = 011102
3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 30

Binarni broj iste apsolutne vrijednosti, ali suprotnog predznaka dobije se izračunavanjem
dvojnog komplementa
01110
10001 -> jedinični komplement
+ 1 dodaje se jedan kako bi se dobio dvojni komplement
= 10010 -> dvojni komplement
Konačno rješenje: -14 prikazan u tehnici dvojnog komplementa u registru od 5 bitova jest
10010

6. Slično kao u prethodnom zadatku. Treba voditi računa da se sada radi o 10-bitnom registru!
+1410 = 00000011102
Negativna vrijednost dobije se izračunavanjem dvojnog komplementa
0000001110
1111110001 -> jedinični komplement
+ 1 dodaje se jedan kako bi se dobio dvojni komplement
= 1111110010 -> dvojni komplement
Konačno rješenje: -14 prikazan u tehnici dvojnog komplementa u registru od 10 bitova jest
1111110010

7. a) Ako se ne koristi tehnika dvojnog komplementa, raspon brojeva koji se može prikazati u
registru od n bitova jest [0, 2n-1]. Najveći broj koji se može prikazati u 12-bitnom registru
jest 212-1 = 4095. Najmanji broj koji se može prikazati jest 0.
b) Ako se koristi tehnika dvojnog komplementa, raspon brojeva koji se može prikazati u
registru od n bitova jest [-2n-1, 2n-1-1]. Najveći broj koji se može prikazati u 12-bitnom
registru jest 211-1 = 2047. Najmanji broj koji se može prikazati jest -2048.

8. a) Ako se ne koristi tehnika dvojnog komplementa, raspon brojeva koji se može prikazati u
registru od 5 bitova jest [0, 31], a u registru od 6 bitova [0, 63]. Potreban je registar od 6
bitova.
b) Ako se koristi tehnika dvojnog komplementa, raspon brojeva koji se može prikazati u
registru od 6 bitova jest [-32, 31], a u registru od 7 bitova [-64, 63]. Potreban je registar
od 7 bitova.

9. a) 00100 -> 4
+ 00111 -> 7
= 01011 -> 11

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 30

b) 01100 -> 12
+ 11011 -> -5
= 00111 -> 7

c) 00111 -> 7
+ 01011 -> 11
= 10010 -> -14
U ovom slučaju rezultat nije kakav bi se očekivao jer se u registru od 5 bitova, u tehnici
dvojnog komplementa, broj 18 ne može prikazati.

d) 01100 -> 12
+ 10000 -> -16
= 11100 -> -4

10. a) 110 : 8 = 13 ostatak 6


13 : 8 = 1 ostatak 5
1 : 8 = 0 ostatak 1

Rješenje: 156
Provjera: 1⋅82 + 5⋅81 + 6⋅80

b) 11010 = 11011102
Binarne znamenke grupirati po tri. PAZITI da se grupiranje obavi "s desna na lijevo":
1 101 1102 = 1568

11. a) 94 : 16 = 5 ostatak 14
5 : 16 = 0 ostatak 5

Rješenje: 5E
Provjera: 5⋅161 + 14⋅160

b) 9410 = 10111102
Binarne znamenke grupirati po četiri. PAZITI da se grupiranje obavi "s desna na lijevo":
101 11102 = 5E16

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 30

12. Svaka heksadekadska znamenka pretvara se u četiri binarne:


F 2 C16 = 1111 0010 11002
4 E16 = 0100 11102

Heksadekadski broj se lako pretvara u oktalni: heksadekadski broj treba napisati kao
binarni broj, zatim binarne znamenke grupirati u grupe po tri. PAZITI da se grupiranje obavi
"s desna na lijevo":
F 2 C16 = 1111 0010 11002 = 111 100 101 1002 = 74548
4 E16 = 0100 11102 = 01 001 1102 = 1168

13. Oktalni broj se lako pretvara u heksadekadski: oktalni broj treba napisati kao binarni broj,
zatim binarne znamenke grupirati u grupe po četiri. PAZITI da se grupiranje obavi "s desna
na lijevo":
7 6 4 3 18 = 111 110 100 011 0012 = 111 1101 0001 10012 = 7D1916

14. -910 = 101112 = 1716 = 278

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 67

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

5. vježbe uz predavanja

1. Koje vrijednosti poprimaju varijable a, b nakon izvođenja sljedećeg programskog odsječka:


char a;
short int b;
a = 120;
b = 32000;
a = a + 10;
b = b + 1000;
Svoje rješenje provjerite tako da programski odsječak, dopunjen naredbom za ispis
vrijednosti varijabli na zaslon i ostalim nužnim naredbama, izvedete na svom računalu.
2. Napisati sadržaj registra u kojem je, prema IEEE 754 standardu za prikaz brojeva u
jednostrukoj preciznosti, pohranjen broj -17.7812510. Sadržaj registra napisati u oktalnom i
heksadekadskom obliku.
3. U registru od 32 bita upisan je broj C2 B0 00 0016. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable tipa float. Rezultat napisati u dekadskom
brojevnom sustavu.
4. U registru od 32 bita upisan je broj 43 00 20 0016. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable tipa float. Rezultat napisati u dekadskom
brojevnom sustavu.
5. U registru od 32 bita upisan je broj 3 01 22 40 00 008. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable tipa float. Rezultat napisati u dekadskom
brojevnom sustavu.
6. U registru od 32 bita upisan je broj 3 77 40 00 00 008. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable tipa float.
7. U registru od 32 bita upisan je broj 7F C0 00 0016. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable tipa float.
8. U registru od 32 bita upisan je broj 80 00 00 0016. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable tipa float.
9. U registru od 32 bita upisan je broj 00 68 00 0016. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable tipa float.
10. U registru od 32 bita upisan je broj 80 00 00 0116. Napisati koji je broj predstavljen u tom
registru, ako registar služi za pohranu varijable:
a. signed int i;
b. unsigned int j;
c. float x;
Rezultate napisati u dekadskom brojevnom sustavu.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 67

11. Napisati sadržaje registara u kojima je, prema IEEE 754 standardu za prikaz brojeva u
jednostrukoj preciznosti, pohranjen sadržaj varijabli x i y nakon obavljanja sljedećih naredbi:

float x, y;
x = 0.f;
y = -3.75f / x;

Sadržaje registara napisati u heksadekadskom obliku.

12. Napisati sadržaj registra u kojem je, prema IEEE 754 standardu za prikaz brojeva u
jednostrukoj preciznosti, pohranjen sadržaj varijable x nakon obavljanja sljedećih naredbi:

float x;
x = 0.f;
x = x / x;

Sadržaj registra napisati u heksadekadskom obliku.

13. Što će se ispisati uz pomoć sljedećih naredbi (napomena: u svim naredbama 0


predstavlja znamenku nula, a ne slovo O)
char c;
c = 'A' + '0';
printf("%d\n", c);
printf("%c\n", c);
printf("%c\n", 'D' - 'A' + '0');
printf("%d\n", 'D' - 'A' + '0');
printf("%d\n", '7' - '5');
printf("%d\n", '7' - 5);
printf("%c\n", '7' - 5);
printf("%d\n", '0' % 10);

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 67

Rješenja

1. Pri rješavanju ovakvih zadataka treba se sjetiti koji se najveći/najmanji brojevi mogu prikazati
u varijablama određenih tipova podataka.
2. Prvi bit za predznak se postavlja na P=1. Time je pitanje predznaka riješeno (upamtiti: u
IEEE 754 formatu se ne koristi ništa što podsjeća na tehniku dvojnog komplementa!)

Sada treba odrediti karakteristiku i mantisu. Prvo pretvoriti broj u binarni oblik:
17.7812510 = 10001.110012
Normalizirati:
10001.110012 = 1.000111001 ⋅ 24
BE = 410 ⇒ K = 4 + 127 = 13110 = 100000112
M = 1.000111001
U 32-bitni registar prepisati P, K, te M (ali BEZ SKRIVENOG BITA!):
1 10000011 00011100100000000000000
Grupirati po tri znamenke s desna na lijevo
11 000 001 100 011 100 100 000 000 000 0002 = 301434400008
Grupirati po četiri znamenke s desna na lijevo
1100 0001 1000 1110 0100 0000 0000 00002 = C18E400016

3. Varijable tipa float pohranjuju se prema IEEE 754 formatu jednostruke preciznosti
C2 B0 00 0016 = 1100 0010 1011 0000 0000 0000 0000 00002
Odrediti predznak: P = 1, stoga je broj negativan.
Odrediti binarni eksponent:
K = 100001012 = 13310 ⇒ BE = 133 - 127 = 6

Odrediti mantisu (vratiti joj skriveni bit!):


"mantisa bez skrivenog bita" = .011000000000000000000002

M = 1.011000000000000000000002
Rezultat se dobije množenjem mantise s 2BE
1.011000000000000000000002 ⋅ 26 = 1011000.02 = 88.010
Ne zaboraviti negativni predznak (jer P=1)
Konačni rezultat: -88.0

4. 128.12510

5. -12.62510
3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 67

6. K = 255, u mantisi su svi bitovi postavljeni na nulu. Radi se o prikazu beskonačnosti. Budući
da je predznak P=1, konačno rješenje jest: -∞.

7. K = 255, a u mantisi postoji jedan ili više bitova koji su postavljeni na jedinicu. U registru je
prikazana vrijednost NaN (Not a Number).

8. K = 0, a u mantisi su svi bitovi postavljeni na 0. Radi se o prikazu broja 0. Budući da je


predznak P=1, konačno rješenje jest: -0.0.

9. K = 0, a u mantisi postoje bitovi koji su postavljeni na jedan. Radi se o prikazu


denormaliziranog broja.
00 68 00 0016 = 0000 0000 0110 1000 0000 0000 0000 00002
BE = -126 (kod denormaliziranog broja ne koristi se formula BE = K - 127)
M = 0.1101 (kod denormaliziranog skriveni bit nije 1, nego 0)
BE
Rezultat se dobije množenjem mantise s 2
0.11012 ⋅ 2-126 = 0.812510 ⋅ 2-126 ≈ 9.55 ⋅ 10-39

10. 80 00 00 0116 = 1000 0000 0000 0000 0000 0000 0000 0001

a) Radi se o prikazu broja u tehnici dvojnog komplementa. Broj je negativan:


1000 0000 0000 0000 0000 0000 0000 0001
0111 1111 1111 1111 1111 1111 1111 1110
+ 1
= 0111 1111 1111 1111 1111 1111 1111 11112 = 214748364710
U registru je prikazan broj -2147483647

b) Radi se o prikazu broja u kojem se ne koristi tehnika dvojnog komplementa. Broj je


pozitivan, unatoč tome što je prvi bit jedinica:
1000 0000 0000 0000 0000 0000 0000 00012 = 214748364910

c) Radi se o prikazu broja u IEEE 754 formatu: ≈ -1.4 ⋅ 10-45

11. Rezultat operacije je -∞. Rješenje jest: FF 80 00 0016

12. Rezultat operacije je NaN. Rješenje jest (jedno od mogućih, jer na predavanjima nismo
specificirali koje vrijednosti trebaju imati bitovi u mantisi kad se prikazuje NaN): 7F C0 00
0016
13. Ispravnost vlastitog rješenja provjeriti izvođenjem programskog odsječka na računalu.

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 102

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

6. vježbe uz predavanja

1. Odredite najveću moguću relativnu i najveću moguću apsolutnu pogrešku koja se može
očekivati pri pohrani broja 2⋅1022 u IEEE 754 formatu jednostruke preciznosti.

2. Gdje se (i zašto) u sljedećem odsječku programa nalaze sintaktičke pogreške:


int thin, tall, short;
float which, while, when, why, who;
char single, double, triple;
signed long a777, 7b, _19;

3. Pronađite koje su konstante ispravno, a koje neispravno napisane. Za ispravno napisane


konstante odredite kojeg su tipa i koliko okteta zauzimaju u memoriji:
2 4u 7f 9.1 14.5U 0101u 12.1L 12.1e+22F
12.1e22 12.1Fe-22 12.1E11L 12.1E11u 0x22L 0xABC
0x2f 2F 0x2F.1F 021.1f

4. Napisati sadržaj registra u kojem je, prema IEEE 754 standardu za prikaz brojeva u
dvostrukoj preciznosti pohranjen broj -0.2510. Sadržaj registra napisati u heksadekadskom
obliku.
5. U registru od 64 bita upisan je broj C0 3D 80 00 00 00 00 0016. Napisati koji je broj
predstavljen u tom registru, ako registar služi za pohranu varijable double x. Rezultat
napisati u dekadskom brojevnom sustavu.
6. Napisati sadržaj registra u kojem je, prema IEEE 754 standardu za prikaz brojeva u
dvostrukoj preciznosti pohranjen broj -∞. Sadržaj registra napisati u heksadekadskom
obliku.
7. Napisati sadržaj registra u kojem je, prema IEEE 754 standardu za prikaz brojeva u
dvostrukoj preciznosti pohranjena vrijednost NaN. Sadržaj registra napisati u
heksadekadskom obliku.
8. Odredite najveću moguću relativnu i najveću moguću apsolutnu pogrešku koja se može
očekivati pri pohrani broja 2⋅1022 u IEEE 754 formatu dvostruke preciznosti.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 102

Rješenja

1. Najveća moguće relativna pogreška ovisi isključivo o broju bitova mantise m. Vodite računa
o tome da parametar m uključuje i skriveni bit. Kod prikaza prema IEEE 754 standardu
jednostruke preciznosti m = 24.
Najveća moguća relativna pogreška iznosi 2-24 ≈ 6 ⋅ 10-8
Najveća moguća apsolutna pogreška ovisi o parametru m i konkretnom broju x koji se
prikazuje:
Najveća moguća apsolutna pogreška iznosi x ⋅ 2-24 ≈ 2 ⋅ 1022 ⋅ 6 ⋅ 10-8 = 1.2 ⋅
1015

2. int thin, tall, short;


float which, while, when, why, who;
char single, double, triple;
signed long a777, 7b, _19;
U prvom retku se za ime varijable koristi ključna riječ short;
U drugom retku se za ime varijable koristi ključna riječ while;
U trećem retku se za ime varijable koristi ključna riječ double;
U četvrtom retku ime varijable 7b započinje znamenkom (nije dopušteno)

3. 2 signed int - 4 okteta


4u unsigned int - 4 okteta
7f pogreška: nedostaje točka
9.1 double - 8 okteta
14.5U pogreška: ne postoji tip unsigned double
0101u unsigned int u oktalnom obliku - 4 okteta
12.1L long double - 8 okteta
12.1e+22F float - 4 okteta
12.1e22 double - 8 okteta
12.1Fe-22 pogreška: F na pogrešnom mjestu
12.1E11L long double - 8 okteta
12.1E11u pogreška: ne postoji tip unsigned double
0x22L long int u heksadekadskom obliku - 4 okteta
0xABC int u heksadekadskom obliku - 4 okteta
0x2f int u heksadekadskom obliku - 4 okteta
2F pogreška: nedostaje točka
0x2F.1F pogreška: ne može se realni broj zapisati u heksadekadskom obliku
021.1F float, 0 na početku nema nikakvo značenje, ali nije pogreška - 4 okteta

4. BFD0000000000000

5. -29.5

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 102

6. FFF0000000000000

7. Prikazano je jedno od mogućih rješenja. Bitno je da su svi bitovi karakteristike postavljeni na


1, te da je barem jedan bit mantise postavljen na 1
FFF8000000000000

8. Najveća moguća relativna pogreška iznosi 2-53 ≈ 1.1 ⋅ 10-16


Najveća moguća apsolutna pogreška iznosi x ⋅ 2-53 ≈ 2.2 ⋅ 106

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 132

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

7. vježbe uz predavanja

1. Napisati C program koji će s tipkovnice učitati cijeli broj x, a zatim na zaslon ispisati tekst
Istina je ako je učitani broj u intervalu [1, 9] ili je u intervalu [80, 90].

2. Napisati C program koji će s tipkovnice učitati cijeli broj m, a zatim na zaslon ispisati tekst
Istina je ako je učitani broj neparan pozitivan broj.

3. Napisati C program koji će na zaslon ispisati tekst Istina je ako uvjet iz 1. zadatka
nije zadovoljen (napisati jedno rješenje uz korištenje operatora negacije i jedno rješenje
bez korištenja operatora negacije).

4. Napisati C program koji će na zaslon ispisati tekst Istina je ako uvjet iz 2. zadatka
nije zadovoljen (napisati jedno rješenje uz korištenje operatora negacije i jedno rješenje
bez korištenja operatora negacije).

5. Napisati C program koji će s tipkovnice učitati dva znaka u varijable c1 i c2 tipa char.
Ako su oba učitana znaka velika slova abecede (A-Z) i pri tome su oba znaka
samoglasnici, ispisati tekst Ucitani znakovi su "veliki" samoglasnici
(primijetite da unutar teksta treba dva puta ispisati i dvostruke navodnike).

6. Ispisati tekst Barem jedan od znakova nije veliki samoglasnik ako uvjet iz
5. zadatka nije zadovoljen (napisati jedno rješenje uz korištenja operatora negacije i
jedno rješenje bez korištenja operatora negacije).

7. Napisati C program koji će s tipkovnice učitati znak. Ako je učitani znak malo slovo
abecede ili znamenka, ispisati tekst Istina je.

8. Napisati C program koji će s tipkovnice učitati dva znaka. Ako oba učitana znaka
predstavljaju heksadekadske znamenke, ispisati poruku Upisan je ispravan
dvoznamenkasti heksadekadski broj.
9. Što je rezultat evaluacije svakog od sljedećih izraza (treba odrediti tip podatka i
vrijednost):
12 / 2*3
15 / 2*3
15. / 2*3
15.f / 2*3
15.f / 2*3.
15 / 2*3.
12 / (2*3)
2 * 2+3
2 * 5%2
2 * (5%2)
(float)15/2/3

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 132

(float)(15/2/3)
(float)(15/2)/3
(float)((15/2)/3)
3.5f * (double)4 + 3 * 5/(double)2

10. Što će biti sadržaj svake od definiranih varijabli nakon obavljanja sljedećeg
programskog odsječka (za varijable tipa char treba navesti njihovu numeričku
vrijednost):
char c1, c2;
float f1, f2;
double f3, f4;
c1 = 132.f - (double)2;
f1 = -2147483648.0;
f2 = -2147483645.0;
f3 = -2147483645.0;
f4 = -2147483645.0f;
c2 = 126;

11. Što će se ispisati programskim odsječkom:

int i;
i = !0 <= 101 % 100;
printf ("%d\n", i);
i = !1 && !200 || !0 && !100;
printf ("%d\n", i);
i = (!1 && !0 || 100) + 'a' - 'A';
printf ("%d\n", i);
i = 'a' - 'A' + 18;
printf ("%c %d\n", i, i);
i = 10;
printf ("%d\n", i==15);
printf ("%d\n", i);

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 132

Rješenja

1. #include <stdio.h>
int main (void) {
int x;
scanf("%d", &x);
if (x >= 1 && x <= 9 || x >= 80 && x <= 90) {
printf("Istina je");
}
return 0;
}

2. #include <stdio.h>
int main (void) {
int m;
scanf("%d", &m);
if (m > 0 && m % 2 != 0) {
printf("Istina je");
}
return 0;
}

3. if (!(x >= 1 && x <= 9 || x >= 80 && x <= 90)) {

ili
if ((x < 1 || x > 9) && (x < 80 || x > 90)) {

4. if (!(m > 0 && m % 2 != 0)) {

ili
if (m <= 0 || m % 2 == 0) {

5. #include <stdio.h>
int main (void) {
char c1, c2;
scanf("%c%c", &c1, &c2);
if ((c1 == 'A' ||
c1 == 'E' ||
c1 == 'I' ||
c1 == 'O' ||
c1 == 'U')
&&
(c2 == 'A' ||
c2 == 'E' ||
c2 == 'I' ||
c2 == 'O' ||
c2 == 'U')) {
printf("Ucitani znakovi su \"veliki\" samoglasnici");
}
return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 132

6. if (!((c1 == 'A' ||
c1 == 'E' ||
c1 == 'I' ||
c1 == 'O' ||
c1 == 'U')
&&
(c2 == 'A' ||
c2 == 'E' ||
c2 == 'I' ||
c2 == 'O' ||
c2 == 'U'))) {

ili

if ( c1 != 'A' &&
c1 != 'E' &&
c1 != 'I' &&
c1 != 'O' &&
c1 != 'U'
||
c2 != 'A' &&
c2 != 'E' &&
c2 != 'I' &&
c2 != 'O' &&
c2 != 'U') {

7. #include <stdio.h>
int main (void) {
char c;
scanf("%c", &c);
if (c >= 'a' && c <= 'z' || c >= '0' && c <= '9') {
printf("Istina je");
}
return 0;
}

8. #include <stdio.h>
int main (void) {
char c1, c2;
scanf("%c%c", &c1, &c2);
if ((c1 >= 'a' && c1 <= 'f' ||
c1 >= 'A' && c1 <= 'F' ||
c1 >= '0' && c1 <= '9')
&&
(c2 >= 'a' && c2 <= 'f' ||
c2 >= 'A' && c2 <= 'F' ||
c2 >= '0' && c2 <= '9')) {
printf("Upisan je ispravan dvoznamenkasti heksadekadski broj");
}
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 03-TipoviPodataka.pdf - do stranice: 132

9. 12 / 2*3
-> 18, int

15 / 2*3
-> 21, int

15. / 2*3
-> 22.5, double

15.f / 2*3
-> 22.5, float

15.f / 2*3.
-> 22.5, double

15 / 2*3.
-> 21.0, double

12 / (2*3)
-> 2, int

2 * 2+3
-> 7, int

2 * 5%2
-> 0, int

2 * (5%2)
-> 2, int

(float)15/2/3
-> 2.5, float

(float)(15/2/3)
-> 2.0, float

(float)(15/2)/3
-> 2.333333, float

(float)((15/2)/3)
-> 2.0, float

3.5f * (double)4 + 3 * 5/(double)2


-> 14.0 + 7.5
-> 21.5, double

10. c1 = -126
c2 = 126
f1 = -2147483648.000000
f2 = -2147483648.000000
f3 = -2147483645.000000
f4 = -2147483648.000000

11. Svoje rješenje provjerite obavljanjem navedenih naredbi u vlastitom C programu.


5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 04-OstaliOperatori.pdf - do stranice: 37

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

8. vježbe uz predavanja
1. Što će se ispisati sljedećim odsječkom programa:
char c, c1;
c = 'a' / 2*1.1;
printf("%d\n", c);

c1 = 1 + c++;
printf("%d %d\n", c, c1);
c1 = ++c + 12;
printf("%d %c %d %c\n", c, c, c1, c1);

2. Što će se ispisati sljedećim odsječkom programa:

int i1 = 5, i2, j1 = 5, j2, k1, k2;


i2 = ++i1 + 3;
printf("%d %d\n", i1, i2);
j2 = j1++ + 3;
printf("%d %d\n", j1, j2);
k1 = i2++ * --j2;
printf("%d %d %d\n", i2, j2, k1);
i2++;
++j2;
k2 = ++i2 * j2++;
printf("%d %d %d\n", i2, j2, k2);

3. Što će se ispisati sljedećim programskim odsječkom:


int i = 23, j = 13, k = 11, m;
printf("%d\n", i || j && k);
printf("%d\n", i | j & k);
m = i == j && k;
printf("%d %d\n", m, -!m < 0);
m = i ^ (j=13);
printf("%d %d\n", m, j);
j = 7;
m = 7;
m = i & ~(j==7);
printf("%d\n", m);
m = ~(~k | k);
printf("%d\n", m);

4. Što će se ispisati sljedećim programskim odsječkom:


int i = 6;
printf("%d\n", i << 3);
printf("%d\n", i);

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 04-OstaliOperatori.pdf - do stranice: 37

5. Što će se ispisati sljedećim odsječkom programa:


int i = 7;
if (i = 3 & 4)
printf("ISTINA JE %d\n", i);
else
printf("NIJE ISTINA %d\n", i);
if (i = 3 && 4)
printf("ISTINA JE %d\n", i);
else
printf("NIJE ISTINA %d\n", i);
printf("Jos jednom upozoravam, NIJE ISTINA\n");
printf("Program zavrsava\n");

6. Što će se ispisati obavljanjem sljedećeg programskog odsječka:


char x, y, z;
x = 2;
y = '1';
z = (y <= x) ? ( ++x ) : ( y += ++x );
printf("%d %c %d %c", x, y, y, z);

7. Što će se ispisati obavljanjem sljedećeg programskog odsječka:


int a = 3, b = 5, c = 9, d;
d = a + (b+=c);
printf("%d %d %d %d", a, b, c, d);

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 04-OstaliOperatori.pdf - do stranice: 37

Rješenja

6.
Prvo se izračunava y <= x → 0
Budući je rezultat "laž", izraz ( ++x ) se uopće ne izračunava!
Izračunava se samo ( y+= ++x ), a zatim se rezultat tog izraza pridružuje varijabli z.
Zbog prefiksnog oblika ++ operatora, varijabla x se prvo uvećava za 1, a zatim se njena
vrijednost dalje koristi u izrazu. Uvećana vrijednost varijable x je 3. y += 3 je isto što i y
= y + 3
Konačno, x = 3, y = '4' (odnosno 52), z = '4' (odnosno 52)
Ispisat će se: 3 4 52 4

7.
Prvo se izračunava (b+=c) → b=14, rezultat cijelog izraza (b+=c) je 14
d = a + 14, tj. d = 17
Ispisat će se:
3 14 9 17

Svoja rješenja ostalih zadataka provjerite izvođenjem programa na vlastitim računalima.

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

9. vježbe uz predavanja
1. S tipkovnice u char varijablu c učitajte jedan znak. Ako je učitano veliko slovo,
ispisati poruku "To je veliko slovo". Ako je učitano malo slovo, ispisati poruku "To je
malo slovo". Ako je učitana znamenka (0-9), ispisati poruku "To je znamenka". Ako
nije učitano ni slovo ni znamenka, ispisati poruku "To je neki drugi znak".

2. S tipkovnice u char varijablu z1 učitajte znak. Ako učitani znak nije heksadekadska
znamenka (0-9, A-F, a-f), ispisati poruku "Nije dobra znamenka" i završiti program.
Inače, ispisati dekadski ekvivalent učitane heksadekadske znamenke. Npr. ako je
učitan znak e, treba ispisati 14.

3. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. Izračunati i na zaslon ispisati


sumu:

1 1 1 1 1 1
- + - + ... + -
1 2 3 4 999 1000
4. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. S tipkovnice učitavati i
sumirati cijele brojeve dok god su oni djeljivi s 3 ili 7. Na kraju ispisati sumu učitanih
brojeva. Podrazumijeva se da se zadnji broj koji je učitan (onaj zbog kojeg se prekida
učitavanje) ne dodaje u sumu. Vodite računa o tome da već i prvi učitani broj može
biti "neispravan".

5. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. S tipkovnice učitavati i


sumirati cijele brojeve dok god su oni djeljivi s 3 ili 7. Na kraju ispisati sumu učitanih
brojeva. Podrazumijeva se da se zadnji broj koji je učitan (onaj zbog kojeg se prekida
učitavanje) također dodaje u sumu. Vodite računa o tome da već i prvi učitani broj
može biti "neispravan".

6. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. S tipkovnice učitati cijeli broj
n koji mora biti između 0 i 16 (uključivo s granicama). Ako broj nije ispravan, ispisati
odgovarajuću poruku. Ako je broj ispravno upisan, učitati n binarnih znamenki i
ispisati dekadski ekvivalent učitanog binarnog broja (ne primjenjuje se tehnika
dvojnog komplementa, pa je dekadski ekvivalent sigurno pozitivan broj).

Npr., ako je korisnik upisao


4
1
1
0
1
program treba ispisati 13 (jer je 11012 = 1310).
Npr., ako je korisnik upisao
0
program treba ispisati 0.
1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

7. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. Načinite program za


izračunavanje n!. Vrijednost za n učitati s tipkovnice. Ako broj nije ispravan (mora biti
cijeli broj veći ili jednak 0), ispisati odgovarajuću poruku.

8. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. Načinite program za


pretvaranje nenegativnog (to znači pozitivnog ili nule) cijelog dekadskog broja u
heksadekadski oblik (uzastopnim dijeljenjem sa 16). Nije potrebno provjeravati je li
učitani broj nenegativan. Znamenke heksadekadskog broja smijete ispisati
"obrnutim" redoslijedom. Npr. za uneseni dekadski broj 725, program treba ispisati
5D2. Za uneseni broj 0, program treba ispisati 0.

9. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. Isto kao prethodni zadatak,
ali za učitani dekadski broj treba ispisati oktalni broj.

10. Riješiti pomoću petlje s ispitivanjem uvjeta na početku. U varijablu tipa int s
tipkovnice učitati nenegativni cijeli broj (ne treba kontrola je li broj nenegativan). Na
zaslon ispisati binarni sadržaj registra te varijable (binarne znamenke se moraju
ispisati ispravnim redoslijedom). Za izdvajanje bitova koristiti bitovni operator & i
operator za posmak bitova prema desno. Može se pretpostaviti da se za pohranu
int tipa podatka koristi 32 bita.

Uputa:

• ako se sadržaj registra 01000000000000000000000000010010 posmakne za 31


mjesto u desno, koja binarna znamenka originalnog broja će se pojaviti na krajnjoj
desnoj poziciji?
• ako se sadržaj registra 01000000000000000000000000010010 posmakne za 30
mjesta u desno, koja binarna znamenka originalnog broja će se pojaviti na krajnjoj
desnoj poziciji?
• ako se sadržaj registra 01000000000000000000000000010010 posmakne za 29
mjesta u desno, koja binarna znamenka originalnog broja će se pojaviti na krajnjoj
desnoj poziciji? I tako dalje...
• vrijednost "krajnje desnog bita" varijable x može se dobiti operacijom x & 1

11. Riješiti pomoću petlje s ispitivanjem uvjeta na kraju (do-while). Usporediti s rješenjem
u kojem se koristila petlja s ispitivanjem uvjeta na početku. Izračunati i na zaslon
ispisati sumu:

1 1 1 1 1 1
- + - + ... + -
1 2 3 4 999 1000

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

12. Riješiti pomoću petlje s ispitivanjem uvjeta na kraju (do-while). Usporediti s rješenjem
u kojem se koristila petlja s ispitivanjem uvjeta na početku. S tipkovnice učitavati i
sumirati cijele brojeve dok god su oni djeljivi s 3 ili 7. Na kraju ispisati sumu učitanih
brojeva. Podrazumijeva se da se zadnji broj koji je učitan (onaj zbog kojeg se prekida
učitavanje) ne dodaje u sumu. Vodite računa o tome da već i prvi učitani broj može
biti "neispravan".

13. Riješiti pomoću petlje s ispitivanjem uvjeta na kraju (do-while). Usporediti s rješenjem
u kojem se koristila petlja s ispitivanjem uvjeta na početku. S tipkovnice učitavati i
sumirati cijele brojeve dok god su oni djeljivi s 3 ili 7. Na kraju ispisati sumu učitanih
brojeva. Podrazumijeva se da se zadnji broj koji je učitan (onaj zbog kojeg se prekida
učitavanje) također dodaje u sumu. Vodite računa o tome da već i prvi učitani broj
može biti "neispravan".

14. Napisati dva rješenja. Jedno rješenje pomoću petlje s ispitivanjem uvjeta na početku
i jedno rješenje pomoću petlje s ispitivanjem uvjeta na kraju. Usporediti rješenja. S
tipkovnice učitati nenegativan cijeli broj N (N može biti nula!). Na zaslon ispisati N
kvocijenata (može biti niti jedan) u obliku realnih brojeva ukupne širine 7 znakova, s
pet decimala iza decimalne točke):
1 2 3 N
...
2 3 4 N+1
15. S tipkovnice učitavati cijele brojeve dok god ne bude upisan broj manji ili jednak nuli.
Na zaslon ispisati sumu učitanih pozitivnih brojeva podijeljenu s najvećim do tada
učitanim pozitivnim brojem i pomnoženu s najmanjim do tada učitanim pozitivnim
brojem. Ako nije upisan niti jedan pozitivni broj, ispisati odgovarajuću poruku.
Primjer: ako korisnik utipka brojeve 2 5 3 2 2 -22, program treba ispisati
5.600000

16. Napišite program koji s tipkovnice učitava dva znaka te ispisuje sve znakove ASCII
tablice koji se nalaze između ta dva znaka. Npr., ako se učitaju znakovi d i k,
program ispisuje defghijk.

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

17. Načinite program koji će ispisati sljedeću tablicu:

A. a b c d e f .F
B. b c d e f g .G
C. c d e f g h .H
D. d e f g h i .I
... itd.
S. s t u v w x .X
T. t u v w x y .Y
U. u v w x y z .Z

Očekuje se da zadatak riješite pomoću dvije programske petlje, a ne npr. ovako:

printf("A. a b c d e f .F\n");
printf("B. b c d e f g .G\n");
printf("C. c d e f g h .H\n");
printf("D. d e f g h i .I\n");
... itd.

18. Načinite program kojim će se učitati član niza a1 koji mora biti cijeli broj veći od 1.
Nije potrebno provjeravati ispravnost unesenog broja. Ispisati članove niza a1, a2, a3,
..., an i ukupan broj članova niza. Član niza ai (za i > 1) izračunava se na sljedeći
način:
ako je ai-1 paran, tada je ai = ai-1 / 2
ako je ai-1 neparan, tada je ai = 3 ai-1 + 1

Niz završava članom an = 2

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

Rješenja

1. #include <stdio.h>

int main (void) {


char c;
scanf("%c", &c);
if (c >= 'A' && c <= 'Z')
printf("To je veliko slovo\n");
else if (c >= 'a' && c <= 'z')
printf("To je malo slovo\n");
else if (c >= '0' && c <= '9')
printf("To je znamenka\n");
else
printf("To je neki drugi znak\n");

return 0;
}

Uočite da je sljedeće rješenje loše (objasnite zašto), iako "program radi":

Loše rješenje !!!

#include <stdio.h>

int main (void) {


char c;
scanf("%c", &c);
if (c >= 'A' && c <= 'Z')
printf("To je veliko slovo\n");
if (c >= 'a' && c <= 'z')
printf("To je malo slovo\n");
if (c >= '0' && c <= '9')
printf("To je znamenka\n");
if (! (c >= 'A' && c <= 'Z' ||
c >= 'a' && c <= 'z' ||
c >= '0' && c <= '9') )
printf("To je neki drugi znak\n");

return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

2. #include <stdio.h>

int main (void) {


char z1;
char dekadskiBroj;
scanf("%c", &z1);
if (z1 >= 'A' && z1 <= 'F' ||
z1 >= 'a' && z1 <= 'f' ||
z1 >= '0' && z1 <= '9' ) {
/* dobar znak */
if (z1 >= 'A' && z1 <= 'F')
dekadskiBroj = z1 - 65 + 10;
else if (z1 >= 'a' && z1 <= 'f')
dekadskiBroj = z1 - 97 + 10;
else
dekadskiBroj = z1 - 48;
printf("heksadekadski %c = dekadski %d\n", z1, dekadskiBroj);
}
else {
printf("Nije dobra znamenka\n");
}
return 0;
}
ili
#include <stdio.h>

int main (void) {


char z1;
scanf("%c", &z1);
if (z1 >= 'A' && z1 <= 'F')
printf("heksadekadski %c = dekadski %d\n", z1, z1 - 65 + 10);
else if (z1 >= 'a' && z1 <= 'f')
printf("heksadekadski %c = dekadski %d\n", z1, z1 - 97 + 10);
else if (z1 >= '0' && z1 <= '9')
printf("heksadekadski %c = dekadski %d\n", z1, z1 - 48);
else
printf("Nije dobra znamenka\n");
return 0;
}

3. #include <stdio.h>
int main (void) {
int i;
float suma, brojnik;
i = 1;
suma = 0.f;
while (i <= 1000) {
brojnik = i % 2 ? 1.f : -1.f;
suma += brojnik / i;
++i;
}
printf("Suma je: %f\n", suma);
return 0;
}

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

4. #include <stdio.h>
int main (void) {
int suma = 0, x;
scanf("%d", &x);
while (x % 3 == 0 || x % 7 == 0) {
suma += x;
scanf("%d", &x);
}
printf("Suma ucitanih brojeva je %d\n", suma);
return 0;
}

5. #include <stdio.h>
int main (void) {
int suma = 0, x;
scanf("%d", &x);
suma += x;
while (x % 3 == 0 || x % 7 == 0) {
scanf("%d", &x);
suma += x;
}
printf("Suma ucitanih brojeva je %d\n", suma);
return 0;
}

6. #include <stdio.h>
int main (void) {
int n, znamenka, dekadski = 0;
scanf("%d", &n);
if (n < 0 || n > 16) {
printf("Upisali ste neispravan broj\n");
}
else {
while (n > 0) {
scanf("%d", &znamenka);
dekadski = dekadski*2 + znamenka;
--n;
}
printf("%d\n", dekadski);
}
return 0;
}

7. #include <stdio.h>
int main (void) {
int n, fakt = 1;
scanf("%d", &n);
if (n < 0) {
printf("Upisali ste neispravan broj\n");
}
else {
while (n > 1) {
fakt *= n;
--n;
}
printf("%d\n", fakt);
}
return 0;
}

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

8. #include <stdio.h>
int main (void) {
int n, ostatak;
scanf("%d", &n);
if (n == 0) {
printf("0\n");
}
else {
while (n > 0) {
ostatak = n % 16;
if (ostatak < 10)
printf("%d", ostatak);
else
printf("%c", 'A' + ostatak - 10);
n = n / 16;
}
}
return 0;
}

9. #include <stdio.h>
int main (void) {
int n, ostatak;
scanf("%d", &n);
if (n == 0)
printf("0\n");
else
while (n > 0) {
ostatak = n % 8;
printf("%d", ostatak);
n = n / 8;
}
return 0;
}

10. #include <stdio.h>


int main (void) {
unsigned nt broj;
int kolikoPosmaknutiDesno, pomocna;
scanf("%u", &broj);
printf("Upisali ste broj %d\n", broj);
kolikoPosmaknutiDesno = 31;
while (kolikoPosmaknutiDesno >= 0) {
pomocna = broj >> kolikoPosmaknutiDesno;
/* sada se u varijabli pomocna, na poziciji nultog bita (najmanje
znacajnog bita) nalazi znamenka koja se u varijabli broj nalazi
na poziciji kolikoPosmaknutiDesno. Vrijednost tog bita,
0 ili 1, moze se dobiti tako da se obavi operacija:
pomocna & 000000000000000000000000000000012 */
printf("%d", pomocna & 1);
/* u sljedecem koraku posmaknuti za 30 mjesta,
u sljedecem za 29 mjesta itd. */
--kolikoPosmaknutiDesno;
}
printf("\n");
return 0;
}

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

Rješenje 11. zadatka

#include <stdio.h> s petljom s ispitivanjem uvjeta na početku


int main (void) {
int i; #include <stdio.h>
float suma, brojnik; int main (void) {
i = 1; int i;
suma = 0.f; float suma, brojnik;
do { i = 1;
brojnik = i % 2 ? 1.f : -1.f; suma = 0.f;
while (i <= 1000) {
suma += brojnik / i; brojnik = i % 2 ? 1.f : -1.f;
++i; suma += brojnik / i;
} while (i <= 1000); ++i;
printf("Suma je: %f\n", suma); }
return 0; printf("Suma je: %f\n", suma);
} return 0;
}

Tijelo petlje će se sigurno izvršiti točno tisuću puta. Jednako je prikladno koristiti obje vrste petlji.
Napomena: u ovom zadatku bi najprikladnija vrsta petlje bila petlja s poznatim brojem ponavljanja,
koja za sada još nije obrađena na predavanjima i zato se ne koristi u rješenju.

Rješenje 12. zadatka

#include <stdio.h> s petljom s ispitivanjem uvjeta na početku


int main (void) {
int suma = 0, x; #include <stdio.h>
do { int main (void) {
scanf("%d", &x); int suma = 0, x;
if (x % 3 == 0 || x % 7 == 0) scanf("%d", &x);
while (x % 3 == 0 || x % 7 == 0) {
suma += x; suma += x;
} while (x % 3 == 0 || x % 7 == 0); scanf("%d", &x);
}
printf("Suma ucitanih brojeva je %d\n", printf("Suma ucitanih brojeva je %d\n",
suma); suma);
return 0; return 0;
} }

Jedan dio tijela petlje se mora izvršiti barem jednom (scanf), a drugi dio tijela petlje (sumiranje) se
možda neće trebati izvršiti niti jednom. Jednako je (ne)prikladno koristiti obje vrste petlji.

s petljom s ispitivanjem uvjeta na početku


Rješenje 13. zadatka
#include <stdio.h> #include <stdio.h>
int main (void) { int main (void) {
int suma = 0, x;
int suma = 0, x; scanf("%d", &x);
do { suma += x;
scanf("%d", &x); while (x % 3 == 0 || x % 7 == 0) {
suma += x; scanf("%d", &x);
} while (x % 3 == 0 || x % 7 == 0); suma += x;
printf("Suma ucitanih brojeva je %d\n", }
suma); printf("Suma ucitanih brojeva je %d\n",
return 0; suma);
} return 0;
}

9
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

Cijelo tijelo petlje se mora izvršiti barem jednom. U ovom zadatku očito je prikladnije koristiti petlju s
ispitivanjem uvjeta na kraju.

Rješenje 14. zadatka


#include <stdio.h>
int main (void) {
int n, i = 1;
scanf("%d", &n);
while (i <= n) {
printf("%7.5f\n", (float)i/(i+1));
++i;
}
return 0;
}

#include <stdio.h>
int main (void) {
int n, i = 1;
scanf("%d", &n);
do {
if (i <= n) {
printf("%7.5f\n", (float)i/(i+1));
++i;
}
} while (i <= n);
return 0;
}

Moguće je da tijelo petlje neće trebati izvršiti niti jednom. U ovom zadatku očito je prikladnije koristiti
petlju s ispitivanjem uvjeta na početku.
Napomena: u ovom zadatku bi najprikladnija vrsta petlje bila petlja s poznatim brojem ponavljanja,
koja za sada još nije obrađena na predavanjima i zato se ne koristi u rješenju.

Rješenje 15. zadatka


#include <stdio.h>

int main (void) {


int suma = 0, najmanji, najveci, ucitani;
do {
scanf("%d", &ucitani);
if (ucitani > 0) {
if (suma == 0)
najmanji = najveci = ucitani;
suma += ucitani;
if (ucitani < najmanji)
najmanji = ucitani;
if (ucitani > najveci)
najveci = ucitani;
}
} while (ucitani > 0);
if (suma > 0)
printf("Rezultat je: %f\n", (float)suma / najveci * najmanji);
else
printf("Nije ucitan niti jedan pozitivan broj\n");
return 0;
}

10
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 33

Rješenje 16. zadatka


#include <stdio.h>

int main(void) { Komentirajte: što će se dogoditi ako se


char c1, c2, c; umjesto znakova d i k s tipkovnice učitaju
scanf("%c %c", &c1, &c2); znakovi k i d ?
c = c1;
while (c <= c2) Što će se dogoditi ako se umjesto znakova d
printf("%c", c++); i k s tipkovnice učitaju znakovi d i d ?
printf("\n");
return 0;
}

Rješenje 17. zadatka Vanjska petlja mijenja vrijednost varijable i od 'A'


#include <stdio.h> do 'U'. Na početku svakog retka se ispisuje
vrijednost varijable i (u formatu %c), a na kraju
int main(void) { retka ispisuje se slovo koje se u ASCII tablici
char i = 'A', j; nalazi "5 mjesta dalje" od slova koje se ispisalo
while (i <= 'U') {
printf("%c. ", i); na početku retka, te na samom kraju znak za
j = i + 'a' - 'A'; skok u novi red.
while (j < i + 'a' - 'A' + 6) {
printf("%c ", j++); Unutarnja petlja mijenja vrijednost varijable j od
} "male verzije" slova koje je ispisano na početku
printf(".%c\n", i++ + 5);
} retka, do slova koje se u ASCII tablici nalazi "6
return 0; mjesta dalje" od početnog malog slova.
}

Rješenje 18. zadatka Komentirajte:


#include <stdio.h> • što se dešava nakon
int main(void) { što se obavi naredba
int ai, brClanova = 0; kojom se ispisao član
printf("Upisite cijeli broj veci od 1: "); niza 2?
scanf("%d", &ai);
while (ai >= 2) { • što će se desiti ako
brClanova = brClanova + 1; korisnik kao prvi član
printf ("Clan a%d = %d\n", brClanova, ai); niza unese broj ≤ 1?
/* izracunaj sljedeci clan */
if (ai % 2 != 0) /* prethodni clan je neparan */
ai = 3 * ai + 1;
else /* prethodni clan je paran */
ai = ai / 2;
}
printf ("Ukupno %d clanova.\n", brClanova);
return 0;
}

11
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

10. vježbe uz predavanja


1. Dopunsko objašnjenje primjera s predavanja

Primjer: Napisati program koji će ispisivati prvih N Fibonaccijevih brojeva

Potrebno je uočiti da za računanje člana niza fi, treba poznavati članove niza fi-1 i fi-2. U
svakom koraku petlje u kojem se računa član niza fi, iskoristit će se članovi fi-1 i fi-2, a
zatim će se pripremiti "nove" vrijednosti za fi-1 i fi-2, tako što će se stari član fi-1 zapisati u
član fi-2, a netom izračunati član fi zapisati u član fi-1.

U programu se član fi čuva u varijabli f, član fi-1 u varijabli f1, a član fi-2 u varijabli f0.
Naredbom za selekciju osigurava se da se članovi počinju izračunavati prema opisanom
principu tek nakon što se obavi ispis članova niza f0 i f1.

Djelovanje programa može se lakše shvatiti ako se ispiše tablica koja pokazuje kako se
varijable mijenjaju u pojedinim koracima petlje. Prikazan je primjer za učitanu vrijednost
n==5:

f0 f1 f
i nakon koraka nakon koraka nakon koraka Ispis u koraku petlje
petlje petlje petlje
0 1 1 1 Fibonnaci (0) = 1
1 1 1 1 Fibonnaci (1) = 1
2 1 2 2 Fibonnaci (2) = 2
3 2 3 3 Fibonnaci (3) = 3
4 3 5 5 Fibonnaci (4) = 5
5 5 8 8 Fibonnaci (5) = 8

2. U varijablu tipa unsigned nt učitati nenegativni cijeli broj. Na zaslon ispisati binarni
sadržaj registra te varijable (binarne znamenke se moraju ispisati ispravnim
redoslijedom). Za izdvajanje bitova koristiti operaciju broj & 2n, pri čemu se n
mijenja od 31 do 0 (može se pretpostaviti da se za pohranu int tipa podatka koristi
32 bita). Uputa: vrijednost tipa podatka unsigned treba se učitati po formatu %u

Primjer: ako je korisnik upisao broj 18, na zaslon treba ispisati


00000000000000000000000000010010

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

3. S tipkovnice učitati cijeli broj n koji mora biti između 0 i 16 (uključivo s granicama).
Ako broj nije ispravan, ispisati odgovarajuću poruku. Nakon toga učitati n binarnih
znamenki i ispisati dekadski ekvivalent učitanog binarnog broja (ne primjenjuje se
tehnika dvojnog komplementa, pa je dekadski ekvivalent sigurno pozitivan broj).

Npr., ako je korisnik upisao


4
1
1
0
1
program treba ispisati 13.

Npr., ako je korisnik upisao


0
program treba ispisati 0.

Riješiti pomoću petlje s poznatim brojem ponavljanja. Je li bolje ovaj zadatak


rješavati pomoću petlje s poznatim brojem ponavljanja ili pomoću petlje s
ispitivanjem uvjeta na početku?

4. Isto kao prethodni zadatak, ali riješiti pomoću petlje s ispitivanjem uvjeta na kraju.
Zašto takva vrsta petlje nije pogodna za rješavanje ovog zadatka?

5. Načinite program koji će s tipkovnice učitati nenegativni cijeli broj iz intervala [0,
4294967295]. Učitani broj treba ispisati u oktalnom obliku. Npr. za učitani broj 250
treba ispisati 00000000372; za učitani broj 4294967295 treba ispisati 37777777777.
Zadatak riješite tako da grupe od po tri bita pretvarate u oktalne znamenke. Za
određivanje grupa po tri bita koristite operator posmaka u desno (za tri mjesta) i
bitovni operator &. Uputa: vrijednost tipa podatka unsigned treba se učitati po
formatu %u.

6. Isto kao prethodni zadatak, ali učitani dekadski broj treba pretvoriti u heksadekadski.

7. Napišite program koji učitava dva znaka te ispisuje sve znakove ASCII tablice koji se
nalaze između ta dva znaka. Npr., ako se učitaju znakovi d i k, program ispisuje
defghijk.

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

8. Načinite program koji će ispisati sljedeću tablicu:


A. a b c d e f .F
B. b c d e f g .G
C. c d e f g h .H
D. d e f g h i .I
... itd.
S. s t u v w x .X
T. t u v w x y .Y
U. u v w x y z .Z

Očekuje se da zadatak riješite pomoću dvije ugniježđene petlje s poznatim brojem


ponavljanja (for), a ne npr. ovako:

printf("A. a b c d e f .F\n");
printf("B. b c d e f g .G\n");
printf("C. c d e f g h .H\n");
printf("D. d e f g h i .I\n");
... itd.

9. Prepravite program iz prethodnog zadatka tako da se na mjestima gdje bi se ispisao


"mali" samoglasnik, umjesto toga ispiše znak '?'.

10. Načinite program za izračunavanje "m povrh n".

m! / ( n! · (m - n)! )

Vrijednosti za m i n učitati s tipkovnice uz kontrolu jesu li te vrijednosti ispravno


zadane (cijeli brojevi veći ili jednaki 0, m je veći ili jednak n).

11. Ispišite sve pitagorine trojke čiji su članovi veći od 0 i manji ili jednaki 100. Ispis treba
izgledati ovako (objašnjenje: oznaka 3^2 u sljedećem ispisu ima značenje 32):

1. trojka: 3^2 + 4^2 = 5^2


2. trojka: 4^2 + 3^2 = 5^2
3. trojka: 5^2 + 12^2 = 13^2
4. trojka: 6^2 + 8^2 = 10^2
5. trojka: 7^2 + 24^2 = 25^2
... itd.
101. trojka: 80^2 + 60^2 = 100^2
102. trojka: 84^2 + 13^2 = 85^2
103. trojka: 84^2 + 35^2 = 91^2
104. trojka: 96^2 + 28^2 = 100^2

Uputa: zadatak možete riješiti tako da pomoću tri ugniježđene petlje testirate svaku
kombinaciju 3 cijela broja: 1 1 1; 1 1 2; 1 1 3; ... 1 1 99; 1 1 100; 1 2 1; 1 2 2; ...; 1 2
100; 1 3 1; ... Ispišite samo one kombinacije 3 cijela broja koji zadovoljavaju "uvjet
pitagorine trojke".

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

Rješenja

Rješenje 2. zadatka
#include <stdio.h>
#include <math.h>
int main (void) {
unsigned int broj, dva_na_ntu;
int n;
scanf("%u", &broj);
printf("Upisali ste broj %u\n", broj);
for (n = 31; n >= 0; --n) {
dva_na_ntu = (unsigned int)pow(2, n);
/* ako u (broj & dva_na_ntu) postoji bit razlicit od 0,
tada ce (broj & dva_na_ntu) biti razlicit od 0, tj. true */
printf("%d", broj & dva_na_ntu ? 1 : 0);
}
printf("\n");
return 0;
}

Petlja s poznatim brojem ponavljanja je najpogodnija za ovaj slučaj jer je u trenutku kad
petlja započinje poznato koliko puta se tijelo te petlje treba obaviti.

Rješenje 3. zadatka
#include <stdio.h>
int main (void) {
int n, i, znamenka, dekadski = 0;
scanf("%d", &n);
if (n < 0 || n > 16) {
printf("Upisali ste neispravan broj\n");
}
else {
for (i = 0; i < n; ++i) {
scanf("%d", &znamenka);
dekadski = dekadski*2 + znamenka;
}
printf("%d\n", dekadski);
}
return 0;
}

Petlja s poznatim brojem ponavljanja je najpogodnija za ovaj slučaj jer je u trenutku kad
petlja započinje poznato koliko puta se tijelo te petlje treba obaviti (uočite, to može biti i
"nula puta", npr. ako u ovom slučaju korisnik za vrijednost varijable n upiše nulu).

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

Rješenje 4. zadatka
#include <stdio.h>
int main (void) {
int n, znamenka, dekadski = 0;
scanf("%d", &n);
if (n < 0 || n > 16) {
printf("Upisali ste neispravan broj\n");
}
else {
if (n > 0) {
do {
scanf("%d", &znamenka);
dekadski = dekadski*2 + znamenka;
--n;
} while (n > 0);
}
printf("%d\n", dekadski);
}
return 0;
}

Petlja s ispitivanjem uvjeta na kraju nije pogodna za rješavanje ovog zadatka, jer je moguće da tijelo petlje
neće biti potrebno obaviti niti jednom (onda kada se za vrijednost varijable n učita 0). Zato je if naredbom
potrebno provjeriti treba li uopće započeti s obavljanjem petlje.

Rješenje 5. zadatka
#include <stdio.h>

int main(void) {
unsigned int a;
int i;
printf("Upisite nenegativni cijeli broj a: ");
scanf ("%u", &a); /* za unsigned se kod citanja koristi %u umjesto %d */
for (i = 10; i >= 0; --i) {
printf("%d", a >> 3*i & 0x7);
}
printf ("\n");
return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

Rješenje 6. zadatka
#include <stdio.h>

int main(void) {
unsigned int a;
int i, broj;
printf("Upisite nenegativni cijeli broj a: ");
scanf ("%u", &a);
for (i = 7; i >= 0; --i) {
broj = a >> 4*i & 0xF;
if (broj <= 9) {
printf("%d", broj);
/* ili printf("%c", broj + '0'); */
}
else {
printf("%c", broj - 10 + 'A');
}
}
printf ("\n");
return 0;
}

Rješenje 7. zadatka
#include <stdio.h>

int main(void) {
char c1, c2;
char i;
scanf("%c %c", &c1, &c2);
for (i = c1; i <= c2; ++i) Komentirajte: što će se dogoditi
printf("%c", i);
printf("\n"); ako se učitaju znakovi k i d
return 0;
}

Rješenje 8. zadatka
#include <stdio.h>

int main(void) {
char i, j;
for (i = 'A'; i <= 'U'; ++i) {
printf("%c. ", i);
for (j = i + 32; j < i + 32 + 6; ++j) {
printf("%c ", j);
}
printf(".%c\n", i + 5);
}
return 0;
}

Vanjska petlja mijenja vrijednost varijable i od 'A' do 'U'. Na početku svakog retka se ispisuje vrijednost varijable i
(naravno, u formatu %c), a na kraju retka ispisuje se slovo koje se u ASCII tablici nalazi "5 mjesta dalje" od slova koje se
ispisalo na početku retka.

Unutarnja petlja mijenja vrijednost varijable j od "male verzije" slova koje je ispisano na početku retka, do slova koje se u
ASCII tablici nalazi "6 mjesta dalje" od početnog malog slova.

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

Rješenje 9. zadatka
#include <stdio.h>

int main(void) {
char i, j;
for (i = 'A'; i <= 'U'; ++i) {
printf("%c. ", i);
for (j = i + 32; j < i + 32 + 6; ++j) {
printf("%c ", j=='a' || j=='e' || j=='i' || j=='o' || j=='u' ? '?' : j);
}
printf(".%c\n", i + 5);
}
return 0;
}

ili
for (j = i + 32; j < i + 32 + 6; ++j) {
if (j=='a' || j=='e' || j=='i' || j=='o' || j=='u')
printf("? ");
else
printf("%c ", j);
}

Rješenje 10. zadatka


#include <stdio.h>

int main(void) {
int m, n, i;
double brojnik, naziv1, naziv2, mpovrhn;

/* unos vrijednosti za m i n */
printf ("Unesite m i n:");
scanf ("%d %d", &m, &n);
if (m < 0 || n < 0 || m < n)
printf("brojevi su neispravno zadani\n");
else {
brojnik = 1;
for (i = 1; i <= m; ++i)
brojnik *= i;

naziv1 = 1;
for (i = 1; i <= n; ++i)
naziv1 *= i;

naziv2 = 1;
for (i = 1; i <= m-n; ++i)
naziv2 *= i;

mpovrhn = brojnik/(naziv1*naziv2);
printf("%d povrh %d iznosi = %g\n", m, n, mpovrhn);
}
return 0;
}

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 61

Rješenje 11. zadatka


#include <stdio.h>

int main(void) {
int i, j, k;
int n = 0;
for (i=1; i <= 100; ++i)
for (j=1; j <= 100; ++j)
for (k=1; k <= 100; ++k)
if (i*i + j*j == k*k) {
++n;
printf("%d. trojka: %d^2 + %d^2 = %d^2\n", n, i, j, k);
}
return 0;
}

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 89

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

11. vježbe uz predavanja


1. Napisati bolje rješenje (bez break i continue) zadatka sa 65. stranice predavanja.

2. Korisnik uzastopno upisuje cijele brojeve u intervalu [1, 9]. Za svaki učitani broj
ispisati broj riječima. Zanemariti brojeve koji su izvan dopuštenog intervala.
Učitavanje prekinuti kada se upiše broj nula. Naputak: za određivanje "naziva" broja
koristiti naredbu switch. Npr.
3
tri
7
sedam
77
zanemarujem
1
jedan
0

3. Korisnik uzastopno upisuje cijele brojeve u intervalu [1, 9]. Za svaki učitani broj
ispisati od kojih je sve brojeva iz tog intervala učitani broj manji. Zanemariti učitane
brojeve koji su izvan dopuštenog intervala. Učitavanje prekinuti kada se upiše broj
nula. Naputak: koristiti naredbu switch s "propadanjem po labelama". Npr.
3
manji je od 4
manji je od 5
manji je od 6
manji je od 7
manji je od 8
manji je od 9
77
zanemarujem
9
8
manji je od 9
0

4. Napišite program koji će ispisati prvih 25 prostih brojeva (uzimajući u obzir definiciju
prema kojoj broj 1 nije primarni broj).

5. Napišite program koji će ispisati sve proste brojeve iz intervala [1000, 10000].

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 89

6. S tipkovnice učitavati cijele brojeve dok god se naizmjence upisuje jedan pozitivan,
jedan negativan, jedan pozitivan broj, itd. Upisivanje pozitivnog broja nakon
pozitivnog ili upisivanje negativnog broja nakon negativnog ili upisivanje nule smatra
se pogreškom. U slučaju takve pogreške program ispisuje sumu svih do tada
ispravno upisanih brojeva (upisanih prije pogreške) i prekida se njegovo izvršavanje.
Prvi broj koji se upiše s tipkovnice može biti ili pozitivan ili negativan.

7. Napišite program za izračunavanje n! koji za realizaciju "petlje" koristi goto naredbu.


Napomena: ovaj zadatak služi za vježbu, a ne za demonstraciju načina na koji bi
trebalo rješavati zadatke s programskim petljama! Programske petlje se u pravilu ne
smiju realizirati pomoću naredbe goto!

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 89

Rješenja

Rješenje 1. zadatka
#include <stdio.h>

int main(void) {
int x;
do {
printf ("Upisite broj :\n");
scanf("%d", &x);
if (x > 100)
printf("Zanemarujem vrijednost\n");
else if (x >= 0)
printf ("Upisani broj je : %d\n", x);
else
printf("Nedopustena vrijednost\n");
} while (x > 0);
return 0;
}

Rješenje 2. zadatka
#include <stdio.h>

int main(void) {
int broj;
do {
scanf("%d", &broj);
if (broj != 0)
switch (broj) {
case 1: printf("jedan\n");
break;
case 2: printf("dva\n");
break;
case 3: printf("tri\n");
break;
case 4: printf("cetiri\n");
break;
case 5: printf("pet\n");
break;
case 6: printf("sest\n");
break;
case 7: printf("sedam\n");
break;
case 8: printf("osam\n");
break;
case 9: printf("devet\n");
break;
default: printf("Zanemarujem\n");
break;
}
} while (broj != 0);
return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 89

Rješenje 3. zadatka
#include <stdio.h>
int main(void) {
int broj;
do {
scanf("%d", &broj);
if (broj != 0)
switch (broj) {
case 1: printf("manji je od 2\n");
case 2: printf("manji je od 3\n");
case 3: printf("manji je od 4\n");
case 4: printf("manji je od 5\n");
case 5: printf("manji je od 6\n");
case 6: printf("manji je od 7\n");
case 7: printf("manji je od 8\n");
case 8: printf("manji je od 9\n");
case 9: break;
default: printf("Zanemarujem\n");
break;
}
} while (broj != 0);
return 0;
}

Rješenje 4. zadatka
#include <stdio.h>
#include <math.h>

int main (void) {


int testBroj = 1, pronadjenoProstih = 0;
int i, jestProst;
while (pronadjenoProstih < 25) {
++testBroj;
/* hipoteza: testBroj jest prost*/
jestProst = 1; /* true */
for ( i = 2; i <= pow(testBroj, 0.5); ++i)
if( testBroj % i == 0 ) {
/* oborena je hipoteza da je testBroj prost */
jestProst = 0; /* false */
break;
}
if (jestProst)
printf("%d. %d\n", ++pronadjenoProstih, testBroj);
}
return 0;
}

ili

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 89

#include <stdio.h>
#include <math.h>

int main (void) {


int testBroj = 1, pronadjenoProstih = 0;
int i;
while (pronadjenoProstih < 25) {
++testBroj;
i = 2;
while ( i <= pow(testBroj, 0.5) && testBroj % i != 0)
++i;
if( i > pow(testBroj, 0.5) )
/* petlja je uspjela proci kroz sve djeljitelje <= pow(testBroj, 0.5) */
printf("%d. %d\n", ++pronadjenoProstih, testBroj);
}
return 0;
}

Rješenje 5. zadatka
#include <stdio.h>
#include <math.h>

int main (void) {


int testBroj;
int i, jestProst;
for (testBroj = 1000; testBroj <= 10000; ++testBroj) {
/* hipoteza: testBroj jest prost*/
jestProst = 1; /* true */
for ( i = 2; i <= pow(testBroj, 0.5); ++i)
if( testBroj % i == 0 ) {
/* oborena je hipoteza da je testBroj prost */
jestProst = 0; /* false */
break;
}
if (jestProst)
printf("%d\n", testBroj);
}
return 0;
}

Rješenje 6. zadatka
#include <stdio.h>

int main(void) {
int suma = 0;
int gotovo = 0;
int prethodni = 0, novi;
do {
scanf("%d", &novi);
if (prethodni == 0 && novi != 0 || prethodni * novi < 0) {
suma += novi;
prethodni = novi;
}
else {
gotovo = 1;
}
} while (!gotovo);

printf("suma = %d\n", suma);


return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 05-KontrolneNaredbe.pdf - do stranice: 89

Rješenje 7. zadatka
#include <stdio.h>

int main(void) {
int n, i = 1;
double f;
scanf("%d", &n);
f = 1.;
opet:
f *= i;
++i;
if (i <= n) goto opet;
printf("%d! = %f\n", n, f);
return 0;
}

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

13. vježbe uz predavanja


1. S tipkovnice, redak po redak, učitati članove cjelobrojne matrice dimenzija 4 retka i 3
stupca. Ispisati matricu (u obliku dvodimenzijske tablice), te aritmetičku sredinu
vrijednosti članova matrice.

2. Definirati i inicijalizirati trodimenzijsko cjelobrojno polje s dimenzijama koje sami


odaberite (npr. 3, 4, 5). Koristiti inicijalizator s vitičastim zagradama (svaki sloj unutar
svojih vitičastih zagrada, svaki redak sloja unutar svojih vitičastih zagrada). Ispišite
polje po slojevima, u sljedećem obliku:
x x x x x
x x x x x
x x x x x
x x x x x

x x x x x
x x x x x
x x x x x
x x x x x

x x x x x
x x x x x
x x x x x
x x x x x

3. Korisnik odabire dimenzije matrice koju želi učitati (brRed, brStup). Broj redaka koje
korisnik može učitati ne smije biti manji od 1 niti veći od 20, a broj stupaca ne smije
biti manji od 1 niti veći od 10. U matricu treba učitati vrijednosti elemenata i ispisati
matricu. Nakon toga treba retke matrice posmaknuti prema gore: redak i dobiva
vrijednosti iz retka i+1, a posljednji redak matrice dobiva vrijednosti 0-tog retka. Npr.
ako je korisnik učitao: brRed=4, brStup=5, te elemente matrice:
1 2 3 4 5
2 1 3 7 1
8 1 1 4 3
4 2 2 3 3
nakon posmaka redaka, matrica treba izgledati ovako:
2 1 3 7 1
8 1 1 4 3
4 2 2 3 3
1 2 3 4 5

Nakon obavljenog posmaka redaka, ispisati novu matricu. Zadatak riješite bez
upotrebe pomoćnog polja.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

4. Korisnik odabire dimenzije matrice koju želi učitati (brRed, brStup). Broj redaka koje
korisnik može učitati ne smije biti manji od 1 niti veći od 4, a broj stupaca ne smije biti
manji od 1 niti veći od 5. S tipkovnice se učitaju vrijednosti elemenata matrice. Nakon
toga u elemente u retku brRed zapisati sume stupaca, u elemente u stupcu brStup
zapisati sume redaka, a u element (brRed,brStup) sumu svih elemenata matrice.
Ispisati dobivenu matricu. Npr. ako je korisnik učitao:
brRed=4, brStup=5, te elemente matrice:
1 2 3 4 5
2 1 3 7 1
8 1 1 4 3
4 2 2 3 3
Nakon izračuna, ispis matrice izgleda ovako:
1 2 3 4 5 15
2 1 3 7 1 14
8 1 1 4 3 17
4 2 2 3 3 14
15 6 9 18 12 60
Zadatak riješite bez upotrebe pomoćnog polja.

5. S tipkovnice upisati cijeli broj n iz intervala [5, 10]. Generirati kvadratnu matricu
dimenzija n x n kojoj su svi elementi glavne i sporedne dijagonale, elementi prvog i
zadnjeg retka, te prvog i zadnjeg stupca postavljeni na vrijednost 1, a svi ostali
elementi matrice postavljeni na vrijednost 8. Generiranu matricu ispisati na zaslon.
Npr. ako korisnik preko tipkovnice za n unese broj 7, na zaslon treba ispisati:

1 1 1 1 1 1 1
1 1 8 8 8 1 1
1 8 1 8 1 8 1
1 8 8 1 8 8 1
1 8 1 8 1 8 1
1 1 8 8 8 1 1
1 1 1 1 1 1 1

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

6. S tipkovnice, uz kontrolu, učitati broj redaka m i broj stupaca n cjelobrojne matrice.


Broj redaka mora biti iz intervala [3, 6], a broj stupaca iz intervala [4, 10]. Nakon toga
učitati članove matrice. Jednodimenzijsko polje nps napuniti vrijednostima najmanjih
članova matrice u pojedinim stupcima, a jednodimenzijsko polje npr napuniti
vrijednostima najmanjih članova matrice u pojedinim retcima. Ispisati učitanu matricu,
a zatim članove polja nps i članove polja npr.

Primjer: ako je učitana matrica (m=4, n=5)


1 2 3 4 5
2 0 3 7 2
8 1 5 4 3
4 2 2 9 3
program treba ispisati:

matrica:
1 2 3 4 5
2 0 3 7 2
8 1 5 4 3
4 2 2 9 3

polje nps:
1 0 2 4 2

polje npr:
1 0 1 2

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

Rješenja

Rješenje 1. zadatka

#include <stdio.h>

#define MAXRED 4
#define MAXSTUP 3

int main(void) {
int i, j, suma = 0;
int mat[MAXRED][MAXSTUP];
for (i = 0; i < MAXRED; ++i) {
/* u i-tom retku obavi sljedece */
for (j = 0; j < MAXSTUP; ++j) {
/* u j-tom stupcu i-tog retka obavi sljedece */
printf("Upisite clan matrice [%d][%d]->", i, j);
scanf("%d", &mat[i][j]);
suma+=mat[i][j];
}
}
for (i = 0; i < MAXRED; ++i) {
for (j = 0; j < MAXSTUP; ++j) {
printf("%5d", mat[i][j]);
}
printf("\n");
}
printf("Aritm. sredina je %f\n", (float)suma/(MAXRED*MAXSTUP));
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

Rješenje 2. zadatka

#include <stdio.h>

#define MAXSLOJ 3
#define MAXRED 4
#define MAXSTUP 5

int main(void) {
int i, j, k;
int tridim[MAXSLOJ][MAXRED][MAXSTUP] =
{
{ { 101, 102, 103, 104, 105},
{ 106, 107, 108, 109, 110},
{ 111, 112, 113, 114, 115},
{ 116, 117, 118, 119, 120 }
},
{ { 201, 202, 203, 204, 205},
{ 206, 207, 208, 209, 210},
{ 211, 212, 213, 214, 215},
{ 216, 217, 218, 219, 220 }
},
{ { 301, 302, 303, 304, 305},
{ 306, 307, 308, 309, 310},
{ 311, 312, 313, 314, 315},
{ 316, 317, 318, 319, 320 }
}
};

for (i = 0; i < MAXSLOJ; ++i) {


for (j = 0; j < MAXRED; ++j) {
for (k = 0; k < MAXSTUP; ++k)
printf("%d ", tridim[i][j][k]);
printf("\n");
}
printf("\n");
}

return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

Rješenje 3. zadatka

#include <stdio.h>

#define MAXRED 20
#define MAXSTUP 10

int main(void) {
int i, j, m, n, pom;
int mat[MAXRED][MAXSTUP];
do {
printf("Upisite m i n:");
scanf("%d %d", &m, &n);
} while (m < 1 || m > 20 || n < 1 || n > 10);

printf("Upisite clanove matrice po retcima:");

for (i = 0; i < m; ++i)


for (j = 0; j < n; ++j)
scanf("%d", &mat[i][j]);

for (j = 0; j < n; ++j) {


/* u svakom stupcu j obavljaj sljedece */
pom = mat[0][j]; /* spasi j-ti clan iz 0-tog retka */

for (i = 0; i < m-1; ++i)


/* clan u i-tom retku postavi na clan iz (i+1)-vog retka */
mat[i][j] = mat[i+1][j];

mat[m-1][j] = pom; /* u zadnji redak stavi spaseni j-ti clan iz 0-tog retka */
}

printf("\n\nIspis nove matrice:\n");

for (i = 0; i < m; ++i) {


for (j = 0; j < n; ++j)
printf("%d ", mat[i][j]);
printf("\n");
}

return 0;
}

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

Rješenje 4. zadatka

#include <stdio.h>

#define MAXRED 4
#define MAXSTUP 5

int main(void) {
int i, j, m, n;
int mat[MAXRED+1][MAXSTUP+1] = {0};
/* dimenzije su uvecane za 1 jer treba osigurati
prostor za dodatni redak i stupac */
do {
printf("Upisite m i n:");
scanf("%d %d", &m, &n);
} while (m < 1 || m > MAXRED || n < 1 || n > MAXSTUP);

printf("Upisite clanove matrice po retcima:");

for (i = 0; i < m; ++i)


for (j = 0; j < n; ++j)
scanf("%d", &mat[i][j]);

/* kontrolni ispis ucitane matrice */


for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j)
printf("%4d ", mat[i][j]);
printf("\n");
}

/* proci cemo kroz sve elemente i svaki element


pribrojiti u odgovarajuce elemente u dodatnom retku
i dodatnom stupcu. Clanovi matrice su inicijalizirani
na 0 pri definiciji (inace bi trebalo clanove retka m i
stupca n prvo postaviti na 0) */

for (i = 0; i < m; ++i)


for (j = 0; j < n; ++j) {
/* dodaj ga u zbroj odgovarajuceg retka */
mat[i][n] += mat[i][j];
/* dodaj ga u zbroj odgovarajuceg stupca */
mat[m][j] += mat[i][j];
/* dodaj ga u zbroj svih elemenata matrice */
mat[m][n] += mat[i][j];
}
printf("\n\nIspis nove matrice:\n");
for (i = 0; i <= m; ++i) {
for (j = 0; j <= n; ++j)
printf("%4d ", mat[i][j]);
printf("\n");
}

return 0;

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

Rješenje 5. zadatka

#include <stdio.h>
#define MAXDIM 10

int main(void) {
int i, j, n;
int mat[MAXDIM][MAXDIM];

/* ucitavanje n */
do {
printf("Upisite n:");
scanf("%d", &n);
} while (n < 1 || n > MAXDIM);

/* generiranje matrice */
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if (i == j || i == n-1-j || j == 0 || i == 0 || j == n-1 || i == n-1)
mat[i][j] = 1;
else
mat[i][j] = 8;

/* ispis matrice */
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j)
printf("%d ", mat[i][j]);
printf("\n");
}

return 0;
}

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 06-Polja.pdf - do stranice: 81

Rješenje 6. zadatka
#include <stdio.h>

#define MAXRED 6
#define MAXSTUP 10

int main(void) {
int i, j, m, n;
int mat[MAXRED][MAXSTUP];
int nps[MAXSTUP], npr[MAXRED];

do {
printf("Upisite m[3,6] i n[4,10]: ");
scanf("%d %d", &m, &n);
} while (m < 3 || m > 6 || n < 4 || n > 10);

printf("Upisite clanove matrice po retcima: ");

for (i = 0; i < m; ++i)


for (j = 0; j < n; ++j)
scanf("%d", &mat[i][j]);

/* odredi najmanji clan u svakom stupcu */


for (j = 0; j < n; ++j) {
/* u svakom stupcu j obavi sljedece */
nps[j] = mat[0][j]; /* pretpostavi da je prvi clan u j-tom stupcu
najmanji clan tog stupca */
for (i = 1; i < m; ++i)
if (mat[i][j] < nps[j])
nps[j] = mat[i][j];
}

/* odredi najmanji clan u svakom retku */


for (i = 0; i < m; ++i) {
/* u svakom retku i obavi sljedece */
npr[i] = mat[i][0]; /* pretpostavi da je prvi clan u i-tom retku
najmanji clan tog retka */
for (j = 1; j < n; ++j)
if (mat[i][j] < npr[i])
npr[i] = mat[i][j];
}

printf("\nmatrica:\n");
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j)
printf("%4d", mat[i][j]);
printf("\n");
}

printf("\npolje nps:\n");
for (j = 0; j < n; ++j)
printf("%4d", nps[j]);
printf("\n");

printf("\npolje npr:\n");
for (i = 0; i < m; ++i)
printf("%4d", npr[i]);
printf("\n");

return 0;
}

9
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

14. vježbe uz predavanja

1. Što će se ispisati sljedećim programom:

#include <stdio.h>
int main (void) {
int a = 2, x = 10;
int *p = &a;
x += *p * 3;
printf ("%d %d\n", *p, x);
return 0;
}

2. Što će se ispisati sljedećim programom:

#include <stdio.h>
int main (void) {
int a = 10, b = 20, *c = &a, *d = &b;
c = &b;
d = &a;
*c = *d + 5;
*d = *c + 3;
printf ("%d %d %d %d\n", a, b, *c+1, *d+1);
return 0;
}

3. Što je neispravno u sljedećem programu:


#include <stdio.h>
int main (void) {
int a, b, *c = &a;
short x, y = 10, *z = &x;
c = &b;
z = &y;
*c = 20;
*z = 30;
c = &y;
printf ("%d %d\n", *c, *z);
return 0;
}

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

4. Što će se ispisati sljedećim programom:

#include <stdio.h>
int main (void) {
int polje[4] = {3, 6, 9, 12};
int *p1, *p2, *p3;
p1 = &polje[0];
p2 = &polje[1];
p3 = &polje[3];
printf ("%d %d %d %d %d\n", *p1, *p2, *p3, *(p2 - 1), *p2 - 1);
return 0;
}

5. Što će se ispisati sljedećim programom:

#include <stdio.h>
int main (void) {
int polje[4][2] = {3, 6, 9, 12, 15, 18, 21, 24};
int *p1, *p2, *p3;
p1 = &polje[0][0];
p2 = &polje[1][0];
p3 = &polje[3][1];
printf ("%d %d %d %d %d\n", *p1, *p2, *p3, *(p1 + 1), *p1 + 1);
return 0;
}

6. Što će se ispisati sljedećim programom:

#include <stdio.h>
int main (void) {
int polje[3][2] = {3, 6, 9, 12, 15, 18};
int *p = polje[0];
int i1 = *p;
int i2 = (*p)++;
int i3 = *p;
int i4 = *++p;
int i5 = *p;
int i6 = *p++;
int i7 = *(p-1);
int i8 = *p;
printf ("%d %d %d %d %d %d %d %d\n", i1, i2, i3, i4, i5, i6, i7, i8);
return 0;
}

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

7. Što će se ispisati sljedećim programom:

#include <stdio.h>
int main (void) {
int polje[3][2] = {1, 2, 3, 4, 5, 6};
int *p = &polje[1][1], i = 5;
printf ("%d\n", *(p + --i));
printf ("%d\n", *--p + --i);
return 0;
}

8. Izrazima zamijenite upitnike u printf naredbi kojom će se ispisati članovi glavne dijagonale
matrice x. Članovima matrice mora se pristupati preko pokazivača p:

#include <stdio.h>
int main(void) {
int x[4][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
int *p = &x[0][0];
printf("%d %d %d %d\n", ?, ?, ?, ?);
return 0;
}

9. S tipkovnice upisati cijeli broj n iz intervala [5, 10]. Generirati kvadratnu matricu dimenzija
n x n kojoj su svi elementi glavne i sporedne dijagonale, elementi prvog i zadnjeg retka, te
prvog i zadnjeg stupca postavljeni na vrijednost 1, a svi ostali elementi matrice postavljeni na
vrijednost 8. Generiranu matricu ispisati na zaslon. Elementima matrice pristupati
isključivo pomoću pokazivača. Npr. ako korisnik preko tipkovnice za n unese broj 7, na
zaslon treba ispisati:

1 1 1 1 1 1 1
1 1 8 8 8 1 1
1 8 1 8 1 8 1
1 8 8 1 8 8 1
1 8 1 8 1 8 1
1 1 8 8 8 1 1
1 1 1 1 1 1 1

Ovaj zadatak se od zadatka br. 5 iz prethodne vježbe razlikuje jedino u tome što se
elementima matrice mora pristupati pomoću pokazivača.

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

10. S tipkovnice, uz kontrolu, učitati broj redaka m i broj stupaca n cjelobrojne matrice. Broj
redaka mora biti iz intervala [3, 6], a broj stupaca iz intervala [4, 10]. Nakon toga učitati
članove matrice. Zatim jednodimenzijsko polje nps napuniti vrijednostima najmanjih članova
matrice u pojedinim stupcima, a jednodimenzijsko polje npr napuniti vrijednostima najmanjih
članova matrice u pojedinim retcima. Ispisati učitanu matricu, a zatim članove polja nps i
članove polja npr. Članovima svih polja mora se pristupati isključivo preko pokazivača.

Primjer: ako je učitana matrica (m=4, n=5)


1 2 3 4 5
2 0 3 7 2
8 1 5 4 3
4 2 2 9 3
program treba ispisati:

matrica:
1 2 3 4 5
2 0 3 7 2
8 1 5 4 3
4 2 2 9 3

polje nps:
1 0 2 4 2

polje npr:
1 0 1 2

Ovaj zadatak se od zadatka br. 6 iz prethodne vježbe razlikuje jedino u tome što se elementima
matrice mora pristupati pomoću pokazivača.

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

Rješenja

Rješenje 3. zadatka

Neispravna je naredba
c = &y;
c je "pokazivač na short", a pridružuje mu se adresa varijable koja je tipa int.

Rješenje 8. zadatka
Kad bi bilo dopušteno članovima polja pristupati pomoću indeksa, tada bi se napisalo:
printf("%d %d %d %d\n", x[0][0], x[1][1], x[2][2], x[3][3]);

Članovima polja se također može pristupiti preko pokazivača. Pokazivač p sadrži adresu
elementa x[0][0]. Do adrese elementa x[1][1] dolazimo tako da preskočimo sve
elemente u prvom retku (ima ih 1*4) i jedan element iz drugog retka, tj. adresi p pribrojimo
1*4+1. Do adrese elementa x[2][2] dolazimo tako da preskočimo sve elemente u prva
dva retka (ima ih 2*4) i dva elementa iz trećeg retka, tj. adresi p pribrojimo 2*4+2. Itd.
printf("%d %d %d %d\n",
*(p+4*0+0), *(p+4*1+1),
*(p+4*2+2), *(p+4*3+3));
ili
printf("%d %d %d %d\n", *(p), *(p+5), *(p+10), *(p+15));

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

Rješenje 9. zadatka

#include <stdio.h>
#define MAXDIM 10

int main(void) {
int i, j, n;
int mat[MAXDIM][MAXDIM];
int *p = &mat[0][0]; /* ili: int *p = mat[0] */

/* ucitavanje n */
do {
printf("Upisite n:");
scanf("%d", &n);
} while (n < 1 || n > MAXDIM);

/* generiranje matrice */
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if (i == j || i == n-1-j || j == 0 || i == 0 || j == n-1 || i == n-1)
*(p + i*MAXDIM + j) = 1;
else
*(p + i*MAXDIM + j) = 8;

/* ispis matrice */
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j)
printf("%d ", *(p + i*MAXDIM + j));
printf("\n");
}

return 0;
}

Česta pogreška pri rješavanju ovog zadatka (i sličnih zadataka) jest da se članu matrice
mat[i][j] pokuša pristupiti pomoću izraza
*(p + i*n + j)
To je pogrešno! Redak matrice mat sadrži MAXDIM članova, a ne n članova. Izraz bi bio
dobar jedino u slučaju kada korisnik za n upiše vrijednost jednaku MAXDIM.

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

Rješenje 10. zadatka

#include <stdio.h>

#define MAXRED 6
#define MAXSTUP 10

int main(void) {
int i, j, m, n;
int mat[MAXRED][MAXSTUP], *pmat = &mat[0][0];
int nps[MAXSTUP], *pnps = &nps[0], npr[MAXRED], *pnpr = &npr[0];

do {
printf("Upisite m[3,6] i n[4,10]: ");
scanf("%d %d", &m, &n);
} while (m < 3 || m > 6 || n < 4 || n > 10);

printf("Upisite clanove matrice po retcima: ");

for (i = 0; i < m; ++i)


for (j = 0; j < n; ++j)
scanf("%d", pmat + i*MAXSTUP+j);

/* odredi najmanji clan u svakom stupcu */


for (j = 0; j < n; ++j) {
/* u svakom stupcu j obavi sljedece */

/* pretpostavi da je prvi clan u j-tom stupcu najmanji clan tog stupca */


*(pnps + j) = *(pmat + 0*MAXSTUP+j);

for (i = 1; i < m; ++i)


if (*(pmat + i*MAXSTUP+j) < *(pnps + j))
*(pnps + j) = *(pmat + i*MAXSTUP+j);
}

/* odredi najmanji clan u svakom retku */


for (i = 0; i < m; ++i) {
/* u svakom retku i obavi sljedece */

/* pretpostavi da je prvi clan u i-tom retku najmanji clan tog retka */


*(pnpr + i) = *(pmat + i*MAXSTUP+0);
for (j = 1; j < n; ++j)
if (*(pmat + i*MAXSTUP+j) < *(pnpr + i))
*(pnpr + i) = *(pmat + i*MAXSTUP+j);
}

printf("\nmatrica:\n");
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j)
printf("%4d", *(pmat + i*MAXSTUP+j));
printf("\n");
}
printf("\npolje nps:\n");
for (j = 0; j < n; ++j)
printf("%4d", *(pnps + j));
printf("\n");

printf("\npolje npr:\n");
for (i = 0; i < m; ++i)
printf("%4d", *(pnpr + i));
printf("\n");

return 0;
}

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 07-Pokazivaci.pdf - do stranice: 23

Česte pogreške pri rješavanju ovog zadatka (i sličnih zadataka) jesu da se članu matrice
mat[i][j] pokuša pristupiti pomoću izraza
*(pmat + i*n + j)

ili
*(pmat + i*MAXRED + j)

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 25

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

15. vježbe uz predavanja

U svim zadacima u kojima se traži definiranje funkcije, treba napisati odgovarajući glavni
program (tj. funkciju main) u kojem ćete po potrebi definirati stvarne argumente, s tipkovnice
učitati njihove vrijednosti, pozvati funkciju i ispisati rezultat.
2
1. Napisati funkciju tipa int koja za zadani cijeli broj n (formalni argument je tipa int) vraća n .
2. Provjerite hoćete li dobiti ispravan rezultat kada pomoću funkcije iz 1. zadatka pokušate
izračunati 500002. Objasnite što se dogodilo.
3. Provjerite hoćete li dobiti ispravan rezultat kada pomoću funkcije iz 1. zadatka pokušate
2 2
izračunati 2.0 i 3.5 . Objasnite što se dogodilo.
4. Napisati funkciju tipa double koja za zadani cijeli broj n (formalni argument je tipa int) vraća
n2. Provjerite hoćete li dobiti ispravan rezultat kada s tom funkcijom pokušate izračunati 22,
500002.
5. Koji je tip funkcije i što vraća funkcija f:
f (void) {
;
;
}
6. Napisati funkciju koja na zaslon ispisuje sve pozitivne parne brojeve između 2 i zadanog
cijelog broja n (u obliku 2 4 6 8 ...). Kojeg je ta funkcija tipa?
7. Napisati funkciju koja na zaslon ispisuje tablicu množenja za zadanih m redaka i n stupaca.
Za ispis brojeva koristite format %5d. Npr. ispis za tablicu množenja od 3 retka i 4 stupca je:
1 2 3 4
1 1 2 3 4
2 2 4 6 8
3 3 6 9 12
8. Napisati funkciju tipa double naziva nfakt za računanje n!. Napisati funkciju tipa double
naziva mpovrhn za računanje m povrh n koja će za izračunavanje koristiti funkciju nfakt. U
glavnom programu (main funkciji) učitavati s tipkovnice cijele brojeve m i n dok god su
ispravno zadani, te izračunavati i ispisivati m povrh n. Prekinuti program kad se zadaju
pogrešne vrijednosti za m i n.
9. Napisati funkciju koja na zaslon ispisuje prvih 20 Fibonaccijevih brojeva (svaki član niza u
novi redak na zaslonu).
10. Napisati funkciju koja na zaslon ispisuje prvih n (n se zadaje kao argument funkcije)
Fibonaccijevih brojeva (svaki član niza u novi redak na zaslonu).
11. Napisati funkciju tipa int koja vraća broj bajtova koji se koriste za pohranu podatka tipa int.
Napomena: različiti prevodioci koriste različiti broj bajtova, te se funkcija koja koristi sljedeću
naredbu return ne može smatrati ispravnom:

return 4;

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 25

Rješenja

Rješenje 1. zadatka

#include <stdio.h>

int kvadrat(int n) {
int kv;
kv = n*n;
return kv;
}

int main(void) {
int arg, rez;
printf("Upisite cijeli broj: ");
scanf("%d", &arg);
rez = kvadrat(arg);
printf("%d na kvadrat jest %d\n", arg, rez);
return 0;
}

Rješenje 2. zadatka

Ukoliko korisnik unese 50000, u varijablu kv neće se pohraniti ispravan rezultat (2500000000 se
ne može pohraniti u varijablu kv jer se radi o broju koji prelazi dopušteni raspon za tip int).
Funkcija će vratiti broj -1794967296

Rješenje 3. zadatka

Koristi se ista funkcija, ali drugačiji glavni program, kojim se s tipkovnice učitava realni broj.
int main(void) {
float arg;
int rez;
printf("Upisite realni broj: ");
scanf("%f", &arg);
rez = kvadrat(arg);
printf("%f na kvadrat jest %d\n", arg, rez);

return 0;
}
Ukoliko korisnik unese 2.0, prilikom prijenosa stvarnog argumenta u formalni, obavit će se
konverzija u cijeli broj 2. Funkcija će vratiti cijeli broj 4.

Ukoliko korisnik unese 3.5, prilikom prijenosa stvarnog argumenta u formalni, obavit će se
konverzija u cijeli broj 3. Funkcija će vratiti cijeli broj 9.

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 25

Rješenje 4. zadatka

#include <stdio.h>

double kvadrat(int n) {
double kv;
kv = (double)n*n;
return kv;
}

int main(void) {
int arg;
double rez;
printf("Upisite cijeli broj: ");
scanf("%d", &arg);
rez = kvadrat(arg);
printf("%d na kvadrat jest %f\n", arg, rez);
return 0;
}

Ovdje je eksplicitna konverzija u tip double stavljena radi toga da se množenje obavi u
double domeni. Inače, opet bi se dogodilo da se pri računanju 500002 dobije negativan
cijeli broj, koji bi se kod pridruživanja varijabli kv pretvorio u realni broj (ali prekasno, jer bi
se kao rezultat dobio negativan realni broj). Testirajte: izbacite cast operator (double) iz
funkcije kvadrat.

Rješenje 5. zadatka

Funkcija je tipa int, a rezultat funkcije je nedefiniran, odnosno vraća "smeće" (vrijednost
koju nije moguće unaprijed odrediti).

Rješenje 6. zadatka

#include <stdio.h>

void ispisiParne (int n) {


int i;
for (i = 2; i <= n; i += 2)
printf("%d ", i);
}

int main(void) {
int arg;
printf("Upisite cijeli broj: ");
scanf("%d", &arg);
ispisiParne(arg);
return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 25

Rješenje 7. zadatka

#include <stdio.h>

void ispisiTablicuMnozenja (int redaka, int stupaca) {


int i, j;
/* ispisi prvi red: "zaglavlje" tablice */
printf(" ");
for (j = 1; j <= stupaca; ++j)
printf("%5d", j);
printf("\n");

/* ispisi tablicu */
for (i = 1; i <= redaka; ++i) {
/* na pocetku svakog retka ispisi redni broj retka */
printf("%5d", i);

for (j = 1; j <= stupaca; ++j)


printf("%5d", i*j);
/* na kraju svakog retka tablice, skoci u novi redak na zaslonu */
printf("\n");
}
}

int main(void) {
int m, n;
printf("Upisite broj redaka: ");
scanf("%d", &m);
printf("Upisite broj stupaca: ");
scanf("%d", &n);
printf("\nTABLICA MNOZENJA:\n");
ispisiTablicuMnozenja(m, n);
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 25

Rješenje 8. zadatka

#include <stdio.h>

double nfakt (int n) {


int i;
double f;
for (f = 1, i = 1; i <= n; ++i) {
f *= i;
}
return f;
}

double mpovrhn (int m, int n) {


return nfakt(m) / ( nfakt(n) * nfakt(m-n) );
}

int main(void) {
int m, n, mn;
do {
printf ("Upisite m i n: ");
scanf("%d %d", &m, &n);
if (m >= 0 && n >= 0 && m >= n) {
mn = mpovrhn(m, n);
printf("%d povrh %d je: %d\n\n", m, n, mn);
}
} while (m >= 0 && n >= 0 && m >= n);
return 0;
}

Rješenje 9. zadatka

#include <stdio.h>

void fibonacci (void) {


int i, f0 = 1, f1 = 1, f = 1;
for (i = 0; i < 20; ++i) {
if (i > 1) {
f = f1 + f0;
f0 = f1;
f1 = f;
}
printf ("%d\n", f);
}
}

int main(void) {
fibonacci();
return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 25

Rješenje 9. zadatka - alternativno

U funkciji je definirano polje veličine 20 članova. Tako se moglo postupiti zato jer je zadano
da treba ispisati točno 20 članova niza.
#include <stdio.h>

void fibonacci (void) {


int i, fbroj[20];
fbroj[0] = fbroj[1] = 1;

for (i = 2; i < 20; ++i)


fbroj[i] = fbroj[i-1] + fbroj[i-2];
for (i = 0; i < 20; ++i)
printf ("%d\n", fbroj[i]);
}

int main(void) {
fibonacci();
return 0;
}

Rješenje 10. zadatka

#include <stdio.h>

void fibonacci (int n) {


int i, f0 = 1, f1 = 1, f = 1;
for (i = 0; i < n; ++i) {
if (i > 1) {
f = f1 + f0;
f0 = f1;
f1 = f;
}
printf ("%d\n", f);
}
}

int main(void) {
fibonacci(30);
return 0;
}

Uočiti: zadatak se ne može riješiti pomoću polja, kao prethodni zadatak, jer se ne zna
unaprijed koliko bi polje u funkciji trebalo biti veliko. Argument n se ne može pri definiciji
polja koristiti kao dimenzija polja jer dimenzija polja pri definiciji mora biti cjelobrojni
konstantni izraz. Dakle, nije dopušteno sljedeće:

void fibonacci (int n) {


int i, fbroj[n];

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 25

Rješenje 11. zadatka

#include <stdio.h>

int kolikoInt(void) {
return sizeof(int);
}

int main(void) {
int brojBajtovaZaInt;
brojBajtovaZaInt = kolikoInt();
printf("Ovaj prevodilac za tip int koristi bajtova: %d\n", brojBajtovaZaInt);
return 0;
}

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 35

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

16. vježbe uz predavanja

U svim zadacima u kojima se traži definiranje funkcije, treba napisati odgovarajući glavni
program (tj. funkciju main) u kojem ćete po potrebi definirati stvarne argumente, s tipkovnice
učitati njihove vrijednosti, pozvati funkciju i ispisati rezultat.
1. Napisati funkciju koja za zadani cijeli broj n vraća n2, ali tako da rezultat vraća preko adrese
koju je dobila kao argument. Funkcija ne smije promijeniti stvarni argument n definiran u
pozivajućem programu. Kojeg je tipa funkcija?
2. Napisati funkciju koja sadržaj neke cjelobrojne varijable n iz pozivajućeg programa mijenja u
2
n . Dakle, funkcija treba promijeniti vrijednost neke cjelobrojne varijable koja je definirana u
pozivajućem programu. Kojeg je tipa funkcija?
3. Napišite funkciju tipa double koja za zadanu vrijednost tipa double vraća zadanu vrijednost
(tipa double) uvećanu za 10.0. Hoćete li dobiti ispravan rezultat ako funkciju pozovete sa
stvarnim argumentom tipa int?
4. Napišite funkciju koja zadanoj varijabli tipa double vrijednost uvećava za 10.0. Dakle, funkcija
treba promijeniti vrijednost neke realne (double) varijable koja je definirana u pozivajućem
programu. Hoćete li dobiti ispravan rezultat ako funkciju pozovete sa stvarnim argumentom
koji je pokazivač na varijablu tipa int?
5. Napišite funkciju koja za dvije zadane vrijednosti tipa int u pozivajući program vraća dvije
vrijednosti: prva vraćena vrijednost je veća među zadanim vrijednostima, a druga vraćena
vrijednost je manja među zadanim vrijednostima. Npr. ako se funkciji zadaju vrijednosti 2 i
3*2, funkcija u pozivajući program mora vratiti vrijednosti 6 i 2.
6. Napišite funkciju koja vrijednosti u zadanim varijablama x, y i z (tipa double) poredava po
veličini, od najveće prema najmanjoj. Drugim riječima, očekuje se da će funkcija zamijeniti
vrijednosti u varijablama x, y i z tako da vrijednosti budu poredane od najveće prema
najmanjoj. Npr. ako se funkcija pozove za varijable x=2.0, y=4.0, z=3.0, nakon izvršavanja
funkcije u varijablama x, y, z se moraju nalaziti vrijednosti x=4.0, y=3.0, z=2.0.
7. Napišite funkciju koja prima pokazivače na dvije varijable tipa int, te vraća pokazivač na onu
od njih koja ima veću vrijednost. Ako varijable imaju istu vrijednost, funkcija vraća pokazivač
na prvu varijablu.
8. Napišite funkciju koja prima pokazivače na dvije varijable tipa int, te vraća vrijednost
varijable koja ima veću vrijednost.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 35

Rješenja

Rješenje 1. zadatka

#include <stdio.h>

void kvad2(int n, int *rez) {


*rez = n*n;
}

int main (void) {


int n, n2;
printf ("Upisite n: ");
scanf("%d", &n);
kvad2(n, &n2);
printf("n na kvadrat (preko adrese) je: %d\n", n2);
printf("Vrijednost varijable n se nije promijenila: %d\n", n);
return 0;
}

Funkcija kvad2 kao drugi argument dobija adresu varijable u koju će zapisati rezultat. Jedina
naredba u toj funkciji upravo to i radi: na adresu kamo pokazuje pokazivač rez, zapisuje n2.
Primijetite da pozivajući program za drugi stvarni argument predaje adresu varijable n2. Tip
funkcije je void, jer funkcija pomoću naredbe return ne treba vratiti niti jednu vrijednost.

Ipak, uočite da će uvjet iz programa (da funkcija ne smije promijeniti stvarni argument) biti narušen
ukoliko se funkcija pozove na sljedeći način: kvad2(n, &n);

Rješenje 2. zadatka

#include <stdio.h>

void kvad3(int *n) {


*n = *n * *n;
}

int main (void) {


int n;
printf ("Upisite n: ");
scanf("%d", &n);
kvad3(&n);
printf("n na kvadrat (promjena originalne varijable preko adrese) je: %d\n",
n);
return 0;
}

Funkcija kvad3 dobija adresu varijable u kojoj se nalazi cijeli broj čiji kvadrat treba izračunati, ali se
na tu istu adresu također zapisuje i rezultat. Varijabla n iz pozivajućeg programa će biti
promijenjena!

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 35

Rješenje 3. zadatka

#include <stdio.h>

double uvecajZa10(double x) {
return x + 10.;
}

int main (void) {


double arg, rez;
printf("Upisite realni broj: ");
scanf("%lf", &arg);
rez = uvecajZa10(arg);
printf("%f uvecan za 10.0 jest %f\n", arg, rez);
return 0;
}

Sada treba testirati što će se dogoditi ako se funkcija pozove s cjelobrojnim argumentom?

int main (void) {


int arg, rez;
printf("Upisite cijeli broj: ");
scanf("%d", &arg);
rez = uvecajZa10(arg);
printf("%d uvecan za 10.0 jest %d\n", arg, rez);
return 0;
}

Ako se funkcija pozove s cjelobrojnim stvarnim argumentom, dobit će se ispravan rezultat jer se pri
prijenosu stvarnog u formalni argument obavlja implicitna konverzija (int→ double), a pri
pridruživanju rezultata funkcije varijabli rez obavlja se implicitna konverzija (double→ int).

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 35

Rješenje 4. zadatka

#include <stdio.h>

void uvecajZa10(double *x) {


*x = *x + 10.;
}

int main (void) {


double arg;
printf("Upisite realni broj: ");
scanf("%lf", &arg);
uvecajZa10(&arg);
printf("Uvecana varijabla jest %f\n", arg);
return 0;
}

Sada treba testirati što će se dogoditi ako se funkciji umjesto pokazivača na varijablu tipa double
preda pokazivač na varijablu tipa int?

int main (void) {


int arg;
printf("Upisite cijeli broj: ");
scanf("%d", &arg);
uvecajZa10(&arg);
printf("Uvecana varijabla jest %d\n", arg);
return 0;
}

Prevodilac će dojaviti upozorenje, ali će program ipak uspjeti prevesti (ako se radi s gcc
prevodiocem, da bi prevođenje uspjelo u ovom primjeru, treba ispustiti opciju -pedantic-errors) .

Rezultat izvršavanja programa neće biti ispravan. To se moglo očekivati: funkcija je dobila
adresu int varijable (pokazuje na neko područje u memoriji od 4 bajta), a "misli" da je dobila
adresu double varijable (adresu koja pokazuje na područje memorije veličine 8 bajta).

Prekršili smo pravilo koje smo definirali na predavanjima: pokazivač na objekte tipa x smije se
koristiti isključivo za pohranu adresa objekata tipa x.

Za vježbu, provjerite kakve ćete rezultate dobiti ako u funkciji, umjesto tipa double koristite tip float.

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 35

Rješenje 5. zadatka

#include <stdio.h>

void poredaj(int a, int b, int *veci, int *manji) {


if (a > b) {
*veci = a;
*manji = b;
}
else {
*veci = b;
*manji = a;
}
}

int main (void) {


int veci, manji;
poredaj(2, 3*2, &veci, &manji);
printf("veci i manji su: %d %d\n", veci, manji);
return 0;
}

Rješenje 6. zadatka

#include <stdio.h>

void poredaj(double *x, double *y, double *z) {


double pom;
if (*x < *y) {
pom = *x;
*x = *y;
*y = pom;
}
if (*x < *z) {
pom = *x;
*x = *z;
*z = pom;
}
if (*y < *z) {
pom = *y;
*y = *z;
*z = pom;
}
}

int main (void) {


double a = 1.0, b = 2.0, c = 3.0;
poredaj(&a, &b, &c);
printf("poredani su: %f %f %f\n", a, b, c);
return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 35

Rješenje 7. zadatka

#include <stdio.h>

int *vratiAdresuVeceg(int *x, int *y) {


if (*x >= *y)
return x;
else
return y;
}

int main (void) {


int a = 5, b = 2;
int *veci;
veci = vratiAdresuVeceg(&a, &b);
printf("veci od zadana dva broja je: %d\n", *veci);
return 0;
}

Rješenje 8. zadatka

#include <stdio.h>

int vratiVrijednostVeceg(int *x, int *y) {


if (*x > *y)
return *x;
else
return *y;
}

int main (void) {


int a = 5, b = 2;
int veci;
veci = vratiVrijednostVeceg(&a, &b);
printf("veci od zadana dva broja je: %d\n", veci);
return 0;
}

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

17. vježbe uz predavanja

1. Napisati prototip (deklaraciju) za svaku funkciju koja se nalazi u rješenjima prethodnih vježbi.
2. U modulu mat2.c napisati funkcije čiji su prototipovi navedeni u nastavku
int binCoeff(int m, int n); /* izracunava "m povrh n" */
int factorial(int n); /* izracunava n! */
int iabsolute(int n); /* izracunava apsolutnu vrijednost */
float fabsolute(float x); /* izracunava apsolutnu vrijednost */
Prototipove navedenih funkcija smjestiti u datoteku s prototipovima mat2.h.
Funkciju main ("glavni program") smjestiti u modul glavni.c U glavnom programu treba
izračunati i na zaslon ispisati rezultate za:
factorial(0)
factorial(25)
factorial(26)
binCoeff(13, 3)
binCoeff(4, 4)
iabsolute(-5)
iabsolute(0)
iabsolute(-5.7f)
fabsolute(-5)
fabsolute(-5.7f)

Testirati prevođenje na dva načina:


• tako da se oba modula prevedu i povežu samo jednim pozivom prevodioca
• tako da se zasebno prevede svaki modul, a zatim se dobiveni objektni kôd poveže u
izvršni kôd

• koje datoteke su stvorene za vrijeme prevođenja na prvi, odnosno drugi način?

3. Što će se ispisati tijekom izvođenja sljedećeg programa:


#include <stdio.h>

void fun(void) {
int x = 5;
printf("%d\n", x);
x++;
}

int main (void) {


fun();
fun();
return 0;
}

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

4. Što će se ispisati tijekom izvođenja sljedećeg programa:


#include <stdio.h>

void fun(void) {
static int x = 5;
printf("%d\n", x);
x++;
}

int main (void) {


fun();
fun();
return 0;
}

5. Što će se ispisati tijekom izvođenja sljedećeg programa:


#include <stdio.h>

void fun(void) {
static int x = 5;
int y = 5;
printf("%d %d\n", ++x, --y);
}

int main (void) {


fun();
fun();
fun();
return 0;
}

6. Što će se ispisati tijekom izvođenja sljedećeg programa:


#include <stdio.h>

int main (void) {


static int i = 5;
int prviPut = 1;
labela:
{
static int i = 10;
int j = 15;
printf("%d %d\n", i, j);
i++;
j++;
}
i++;
printf("%d\n", i);
if (prviPut) {
prviPut = 0;
goto labela;
}
return 0;
}

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

7. Što će se ispisati tijekom izvođenja sljedećeg programa:


#include <stdio.h>

static int x = 25;

void fun1(void) {
static int x = 5;
printf("%d\n", ++x);
}

void fun2(void) {
int x = 10;
printf("%d\n", ++x);
}

void fun3(void) {
printf("%d\n", ++x);
}

int main (void) {


x++;
{
static int x = 15;
{
int x = 20;
printf("%d\n", x++);
}
printf("%d\n", x++);
}
printf("%d\n", x++);
fun1();
fun2();
fun3();

fun1();
fun2();
fun3();
return 0;
}

U zadacima u kojima se traži definiranje funkcije, treba napisati prototipove funkcija, te


odgovarajući glavni program (tj. funkciju main) u kojem ćete po potrebi definirati stvarne
argumente, pozvati funkciju i ispisati rezultat.

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

8. Napisati funkciju zbroji tipa int koja vraća zbroj dvaju zadanih cijelih brojeva i funkciju
mnozi tipa int koja vraća umnožak dvaju zadanih cijelih brojeva. Svaka od funkcija, osim što
izračunava rezultat i vraća ga u pozivajući program, na zaslon ispisuju koliko je puta bila
pozvana. Npr. ako se u glavnom programu obave naredbe:
printf("2*2=%d\n", mnozi(2,2));
printf("2+3=%d\n", zbroji(2,3));
printf("4+2=%d\n", zbroji(4,2));
printf("2*5=%d\n", mnozi(2,5));
printf("2*3=%d\n", mnozi(2,3));
na zaslonu se treba ispisati:

Funkcija mnozi do sada je pozvana 1 puta ← ispisano u funkciji mnozi


2*2=4 ← ispisano u glavnom programu
Funkcija zbroji do sada je pozvana 1 puta ← ispisano u funkciji zbroji
2+3=5 ← ispisano u glavnom programu
Funkcija zbroji do sada je pozvana 2 puta ← ispisano u funkciji zbroji
4+2=6 ← ispisano u glavnom programu
Funkcija mnozi do sada je pozvana 2 puta ← ispisano u funkciji mnozi
2*5=10 ← ispisano u glavnom programu
Funkcija mnozi do sada je pozvana 3 puta ← ispisano u funkciji mnozi
2*3=6 ← ispisano u glavnom programu

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

9. Slično kao prethodni zadatak, uz dodatak: svaka od funkcija mora ispisati ne samo koliko je
puta bila pozvana ona sama, nego i koliko puta je bila pozvana bilo koja od funkcija zbroji i
mnozi. Npr. ako se u glavnom programu obave naredbe:
printf("2*2=%d\n", mnozi(2,2));
printf("2+3=%d\n", zbroji(2,3));
printf("4+2=%d\n", zbroji(4,2));
printf("2*5=%d\n", mnozi(2,5));
printf("2*3=%d\n", mnozi(2,3));
na zaslonu se treba ispisati:

Funkcija mnozi do sada je pozvana 1 puta ← ispisano u funkciji mnozi


Funkcije zbroji i mnozi do sada su pozvane 1 puta ← ispisano u funkciji mnozi
2*2=4 ← ispisano u glavnom programu
Funkcija zbroji do sada je pozvana 1 puta ← ispisano u funkciji zbroji
Funkcije zbroji i mnozi do sada su pozvane 2 puta ← ispisano u funkciji zbroji
2+3=5 ← ispisano u glavnom programu
Funkcija zbroji do sada je pozvana 2 puta ← ispisano u funkciji zbroji
Funkcije zbroji i mnozi do sada su pozvane 3 puta ← ispisano u funkciji zbroji
4+2=6 ← ispisano u glavnom programu
Funkcija mnozi do sada je pozvana 2 puta ← ispisano u funkciji mnozi
Funkcije zbroji i mnozi do sada su pozvane 4 puta ← ispisano u funkciji mnozi
2*5=10 ← ispisano u glavnom programu
Funkcija mnozi do sada je pozvana 3 puta ← ispisano u funkciji mnozi
Funkcije zbroji i mnozi do sada su pozvane 5 puta ← ispisano u funkciji mnozi
2*3=6 ← ispisano u glavnom programu

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

10. Što će se ispisati tijekom izvođenja sljedećeg programa:

datoteka s prototipovima proto.h modul modulA.c


void fun1(void); #include <stdio.h>
void fun2(void); #include "proto.h"
void fun3(void); extern int x = 20;
void fun4(void);
void fun2(void) {
x += 4;
printf("%d\n", x);
modul glavni.c }
#include <stdio.h>
#include "proto.h"
extern int x;
modul modulB.c
int main(void) { #include <stdio.h>
int x = 30; #include "proto.h"
x += 2;
printf("%d\n", x); void fun3(void) {
fun1(); static int x = 5;
fun2(); x += 5;
fun3(); printf("%d\n", x);
fun4(); }
fun3();
return 0; void fun4(void) {
} extern int x;
x += 6;
void fun1(void) { printf("%d\n", x);
x += 3; }
printf("%d\n", x);
}

Provjeriti rješenje izvođenjem programa na vlastitom računalu i pri tome testirati


prevođenje na dva načina:
• tako da se svi moduli prevedu i povežu samo jednim pozivom prevodioca
• tako da se zasebno prevede svaki modul, a zatim se dobiveni objektni kôd poveže u
izvršni kôd

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

Rješenja

Rješenje 2. zadatka
modul glavni.c
#include <stdio.h>
#include "mat2.h"

int main(void) {
printf("%d\n", factorial(0));
printf("%d\n", factorial(25));
printf("%d\n", factorial(26)); /* zasto ovdje rezultat nece biti dobar?*/
printf("%d\n", binCoeff(13, 3));
printf("%d\n", binCoeff(4, 4));
printf("%d\n", iabsolute(-5));
printf("%d\n", iabsolute(0));
printf("%d\n", iabsolute(-5.7f));
printf("%3.1f\n", fabsolute(-5));
printf("%3.1f\n", fabsolute(-5.7f));
return 0;
}

modul mat2.c
#include "mat2.h"

int binCoeff(int m, int n) {


return factorial(m) / ( factorial(n) * factorial(m - n) );
}

int factorial(int n) {
int i, f = 1;
for (i = 2; i <= n; i++) {
f = f * i;
}
return f;
}

int iabsolute(int n) {
return n >= 0 ? n : -n;
}

float fabsolute(float x) {
return x >= 0.0f ? x : -x;
}

datoteka s prototipovima funkcija mat2.h

int binCoeff(int m, int n);


int factorial(int n);
int iabsolute(int n);
float fabsolute(float x);

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

Rješenje 3. zadatka
Pri svakom pozivu funkcije varijabla x se ponovno inicijalizira. Ispisat će se:
5
5

Rješenje 4. zadatka
Varijabla x se inicijalizira samo jednom, na početku izvođenja programa, a njezina vrijednost ostaje
sačuvana do kraja izvođenja programa (ne gubi se završetkom funkcije). Ispisat će se:
5
6

Rješenje 5. zadatka
Potrebno je uočiti koje su varijable definirane u programu, te na temelju smještajnog razreda kojem
pripadaju odrediti njihovo područje važenja i trajnost.

Varijabla x je statička vrijabla. To znači da se njezina trajnost proteže od početka do završetka


programa. Varijabla se inicijalizira samo jednom, na početku izvođenja programa (čak i prije nego
se prvi puta pozove funkcija), te njena vrijednost ostaje sačuvana do završetka programa. Varijabla
x je definirana unutar funkcije, stoga se njezino područje važenja (tj. "područje programa u kojem je
vidljiva") proteže od mjesta u funkciji na kojem je definirana do kraja funkcije.

Varijabla y je automatska varijabla. Varijabla se inicijalizira svaki puta kad se pozove funkcija, a
njezina vrijednost se gubi u trenutku završetka funkcije.

x-trajnost y-trajnost
x-važenje y-važenje
void fun(void) {
static int x = 5;
int y = 5;
printf("%d %d\n", ++x, --y);
}

int main (void) {


fun();
fun();
fun();
return 0;
}

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

Rješenje 6. zadatka
Ovdje je važno uočiti da postoje dvije varijable naziva i. Na slici koja prikazuje područja važenja i
trajnosti, prva varijabla i (definirana na početku glavnog programa) označena je oznakom i1, a
druga oznakom i2.

i1-trajnost i2-trajnost
i1-važenje
#include <stdio.h>

int main (void) {


static int i = 5;
int prviPut = 1;
labela: i2-važenje
{
static int i = 10;
int j = 15;
printf("%d %d\n", i, j);
i++;
j++;
}
i++;
printf("%d\n", i);
if (prviPut) {
prviPut = 0;
goto labela;
}
return 0;
}

Rješenje 7. zadatka
Ovdje je važno uočiti da postoji 5 različitih varijabli naziva x. Kad se odredi trajnost i područje
važenja svake od tih varijabli, zadatak je lako riješiti.

9
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

Rješenje 8. zadatka
#include <stdio.h>

int zbroji(int x, int y);


int mnozi(int x, int y);

int main (void) {


printf("2*2=%d\n", mnozi(2,2));
printf("2+3=%d\n", zbroji(2,3));
printf("4+2=%d\n", zbroji(4,2));
printf("2*5=%d\n", mnozi(2,5));
printf("2*3=%d\n", mnozi(2,3));
return 0;
}

int zbroji(int x, int y) {


static int brojPoziva = 0;
brojPoziva++;
printf("Funkcija zbroji do sada je pozvana %d puta\n", brojPoziva);
return x+y;
}

int mnozi(int x, int y) {


static int brojPoziva = 0;
brojPoziva++;
printf("Funkcija mnozi do sada je pozvana %d puta\n", brojPoziva);
return x*y;
}

10
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 64

Rješenje 9. zadatka

#include <stdio.h>

int zbroji(int x, int y);


int mnozi(int x, int y);

int ukupniBrojPoziva = 0;

int main (void) {


printf("2*2=%d\n", mnozi(2,2));
printf("2+3=%d\n", zbroji(2,3));
printf("4+2=%d\n", zbroji(4,2));
printf("2*5=%d\n", mnozi(2,5));
printf("2*3=%d\n", mnozi(2,3));

return 0;
}

int zbroji(int x, int y) {


static int brojPoziva = 0;
brojPoziva++;
ukupniBrojPoziva++;
printf("Funkcija zbroji do sada je pozvana %d puta\n", brojPoziva);
printf("Funkcije zbroji i mnozi do sada su pozvane %d puta\n", ukupniBrojPoziva);
return x+y;
}

int mnozi(int x, int y) {


static int brojPoziva = 0;
brojPoziva++;
ukupniBrojPoziva++;
printf("Funkcija mnozi do sada je pozvana %d puta\n", brojPoziva);
printf("Funkcije zbroji i mnozi do sada su pozvane %d puta\n", ukupniBrojPoziva);
return x*y;
}

Rješenje 10. zadatka

Ovdje je važno uočiti postojanje definicija triju različitih varijabli x.

• na početku modula modulA.c definirana je eksterna varijabla x


• na početku funkcije main definirana je automatska varijabla x
• na početku funkcije fun3 definirana je statička varijabla x

Nakon što se odredi trajnost i područje važenja svake pojedine varijable, zadatak je lako riješiti.

11
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 78

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

18. vježbe uz predavanja

U svim zadacima u kojima se traži definiranje funkcije, treba napisati odgovarajući glavni
program (tj. funkciju main) u kojem ćete po potrebi definirati stvarne argumente, pozvati funkciju
i ispisati rezultat.

1. Napišite funkciju toApsDim koja vrijednosti elemenata cjelobrojnog jednodimenzijskog polja


mijenja u njihove apsolutne vrijednosti. Funkciju, glavni program i prototipove smjestite u tri
zasebne datoteke. Testirati prevođenje na dva načina:
• tako da se oba modula prevedu i povežu samo jednim pozivom prevodioca
• tako da se zasebno prevede svaki modul, a zatim se dobiveni objektni kôd poveže u
izvršni kôd

2. Napišite funkciju koja u zadanom jednodimenzijskom realnom polju prebroji koliko članova je
veće od 0.0, koliko članova je manje od 0.0 i koliko članova je jednako 0.0. Dobivene
vrijednosti funkcija mora vratiti u pozivajući program. Funkciju, glavni program i prototipove
smjestite u tri zasebne datoteke. Testirati prevođenje na dva načina:
• tako da se oba modula prevedu i povežu samo jednim pozivom prevodioca
• tako da se zasebno prevede svaki modul, a zatim se dobiveni objektni kôd poveže u
izvršni kôd

3. Što će se ispisati sljedećim programom:

#include <stdio.h>
int main (void) {
int a = 2, x = 10;
int *p = &a;
x += *p * 3;
printf ("%d %d\n", *p, x);
return 0;
}

4. Što će se ispisati sljedećim programom:

#include <stdio.h>
void f (int *p) {
printf ("%d %d\n", *p, *p+1);
}
int main (void) {
int polje[6] = {1, 2, 3, 4, 5, 6};
int *pp;
pp = &polje[0];
f(pp++);
f(pp);
f(++pp);
return 0;
}

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 78

5. Što će se ispisati sljedećim programom:

#include <stdio.h>
void f (int *p) {
static int i = 2;
printf ("%d\n", *(p + ++i));
}

int main (void) {


int polje[8] = {1, 2, 3, 4, 5, 6, 7, 8};
f(&polje[0]);
f(&polje[0]);
f(&polje[0]);
f(&polje[1]);
return 0;
}

6. Što će se ispisati sljedećim programom:

#include <stdio.h>
void f (int *p) {
int i = 3;
printf ("%d\n", *(p + --i));
}
int main (void) {
int polje[6] = {1, 2, 3, 4, 5, 6};
f(&polje[0]);
f(&polje[1]);
f(&polje[2]);
return 0;
}

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 78

Rješenja

Rješenje 1. zadatka
glavni.c
#include <stdio.h>
#include "toapsdim.h"

#define MAXDIM 100

int main (void) {


int m;
int polje[MAXDIM];
int i;

printf ("Upisite m manji ili jednak %d: ", MAXDIM);


scanf("%d", &m);
printf ("Upisite elemente polja:\n");
for (i = 0; i < m; ++i)
scanf("%d", &polje[i]);

printf("\nSlijedi ispis ucitanog niza\n\n");


for (i = 0; i < m; ++i)
printf("%d ", polje[i]);

toApsDim(&polje[0], m);

printf("\nSlijedi ispis izmijenjenog polja\n\n");


for (i = 0; i < m; ++i)
printf("%d ", polje[i]);
return 0;
}

toapsdim.c
#include "toapsdim.h"

void toApsDim(int *polje, int n) { /* ili (int polje[], int n) */


int i;
for (i = 0; i < n; ++i)
if (*(polje + i) < 0)
*(polje + i) = - *(polje + i);
}

toapsdim.h
void toApsDim(int *polje, int n);

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 78

Rješenje 2. zadatka

funkcije.h
void prebroji(float *polje, int n,
int *vecihOdNula, int *manjihOdNula, int *jednakihNula);

funkcije.c
#include "funkcije.h"
void prebroji(float *polje, int n,
int *vecihOdNula, int *manjihOdNula, int *jednakihNula) {
int i;
*vecihOdNula = *manjihOdNula = *jednakihNula = 0;
for (i = 0; i < n; ++i)
if (*(polje + i) < 0.0)
(*manjihOdNula)++;
else if (*(polje + i) == 0.0)
(*jednakihNula)++;
else
(*vecihOdNula)++;
return;
}

test.c
#include <stdio.h>
#include "funkcije.h"

#define MAXDIM 100

int main (void) {


int m;
float polje[MAXDIM];
int i;
int vecih, manjih, jednakih;

printf ("Upisite m manji ili jednak %d: ", MAXDIM);


scanf("%d", &m);
printf ("Upisite elemente polja:\n");
for (i = 0; i < m; ++i)
scanf("%f", &polje[i]);

printf("\n\nSlijedi ispis ucitanog niza\n");


for (i = 0; i < m; ++i)
printf("%f\n", polje[i]);

prebroji(&polje[0], m, &vecih, &manjih, &jednakih);


printf("\nn>0 ima: %d n<0 ima: %d n==0 ima: %d\n",
vecih, manjih, jednakih);
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

19. vježbe uz predavanja

U svim zadacima u kojima se traži definiranje funkcije, treba napisati odgovarajući glavni
program (tj. funkciju main) u kojem ćete po potrebi definirati stvarne argumente, pozvati funkciju
i ispisati rezultat.

1. Napišite funkciju koja u zadanom nizu znakova (jednodimenzijskom polju znakova


terminiranom sa znakom '\0') pronalazi sve samoglasnike i ispisuje ih na zaslon. Npr. za
zadani niz Antigona, ispisuje Aioa.
2. Napišite funkciju koja iz zadanog niza znakova izbacuje sve samoglasnike. Npr. ako se
funkciji zada niz znakova Antigona, funkcija ga mora promijeniti u niz znakova ntgn.

3. Što će se ispisati sljedećim programom:

#include <stdio.h>

void f (int *p) {


int i1 = *p;
int i2 = (*p)++;
int i3 = *p;
int i4 = *++p;
int i5 = *p;
int i6 = *p++;
int i7 = *(p-1);
int i8 = *p;
printf ("%d %d %d %d %d %d %d %d\n", i1, i2, i3, i4, i5, i6, i7, i8);
}

int main (void) {


int polje[3][2] = {3, 6, 9, 12, 15, 18};
f(&polje[0][0]);
return 0;
}

4. Što će se ispisati sljedećim programom:

#include <stdio.h>

void f (int *p) {


printf ("%d %d\n", *p, *p+1);
}

int main (void) {


int polje[3][2] = {1, 2, 3, 4, 5, 6};
int *pp;
pp = &polje[0][0];
f(pp++);
f(++pp);
return 0;
}

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

5. Što će se ispisati sljedećim programom:

#include <stdio.h>

void f (int *p) {


static int i = 2;
printf ("%d\n", *(p + ++i));
}

int main (void) {


int polje[3][2] = {1, 2, 3, 4, 5, 6};
f(&polje[0][0]);
f(&polje[0][0]);
f(&polje[0][0]);
return 0;
}

6. Što će se ispisati sljedećim programom:

#include <stdio.h>

void f (int *p) {


static int i = 0;
i++;
printf ("%d\n", *(p + --i));
}

int main (void) {


int polje[3][2] = {1, 2, 3, 4, 5, 6};
f(&polje[0][0]);
f(&polje[1][0]);
f(&polje[1][1]);
return 0;
}

7. Napisati funkciju genmat koja u dvodimenzijskom cjelobrojnom polju definiranom s


dimenzijama 4 retka i 4 stupca (funkcija radi isključivo s poljima dimenzija 4x4) upisuje četiri
jedinice na glavnu dijagonalu.
U pozivajućem programu definirajte polje, sve članove polja inicijalizirajte na nulu, pozovite
funkciju genmat, te na zaslon ispišite dobiveni rezultat. Ispis mora izgledati ovako:

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
Nakon toga pokušajte napisati drugačiji glavni program: definirajte polje od 5 redaka i 5
stupaca, inicijalizirajte sve elemente polja na nulu, pozovite istu funkciju genmat i ispišite
svih 5x5 članova polja. Možete li predvidjeti kako će izgledati ispis? Zašto ispisana tablica ne
izgleda (što bi se možda moglo očekivati) ovako:

1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 0

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

8. Napisati funkciju tablica koja u dvodimenzijsko cjelobrojno polje definirano u pozivajućem


programu upisuje tablicu množenja od m redaka i n stupaca.
Funkcija mora biti u stanju baratati s poljem proizvoljnih dimenzija. Npr. u glavnom programu
može se definirati polje dimenzija 20x10, a zatim pozvati funkciju tako da se polje napuni
tablicom množenja dimenzija 5x7; ista funkcija također mora na ispravan način generirati npr.
tablicu množenja dimenzija 6x4 u polju koje je u glavnom programu definirano s dimenzijama
30x20.
U pozivajućem programu definirati polje, s tipkovnice učitati m i n (sigurno manji ili jednaki
15), pozvati funkciju tablica, te na zaslon ispisati dobivenu tablicu množenja. Npr. tablica
množenja od 3 retka i 4 stupca izgleda ovako:

1 2 3 4
2 4 6 8
3 6 9 12

9. Napišite funkciju transp za transponiranje cjelobrojne matrice od m redaka i n stupaca.


Funkcija mora transponirati matricu, ali također i zamijeniti vrijednosti u varijablama m i n
pozivajućeg programa u kojima su evidentirane dimenzije matrice.
U funkciji definirajte, te za transponiranje koristite pomoćno polje. Ideja za korištenje
pomoćnog polja: prepisati elemente mat[i][j] iz zadane matrice u elemente pom[j][i]
pomoćne matrice, a zatim svaki element pom[i][j] upisati natrag u element mat[i][j].
Jednako kao u prethodnom zadatku, funkcija mora biti u stanju baratati s poljem proizvoljnih
dimenzija, uz ograničenje da zadano polje nikad neće imati dimenzije veće od 100x100.
Treba napomenuti da je ovakvo rješenje (s pomoćnom matricom) dobro samo za vježbu.
Stoga načinite i bolju (tj. ispravnu) funkciju koja matricu transponira bez korištenja
pomoćnog polja! Primjer transponiranja matrice bez korištenja pomoćnog polja prikazan je na
predavanjima o dvodimenzijskim poljima.

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

Rješenja

Rješenje 1. zadatka
#include <stdio.h>

void ispisSamoglasa (char niz[]);

int main (void) {


char niz[] = "Antigona";
ispisSamoglasa(niz);
printf("\n");
return 0;
}

void ispisSamoglasa (char niz[]) { /* ili bolje (char *niz) */


int i = 0;
while (niz[i] != '\0') {
if (niz[i] == 'a' || niz[i] == 'A' ||
niz[i] == 'e' || niz[i] == 'E' ||
niz[i] == 'i' || niz[i] == 'I' ||
niz[i] == 'o' || niz[i] == 'O' ||
niz[i] == 'u' || niz[i] == 'U')
printf("%c", niz[i]);
++i;
}
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

Rješenje 2. zadatka
#include <stdio.h>

void izbaciSamoglase (char *niz);

int main (void) {


char niz[] = "Antigona";
printf("%s\n", niz);
izbaciSamoglase(niz);
printf("%s\n", niz);
return 0;
}

void izbaciSamoglase (char *niz) { /* ili (char niz[]) */


int i = 0, potroseno = 0;
while (*(niz + i) != '\0') {
if (*(niz + i) != 'a' && *(niz + i) != 'A' &&
*(niz + i) != 'e' && *(niz + i) != 'E' &&
*(niz + i) != 'i' && *(niz + i) != 'I' &&
*(niz + i) != 'o' && *(niz + i) != 'O' &&
*(niz + i) != 'u' && *(niz + i) != 'U')
*(niz + potroseno++) = *(niz + i);
++i;
}
*(niz + potroseno) = '\0';
/* VAZNO PITANJE: sto bi bio rezultat bez prethodne naredbe? */
}

Ovdje je važno uočiti da u ovoj funkciji nije moguće* koristiti pomoćni niz jer nije poznata najveća
dopuštena duljina ulaznog niza (a taj je podatak potreban pri definiciji pomoćnog niza). Tek kad bi
zadatak glasio: napišite funkciju koja iz zadanog niza znakova izbacuje sve samoglasnike, pri čemu
zadani niz sigurno nije dulji od 1000 znakova, tada bi postojala mogućnost u funkciji koristiti
pomoćni niz (tada bi se u funkciji mogao definirati pomoćni niz duljine 1001 znaka).

* moguće je npr. uz korištenje funkcije malloc, međutim ta se funkcija ne razmatra na ovom predmetu

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

Rješenje 7. zadatka

#include <stdio.h>

void genmat (int *polje) {


int i;
for (i = 0; i < 4; ++i)
*(polje + i + i*4) = 1;
}

int main (void) {


int mat[4][4] = {0};
int i, j;
genmat(&mat[0][0]);
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j)
printf("%d ", mat[i][j]);
printf("\n");
}
return 0;
}

Rezultat:

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

Slijedi poziv iste funkcije s poljem koje je definirano s dimenzijama 5x5:


int main () {
int mat[5][5] = {0};
int i, j;
genmat(&mat[0][0]);
for (i = 0; i < 5; ++i) {
for (j = 0; j < 5; ++j)
printf("%d ", mat[i][j]);
printf("\n");
}
return 0;
}

Rezultat:

1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
0 0 0 0 0

Zašto? Funkcija genmat u prvom koraku for petlje upiše vrijednost 1 na adresu *(polje+0+0), a time
zapravo upiše jedinicu u element polja mat[0][0], što je u redu. Međutim, kada u drugom koraku for
petlje upiše vrijednost 1 na adresu *(polje+1+1*4), zapravo je upisala jedinicu u element polja
mat[1][0]. Pojednostavljeno, funkcija (zato što je tako napisana) do prvog člana drugog retka dolazi
tako da se preskoči 4 člana polja (a to je istina samo onda kada se funkciji preda polje koje je
definirano tako da mu je broj stupaca jednak 4). Očito, ako funkcija mora baratati s poljima različitih
dimenzija, mora imati informaciju o stvarnom broju stupaca polja (broju stupaca pri definiciji polja).

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

Rješenje 8. zadatka

#include <stdio.h>

#define MAXRED 15
#define MAXSTUP 15

void tablica(int *polje, int m, int n, int brclanstup);

int main (void) {


int m, n;
int polje[MAXRED][MAXSTUP];
int i, j;

printf ("Upisite m i n koji su manji ili jednaki %d i %d: ", MAXRED, MAXSTUP);
scanf("%d %d", &m, &n);
/* ovdje bi, naravno, trebalo napraviti provjeru unesenih vrijednosti */
tablica(&polje[0][0], m, n, MAXSTUP);
printf("\nSlijedi ispis tablice mnozenja\n\n");
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j)
printf("%5d", polje[i][j]);
printf("\n");
}
return 0;
}

void tablica(int *polje, int m, int n, int brclanstup) {


int i, j;
for (i = 0; i < m; ++i)
for (j = 0; j < n; ++j)
*(polje + i*brclanstup + j) = (i+1) * (j+1);
}

Važna napomena: česta pogreška koja se pronalazi u rješenjima ovakvih zadataka jest da se u
funkciji umjesto formalnog argumenta brclanstup koristi simbolička konstanta MAXSTUP
definirana na početku modula. Zašto to ne valja? Zato jer bi tada funkcija ispravno radila samo s
onim poljima koja su definirana tako da im je broj stupaca jednak MAXSTUP. Npr, ako bi se u
glavnom programu definiralo još jedno polje, drugačijih dimenzija, funkcija u tom polju ne bi mogla
generirati ispravnu tablicu množenja.

int polje2[10][10];
...
tablica(&polje2[0][0], 5, 6, 10);
...

Također, pogrešno je koristiti globalnu ili statičku varijablu za "prijenos" informacije o broju stupaca
u funkciju.

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

Rješenje 9. zadatka

#include <stdio.h>

#define MAXRED 20
#define MAXSTUP 20

void transp(int *polje, int *m, int *n, int brclanstup);

int main (void) {


int m, n;
int polje[MAXRED][MAXSTUP];
int i, j;
printf ("Upisite m i n koji su manji ili jednaki %d i %d: ", MAXRED, MAXSTUP);
scanf("%d %d", &m, &n);
printf ("Upisite elemente matrice po retcima:\n");
for (i = 0; i < m; ++i)
for (j = 0; j < n; ++j)
scanf("%d", &polje[i][j]);

printf("\nSlijedi ispis originalne matrice\n\n");


for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j)
printf("%d ", polje[i][j]);
printf("\n");
}
transp(&polje[0][0], &m, &n, MAXSTUP);

printf("\nSlijedi ispis transponirane matrice\n\n");


for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j)
printf("%d ", polje[i][j]);
printf("\n");
}

return 0;
}

/*Dimenzije pomocne matrice su 100x100, kako bi se osiguralo da se


i najveca moguca zadana matrica moze prepisati u pomocnu matricu. */
#define MAXDIMPOMOCNA 100

void transp(int *polje, int *pm, int *pn, int brclanstup) {


int pom[MAXDIMPOMOCNA][MAXDIMPOMOCNA];
int i, j;
int pomocna;
for (i = 0; i < *pm; ++i)
for (j = 0; j < *pn; ++j)
pom[j][i] = *(polje + i*brclanstup + j);
/* zamijeni *pm i *pn */
pomocna = *pm;
*pm = *pn;
*pn = pomocna;
for (i = 0; i < *pm; ++i)
for (j = 0; j < *pn; ++j)
*(polje + i*brclanstup + j) = pom[i][j];

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 102

/* BOLJA funkcija za transponiranje (bez pomocnog polja) */


void transp(int *polje, int *pm, int *pn, int brclanstup) {
int najvecaDim, i, j, pomClan, pomDim;
najvecaDim = *pm > *pn ? *pm : *pn;
for (i = 0; i < najvecaDim - 1; ++i) {
for (j = i+1; j < najvecaDim; ++j ) {
pomClan = *(polje + i*brclanstup + j);
*(polje + i*brclanstup + j) = *(polje + j*brclanstup + i);
*(polje + j*brclanstup + i) = pomClan;
}
}
pomDim = *pm;
*pm = *pn;
*pn = pomDim;
}

9
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 122

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

20. vježbe uz predavanja

1. Na vlastitom računalu testirajte sve primjere vezane uz makro definicije s predavanja.

2. Napišite program koji će poslužiti kao primjer kojim ćete "dokazati" da sljedeće macro
definicije nisu ispravno napisane:
#define ZBROJI(a, b) a + b
#define ODUZMI(a, b) (a)-(b)
#define PODIJELI(x, y) (x/y)
#define OPETPODIJELI(x, y) (x)/(y)

Koja pravila pisanja ove macro definicije ne zadovoljavaju? Zatim u svom programu ispravite
navedene macro definicije i ponovo izvedite program.

3. Napisati funkciju traziPrviSamoglas koja u zadanom nizu znakova pronalazi prvi samoglasnik
(malo ili veliko slovo) koji se pojavljuje u nizu. Funkcija u pozivajući program vraća pokazivač
na pronađeni samoglasnik, a ako u nizu nema niti jedan samoglasnik, vraća null pokazivač.
Napisati glavni program koji će pomoću funkcije gets učitati niz znakova ne dulji od 80
znakova, te pomoću funkcije traziPrviSamoglas pronaći te na zaslon ispisati prvi samoglasnik
učitanog niza ili poruku "U nizu nema samoglasnika".

4. Definirati tip podatka tTocka kojim se opisuje jedna točka u pravokutnom koordinatnom
sustavu (x i y su vrijednosti tipa double). Napisati prototip funkcije udaljToc koja za dvije
točke zadane pomoću tipa podatka tTocka izračunava udaljenost među točkama (double).
Definiciju tipa tTocka i prototip funkcije udaljToc napisati u zaglavnoj datoteci geom.h.
Definiciju funkcije udaljToc napisati u modulu geom.c
Napisati glavni program koji će u varijable t1 i t2 tipa tTocka učitati koordinate dviju točaka,
zatim pomoću funkcije udaljToc izračunati njihovu udaljenost, te izračunatu vrijednost ispisati
na zaslon.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 122

Rješenja

Rješenje 2. zadatka

#include <stdio.h>

#define ZBROJI(a, b) a + b
#define ODUZMI(a, b) (a)-(b)
#define PODIJELI(x, y) (x/y)
#define OPETPODIJELI(x, y) (x)/(y)

int main(void) {
int c = ZBROJI(3, 2) * 5;
float z = ODUZMI(3.f, 2.f) * 5.f;
int d = PODIJELI(20, 2*5);
float w = 20.f / OPETPODIJELI(10.f, 2.f);

printf("ZBROJI(3, 2) * 5 = 25? dobije se: %d\n", c);


printf("ODUZMI(3.f, 2.f) * 5.f = 5.0? dobije se: %f\n", z);
printf("PODIJELI(20, 2*5) = 2? dobije se: %d\n", d);
printf("20.f / OPETPODIJELI(10.f, 2.f) = 4.0? dobije se: %f\n", w);

return 0;
}

Ispravne macro definicije:


#define ZBROJI(a, b) ((a) + (b))
#define ODUZMI(a, b) ((a)-(b))
#define PODIJELI(x, y) ((x)/(y))
#define OPETPODIJELI(x, y) ((x)/(y))

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 122

Rješenje 3. zadatka

#include <stdio.h>

char *traziPrviSamoglas(char *niz) {


char *samoglas = NULL;
while (*niz) {
if (*niz == 'a' || *niz == 'A' ||
*niz == 'e' || *niz == 'E' ||
*niz == 'i' || *niz == 'I' ||
*niz == 'o' || *niz == 'O' ||
*niz == 'u' || *niz == 'U') {
samoglas = niz;
break;
}
++niz;
}
return samoglas;
}

int main (void) {


char niz[80+1];
char *samoglas;
gets(niz);
samoglas = traziPrviSamoglas(niz);
if (samoglas != NULL) {
printf("Prvi samoglasnik u nizu \"%s\" je znak \'%c\'\n", niz, *samoglas);
}
else {
printf("U nizu \"%s\" nema samoglasnika\n", niz);
}
return 0;
}

Funkcija se može vrlo lako prepraviti tako da pronalazi posljednji samoglasnik u nizu.

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 08-Funkcije.pdf - do stranice: 122

Rješenje 4. zadatka

glavni.c
#include <stdio.h>
#include "geom.h"

int main(void) {
tTocka t1, t2;

printf("Upisite koordinate tocke t1:");


scanf("%lf%lf", &t1.x, &t1.y);
printf("Upisite koordinate tocke t2:");
scanf("%lf%lf", &t2.x, &t2.y);

printf("Udaljenost izmedju t1 i t2 je %f\n", udaljToc(t1, t2));


return 0;
}

geom.h
typedef struct {
double x;
double y;
} tTocka;

double udaljToc (tTocka t1, tTocka t2);

geom.c
#include <math.h>
#include "geom.h"

double udaljToc (tTocka t1, tTocka t2) {


return sqrt(pow(t2.x - t1.x, 2.) + pow(t2.y - t1.y, 2.));
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

21. vježbe uz predavanja

U svim zadacima u kojima se traži definiranje funkcije, treba napisati odgovarajući glavni
program (tj. funkciju main) u kojem ćete po potrebi definirati stvarne argumente, pozvati funkciju
i ispisati rezultat.
1. Na svom računalu testirajte primjere s predavanja vezane uz funkcije fabs i abs, te primjer
kojim je prikazana razlika između funkcije exit i naredbe return.
2. S tipkovnice učitati cijeli broj n uz kontrolu da je 3 ≤ n ≤ 20. Na slučajan način odabrati n
velikih slova (među znakovima A-Z) i ispisati ih na zaslon.
3. Generirati 10 000 cijelih brojeva iz zatvorenog intervala [50,60]. Na zaslon ispisati frekvenciju
pojavljivanja svakog od brojeva.
50 se pojavio 1100 puta
51 se pojavio 987 puta
...
60 se pojavio 1083 puta
4. Napisati funkciju koja u zadano dvodimenzijsko cjelobrojno polje "ispaljuje zadani broj
hitaca". Element polja u kojeg pojedini hitac pogađa odabire se na slučajan način (funkcija na
slučajan način odabere redak elementa, a zatim na slučajan način odabere stupac
elementa). Vrijednost elementa polja koji je "pogođen", funkcija uvećava se za jedan.
Funkcija treba inicijalizirati generator pseudoslučajnih brojeva samo pri prvom pozivu, a prije
nego počne "gađati" polje, mora elemente polja inicijalizirati na vrijednost 0.
U glavnom programu definirati polje maksimalnih dimenzija 10x10, s tipkovnice učitati m i n,
te "broj "hitaca h koje u polje dimenzija mxn funkcija treba "ispaliti". Pozvati funkciju te u
obliku tablice ispisati sadržaj polja nakon što je "pogođeno" s h hitaca, a zatim u nastavku
programa to ponoviti (s istim argumentima).
Što će se dogoditi ako funkciju prepravite tako da se generator pseudoslučajnih brojeva
inicijalizira pri svakom pozivu funkcije? Zašto se tada (u najvećem broju slučajeva) dobiju
dva jednaka polja?

5. Napisati funkciju obrniNiz koja obrće niz znakova. Npr. niz znakova "ABCDE" mijenja u niz
znakova "EDCBA". Uputa: 1. znak zamijeniti s n-tim znakom, 2. znak zamijeniti s n-1-vim
znakom, itd.
6. Napisati funkciju umetniZnak koja na početak zadanog niza znakova umeće zadani znak.
Funkcija može računati na to da je za niz u pozivajućem programu rezervirano dovoljno
memorije. U funkciji se ne smiju koristiti funkcije iz <string.h>.
7. Napisati funkciju umetniZnakove koja ispred svakog znaka zadanog niza umeće zadani znak
(npr, ako se funkciji zada niz "Studeni" i znak 'X', funkcija mijenja niz u "XSXtXuXdXeXnXi").
Funkcija može računati na to da je za niz u pozivajućem programu rezervirano dovoljno
memorije. U funkciji se ne smiju koristiti funkcije iz <string.h>.
8. Napisati vlastitu funkciju myStrcpy koja obavlja isto što i funkcija strcpy definirana u string.h.
U funkciji se ne smiju koristiti funkcije iz <string.h>.
9. Napisati vlastitu funkciju myStrlen koja obavlja isto što i funkcija strlen definirana u string.h
(jedina razlika neka bude u tome što myStrlen vraća int, umjesto size_t). U funkciji se ne
smiju koristiti funkcije iz <string.h>.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

10. Napisati vlastitu funkciju myStrcat koja obavlja isto što i funkcija strcat definirana u string.h. U
funkciji se ne smiju koristiti funkcije iz <string.h>.
11. Napisati funkciju koja kao rezultat vraća koliko puta se niz s2 pojavljuje unutar niza s1. U
glavnom programu pomoću funkcije gets učitati dva niza, pozvati funkciju i ispisati rezultat. U
funkciji je dopušteno koristiti funkcije iz biblioteke <string.h>.

12. Što će biti sadržaj nizova znakova s1, s2 i s3 nakon obavljanja odsječka programa:

char s1[20] = "ef123f156xyz", s2[20]="ABCD", s3[20];


strcat(strcat(s2, "abc"), strcpy(s3, strstr(strchr(s1, '2'), "f1")));
13. Napisati macro MYTOUPPER koja obavlja isto što i funkcija toupper definirana u <ctype.h>.
Napisati glavni program koji će pomoću funkcije gets učitati niz znakova (sigurno ne dulji od
40 znakova), te na zaslon ispisati učitani niz, ali tako da su sva mala slova pretvorena u
velika. Za pretvaranje malih slova u velika koristiti macro MYTOUPPER.
14. Napisati vlastitu funkciju myStrchr koja obavlja isto što i funkcija strchr definirana u
<string.h>. U funkciji se ne smiju koristiti funkcije iz <string.h>.
15. Napisati vlastitu funkciju myStrstr koja obavlja isto što i funkcija strstr definirana u
<string.h>. U funkciji se ne smiju koristiti funkcije iz <string.h>.
16. Napisati program kojim će se generirati 1000 slučajnih znakova čije su ASCII vrijednosti u
intervalu [32,126]. Na zaslon ispisati koliko dobivenih znakova je slovo, koliko dobivenih
znakova je znamenka, a koliko dobivenih znakova nije niti znamenka niti slovo. Za ispitivanje
znakova koristite ugrađene macro definicije iz <ctype.h>.

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Rješenja

Rješenje 2. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main (void) {


int n, i, slucajni;
char ascii;
do {
printf("Upisite n:");
scanf("%d", &n);
}
while (n < 3 || n > 20);

srand ((unsigned) time(NULL));

for (i = 0; i < n; ++i) {


slucajni = rand();
/* interval [a=0, b=RAND_MAX] preslikati u interval [c='A', d='Z'] */
ascii = (float) slucajni / (RAND_MAX+1) * ('Z'-'A'+1) + 'A';
/* moze i ovako: ascii = slucajni % ('Z' - 'A' + 1) + 'A'; */
printf("%c", ascii);
}
printf("\n");
}

Rješenje 3. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define DG 50
#define GG 60

int main (void) {


int i, slucajni, slucajni2;
int polje[GG-DG+1] = {0};

srand ((unsigned) time(NULL));


for (i = 0; i < 1000; ++i) {
slucajni = rand();
/* interval [a=0, b=RAND_MAX] preslikati u interval [c=DG, d=GG] */
slucajni2 = (float) slucajni / (RAND_MAX+1) * (GG-DG+1) + DG;
/* moze i ovako: slucajni2 = slucajni % (GG - DG + 1) + DG; */
polje[slucajni2-DG]++;
}
for (i = DG; i <= GG; ++i) {
printf("%d se pojavio %d puta\n", i, polje[i-DG]);
}
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Rješenje 4. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAXR 10
#define MAXS 10

void gadjaj(int *polje, int m, int n, int maxstup, int brojHitaca) {


static int generatorInicijaliziran = 0;
int i, j, redak, stupac;
if (! generatorInicijaliziran) {
srand ((unsigned) time(NULL));
generatorInicijaliziran = 1;
}

for (i = 0; i < m; ++i)


for (j = 0; j < n; ++j)
*(polje + i*maxstup + j) = 0;

for (i = 0; i < brojHitaca; ++i) {


/* slucajni redak */
redak = rand() % m;
/* slucajni stupac */
stupac = rand() % n;
*(polje + redak * maxstup + stupac) += 1;
}
}

void ispisiPolje(int *polje, int m, int n, int maxstup) {


int i, j;
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j)
printf("%5d", *(polje + i*maxstup + j));
printf("\n");
}
}

int main (void) {


int m, n, brojHitaca;
int polje[MAXR][MAXS];
printf("Upisite m, n i broj hitaca -> ");
scanf("%d %d %d", &m, &n, &brojHitaca);

gadjaj(&polje[0][0], m, n, MAXS, brojHitaca);


ispisiPolje(&polje[0][0], m, n, MAXS);

printf("\n");

gadjaj(&polje[0][0], m, n, MAXS, brojHitaca);


ispisiPolje(&polje[0][0], m, n, MAXS);
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Funkcija će pri svakom pozivu ponovo inicijalizirati generator ako se blok naredbi

if (! generatorInicijaliziran) {
srand ((unsigned) time(NULL));
generatorInicijaliziran = 1;
}
zamijeni sa
srand ((unsigned) time(NULL));

Druga inicijalizacija generatora će se tada dogoditi vrlo vjerojatno s istim početnim uvjetima-seed
(jer će se oba poziva funkcije vrlo vjerojatno obaviti unutar iste sekunde), stoga će i nizovi
generiranih pseudoslučajnih brojeva biti jednaki.

Rješenje 5. zadatka
#include <stdio.h>
#define MAX 20

void obrniNiz(char *niz);

int main (void) {


char niz[MAX+1];
printf ("Upisite niz znakova (ne dulji od %d znakova):", MAX);
gets(niz);
printf("%s\n", niz);
obrniNiz(niz);
printf("%s\n", niz);
/* VAZNO PITANJE: */
/* zasto funkciju nije moguce pozvati ovako: obrniNiz("Prosinac"); */
return 0;
}

void obrniNiz(char *niz) {


int i;
char pom;
int duljina = 0;
while (*(niz + duljina))
duljina++;
for (i = 0; i < duljina/2; ++i) {
pom = niz[i];
niz[i] = niz[duljina-1-i];
niz[duljina-1-i] = pom;
}
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Rješenje 6. zadatka
#include <stdio.h>
#include <string.h>

void umetniZnak(char *niz, char c);

int main (void) {


char niz[7+1+1];
strcpy(niz, "Studeni");
umetniZnak(niz, 'A');
printf("%s\n", niz);
/* VAZNO PITANJE: */
/* zasto funkciju nije moguce pozvati ovako: umetniZnak("Studeni", 'A'); */
return 0;
}

void umetniZnak(char *niz, char c) {


int i;
int duljina = 0;
while (*(niz + duljina))
++duljina;
niz[duljina+1] = '\0';
for (i = duljina; i > 0; --i)
niz[i] = niz[i-1];
niz[0] = c;
}

Rješenje 7. zadatka
#include <stdio.h>
#include <string.h>

void umetniZnakove(char *niz, char c);

int main (void) {


char niz[7+1+7];
strcpy(niz, "Studeni");
umetniZnakove(niz, 'X');
printf("%s\n", niz);
/* VAZNO PITANJE: */
/* zasto funkciju nije moguce pozvati ovako: umetniZnakove("Studeni", 'A'); */
return 0;
}

void umetniZnakove(char *niz, char c) {


int i;
int duljina = 0;
while (*(niz + duljina))
++duljina;
*(niz + 2*duljina) = '\0';
for (i = duljina - 1; i >= 0; --i) {
*(niz + 2*i + 1) = *(niz + i);
*(niz + 2*i) = c;
}
}

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Rješenje 8. zadatka
#include <stdio.h>

char *myStrcpy(char *cilj, char *izvor);

int main (void) {


char ciljniNiz[20+1];
char *izvorniNiz = "Niz znakova";
myStrcpy(ciljniNiz, izvorniNiz);
printf("%s\n", ciljniNiz);
myStrcpy(ciljniNiz, "Ana");
printf("%s\n", ciljniNiz);
/* moze i ovako: objasnite zasto! */
printf("%s\n", myStrcpy(ciljniNiz, "Iva"));
/* VAZNO PITANJE: */
/* zasto funkciju nije moguce pozvati ovako: myStrcpy(" ", "Ana"); */
return 0;
}

char *myStrcpy(char *cilj, char *izvor) {


int i = 0;
while (*(izvor+i)) {
*(cilj+i) = *(izvor+i);
++i;
}
*(cilj+i) = '\0';
return cilj;
}

Rješenje 9. zadatka
#include <stdio.h>

int myStrlen(char *niz);

int main (void) {


char niz[20+1] = "Ovo je niz";
char *konst = "Ovo je konstantni niz";
printf("%d\n", myStrlen(niz));
printf("%d\n", myStrlen(konst));
printf("%d\n", myStrlen("Ovo je jos jedan konstatni niz"));
return 0;
}

int myStrlen(char niz[]) {


int i = 0;
while (niz[i]) ++i;
return i;
}

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Rješenje 10. zadatka


#include <stdio.h>

char *myStrcat(char *cilj, char *izvor);

int main (void) {


char ciljniNiz[30+1] = "Prvi";
char ciljniNiz2[30+1] = "Pocetak";
char *izvorniNiz = "Drugi";
myStrcat(ciljniNiz, izvorniNiz);
printf("%s\n", ciljniNiz);
myStrcat(ciljniNiz, "Treci");
printf("%s\n", ciljniNiz);
/* moze i ovako: objasnite zasto! */
printf("%s\n", myStrcat(ciljniNiz, "Cetvrti"));
/* VAZNO PITANJE: */
/* zasto funkciju nije moguce pozvati ovako: myStrcat("ABC", "EFG") */
/* proucite sljedecu naredbu */
myStrcat(myStrcat(ciljniNiz2, "Sredina"), "Kraj");
printf("%s\n", ciljniNiz2);
return 0;
}

char *myStrcat(char cilj[], char *izvor) { /* takodjer moze char *cilj */


int i = 0, j = 0;
while (cilj[i])
++i;
while (izvor[j])
cilj[i++] = izvor[j++];
cilj[i] = '\0';
return cilj;
}

Rješenje 11. zadatka


#include <stdio.h>
#include <string.h>

int brojPodnizova(char *s1, char *s2) {


char *pocetakPotrage = s1;
int brojac = 0;
while ((pocetakPotrage = strstr(pocetakPotrage, s2)) != NULL) {
++brojac;
++pocetakPotrage;
}
return brojac;
}

int main (void) {


char s1[40+1];
char s2[40+1];
printf("Upisite nizove s1 i s2\n");
gets(s1);
gets(s2);
printf("Niz %s se unutar niza %s pojavljuje %d puta\n",
s2,
s1,
brojPodnizova(s1, s2));
return 0;
}

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Rješenje 13. zadatka


#include <stdio.h>
#define MYTOUPPER(c) ((c) >= 'a' && (c) <= 'z' ? \
(c) - 'a' + 'A' : (c))

int main (void) {


char niz[40];
int i = 0;
gets(niz);
while (niz[i] != 0) {
putchar(MYTOUPPER(niz[i])); /* ili printf("%c", MYTOUPPER(niz[i])); */
++i;
}
return 0;
}

Rješenje 14. zadatka


#include <stdio.h>

char *myStrchr(char *niz, char c) {


while (*niz != '\0') {
if (*niz == c)
return niz;
++niz;
}
return NULL;
}

int main (void) {


char *nadjen;
nadjen = myStrchr("Neki niz", 'k');
if (nadjen != NULL)
printf("Nasao sam:%c\n", *nadjen);
else
printf("Nisam nasao\n");

nadjen = myStrchr("Neki niz", 'K');


if (nadjen != NULL)
printf("Nasao sam:%c\n", *nadjen);
else
printf("Nisam nasao\n");

return 0;
}

9
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 38

Rješenje 15. zadatka


#include <stdio.h>

char *myStrstr(char *niz, char *podniz) {


char *pocetakTraganja = niz;
while (*pocetakTraganja != '\0') {
int i = 0;
while (pocetakTraganja[i] == podniz[i] && podniz[i] != '\0')
++i;
if (podniz[i] == '\0')
return pocetakTraganja;
++pocetakTraganja;
}
return NULL;
}

int main (void) {


char *nadjen;
nadjen = myStrstr("Neki tekst i drugi tekst", "tek");
if (nadjen != NULL)
printf("Nasao sam:%s\n", nadjen);
else
printf("Nisam nasao\n");

nadjen = myStrstr("Neki tekst i drugi tekst", "Tekst");


if (nadjen != NULL)
printf("Nasao sam:%s\n", nadjen);
else
printf("Nisam nasao\n");

return 0;
}

Rješenje 16. zadatka


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>

int main (void) {


char slucajniZnak;
int i, slova = 0, znamenki = 0, ostalih = 0;

srand ((unsigned) time(NULL));


for (i = 0; i < 1000; ++i) {
slucajniZnak = rand() % (126 - 32 + 1) + 32;
if (isalpha(slucajniZnak))
++slova;
else if (isdigit(slucajniZnak))
++znamenki;
else
++ostalih;
}
printf("%d slova, %d znamenki, %d ostalih znakova\n",
slova, znamenki, ostalih);
return 0;
}

10
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 52

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

22. vježbe uz predavanja

1. Na svom računalu testirajte sve primjere s predavanja.

2. Napisati program koji pomoću funkcije getchar s tipkovnice učitava znakove u niz s1 dok god
ne bude učitan znak 'X' (znak 'X' se ne dodaje u niz s1). Zatim u niz s2 učitava znakove dok
se ne pojavi znak 'Y' (znak 'Y' se ne dodaje u niz s2). Osigurati da nizovi s1 i s2 budu
ispravno terminirani (tj. na kraju niza se nalazi znak '\0'). Nakon učitavanja, pomoću funkcije
putchar ispisati nizove s1 i s2 na zaslon, svaki u svoj redak. Nizovi s1 i s2 sigurno nisu dulji
od 80 znakova.
Primjer: ako se preko tipkovnice unese: Ovo je
neki tekst.XA ovo
je nastavakYOstatak se ne ucitava

kao rezultat treba ispisati: Ovo je


neki tekst.
A ovo
je nastavak

3. Napisati program kojim će se u dvodimenzionalno znakovno polje učitati tekst s tipkovnice.


Svaki redak teksta treba učitati u zasebni redak polja. Učitavanje redaka teksta treba
prekinuti kad se učita prazan redak ili se dođe do granice od najviše 10 dozvoljenih redaka.
Može se računati da niti jedan redak teksta neće biti dulji od 80 znakova. Za čitanje teksta
koristiti funkciju gets iz <stdio.h>. Na kraju, pomoću funkcije printf, na zaslon ispisati sve
učitane retke teksta, svaki redak teksta u svom retku na zaslonu.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 52

Rješenja

Rješenje 2. zadatka
#include <stdio.h>

int main(void) {
char s1[80+1], s2[80+1], c;
int i;

i = 0;
while((c = getchar()) != 'X')
s1[i++] = c;
s1[i] = '\0';

i = 0;
while((c = getchar()) != 'Y')
s2[i++] = c;
s2[i] = '\0';

i = 0;
while (s1[i] != '\0')
putchar(s1[i++]);

printf("\n");

i = 0;
while (s2[i] != '\0')
putchar(s2[i++]);

return 0;
}

Rješenje 3. zadatka
#include <stdio.h>

#define MAXRED 10
#define MAXSTUP 80

int main (void) {


char polje[MAXRED][MAXSTUP+1];
int i, ucitanoRedaka = 0;

while (ucitanoRedaka < 10) {


/* gets kao argument koristi adresu prvog clana odgovarajuceg
retka 2D polja */
gets(&polje[ucitanoRedaka][0]);
if (polje[ucitanoRedaka][0] == '\0')
/* ucitan je prazan redak, prekini ucitavanje */
break;
++ucitanoRedaka;
}
for (i = 0; i < ucitanoRedaka; ++i)
printf("%s\n", &polje[i][0]);
return 0;
}

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 77

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

23. vježbe uz predavanja

1. Što će se ispisati sljedećim programskim odsječkom. Izvođenjem programa na svom


računalu provjerite svoj odgovor. Ulazni podaci su 11 12 13 1e
int i, j, k, m;
scanf("%d %o %x %x", &i, &j, &k, &m);
printf("%d %d %d %d\n", i, j, k, m);

2. Na svom računalu izvedite sljedeći programski odsječak, uz ulazne podatke 1 2 3.0 4.0
int i;
short j;
float x;
double y;
scanf("%d %d %f %f", &i, &j, &x, &y);
printf("%d %d %f %f\n", i, j, x, y);
Jesu li se printf naredbom ispisale ispravne vrijednosti? Objasnite zašto. Što treba
promijeniti u formatu scanf naredbe da bi odsječak radio ispravno? Izvođenjem programa na
svom računalu provjerite svoj odgovor.

3. Koje su vrijednosti svih definiranih varijabli nakon obavljanja sljedećeg odsječka programa:
int rez1, rez2, rez3;
int a, b, c;
short d;
char e;
float x, y;
double z, w;
rez1 = scanf("%3d%d%d %hx%c", &a, &b, &c, &d, &e);
rez2 = scanf("%f%5f", &x, &y);
rez3 = scanf(" %lf %lf", &z, &w); 12345 6
a2m
ako su preko tipkovnice uneseni sljedeći podaci: 11-10 .1+ 3

4. Koje su vrijednosti svih definiranih varijabli nakon obavljanja sljedećeg odsječka programa:
int rez1, rez2;
int a, b;
char s1[10+1], s2[10+1], s3[10+1], s4[10+1];
rez1 = scanf("%3d %d", &a, &b);
rez2 = scanf("%s%s%4s %s", s1, s2, s3, s4);
ako su preko tipkovnice uneseni sljedeći podaci:

12ab Marija
Marica Ana

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 77

5. Napisati program koji će pomoću funkcije scanf iz <stdio.h> učitati dva niza znakova s1 i
s2, čiji se sadržaj unosi preko tipkovnice i to tako da se svaki niz utipka u svojem retku.
Oznaka kraja retka se ne učitava u niz znakova. Npr. sadržaj ulaza može izgledati ovako:

Dva psa.
Jedan macak.

Može se računati da niti jedan redak teksta neće biti dulji od 30 znakova. Program treba
formirati niz s3, čiji sadržaj nastaje spajanjem nizova s1 i s2, te dobiveni niz s3 ispisati na
zaslon. U navedenom primjeru na zaslon treba ispisati:

Dva psa.Jedan macak.

6. Preko tipkovnice se unose matični brojevi i datumi rođenja osoba. Datum rođenja sadrži redni
broj dana, redni broj mjeseca i redni broj godine. Npr. sadržaj ulaza može izgledati ovako:

101 15.5.1989
1526 17.6.1987
17 9.12.1987
0

Za svaku osobu pomoću funkcije scanf učitati matični broj, redni broj dana, redni broj
mjeseca i redni broj godine. Učitavanje se prekida kada se za matični broj upiše 0. Nakon
završenog učitavanja, ispisati matične brojeve i godine rođenja osoba. Za prikazani primjer
ulaza, izlaz treba izgledati ovako:

101. 1989.
1526. 1987.
17. 1987.

Može se pretpostaviti da će korisnik unijeti podatke za najviše 100 osoba.

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 77

7. Što će se ispisati sljedećim programom:

#include <stdio.h>

int main(void) {
printf("|%d|\n", 10);
printf("|%5d|\n", 10);
printf("|%1d|\n", 10);

printf("|%s|\n", "Ana");
printf("|%5s|\n", "Ana");
printf("|%2s|\n", "Ana");

printf("|%x|\n", 27);
printf("|%6x|\n", 27);

printf("|%o|\n", 9);
printf("|%6o|\n", 9);
printf("|%1o|\n", 9);

printf("|%f|%7.4f|%7.2f|\n", 23.127, 23.127, 23.127);


printf("|%e|%12.4e|%.2e|\n", 0.00021278, 0.00021278, 0.00021278);

return 0;
}

8. Napisati program koji će s tipkovnice pročitati cijeli broj broj n (1 ≤ n ≤ 15). Program treba na
zaslon ispisati "tablicu množenja". Npr. za zadani n=12, ispis na zaslon treba izgledati ovako:

Tablica mnozenja 12x12


1 2 3 4 5 6 7 8 9 10 11 12
----+------------------------------------------------
1! 1 2 3 4 5 6 7 8 9 10 11 12
2! 2 4 6 8 10 12 14 16 18 20 22 24
3! 3 6 9 12 15 18 21 24 27 30 33 36
4! 4 8 12 16 20 24 28 32 36 40 44 48
5! 5 10 15 20 25 30 35 40 45 50 55 60
6! 6 12 18 24 30 36 42 48 54 60 66 72
7! 7 14 21 28 35 42 49 56 63 70 77 84
8! 8 16 24 32 40 48 56 64 72 80 88 96
9! 9 18 27 36 45 54 63 72 81 90 99 108
10! 10 20 30 40 50 60 70 80 90 100 110 120
11! 11 22 33 44 55 66 77 88 99 110 121 132
12! 12 24 36 48 60 72 84 96 108 120 132 144
----+------------------------------------------------

Npr. za zadani n=1, ispis na zaslon treba izgledati ovako:

Tablica mnozenja 1x1


1
----+----
1! 1
----+----

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 77

Rješenja

Rješenje 5. zadatka
#include <stdio.h>
#include <string.h>
#define MAXNIZ 30

int main (void) {


char s1[MAXNIZ+1], s2[MAXNIZ+1], s3[2*MAXNIZ+1];
/* procitaj prvi niz. Citaj dok ne dodjes do \n */
scanf("%[^\n]", s1);
/* procitaj znak '\n' koji je preostao na ulazu */
getchar();
/* procitaj drugi niz. Citaj dok ne dodjes do \n */
scanf("%[^\n]", s2);
/* kopiraj s1 u s3 */
strcpy(s3, s1);
/* dodaj s2 na kraj s3 */
strcat(s3, s2);

printf("%s\n", s3);
return 0;
}

Rješenje 6. zadatka
#include <stdio.h>
#define MAX 100

int main(void) {
int dan, mjesec;
int matBroj, matBrojevi[MAX], godine[MAX];
int brojUcitanih = 0, i;
char tocka;
do {
scanf("%d", &matBroj);
if (matBroj != 0) {
matBrojevi[brojUcitanih] = matBroj;
scanf("%d%c%d%c%d", &dan, &tocka, &mjesec, &tocka,
&godine[brojUcitanih]);
++brojUcitanih;
}
} while (matBroj != 0);
for (i = 0; i < brojUcitanih; ++i)
printf("%4d. %4d.\n", matBrojevi[i], godine[i]);
printf("\n");
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 09-UgradjeneFunkcije.pdf - do stranice: 77

Rješenje 8. zadatka
#include <stdio.h>

int main(void) {
int n, i, j;
do {
printf("Upisite vrijednost za n: ");
scanf ("%d",&n);
} while (n < 1 || n > 15 );

printf("Tablica mnozenja %dx%d\n", n, n);


printf(" ");
for (i = 1; i <= n; ++i) {
printf("%4d", i);
}
printf("\n");

printf("----+", i);
for (i = 1; i <= n; ++i) {
printf("----", i);
}
printf("\n");

for (i = 1; i <= n; ++i) {


printf("%4d!", i);
for (j = 1; j <= n; ++j) {
printf("%4d", i*j);
}
printf("\n");
}

printf("----+", i);
for (i = 1; i <= n; ++i) {
printf("----", i);
}
printf("\n");
return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

24. vježbe uz predavanja

1. Napisati program koji će sadržaj tekstualne datoteke ulaz.txt prepisati na zaslon, ali tako
da se umjesto malih slova ispisuju velika. Za čitanje znakova iz datoteke treba koristiti
funkciju fgetc. Pomoću editora (npr. notepad) prirediti tekstualnu datoteku ulaz.txt,
pohraniti ju unutar nekog kazala (direktorija), npr. c:\tmp, te testirati program.
2. Napisati funkciju broji koja kao argument prima niz znakova koji predstavlja ime
tekstualne datoteke (tip podatka char *). Funkcija treba otvoriti tok podataka za čitanje iz
datoteke sa zadanim imenom (tj. "otvoriti datoteku"), prebrojati samoglasnike (broje se i
"mali" i "veliki" samoglasnici), zatvoriti tok podataka (tj. "zatvoriti datoteku"), te u pozivajući
program vratiti broj samoglasnika. Ako funkcija ne uspije otvoriti datoteku, kao broj
samoglasnika vraća -1. Za čitanje znakova iz datoteke treba koristiti funkciju fgetc. Pomoću
editora (npr. notepad) prirediti jednu tekstualnu datoteku, te napisati glavni program kojim će
se testirati rad funkcije.
3. Slično kao u prethodnom zadatku. Funkcija broji kao argument prima tok podataka (tip
podatka *FILE) koji je već otvoren za tekstualnu datoteku. Glavni program otvara tok
podataka za postojeću tekstualnu datoteku, predaje ga funkciji, a kad funkcija obavi brojanje,
glavni program ispisuje rezultat i zatvara tok podataka.
4. Prepraviti rješenje zadatka 6. (ispis tablice množenja) iz prethodnih vježbi uz predavanja.
Tablicu množenja, umjesto na zaslon, treba zapisati u tekstualnu datoteku čije ime treba
učitati s tipkovnice. Editorom (npr. notepad) provjeriti sadržaj dobivene datoteke.
5. Napisati program koji pomoću funkcije fscanf čita realne brojeve iz tekstualne datoteke
brojevi.txt, te po završetku čitanja (kada se dođe do kraja datoteke ili se pri čitanju
dogodi pogreška) na zaslon ispisuje ili aritmetičku sredinu učitanih brojeva ili poruku "Nije
procitan niti jedan broj". Npr. za sadržaj datoteke:
22 13.5 -2 1
11.0 -3.5

na zaslon treba ispisati: 7.000000

Npr. za sadržaj datoteke


a11 4.5 22
4.2 11

na zaslon treba ispisati: Nije procitan niti jedan broj.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

6. U tekstualnu datoteku osobe.txt editorom upisati podatke o osobama (matični broj, ime,
prezime i datum rođenja). Primjer sadržaja datoteke prikazan je ovdje:
952 Nikolina Medvedec 15.5.1989
101 Iva Vurnek 17.6.1987
412 Natalija Voras 11.6.1988
551 Anatolij Ozimec 24.2.1989
115 Franjo Zdilar 22.11.1986
471 Ivana Suhina 8.6.1988
Napisati program koji će na zaslon ispisati sve podatke o osobama iz datoteke osobe.txt
čije ime sadrži niz znakova na. Za datoteku iz primjera, program treba na zaslon ispisati
sljedeće:
952 Nikolina Medvedec 15.5.1989
551 Anatolij Ozimec 24.2.1989
471 Ivana Suhina 8.6.1988

7. U tekstualnoj datoteci mjerenja.txt nalaze se zapisi o mjerenjima temperature u obliku:


#ddd#NN#hh#x.x#hh#xx.x#hh#xx.x#...hh#xx.x#
U zapisu se nalazi redni broj dana u godini (ddd), broj mjerenja obavljenih tog dana (NN),
sat u kojem je obavljeno mjerenje (hh), izmjerena temperatura (x.x). Npr.
#175#4#3#-11.5#12#2.0#16#5.0#22#-2.5#
Prethodni zapis znači da su u danu s rednim broje 175 obavljena 4 mjerenja: u 3 sata
temperatura je bila -11.5 stupnjeva, u 12 sati 2 stupnja, u 16 sati 5 stupnjeva i u 22 sata -2.5
stupnja.
Za svaki zapis iz datoteke mjerenja.txt ispisati na zaslon redni broj dana i srednju
vrijednost izmjerenih temperatura za taj dan.

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

8. Ovaj zadatak je važan za razumijevanje funkcije fgets. U predavanjima prvo pažljivo pročitati
što točno radi funkcija fgets.
Uz pretpostavku da je sadržaj datoteke podaci.txt:
abcde
fghijk
lmnoprs
ABCDEFGH

što će biti sadržaj datoteke izlaz.txt nakon obavljanja sljedećeg programa:

#include <stdio.h>
#include <stdlib.h>
#define MAXLIN 7

int main (void) {


FILE *du, *di;
char linija[MAXLIN];

du = fopen ("podaci.txt", "r");


di = fopen ("izlaz.txt", "w");
while (fgets(linija, MAXLIN, du) != NULL ) {
fputs (linija, di);
}
fclose (du);
fclose (di);

return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

Rješenja

Rješenje 1. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main (void) {


int c;
FILE *tokPod;
char *imeDat = "ulaz.txt";
tokPod = fopen(imeDat, "r");

if (tokPod == NULL) {
printf("Ne mogu otvoriti %s\n", imeDat);
exit(1);
}

while ((c = fgetc(tokPod)) != EOF)


putchar(toupper(c)); /* ili fputc(toupper(c), stdout); */

fclose(tokPod);
return 0;
}

Rješenje 2. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define MAXIMEDAT 64

int broji (char *ime) {


int broj;
char c;
FILE *ulTok;

ulTok = fopen (ime, "r");


if (ulTok != NULL) {
broj = 0;
while ((c = fgetc(ulTok)) != EOF) {
c = toupper(c);
if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U')
++broj;
}
fclose(ulTok);
return broj;
}
else {
/* otvaranje ulaznog toka podataka nije uspjelo */
broj = -1;
}
return broj;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

int main (void) {


char imedat[MAXIMEDAT+1];
int broj;
printf("Upisite ime datoteke>");
scanf("%s", imedat);
broj = broji(imedat);
if (broj == -1)
printf("Problemi kod otvaranja datoteke %s\n", imedat);
else
printf("U datoteci %s ima %d samoglasnika\n", imedat, broj);
return 0;
}

Rješenje 3. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define MAXIMEDAT 64

int broji (FILE *ulTok) {


int broj = 0;
char c;
while ((c = fgetc(ulTok)) != EOF) {
c = toupper(c);
if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U')
++broj;
}
return broj;
}

int main (void) {


char imedat[MAXIMEDAT+1];
int broj;
FILE *ulaz;
printf("Upisite ime datoteke>");
scanf("%s", imedat);

ulaz = fopen (imedat, "r");


if (ulaz != NULL) {
broj = broji(ulaz);
printf("U datoteci %s ima %d samoglasnika\n", imedat, broj);
fclose(ulaz);
}
else {
printf("Problemi kod otvaranja datoteke %s\n", imedat);
}
return 0;
}

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

Rješenje 4. zadatka
#include <stdio.h>

int main(void) {
int n, i, j;
char imeDat[64+1];
FILE *tok;

printf("Upisite ime datoteke: ");


scanf("%s", imeDat);
do {
printf("Upisite vrijednost za n: ");
scanf ("%d",&n);
} while (n < 1 || n > 15 );

tok = fopen(imeDat, "w");

fprintf(tok, "Tablica mnozenja %dx%d\n", n, n);


fprintf(tok, " ");
for (i = 1; i <= n; ++i) {
fprintf(tok, "%4d", i);
}
fprintf(tok, "\n");

fprintf(tok, "----+", i);


for (i = 1; i <= n; ++i) {
fprintf(tok, "----", i);
}
fprintf(tok, "\n");

for (i = 1; i <= n; ++i) {


fprintf(tok, "%4d!", i);
for (j = 1; j <= n; ++j) {
fprintf(tok, "%4d", i*j);
}
fprintf(tok, "\n");
}

fprintf(tok, "----+", i);


for (i = 1; i <= n; ++i) {
fprintf(tok, "----", i);
}
fprintf(tok, "\n");

fclose(tok);
return 0;
}

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

Rješenje 5. zadatka
#include <stdio.h>

int main (void) {


float x, suma = 0.0f;
int brojac = 0;
FILE *ulTok;

ulTok = fopen ("brojevi.txt", "r");


while (fscanf(ulTok, "%f", &x) == 1 ) {
suma += x;
++brojac;
}
fclose (ulTok);
if (brojac > 0)
printf("%f\n", suma/brojac);
else
printf("Nije procitan niti jedan broj\n", suma/brojac);

return 0;
}

Rješenje 6. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (void) {


FILE *ulTok;
char tocka;
int mbr;
char ime[15+1];
char prez[15+1];
short int dan;
short int mjesec;
short int godina;

ulTok = fopen ("osobe.txt", "r");

while (fscanf(ulTok, "%d%s%s%hd%c%hd%c%hd",


&mbr,
ime,
prez,
&dan,
&tocka,
&mjesec,
&tocka,
&godina) == 8)
if (strstr(ime, "na") != NULL)
printf("%d %s %s %d.%d.%d\n", mbr, ime, prez, dan, mjesec, godina);
fclose (ulTok);
return 0;
}

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 23

Rješenje 7. zadatka
#include <stdio.h>

int main (void) {


FILE *du;

int dan, brojMj, sat, i;


float temp;
float suma;
char c;

du = fopen("mjerenja.txt", "r");

while (fscanf(du, "%c%d%c%d%c", &c, &dan, &c, &brojMj, &c) == 5) {


suma = 0.0f;
for (i = 0; i < brojMj; ++i) {
fscanf(du, "%d%c%f%c", &sat, &c, &temp, &c);
suma += temp;
}
printf("%3d: %f\n", dan, suma/brojMj);
/* sad procitati \n koji je ostao neprocitan */
fscanf(du, "%c", &c);
}

fclose(du);
return 0;
}

Rješenje 8. zadatka

Nakon 1. čitanja sadržaj polja linija je: abcde\n\0


Nakon 2. čitanja sadržaj polja linija je: fghijk\0
Nakon 3. čitanja sadržaj polja linija je: \n\0
Nakon 4. čitanja sadržaj polja linija je: lmnopr\0
Nakon 5. čitanja sadržaj polja linija je: s\n\0
Nakon 6. čitanja sadržaj polja linija je: ABCDEF\0
Nakon 7. čitanja sadržaj polja linija je: GH\0
8. čitanje će vratiti NULL
Sadržaj datoteke izlaz.txt je: abcde
fghijk
lmnoprs
ABCDEFGH

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 44

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

25. vježbe uz predavanja

1. U tekstualnu datoteku ulaz.txt editorom su upisani podaci o osobama (matični broj i


prezime). Primjer sadržaja datoteke prikazan je ovdje:
952 Medvedec
101 Vurnek
205 Habajec
412 Voras
551 Ozimec
115 Zdilar
104 Pugelnik
471 Suhina
Napisati program koji će sadržaj datoteke ulaz.txt prepisati u novu binarnu datoteku
izlaz.bin. Jedan zapis datoteke izlaz.bin sadrži: matični broj (long) i prezime (15+1
znak).
2. Napisati program koji će na zaslon ispisati matične brojeve i prezimena svih osoba u čijim se
prezimenima nalazi malo slovo a. Podaci o osobama se nalaze u postojećoj binarnoj datoteci
izlaz.bin koja je dobivena kao rezultat obavljanja programa iz prethodnog zadatka.
Napomena: kod rješavanja ovog, a također i svih sličnih zadataka s datotekama, nije
dopušteno sve zapise "učitati u memoriju", npr. u jedno veliko polje, i onda po tom polju tražiti
zapise koji zadovoljavaju neki uvjet. Umjesto toga, u memoriju učitati prvi zapis, provjeriti
treba li na zaslon ispisati podatke iz tog zapisa, zatim učitati drugi zapis, itd.
3. Svaki zapis datoteke slucajni.bin treba sadržavati neki cijeli broj n (tipa int) koji može
poprimiti vrijednosti iz intervala [2, 8], te n cijelih brojeva (tipa int) koji poprimaju vrijednosti iz
intervala [150, 160]. Napisati program koji će u novu binarnu datoteku slucajni.bin
upisati 20 zapisa koji se formiraju na slučajan način. Za svaki zapis prvo treba na slučajan
način odrediti n, a zatim na slučajan način odrediti svaku od n vrijednosti koje čine ostatak
zapisa.
4. Napisati program koji će na zaslon ispisati sve zapise datoteke slucajni.bin koja je
nastala kao rezultat obavljanja programa iz prethodnog primjera. Npr. ispis može izgledati
ovako:
6 153 160 155 159 152 152
5 160 152 150 153 160
2 160 159
4 152 152 155 151
5 155 155 158 159 153
3 151 158 151
2 150 153
2 158 156
4 150 151 153 152
3 156 153 154
8 150 154 157 155 155 155 158 156
4 153 159 155 157
8 155 150 159 152 152 154 152 160
3 153 156 158
7 157 158 160 160 155 158 157
2 151 159
3 156 152 159
7 157 157 152 153 152 155 151
8 160 158 159 157 154 156 159 152
5 157 159 160 153 157

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 44

5. Napisati program kojim će se u novu binarnu datoteku slova.bin redom upisati sva velika,
a nakon njih sva mala slova abecede.

6. Funkcijama fseek i ftell odrediti i ispisati na zaslon broj znakova u datoteci slova.bin iz
prethodnog zadatka.
7. Jednim pozivom funkcije scanf u varijablu s učitati vrijednosti svih njenih članova:
struct str1 {
int stanje[2];
};
struct str2 {
struct str1 x;
float k;
} s;
8. Jednim pozivom funkcije scanf u varijablu w učitati vrijednosti svih njenih članova:
struct str1 {
float stanje[2];
};
struct str2 {
struct str1 y;
int k;
char ime[10+1];
} w;
9. Jednim pozivom funkcije scanf u varijablu b učitati vrijednosti svih njenih članova:
struct str1 {
float x;
int k;
};
struct str2 {
struct str1 z1;
struct str1 z2;
} b;

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 44

Rješenja

Rješenje 1. zadatka
#include <stdio.h>

int main (void) {


FILE *ulTok, *izTok;

long int mbr;


char prez[15+1];

ulTok = fopen ("ulaz.txt", "r");


izTok = fopen ("izlaz.bin", "wb");

while (fscanf(ulTok, "%ld%s",


&mbr,
prez) == 2) {
fwrite(&mbr, sizeof(mbr), 1, izTok);
fwrite(&prez, sizeof(prez), 1, izTok);
}
fclose (ulTok);
fclose (izTok);

return 0;
}

Rješenje 2. zadatka
#include <stdio.h>
#include <string.h>

int main (void) {


FILE *ulTok;
long int mbr;
char prez[15+1];

ulTok = fopen ("izlaz.bin", "rb");

while (fread(&mbr, sizeof(mbr), 1, ulTok) == 1 &&


fread(&prez, sizeof(prez), 1, ulTok) == 1)
if (strchr(prez, 'a') != NULL)
printf("%d %s\n", mbr, prez);
fclose (ulTok);
return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 44

Rješenje 3. zadatka
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define MIN_N 2
#define MAX_N 8
#define DG 150
#define GG 160
#define BROJ_ZAPISA 20

int main (void) {


FILE *izTok;
int i, j, n, polje[MAX_N];

izTok = fopen ("slucajni.bin", "wb");


/* inicijalizacija generatora sluc. brojeva */
srand ((unsigned) time(NULL));

for (i = 1; i <= BROJ_ZAPISA; ++i) {


/* odaberi slucajan n */
n = rand() % (MAX_N - MIN_N + 1) + MIN_N;
/* odaberi n slucajnih brojeva */
for (j = 0; j < n; ++j)
polje[j] = rand() % (GG - DG + 1) + DG;
fwrite(&n, sizeof(n), 1, izTok);

fwrite(polje, sizeof(int), n, izTok);


/* ili fwrite(polje, sizeof(int)*n, 1, izTok); */
}
fclose (izTok);
return 0;
}

Rješenje 4. zadatka
#include <stdio.h>

#define MAX_N 8

int main (void) {


FILE *ulTok;
int i, n, polje[MAX_N];

ulTok = fopen ("slucajni.bin", "rb");

while (fread (&n, sizeof(n), 1, ulTok) == 1) {


fread (polje, sizeof(int), n, ulTok);
/* ili fread (polje, sizeof(int)*n, 1, ulTok); */
printf("%d ", n);
for (i = 0; i < n; ++i)
printf("%d ", polje[i]);
printf("\n");
}
fclose (ulTok);
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 44

Rješenje 5. zadatka
#include <stdio.h>

int main (void) {


FILE *izTok;
char c;
izTok = fopen ("slova.bin", "wb");
for (c = 'A'; c <= 'Z'; ++c) {
fwrite(&c, sizeof(c), 1, izTok);
}
for (c = 'a'; c <= 'z'; ++c) {
fwrite(&c, sizeof(c), 1, izTok);
}
fclose (izTok);
return 0;
}

Rješenje 6. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main (void) {


FILE *ulTok;
char c;
int brojZnakova, slucajnaPozicija, brojIspisanih = 0;

ulTok = fopen ("slova.bin", "rb");


fseek(ulTok, 0L, SEEK_END);
/* znak je velicine jednog bajta, stoga je broj znakova
jednak broju bajtova */
brojZnakova = ftell(ulTok);
printf("Broj znakova u datoteci jest: %d\n", brojZnakova);

fclose (ulTok);
return 0;
}

Rješenje 7. zadatka
scanf("%d%d%f", &s.x.stanje[0], &s.x.stanje[1], &s.k);
/* ispis radi provjere */
printf("%d\n%d\n", s.x.stanje[0], s.x.stanje[1]);
printf("\n");
printf("%f\n", s.k);

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 44

Rješenje 8. zadatka
scanf("%f%f%d%10s", &w.y.stanje[0], &w.y.stanje[1], &w.k, w.ime);
/* ispis radi provjere */
printf("%f\n%f\n", w.y.stanje[0], w.y.stanje[1]);
printf("\n");
printf("%d\n", w.k);
printf("\n");
printf("%s\n", w.ime);

Rješenje 9. zadatka
scanf("%f%d%f%d", &b.z1.x, &b.z1.k, &b.z2.x, &b.z2.k);
/* ispis radi provjere */
printf("%f\n%d\n", b.z1.x, b.z1.k);
printf("\n");
printf("%f\n%d\n", b.z2.x, b.z2.k);

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

Napomene:
- Savjetuje se navedene zadatke riješiti ubrzo nakon predavanja
- Savjetuje se ne gledati rješenja prije nego se pokuša samostalno riješiti zadatke

26. vježbe uz predavanja

1. Napisati program kojim će se u novu binarnu datoteku slova.bin redom upisati sva velika,
nakon njih sva mala slova abecede, a nakon njih sve znamenke.
2. Na slučajan način (funkcijom rand) odabirati pozicije u datoteci slova.bin iz prethodnog
zadatka, sa svake odabrane pozicije pročitati jedan znak i ispisati ga na zaslon. Postupak
završiti nakon što se na zaslon ispiše 40 znakova ili veliki znak 'X'.

3. U tekstualnu datoteku ulaz.txt editorom su upisani podaci o osobama (matični broj, ime,
prezime i datum rođenja). Primjer sadržaja datoteke prikazan je ovdje:
952 Nikolina Medvedec 15.05.1989
101 Davor Vurnek 17.06.1987
205 Zoran Habajec 09.12.1987
412 Davor Voras 11.06.1988
551 Zvonimir Ozimec 24.02.1989
115 Franjo Zdilar 22.01.1986
104 Stipe Pugelnik 03.05.1987
471 Nina Suhina 08.06.1988
Napisati program koji će sadržaj datoteke ulaz.txt prepisati u novu binarnu datoteku
izlaz.bin. Jedan zapis datoteke izlaz.bin sadrži: matični broj (long), ime (15+1 znak),
prezime (15+1 znak), dan rođenja (short), mjesec rođenja (short), godinu rođenja (short).
Koristiti strukture!
4. Napisati program koji će na zaslon ispisati matične brojeve, imena i prezimena svih osoba
koje rođendan imaju u mjesecu lipnju. Podaci o osobama se nalaze u postojećoj binarnoj
datoteci izlaz.bin koja je dobivena kao rezultat obavljanja programa iz prethodnog
zadatka. Koristiti strukture!
Napomena: kod rješavanja ovog, a također i svih sličnih zadataka s datotekama, nije
dopušteno sve zapise "učitati u memoriju", npr. u jedno veliko polje, i onda po tom polju tražiti
zapise koji zadovoljavaju neki uvjet. Umjesto toga, u memoriju učitati prvi zapis, provjeriti
treba li na zaslon ispisati podatke iz tog zapisa, zatim učitati drugi zapis, itd.
5. Koristi se slijedna tekstualna datoteka ulaz.txt opisana u 3. zadatku. Napisati program koji
će na zaslon ispisati prezime i ime za svaki treći zapis iz datoteke, počevši od prvog zapisa
(tj. za prvi zapis, za četvrti zapis, za sedmi zapis, itd).
6. Rezultat ispisa na zaslon (standardni izlaz) iz prethodnog zadatka preusmjeriti u datoteku
c:/tmp/rezultat.txt
7. U direktnoj binarnoj datoteci bodovi nalaze se podaci o 10 studenata i bodovima koje su
dobili za zalaganje na nastavi. Svaki zapis sadrži matični broj (int), prezime i ime (20+1 znak)
i broj bodova (int). Matični brojevi su u rasponu od 1-10, a redni broj zapisa odgovara
matičnom broju. Napisati program kojim će se za jednog slučajno odabranog studenta za
10% povećati dotadašnju vrijednost njegovih bodova. Ograničiti uvećani broj bodova na
maksimalnih 500 bodova.

1
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

8. Napisati program koji na kraj datoteke mjerenja.txt koja je opisana u 7. zadatku iz 23. vježbi
uz predavanja, dodaje jedan novi zapis o mjerenjima temperature. Preko tipkovnice se
učitava redni broj dana, broj mjerenja (ne više od 24) i parovi (sat, temperatura). Ukoliko u
datoteci već postoji zapis o učitanom rednom broju dana, dojavljuje se odgovarajuća poruka.
9. Uz pretpostavku da se dnevno mogu obaviti najviše 24 mjerenja temperature, prepišite
datoteku mjerenje.txt u odgovarajuću direktnu binarnu datoteku mjerenja.bin. Redni broj
zapisa u datoteci mjerenja.bin odgovara rednom broju dana.
10. Napišite program koji za redni broj dana učitan preko tipkovnice, čita zapis iz datoteke
mjerenja.bin i ispisuje vremena mjerenja i temperature izmjerene tog dana. Ukoliko mjerenje
za zadani dan ne postoji, ispisati odgovarajuću poruku.

2
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

Rješenja

Rješenje 1. zadatka
#include <stdio.h>

int main (void) {


FILE *izTok;
char c;
izTok = fopen ("slova.bin", "wb");
for (c = 'A'; c <= 'Z'; ++c) {
fwrite(&c, sizeof(c), 1, izTok);
}
for (c = 'a'; c <= 'z'; ++c) {
fwrite(&c, sizeof(c), 1, izTok);
}
for (c = '0'; c <= '9'; ++c) {
fwrite(&c, sizeof(c), 1, izTok);
}
fclose (izTok);
return 0;
}

Rješenje 2. zadatka
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main (void) {


FILE *ulTok;
char c;
int brojZnakova, slucajnaPozicija, brojIspisanih = 0;

ulTok = fopen ("slova.bin", "rb");


fseek(ulTok, 0L, SEEK_END);
/* znak je velicine jednog bajta, stoga je broj znakova
jednak broju bajtova */
brojZnakova = ftell(ulTok);

srand((unsigned)time(NULL));
do {
/* slucajna pozicija u datoteci: [0, brojZnakova - 1] */
slucajnaPozicija = rand() % brojZnakova;
fseek(ulTok, slucajnaPozicija, SEEK_SET);
fread(&c, sizeof(c), 1, ulTok);
printf("%c", c);
++brojIspisanih;
} while (c != 'X' && brojIspisanih < 40);
printf("\n");
fclose (ulTok);
return 0;
}

3
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

Rješenje 3. zadatka
#include <stdio.h>
int main (void) {
FILE *ulTok, *izTok;
char tocka;

struct {
long int mbr;
char ime[15+1];
char prez[15+1];
short int dan;
short int mjesec;
short int godina;
} osoba;

ulTok = fopen ("ulaz.txt", "r");


izTok = fopen ("izlaz.bin", "wb");

while (fscanf(ulTok, "%ld%s%s%hd%c%hd%c%hd",


&osoba.mbr,
osoba.ime,
osoba.prez,
&osoba.dan,
&tocka,
&osoba.mjesec,
&tocka,
&osoba.godina) == 8) {
fwrite(&osoba, sizeof(osoba), 1, izTok);
}
fclose (ulTok);
fclose (izTok);
return 0;
}

Rješenje 4. zadatka
#include <stdio.h>

int main (void) {


FILE *ulTok;
struct {
long int mbr;
char ime[15+1];
char prez[15+1];
short int dan;
short int mjesec;
short int godina;
} osoba;

ulTok = fopen ("izlaz.bin", "rb");

while (fread(&osoba, sizeof(osoba), 1, ulTok) == 1) {


if (osoba.mjesec == 6)
printf("%d %s %s\n",
osoba.mbr,
osoba.ime,
osoba.prez);
}
fclose (ulTok);
return 0;
}

4
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

Rješenje 5. zadatka
#include <stdio.h>

int main (void) {


FILE *ulTok;
long int mbr;
char ime[15+1];
char prez[15+1];
char datum[2+1+2+1+4+1];
int rbr = 0;

ulTok = fopen ("ulaz.txt", "r");

while (fscanf(ulTok, "%ld%s%s%s",


&mbr,
ime,
prez,
datum) == 4) {
if (rbr % 3 == 0)
printf("%s %s\n", ime, prez);
++rbr;
}
fclose (ulTok);
return 0;
}

Rješenje 6. zadatka

Uz pretpostavku da je ime datoteke s izvršnim kodom svakitreci.exe:


svakitreci.exe > c:/tmp/rezultat.txt
Sadržaj datoteke rezultat.txt može se provjeriti pomoću nekog editora, npr. notepad.

Rješenje 7. zadatka
Zadatak ilustrira kako se na slučajan način odabire redni broj zapisa, kako se čita odabrani zapis iz
direktne tekstualne datoteke, te kako se sadržaj zapisa direktne tekstualne datoteke može
promijeniti. Također ilustrira kako se ista datoteka može koristiti i za čitanje i za pisanje.

NAPOMENA: između operacija čitanja i pisanja u isti tok podataka mora se nalaziti barem jedan
poziv funkcije fseek nad tim tokom podataka (čak i u slučaju kad nam pomak značke nije potreban
jer se značka već nalazi na željenoj poziciji). Između operacija pisanja i čitanja iz istog toka
podataka, mora se nalaziti barem jedan poziv funkcije fseek ili fflush. Funkcija fflush(tokPodataka)
prazni međuspremnike toka podataka. Ne pridržavamo li se tih pravila, mogli bismo izvodeći svoje
programe za vježbu dobiti posve pogrešne rezultate. Na završnom ispitu se neće inzistirati na tom
detalju (neće se "oduzimati bodovi" u slučaju nepoštovanja tih pravila)

Dakle, ako u programu za vježbu imamo pisanje pa čitanje iz istog toka podataka
fwrite(..., tokPodataka);
/* ovdje negdje između se mora nalaziti ili fflush(tokPodataka) ili fseek(tokPodataka, ...) */
fread(..., tokPodataka);

Ako u programu za vježbu imate čitanje pa pisanje u isti tok podataka


fread(..., tokPodataka)
/* ovdje negdje između se mora nalaziti fseek(tokPodataka, ...) */
fwrite(..., tokPodataka)

5
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main (void) {


FILE *dUlIzl;
struct {
int mbr;
char prezIme[20+1];
int brBod;
} zapis;
int mbr;
dUlIzl = fopen("bodovi", "r+b");

/* inicijaliziraj generator slucajnih brojeva */


srand((unsigned) time(NULL));
/* odaberi slucajni broj iz intervala [1,10] */
mbr = rand() % 10 + 1;

printf("(Kontrolni ispis)povecati bodove za mbr: %d\n", mbr);


/* Postavi kazaljku neposredno ISPRED odgovarajuceg zapisa */
fseek(dUlIzl, (long)sizeof(zapis)*(mbr-1), SEEK_SET);
/* Procitaj cijeli zapis u strukturu */
fread(&zapis, sizeof(zapis), 1, dUlIzl);
/* Povecaj broj bodova */
zapis.brBod *= 1.1;
if (zapis.brBod > 500)
zapis.brBod = 500;
/* VAZNO: ne zaboraviti zapisati promijenjene podatke natrag u datoteku!!! */
/* Postavi kazaljku neposredno ISPRED odgovarajuceg zapisa jer nakon
prethodnog citanja, kazaljka je bila neposredno IZA odgovarajuceg zapisa */
fseek(dUlIzl, -1L*(long)sizeof(zapis), SEEK_CUR);
/* Zapisi sadrzaj cijele strukture u datoteku */
fwrite(&zapis, sizeof(zapis), 1, dUlIzl);

fclose(dUlIzl);
return 0;
}

U ovom zadatku je fseek između fread i fwrite ionako bio potreban, pa se nije moglo pogriješiti u
odnosu na prethodnu napomenu.

6
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

Rješenje 8. zadatka
Zadatak ilustrira kako se na kraj slijedne tekstualne datoteke može dodati zapis.

#include <stdio.h>
#include <stdlib.h>

int main (void) {


FILE *di;
int dan, noviDan, i;
int sati[24];
float temp[24];
int brojMjerenja;
char ostatakRetka[512];
char c;

di = fopen("mjerenja.txt", "a+");
/* ucitati redni broj novog dana */
printf("Upisite redni broj novog dana>");
scanf("%d", &noviDan);

/* ako redni broj dana vec postoji, zavrsiti program */


while (fscanf(di, "%c%d%", &c, &dan) == 2) {
if (dan == noviDan) {
printf("Dan vec postoji\n");
exit(1);
}
/* preskociti ostatak retka */
fgets(ostatakRetka, 512, di);
}

/* ucitati broj mjerenja */


printf("Upisite broj mjerenja>");
scanf("%d", &brojMjerenja);

/* ucitati parove u polja sati i temp */


for (i=0; i < brojMjerenja; ++i) {
printf("Upisite %d. par sata i temperature>", i+1);
scanf("%d %f", &sati[i], &temp[i]);
}
/* ovdje bi se moglo provjeriti jesu li unesene "duple"
vrijednosti sati, ali to se nije trazilo */

/* zapisati redni broj dana i broj mjerenja */


/* fseek na kraj datoteke nije potreban jer je datoteka
otvorena u modu "a+" */
fprintf(di, "#%d#%d#", noviDan, brojMjerenja);

/* zapisati parove sat-temp */


for (i = 0; i < brojMjerenja; ++i) {
fprintf(di, "%d#%.1f#", sati[i], temp[i]);
}

/* zapisati "novi red" \n */


fprintf(di, "\n");

fclose(di);
return 0;
}

7
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

Rješenje 9. zadatka
Zadatak ilustrira pisanje u direktnu tekstualnu datoteku čiji zapis, između ostalog, sadrži polje.

#include <stdio.h>

int main (void) {


FILE *du, *di;
struct {
int rbrDan;
int brMjer;
int sati[24];
float temp[24];
} zapis;
int i;
char c;
float suma = 0.0f;

du = fopen("mjerenja.txt", "r");
di = fopen("mjerenja.bin", "wb");

while (fscanf(du, "%c%d%c%d%c", &c, &zapis.rbrDan, &c, &zapis.brMjer, &c)


== 5) {
for (i = 0; i < zapis.brMjer; ++i) {
fscanf(du, "%d%c%f%c", &zapis.sati[i], &c, &zapis.temp[i], &c);
}
/* procitaj \n s kraja retka */
fscanf(du, "%c", &c);
/* zapisati u dir. binarnu datoteku */
fseek(di, (long)sizeof(zapis)*(zapis.rbrDan-1), SEEK_SET);
fwrite(&zapis, sizeof(zapis), 1, di);
}
fclose(du);
fclose(di);

return 0;
}

8
Programiranje i programsko inženjerstvo, ZPR-FER-UNIZG
Vježbe uz predavanja 10-Datoteke.pdf - do stranice: 75

Rješenje 10. zadatka


Zadatak ilustrira čitanje iz direktne binarne datoteke čiji zapis, između ostalog, sadrži polje. U
rješenju zadatka treba uočiti da zapis direktne binarne datoteke može biti "prazan". Uočiti na koji se
način utvrđuje da je zapis "prazan".

#include <stdio.h>

int main (void) {


FILE *du;
struct {
int rbrDan;
int brMjer;
int sati[24];
float temp[24];
} zapis;
int i, rbrDan;
du = fopen("mjerenja.bin", "rb");

printf("Upisite redni broj dana>");


scanf("%d", &rbrDan);

fseek(du, (long)(rbrDan-1)*sizeof(zapis), SEEK_SET);


fread(&zapis, sizeof(zapis), 1, du);

if (zapis.rbrDan == rbrDan) {
printf("mjerenja za dan: %d\n", zapis.rbrDan);
for (i=0; i < zapis.brMjer; ++i) {
printf(" Sat: %2d Temperatura: %5.1f\n",
zapis.sati[i], zapis.temp[i]);
}
}
else {
printf("Nema podataka o mjerenju za zadani dan\n");
}
fclose(du);

return 0;
}

9
FAKULTET ELEKTROTEHNIKE, STROJARSTVA I BRODOGRADNJE
SVEUČILIŠTE U SPLITU

(UVOD U)
RAČUNALA I PROGRAMIRANJE

Laboratorijske vježbe

Bonković Mirjana / Braović Maja / Goić Ranko

Listopad, 2010.
KATEDRA ZA MODELIRANJE I INTELIGENTNE RAČUNALNE SUSTAVE (KaMIS)

Laboratorij za robotiku i inteligentne sustave (LaRIS)

Predavanja: dr. sc. Mirjana Bonković, red. prof.


dr. sc. Ranko Goić, doc.
mr. sc. Ana Kuzmanić Skelin

Laboratorijske vježbe: Maja Braović, mag. ing.


Bruno Batarelo, dipl. ing.
Ante Denić, dipl. ing.

Dodatna literatura za kolegij (Uvod u) Računala i programiranje:

1. Gottfried, B.: "Schaum's Outline Series: Programming with C", Second Edition, McGraw-Hill,
1996.
2. Vulin, R.: "Zbirka riješenih zadataka iz C-a", Školska knjiga, Zagreb, 2003.
3. Parlante, N.: "Essential C", 2003, http://cslibrary.stanford.edu/101/EssentialC.pdf.
4. Materijali dostupni preko MIT OpenCourseWare projekta:
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/.

2
VJEŽBA 1

Povijest programskog jezika C

Programski jezik C nastao je 1972. godine u Bell laboratorijima, kao rezultat rada računalnog
znanstvenika Dennisa Ritchiea. On je prvi kreirao i primijenio programski jezik C.

Slika 1.1. Računalni znanstvenici Ken Thompson (lijevo) i Dennis Ritchie (desno) [1].

Većina bitnih ideja i koncepata koji su korišteni prilikom razvijanja programskog jezika C došlo je iz
programskog jezika BCPL (engl. Basic Combined Programming Language), ali samo posredno, preko
programskog jezika B kojega je razvio Ken Thompson 1970. godine za prvi UNIX sustav na DEC PDP
računalu (engl. Digital Equipment Corporation Programmed Data Processor).

Dennis Ritchie i Ken Thompson su 1983. godine nagrađeni Turingovom nagradom (za teoretski rad
na području generičkih operacijskih sustava te za implementaciju operacijskog sustava UNIX), što je
jedna od najvećih počasti koju računalni znanstvenici mogu dobiti.

Zašto C?

Programski jezik C je inicijalno dizajniran za implementaciju sistemskog softvera (jezgra UNIX


sustava je gotovo u potpunosti napisana u C-u), ali danas se upotrebljava kao jezik opće namjene.
To znači da se pomoću njega mogu implementirati ne samo operacijski sustavi, već i računalne igre,
driveri, različite aplikacije i sl. Iako danas sve popularniji postaju objektno-orijentirani programski
jezici (npr. Java ili C#), C se još uvijek često koristi jer programeru omogućuje veću kontrolu nad
programom i obično se takvi programi izvršavaju brže nego njihovi ekvivalenti napisani u nekom od
objektno-orijentiranih jezika.

C jezik bi se mogao nazvati jezikom niže razine sa stajališta objektno-orijentiranog programera, ali
sa stajališta programera koji piše programe u Asembleru (engl. Assembly language) ili (teoretski) u
strojnom jeziku (npr. 00010110 01010111 11111000 10000001), bio bi shvaćen kao jezik više

3
razine. Izrazi "jezik niže razine" te "jezik više razine" su dosta relativni i obično jako vezani uz
kontekst u kojemu se koriste.

Kako do izvršne datoteke?

Proces stvaranja izvršne datoteke sastoji se od 3 koraka:

1. Programer napiše izvorni kod programa (engl. source code). Datoteke u kojima se nalazi
izvorni kod imaju ekstenziju .c (ako su napisane u C-u), i može ih biti više od jedne.
2. Izvorni kod se prevodi u objektni kod pomoću prevoditelja (engl. compiler). Prevoditelj u
objektni kod posebno prevede svaku datoteku u kojoj se nalazi izvorni kod. Datoteke u
kojima se nalazi objektni kod sadrže kod razumljiv računalu (strojni kod), te imaju ekstenziju
.obj ili .o.
3. Datoteke u kojima se nalazi objektni kod i biblioteke koje su specificirane u njemu se
povezuju u jedinstvenu datoteku pomoću poveznika (engl. linker). Ta jedinstvena datoteka
naziva se izvršna datoteka, i ima ekstenziju .exe.

Slika 1.2. Proces kreiranja izvršne datoteke.

Važno je napomenuti da je prevođenje izvornog koda u strojni kod jednosmjeran proces, tj. strojni
kod se gotovo nikad u potpunosti ne može uspješno prevesti natrag u izvorni kod.

4
Ukratko o C programima

Opći oblik C programa izgleda ovako:

#include <stdio.h>
#include ...

int main()
{
Naredbe napisane u C-u...
return 0;
}

Sve naredbe koje započinju znakom # nazivaju se predprocesorske naredbe.


Naredba #include se koristi kada se u programu koji se piše trebaju koristiti unaprijed
isprogramirane funkcije (posebni dijelovi programskog koda o kojima će biti više govora kasnije). Uz
ovu naredbu mora stajati parametar oblika <ime_datoteke.h>. Taj parametar definira ime datoteke
u kojoj se nalaze prototipovi ili deklaracije funkcija koje će se koristiti u programu. Takve datoteke
imaju ekstenziju .h (engl. header file), i često se nazivaju standardnim bibliotekama.
U programima se najčešće koriste naredbe za ispis znakova na ekran, za unos znakova sa
tipkovnice, za otvaranje i zatvaranje tekstualnih datoteka, itd. Deklaracije svih ovih (i mnogih
drugih) funkcija nalaze se u datoteci standard input/output header, i zato se na početku gotovo
svakog C programa nalazi naredba #include <stdio.h>.
Naravno, na početku svakog C programa može se nalaziti više #include naredbi, a ne samo jedna.

U programskim jezicima često se nailazi na koncept funkcije. Funkcija je dio programa koji ima
svoje ime, te koji može primati određene argumente i vratiti određeni argument (ako funkcija vrati
nulu, to obično znači da su sve naredbe u njoj uspješno izvršene). Funkcije se koriste kako bi se
povećala preglednost programa, te kako bi programeri mogli koristiti već unaprijed isprogramirana
rješenja za učestale probleme.

Funkcija main() je glavna funkcija u C jeziku. Jedina razlika između ove funkcije i svih ostalih jest što
će se funkcija main() uvijek izvesti prije svih ostalih funkcija. Ostale se funkcije moraju pozvati iz
funkcije main() da bi se uopće mogle izvršiti.

Linija koda int main() kaže da funkcija main() vraća cijeli broj (engl. integer).

Unutar vitičastih zagrada piše se kod programa. Na kraju programa se pomoću naredbe return
može specificirati vrijednost koju će funkcija vratiti. U ovome slučaju funkcija main() vraća nulu.

Nakon svake naredbe stavlja se točka zarez (';'). Ona označava kraj jedne naredbe i početak druge.

Prvi program u C-u

Slijedeći program je najmanji i najjednostavniji program koji se može napisati u C-u. Program ne
radi ništa.

5
#include <stdio.h>

int main()
{
return 0;
}

Ako nije potrebno da funkcija vraća neku vrijednost, onda bi se gornji program mogao napisati u
slijedećem (ekvivalentnom) obliku:

#include <stdio.h>

void main()
{
}

Program također ne radi ništa.

Hello World!

Najjednostavniji program napisan u bilo kojem programskom jeziku (osim onih programa koji ne
rade ništa), bio bi program koji na ekran ispisuje nekakav tekst. U računarstvu se tradicionalno za
takav tekst uzima rečenica "Hello World!".

Slijedeći program na ekran ispisuje "Hello World!":

#include <stdio.h>

int main()
{
printf("Hello World!\n");
return 0;
}

Naredba printf("Neki tekst..."); se koristi za ispis teksta na ekran računala. Tekst se piše unutar
navodnika, a ako se nakon teksta još doda i znak '\n', to znači da će kursor nakon ispisa teksta na
ekran prijeći u novu liniju.

Upotrebu naredbe printf() omogućuje predprocesorska naredba #include <stdio.h>. U biblioteci


<stdio.h> se nalazi prototip naredbe printf().

Varijable

Varijable su memorijske lokacije čija se vrijednost tijekom izvođenja programa može promijeniti, tj.
varijable su imena koja koristimo za memorijske lokacije na kojima se nalaze vrijednosti s kojima

6
radimo.

Postoje različiti tipovi varijabli:

• char (engl. character) – znakovni tip


• int (engl. integer) – cijeli broj
• short – kraći oblik cijelog broja
• long – duži oblik cijelog broja
• float (engl. floating point) – realni broj
• double – realni broj dvostruke točnosti

Različiti tipovi varijabli zauzimaju različite količine memorije.

Varijable moraju biti prijavljene prije upotrebe, i to najčešće na početku funkcije, prije bilo koje
izvršne naredbe. Kaže se da se varijable deklariraju. Deklaracijom se varijabli pridružuju ime i tip
(npr. određuje se da li će varijabla sadržavati znak ili broj), te se deklarira potrebna količina
memorije (npr. 1 bajt za znak ili 4 bajta za cijeli broj).

Na primjer, ovako se deklarira cjelobrojna varijabla a:

int a;

Ovo znači da je deklariran memorijski prostor (imena 'a') u koji će se spremiti cijeli broj.

Primjeri deklaracije varijabli:

int varijabla1, varijabla2;


float varijabla3, varijabla4, varijabla5;
char varijabla6;

Za razliku od deklaracije varijable, definicija varijable bi varijabli pridružila i neku vrijednost. Na


primjer:

int varijabla1 = 5;
float varijabla2 = 2.3;
char varijabla3 = 'c';

int varijabla4 = varijabla1; // varijabla4 = 5

int varijabla5, varijabla6;


varijabla5 = varijabla6 = 7; // varijabla5 = 7, varijabla6 = 7

char a = 'A'; // a = A
char b = 65; // b = A --> u ASCII tablici, znak 'A' je predstavljen sa brojem 65

Imena varijabli sastoje se od slova i znamenki, pri čemu prvi znak mora uvijek biti slovo. Znak
podcrte '_' (engl. underscore) uvažava se kao slovo, što je bitna stvar ako se želi povećati čitljivost

7
programa.

Programeri varijablama obično daju imena u nekom od slijedećih formata:

int varijabla;
int druga_varijabla;
int trecaVarijabla;

Primjeri neispravnih imena varijabli:

int 1varijabla; // prvi znak ne smije biti broj


int prva varijabla; // nisu dozvoljeni razmaci
int $varijabla; // znak '$' nije dozvoljen – samo slova, brojke ili '_'
int const; // const je ključna riječ (unaprijed rezervirana)

Operatori u C-u

Aritmetički operatori: +, -, *, /, te modul operator % (ostatak dijeljenja).

Relacijski operatori: < (manje), > (veće), <= (manje ili jednako), >= (veće ili jednako), == (jednako),
!= (nije jednako). Relacijski operatori se koriste kod usporedbi.

Logički operatori: && (i) i || (ili).

Operatori uvećavanja (inkrementiranja) i umanjivanja (dekrementiranja): ++ i --. Njihova bitna


karakteristika je da mogu biti korišteni kao sufiks operatori (npr. varijabla++) ili kao prefiks
operatori (npr. ++varijabla).

Operator konverzije tipova: cast. Ako u programskom kodu naiđemo na operator čiji su operandi
različitog tipa (npr. jedan je int, a drugi float), čitav će izraz dobiti konačnu vrijednost po točno
određenim pravilima. Cast operator pretvara izraz bilo kojeg tipa u željeni tip. Općenita formula
glasi: (tip) izraz.

Primjer:

#include <stdio.h>

void main()
{
int x;
char y = 'A';
x = (int) y;
printf("x = %d\n", y);
}

8
ISPIS PROGRAMA:
x = 65

U gornjem primjeru, varijabli x se dodjeljuje ASCII vrijednost varijable y (odnosno znaka A), a to je
65.

Operatori za manipulaciju bitovima (bitznačajni operatori):


• & binarno I (AND)
• | binarno ILI (OR)
• ^ binarno ekskluzivno ILI (XOR)
• ~ jedinični komplement (NOT)
• << pomak u lijevo (SHIFT LEFT)
• >> pomak u desno (SHIFT RIGHT)

Operatori dodjele vrijednosti. Većina binarnih operatora ima odgovarajući operator dodjele
vrijednosti po pravilu: izraz1 operator= izraz2. To je ekvivalentno izrazu: izraz1 = (izraz1) operator
(izraz2). Na primjer, a *= b je ekvivalentno izrazu a = a * b. a *= b je samo kraći način zapisa izraza
a = a * b.

Napomena: obratite pozornost na operator dodjele vrijednosti (=) i operator uspoređivanja dviju
vrijednosti (==). Ovi operatori nisu jednaki! Miješanje ovih dvaju operatora je jedna od najčešćih
grešaka u programiranju! Ovakva se greška naziva logička greška, i prevoditelj vas na nju neće
upozoriti.

Operator '=' nekoj varijabli dodjeljuje neku vrijednost, npr. a = 3.

Operator '==' uspoređuje dvije varijable i vraća nulu ili jedinicu, ovisno o tome jesu li te varijable
jednake.

Neke od najčešće korištenih funkcija u C-u

Neke od najčešće korištenih funkcija u C-u su:

printf("%d", argument) ispisuje znak ili niz znakova na ekran


scanf("%d", &argument) prihvaća znak ili niz znakova unesenih sa tipkovnice
getchar() prihvaća samo jedan znak sa tipkovnice
putchar() ispisuje samo jedan znak na ekran
toupper(c) pretvara mala slova u velika
tolower(c) pretvara velika slova u mala

9
DODATAK

Microsoft (MS) Visual Studio 2010 Express

Svi programi opisani u vježbama iz kolegija (Uvod u) Računala i programiranje mogu se izvršavati u
MS Visual Studio integriranoj razvojnoj okolini (engl. Integrated Development Environment ili IDE).
IDE je razvojna okolina unutar koje programeri pišu i testiraju svoje programe.

Na linku http://www.microsoft.com/express/Downloads/ može se pronaći Microsoft Visual Studio


2010 Express. To je IDE koji se koristi u edukacijske i nekomercijalne svrhe.

Da biste instalirali MS Visual Studio Express 2010, slijedite ove upute:

1. Otiđite na web stranicu http://www.microsoft.com/express/Downloads/.


2. Odaberite Visual C++ 2010 Express.
3. Odaberite engleski jezik.
4. Otvoriti će se prozor koji vas pita želite li skinuti aplikaciju sa interneta. Kliknite OK.
Napomena: program koji ste sačuvali je samo aplikacija koja će pokrenuti skidanje MS
Visual Studio 2010 Express sa interneta.
5. Pokrenite skinutu aplikaciju i slijedite postupak instalacije.
6. Pričekajte dok se aplikacija ne instalira (ovo će malo potrajati...).

Pokrenite aplikaciju. Pojaviti će se ovakav prozor:

10
Da biste mogli napisati i pokrenuti prvi program u C-u, slijedite ove upute:

1. Kliknite na File --> New --> Project.

2. Odaberite Win32 Console Application.

3. Odaberite ime novog projekta (npr. prviProjekt) i kliknite OK.

4. Otvoriti će se novi prozor imena Win32 Application Wizard. Pod Application Settings
odaberite Console application i Empty project, te deselektirajte Precompiled header.

11
5. Kliknite Finish. Otvoriti će se ovakav prozor:

6. Sa lijeve strane možete vidjeti nekoliko datoteka. Desnim klikom miša kliknite na datoteku
imena Source Files, te odaberite Add --> New Item. Odaberite C++ File (.cpp). Novoj datoteci
dodijelite neko ime (npr. mojPrviProgram). Kliknite Add. Otvoriti će se upravo kreirana
tekstualna datoteka.

12
7. U datoteku upišite slijedeći programski kod:

#include <stdio.h>

void main()
{
printf("Hello World!\n");
getchar(); /* program čeka unos znaka sa tipkovnice */
}

Na kraju programa nalazi se poziv funkcije getchar(). Ta funkcija čeka na unos znaka sa
tipkovnice. Da se u programu ne nalazi ova linija koda, prozor sa tekstom Hello World! bi se
zatvorio čim bi se program izvršio (gotovo trenutačno), te ne biste uspjeli vidjeti rezultate
programa.

8. Kliknite Debug --> Build Solution, pa zatim Debug --> Start Debugging. Alternativno možete
pritisnuti F7 (Build Solution) i F5 (Start Debugging).

9. Vaš program će se izvršiti. Otvoriti će se slijedeći prozor:

10. Pritisnite Enter da bi zatvorili prozor.

13
VJEŽBA 2

Komentari u C-u

#include <stdio.h>

void main()
{
printf("Hello World!\n"); /* ispisuje "Hello World!" na ekran */
}

Prilikom prevođenja programa, prevoditelj zanemaruje sve što se nalazi unutar znakova '/*' i '*/'.
Oni označavaju početak i kraj komentara.

/* ovo je komentar */

/*
i ovo je komentar
*/

Ovakva vrsta komentara se danas sve rijeđe koristi. Popularnost im je pala nakon što su u
programiranje uvedeni jednoredni komentari "uvezeni" iz programskog jezika C++.

// komentar

Gornji komentar je jednoredi komentar. Prednost ovakvih komentara je što programer ne mora
paziti na završetak komentara, a nedostatak je taj što su ograničeni na jedan redak.

Komentari su posebno važni kod velikih programa (sa više tisuća linija koda), jer programski kod
postaje pregledniji i razumljiviji.

Escape nizovi

Kombinacije znakova koje započinju sa znakom '\' (engl. backslash), te iza kojih slijedi neki drugi
znak, slovo, ili niz brojeva (ako se koristi oktalni ili heksadecimalni zapis), nazivaju se escape nizovi.
Njihova zadaća jest da promijene značenje određenih znakova ili simbola (Tablica 2.1). Na primjer,
znak 'n' se tretira na jedan način kada predstavlja ime varijable, a na drugi način kada se ispred
njega nalazi znak '\'.

Escape nizovi koji se najčešće koriste u C-u:

Tablica 2.1. Escape nizovi

Znak Escape niz ASCII


zvono (upozorenje) \a 007

14
(engl. bell code, audible alert)
backspace \b 008
vodoravni tabulator \t 009
okomiti tabulator \v 011
novi red ili LF (engl. Line Feed) \n 010
nova stranica \f 012
CR (engl. Carriage Return) \r 013
navodnik \" 034
jednostruki navodnik (apostrof) \' 039
upitnik \? 063
backslash \\ 092
null znak \0 000

Znakovi pretvorbe

#include <stdio.h>

int main()
{
int a; // deklariramo cjelobrojnu varijablu a
a = 10; // varijabli a pridružujemo vrijednost 10
printf("%d\n", a); // na ekran ispisujemo vrijednost varijable a
return 0; // funkcija vraća nulu
}

U gornjem se primjeru koristi znak %d. Kada se ispred nekih određenih slova (Tablica 2.2) nalazi
znak '%', onda slovo predstavlja znak pretvorbe (engl. conversion character). On označava tip ili
format znaka koji se ispisuje na ekran ili učitava sa tipkovnice (npr. int, float...).

Tablica 2.2. Znakovi pretvorbe

Znak pretvorbe Značenje


c podatak je znak
d podatak je decimalna cjelobrojna vrijednost s predznakom
e podatak je realna vrijednost u eksponencijalnoj formi
f podatak je realna vrijednost bez eksponencijalne forme
g podatak je realna vrijednost
podatak se zapisuje u najkraćoj mogućoj formi (ili f ili e)
i podatak je decimalna cjelobrojna vrijednost s predznakom

15
podatak može biti zapisan u dekadskom, oktalnom ili heksadecimalnom
brojevnom sustavu
o podatak je oktalna vrijednost, bez vodeće nule
s podatak je niz znakova (engl. string)
null znak ('\0') se automatski dodaje na kraj stringa
u podatak je decimalna vrijednost bez predznaka
x podatak je heksadecimalna vrijednost, bez vodećeg 0x
[. . .] podatak je niz znakova koji može sadržavati razmake

Funkcija printf()

Funkcija printf() se koristi za ispis znakova na ekran računala.

Primjer:

#include <stdio.h>

void main()
{
int a = 5;
float b = 5.1;

// na ekran ispisujemo vrijednost cjelobrojne varijable a


printf("Vrijednost varijable a = %d\n", a);

// na ekran ispisujemo vrijednost realne varijable b


printf("Vrijednost varijable b = %f\n", b);

// program čeka na unos znaka sa tipkovnice


getchar();
}

Funkcija printf() dozvoljava korištenje ograničenja na minimalnu duljinu niza koji se upisuje (npr. niz
brojeva). Ako je niz veći od minimalne duljine, onda ograničenje nema nikakvog utjecaja na ispis
niza. U programerskim krugovima ta je situacija poznata pod imenom "override". Funkcija printf()
također dozvoljava specifikaciju točnosti nekog broja (npr. zaokruživanje broja na određeni broj
decimala iza decimalne točke).

Primjer:

#include <stdio.h>

void main()
{

16
int a = 12345;
float b = 345.678;

printf("%3d\n", a);
printf("%10d\n\n", a);

printf("%6g\n", b);
printf("%13g\n\n", b);

printf("%13e\n", b);
printf("%16e\n\n", b);
printf("%.4f\n", b);
printf("%.30e\n", b);

getchar();
}

ISPIS PROGRAMA:

Funkcija scanf()

Funkcija scanf() se koristi za učitavanje znakova sa tipkovnice.

Primjer:

#include <stdio.h>

void main()
{
int a;
float b;

// sa tipkovnice se učitava cijeli broj i sprema se u varijablu a


scanf("%d", &a);

// sa tipkovnice se učitava realni broj i sprema se u varijablu b

17
scanf("%f", &b);

getchar();
}

Kada se ispred imena varijable nalazi znak &, onda &ime_varijable predstavlja adresu te varijable.
Da bi funkcija scanf() mogla nekoj varijabli promijeniti vrijednost, najprije mora znati na kojoj se
memorijskoj adresi ta varijabla nalazi.

Kao i funkcija printf(), funkcija scanf() omogućava postavljanje ograničenja na duljinu niza koji se
učitava sa tipkovnice.

Primjer:

#include <stdio.h>

void main()
{
int a, b, c;
scanf("%3d %3d %3d", &a, &b, &c);
printf("a = %d b = %d c = %d\n", a, b, c);
}

Unos: 1 2 3
Ispis: a = 1 b = 2 c = 3

Unos: 123 456 789


Ispis: a = 123 b = 456 c = 789

Unos: 123456789
Ispis: a = 123 b = 456 c = 789

Unos: 1234 5678 9


Ispis: a = 123 b = 4 c = 567
Napomena: preostala dva znaka će biti ignorirana, osim ako ih ne pokupi neka druga scanf()
funkcija.

18
ZADACI

Zadatak 2.1. Napišite program koji ispisuje zauzeće memorije u bajtovima (engl. byte) za sve
standardne tipove programskog jezika C (char, int, short, long, float, double, unsigned short,
unsigned int, unsigned long). Koristite funkciju sizeof().

Rješenje:

#include <stdio.h>

void main ()
{
printf("Sizeof(char) = %d", sizeof(char));
printf("\nSizeof(int) = %d", sizeof(int));
printf("\nSizeof(short) = %d", sizeof(short));
printf("\nSizeof(long) = %d", sizeof(long));
printf("\nSizeof(float) = %d", sizeof(float));
printf("\nSizeof(double) = %d", sizeof(double));
printf("\nSizeof(unsigned short) = %d", sizeof(unsigned short));
printf("\nSizeof(unsigned int) = %d", sizeof(unsigned int));
printf("\nSizeof(unsigned long) = %d\n", sizeof(unsigned long));

getchar();
}

ISPIS PROGRAMA:

Zadatak 2.2. Napišite program u kojem deklarirate integer i char varijablu. Objema pridijelite
vrijednost znakovne konstante (primjerice 'c'). Ispišite vrijednosti varijabli i veličinu memorije koju
zauzimaju. Kako komentirate rezultate?

Rješenje:

#include <stdio.h>

void main()

19
{
int i = 'c';
char n = 'c' ;

printf("sizeof(int) = %d\n", sizeof(int));


printf("sizeof(char) = %d\n", sizeof(char));
printf("vrijednost (i) = %d\n", i);
printf("vrijednost (n) = %d\n", n);

printf("vrijednost (i) = %c\n", i);


printf("vrijednost (n) = %c\n", n);

getchar();
}

ISPIS PROGRAMA:

Zadatak 2.3. Napišite program koji ispisuje znakove 'z' i 'Z', s tim da su za prvi znak rezervirana 3
mjesta za ispis na ekran, a za drugi 5 mjesta.

Rješenje:

#include <stdio.h>

void main()
{
printf("Slova:\n%3c\n%5c\n", 'z', 'Z');
getchar();
}

Zadatak 2.4. Primjer cjelobrojnog i realnog dijeljenja. Kako komentirate rezultate programa?

#include <stdio.h>

void main()
{
int a = 5;
int b = 2;

20
int d = 5/2; // cjelobrojno dijeljenje – rezultat je 2
float c = a/b; // Iako je c float, vrši se cjelobrojno dijeljenje jer su i a i b cijeli brojevi

printf("c = %f\n",c);
printf("Uzrok problema : 5/2 = %f\n", 5/2);
printf("Popravljeno : 5.0/2.0 = %f\n", 5.0/2.0);
printf("Moze i : 5/2.0 = %f i 5.0/2 = %f \n", 5/2.0, 5.0/2);
printf("Za varijable moramo uvesti cast-ing : %f\n", (float)a/(float)b);
getchar();
}

ISPIS PROGRAMA:

Zadatak 2.5. Napišite program za unos cijelog broja sa tipkovnice.

Rješenje:

#include <stdio.h>

void main()
{
int x;

printf("Unesite cijeli broj: ");


scanf("%d", &x);

printf("Unijeli ste broj: %d\n", x);

getchar();
getchar();
}

Zadatak 2.6. Napišite program za unos cijelog broja sa tipkovnice. Neka program ispiše kvadrat tog
broja.

Rješenje:

#include <stdio.h>

21
void main()
{
int a, b;

printf("Unesite varijablu a.\n");


scanf("%d", &a); // sa tipkovnice se učitava varijabla a

b = a * a; // u varijablu b ide vrijednost kvadrata broja a

printf("Kvadrat broja a je %d.\n", b);

getchar();
getchar();
}

22
DOMAĆI RAD

Zadatak 2.7. Napišite program za unos dva realna broja. Neka program ispiše rezultat njihovog
zbrajanja, oduzimanja, množenja i dijeljenja.

Zadatak 2.8. Napišite program za unos realnog broja. Neka program ispiše kvadrat i korijen tog
broja. Napomena: funkcija za računanje korijena je sqrt() (engl. square root) i definirana je u
biblioteci <math.h>.

Zadatak 2.9. Napišite program koji za proizvoljni radijus računa opseg kruga.

23
DODATAK

ASCII tablica

Tablica 2.3. ASCII tablica

24
VJEŽBA 3

Naredbe kontrole toka

Naredbe kontrole toka svoje djelovanje zasnivaju na logičkim izrazima. Najčešće se koriste u svrhu
grananja programa, tj. odabira jedne od nekoliko mogućih radnji.

Jedna od najčešće korištenih naredbi za kontrolu toka je if-else konstrukcija.

If-else konstrukcija općenito ima slijedeću sintaksu:

if (logički izraz)
naredba1

if (logički izraz)
naredba 1
else
naredba2

Slika 3.1. Grafički prikaz grananja

Primjer (if-else konstrukcija): Programsko rješenje za grananje prikazano na slici 3.1:

#include <stdio.h>

void main()
{
int a = 7;
int b = 3;

if (a > b)
printf("Vrijednost varijable a = %d.\n", a);
else
printf("Vrijednost varijable b = %d.\n", b);

getchar();

25
}

ISPIS PROGRAMA:
Vrijednost varijable a = 7.

Umjesto if-else konstrukcije ponekad se može koristiti uvjetni operator. Uvjetni operator je
ternarni operator, jer ima tri elementa.

Opći oblik:

logički_izraz ? izraz_1 : izraz_2;

Program bi u ovom slučaju ispitao vrijednost logičkog izraza, te ako je ta vrijednost jednaka jedinici
izvršio bi se izraz 1, a ako je jednaka nuli izvršio bi se izraz 2.

Primjer (uvjetni operator): Program provjerava da li je varijabla a veća od nule. Ako jest, postavlja
varijablu b na jedinicu, a ako nije, postavlja varijablu b na nulu. Zatim ispisuje vrijednost varijable b.

#include <stdio.h>

void main()
{
int a = 7;
int b;

(a > 0) ? b = 1 : b = 0;

printf("b = %d \n", b);

getchar();
}

ISPIS PROGRAMA:
b=1

Programske petlje

Programske petlje se koriste kada se više puta želi ponoviti ista naredba ili blok naredbi. U
programskom jeziku C postoje tri petlje: for, while i do-while.

Opći oblik programske petlje for:

for (inicijalizacija; uvjet; promjena vrijednosti)


{
blok naredbi
}

26
Primjer (for petlja): Program ispisuje brojeve od 0 do 9.

#include <stdio.h>
void main()
{
int a;

for (a = 0; a < 10; a++)


printf("%d\n", a);

getchar();
}

Opći oblik programske petlje while:

while (uvjet)
{
blok naredbi
}

Primjer (while petlja): Program ispisuje brojeve od 9 do 0.

#include <stdio.h>

void main()
{
int a = 9;

while (a > -1)


{
printf("%d\n", a);
a--;
}

getchar();
}

Opći oblik programske petlje do-while:

do
{
blok naredbi
} while (uvjet);

27
Primjer (do-while petlja): Program ispisuje brojeve od 0-9.

#include <stdio.h>

void main()
{
int a = 0;

do
{
printf("%d\n", a);
a++;
}
while (a < 10);

getchar();
}

Petlje for i while se ne moraju uopće izvršiti (ako uvjet nije ispunjen), ali petlja do-while je
specifična po tome što se ona uvijek izvrši barem jedan put, pa tek nakon prvog izvršavanja
provjerava uvjet.

28
ZADACI

Zadatak 3.1. Napišite program koji prihvaća i uspoređuje bilo koja dva cijela broja unesena sa
tipkovnice. Neka se na ekran ispiše rezultat usporedbe tih brojeva.

Rješenje:

#include <stdio.h>

void main()
{
int a;
int b;

printf("Unesite prvi broj: ");


scanf("%d", &a);

printf("Unesite drugi broj: ");


scanf("%d", &b);

if (a > b)
printf("%d > %d \n", a, b);
else if (a < b)
printf("%d > %d \n", b, a);
else
printf("%d = %d \n", a, b);

getchar();
getchar();
}

Zadatak 3.2. Napišite program koji ispisuje sumu svih brojeva od 1 do 10.

Rješenje:

#include<stdio.h>

void main()
{
int i;
int suma = 0;

for (i = 1; i <= 10; i++)


suma = suma + i;

29
printf("Suma je %d.\n", suma);

getchar();
}

Zadatak 3.3. Napišite program koji od korisnika traži da unese dvije varijable (tipa int), s tim da
druga varijabla mora biti manja od prve. Zahtjev za unos druge varijable se ponavlja (koristite while
petlju) sve dok korisnik ne unese cijeli broj koji je manji od prvog broja. Program zatim treba
ispisati: "Prva varijabla je (ispisati vrijednost), a druga je (ispisati vrijednost). Druga varijabla je
manja od prve."

Rješenje:

#include <stdio.h>

void main()
{
int a;
int b;
int uvjet = 1;

printf("Upisite vrijednost prve varijable: ");


scanf("%d", &a);

while (uvjet) // ponavlja se sve dok je uvjet jednak jedinici


{
printf("Upisite vrijednost druge varijable tako da bude MANJA od prve: ");
scanf("%d", &b);

if (b < a)
uvjet = 0;
}

printf("Prva varijabla je %d, a druga je %d. Druga varijabla je manja od prve.\n", a, b);

getchar();
getchar();
}

Zadatak 3.4. Napišite program u kojem korisnik unosi tri cijela broja, a program ih sortira po veličini
(od najmanjeg prema najvećem) isključivo korištenjem if naredbi. Ne koristite petlje!

Rješenje:

#include <stdio.h>

30
void main()
{
int a, b, c;
int temp;

printf("Upisite 1. broj: ");


scanf("%d", &a);

printf("Upisite 2. broj: ");


scanf("%d", &b);

printf("Upisite 3. broj: ");


scanf("%d", &c);

// ako je a > b, b postaje a


if (a > b)
{
temp = a;
a = b;
b = temp;
}

// ako je a > c, c postaje a


if (a > c)
{
temp = a;
a = c;
c = temp;
}

// ako je b > c, c postaje b


if (b > c)
{
temp = b;
b = c;
c = temp;
}

printf("a = %d, b = %d, c = %d\n", a, b, c);

getchar();
getchar();
}

Zadatak 3.5. Napišite program u kojem korisnik unosi ocjene ispita, sve dok se ne unese 0. Ocjene
izvan dopuštenog raspona ocjena od 1 do 5 se zanemaruju. Program treba ispisati koliko je na

31
ispitu bilo pozitivnih (prolaznih), a koliko negativnih (nedovoljnih) ocjena, te kolika je bila prosječna
ocjena ispita.

Rješenje:

#include <stdio.h>

void main ()
{
int ocjena, brPoz = 0, brNeg = 0, suma = 0;
float prosjek;

do
{
printf("Unesite ocjenu: \n");
scanf("%d", &ocjena);

if ((ocjena < 0) || (ocjena > 5))


{
printf("NEPOSTOJECA OCJENA!\n");
}

else
{
suma += ocjena;

if (ocjena == 1)
brNeg++;

else if (ocjena > 1)


brPoz++;
}
} while (ocjena != 0);

prosjek = (float)suma/(brPoz + brNeg);

printf("\nBroj pozitivnih ocjena: %d\n", brPoz);


printf("Broj negativnih ocjena: %d\n", brNeg);
printf("--------------------------\n");
printf("Ukupno ocjena: \t\t%d\n", brPoz + brNeg);
printf("\nProsjecna ocjena iznosi %g.\n", prosjek);
getchar();
getchar();
}

32
Zadatak 3.6. Što je rezultat izvođenja slijedećih programa? Ispišite sve međurezultate do cilja!

a) b) c)

#include <stdio.h> #include <stdio.h> #include <stdio.h>

void main() void main() void main()


{ { {
int i; int i = 5; int i = 5;
for (i = 0; i < 5; i++) while (i) while (i)
printf("%d\n",i); printf("%d\n", --i); printf("%d\n", i--);
} } }

d) e) f)

#include <stdio.h> #include <stdio.h> #include <stdio.h>

void main() void main() void main()


{ { {
int i = 5; int i = 5; int i = 5;
i = i + 2; int uvjet = 1;
if (--i > 4) int suma = 0;
if (i < 5) i = i + 3;
printf ("Izlaz A\n"); while (uvjet)
printf("%d\n", i); {
else } if (i-- > 2)
printf("Izlaz B\n"); uvjet = 0;
} suma = suma + i;
}

printf("%d\n", suma);
}

Rješenja:

a) b) c)

0 4 5
1 3 4
2 2 3
3 1 2
4 0 1

d) e) f)

Izlaz B 4 4

33
DODATNI ZADACI

Zadatak 3.7. Napišite program koji pomoću for petlje ispisuje kvadrate, kubove i korijene prvih 20
prirodnih brojeva. Napomena: funkcija za računanje korijena je sqrt (engl. square root) i nalazi se u
standardnoj biblioteci <math.h>.

Zadatak 3.8. Napišite program koji generira i ispisuje deset slučajnih brojeva. Napomena: koristite
standardne biblioteke <stdlib.h> i <time.h>, te funkcije srand() i rand().

Zadatak 3.9. Napišite program za pogađanje broja generiranog od strane računala. Broji se broj
pokušaja, a pri svakom pokušaju računalo daje informaciju da li je broj veći, manji ili pogođen. Ako
je broj pogođen, izlazi se iz programa, uz ispis pogođenog broja te ukupnog broja pokušaja.

Napomena vezana uz zadatke 3.8 i 3.9: U programiranju ne postoje stvarno slučajni brojevi, već
samo pseudoslučajni. Generator pseudoslučajnih brojeva će za istu ulaznu vrijednost uvijek
generirati iste pseudoslučajne brojeve. Funkcija srand() postavlja inicijalnu vrijednost za generator
slučajnih brojeva koji je implementiran u funkciji rand(). Ako se ne koristi srand(), rand() će
izgenerirati uvijek isti niz pseudoslučajnih brojeva [2].

DOMAĆI RAD

Zadatak 3.10. Napišite program u kojem korisnik unosi četiri cjelobrojne varijable, a program ih
sortira po veličini (od najveće prema najmanjoj) isključivo korištenjem if naredbi (biti će vam
potrebno šest if naredbi). Ne koristite petlje!

Zadatak 3.11. a) Napišite program koji ispisuje cijelu ASCII tablicu. b) Napišite program u kojem
korisnik unosi neki znak (slovo ili broj) a program onda ispisuje sva ostala slova ili brojeve koji se u
ASCII tablici nalaze iza unesenog znaka. Na primjer, ako korisnik upiše broj '7', program treba
ispisati '8 9'. Ako korisnik unese 'b', program treba ispisati ostatak abecede. Razlikujte mala i velika
slova! Ignorirajte sve unesene znakove koji ne predstavljaju slovo ili broj! Napomena: možete
koristiti funkcije isdigit(), isupper() i islower() za provjeru unesenih znakova, ali onda morate
uključite biblioteku <ctype.h>.

Zadatak 3.12. Napišite program koji ispisuje rješenja kvadratne jednadžbe. Neka korisnik unese
koeficijente kvadratne jednadžbe. Podsjetnik:

2
ax bxc=0

−b± b2 −4ac
x=
2a

34
VJEŽBA 4

Naredba switch-case

Ako u izvornom kodu postoji posebno dugačak lanac if-else naredbi, dobra je praksa takve naredbe
zamijeniti sa naredbom switch-case. Naredba switch-case je preglednije zapisana if-else naredba.
Najčešće se koristi za stvaranje izbornika (engl. menu) [3]. Na primjer, ako korisnik unese broj '1',
izvrši se jedna naredba, a ako unese '2', izvrši se neka druga naredba.

Opći oblik naredbe switch-case:

switch (izraz)
{
case 'vrijednost izraza 1':
...
break;
case 'vrijednost izraza 2':
...
break;
...
default: // izvršava se ako nijedan drugi uvjet nije zadovoljen
...
}

Primjer (switch-case naredba): Program dozvoljava unos jednoznamenkastog cijelog broja sa


tipkovnice, te obaviještava korisnika o tome je li uneseni broj paran, neparan ili jednak nuli.

#include <stdio.h>

void main()
{
int a;

printf("Unesite cijeli broj: ");


scanf("%d", &a);

switch (a)
{
case 0:
printf("Uneseni broj je jednak nuli.\n");
break;
case 1:
case 3:
case 5:
case 7:
case 9:

35
printf("Uneseni broj je neparan.\n");
break;
case 2:
case 4:
case 6:
case 8:
printf("Uneseni broj je paran.\n");
break;
default:
printf("Dozvoljen je unos samo jednoznamenkastih brojeva.\n");
break;
}

getchar();
getchar();
}

Primijetite da je nakon više case naredbi izostavljena naredba break. To znači da će se za sve te
case naredbe izvršiti isti blok programskog koda (prvi na koji program naiđe tijekom izvođenja).
Ovakva je situacija poznata pod imenom "propadanje" kroz switch-case naredbu (engl. fall-
through).

Naredbe break i continue

Naredba break se koristi za prekid izvršavanja neke petlje. Slično, naredba continue se koristi za
prekid jedne iteracije neke petlje, te skok na iduću iteraciju.

Primjer (naredba break):

#include <stdio.h>

void main()
{
int i;

for (i = 0; i < 3; i++)


{
printf("Unutar petlje...\n");
break; // izlazak iz petlje
}

printf("Izasli smo iz for petlje!\n");

getchar();
}

36
ISPIS PROGRAMA:
Unutar petlje...
Izasli smo iz petlje!

Primjer (naredba continue):

#include <stdio.h>

void main()
{
int i;

for (i = 0; i < 3; i++)


{
printf("Prvi tekst...\n");
continue; // skače na provjeru uvjeta
printf("Drugi tekst...\n"); // ovaj se dio koda nikad ne izvrši
}

getchar();
}

ISPIS PROGRAMA:
Prvi tekst...
Prvi tekst...
Prvi tekst...

Naredba goto

Naredba goto je naredba bezuvjetnog skoka. Izvršavanjem naredbe goto program se grana na
zadanu programsku liniju [3].

Opći oblik:

#include <stdio.h>

void main()
{
ime_labele:
...programski kod...

goto ime_labele;
}

37
Primjer (goto naredba):

#include <stdio.h>

void main()
{
int i = 0;
start: // start je ime labele
printf("Beam me up, Scotty!\n");
if (i == 0)
{
i = 1;
goto start; // program skače na labelu start
}

getchar();
}

ISPIS PROGRAMA:
Beam me up, Scotty!
Beam me up, Scotty!

Većina programera izbjegava korištenje goto naredbe, budući da ona najčešće smanjuje
preglednost i razumljivost programskog koda. U programskim jezicima više razine ova se naredba
gotovo nikad ne koristi, a neki je jezici čak i zabranjuju. Sve što se može napraviti sa naredbom
goto, može se napraviti i sa standardnim petljama u C-u.

End-of-File (EOF)

End-of-File (EOF) označava stanje u kojem se nađe operacijski sustav kada na standardnom ulazu
ponestane znakova za čitanje. EOF je implementiran kao cjelobrojna konstanta koja ovisi o
operacijskom sustavu, i na Windows-ima je definirana kao -1.

Ako koristite neki drugi operacijski sustav, na slijedeći način možete provjeriti vrijednost konstante
EOF:

#include <stdio.h>

void main()
{
printf("%d\n", EOF);
getchar();
}

38
Funkcija getchar()

Funkcija getchar() se koristi za čitanje samo jednog znaka sa standardnog ulaza.

Prototip funkcije:

int getchar(void);

Primijetite da funkcija vraća cijeli broj, a ne znak!

Primjer:

#include <stdio.h>

void main()
{

int i;
int brojac = 0;

while ((i = getchar()) != EOF)


brojac++;

printf("Broj upisanih znakova: %d.\n", brojac);

getchar();
}

Da bi zaustavili unos znakova u gornjem programu, tj. da bi signalizirali operacijskom sustavu da


želite prestati sa unosom znakova, pozicionirajte se u novi redak i pritisnite Ctrl-Z (Windows) ili Ctrl-
D (Linux). Funkcija getchar() će onda znati da je došlo do EOF, i vratiti će -1.

Umjesto da pritišću Ctrl-Z ili Ctrl-D kada žele prekiniti unos znakova, programeri često koriste
makro naredbe.

Primjer:

#include <stdio.h>

#define EOF '\n' // makro naredba koja EOF u programskom kodu zamjenjuje sa \n

void main()
{

int i;
int brojac = 0;

39
while ((i = getchar()) != EOF)
brojac++;

printf("Upisali ste %d znakova.\n", brojac);

getchar();
}

U ovome programu više nije potrebno pritisnuti Ctrl-Z ili Ctrl-D za prekid unosa znakova, već je
potrebno samo prijeći u novu liniju, tj. stisnuti enter.

Napomena: jedna od čestih grešaka u programiranju jest dodjela vrijednosti koju vraća funkcija
getchar() nekoj znakovnoj varijabli, te onda uspoređivanje te varijable sa EOF.

Primjer:

#include <stdio.h>

void main()
{

char i; // primijetite da je ovdje sada char, a ne int --> ovo se ne preporučuje


int brojac = 0;

while ((i = getchar()) != EOF)


brojac++;

printf("Broj upisanih znakova: %d.\n", brojac);

getchar();
}

Sada pretpostavimo da char varijabla može sadržavati jednu od 128 znakovnih konstanti (u ASCII
tablici je 128 znakova). Funkcija getchar() može vratiti cjelobrojnu vrijednost bilo koje od tih 128
znakovnih konstanti, ali može vratiti i -1 kada naiđe na EOF. Dakle, funkcija getchar() može vratiti
ukupno 129 mogućih cjelobrojnih vrijednosti.

U gornjem primjeru, kada se cjelobrojna vrijednost koju vraća funkcija getchar() (ukupno 129
mogućih vrijednosti) pokuša mapirati u char varijablu (ukupno 128 mogućih vrijednosti), mora doći
do kolizije.

Ako se slučajno -1 konvertira u 65 (znak 'A' u ASCII tablici), program može prestati sa čitanjem
znakova iz datoteke ili sa standarnog ulaza kada naiđe na znak 'A', jer će pomisliti da je riječ o
oznaci za EOF. Da je pak varijabla 'i' bila deklarirana kao unsigned char, EOF se nikada ne bi
konvertirao u negativnu vrijednost, pa bi program zaglavio u beskonačnoj petlji.

Međutim, ovakve vas stvari trebaju zabrinjavati samo kada niste sigurni koliko memorije zauzimaju

40
int i char varijable. U današnje su vrijeme uglavnom i jedna i druga dovoljno velike da, bez kolizije
sa nekom drugom vrijednošću, prihvate vrijednost koju vraća funkcija getchar(). Ipak, kada se radi o
uspoređivanju te vrijednosti sa EOF, uvijek se preporučuje koristiti int varijablu umjesto char
varijable. Ako se pak ipak odlučite za char, morate pripaziti da uvijek bude deklarirana kao char ili
signed char, a nikada unsigned char!

41
ZADACI

Zadatak 4.1. Napišite program koji oponaša rad jednostavnog kalkulatora koji podržava operacije
zbrajanja, oduzimanja, množenja i dijeljenja. Korisnik programu zadaje izraz, primjerice 9 * 5, a
program ispisuje rezultat tog izraza. Koristite naredbu switch-case.

Rješenje:

#include <stdio.h>

void main()
{
int broj1 = 0, broj2 = 0;
float rezultat;
char operator1;

printf("Unesite izraz: \n");


scanf("%d %c %d", &broj1, &operator1, &broj2);

switch (operator1)
{
case '+':
rezultat = broj1 + broj2;
printf("%d %c %d = %.4f\n", broj1, operator1, broj2, rezultat);
break;

case '-':
rezultat = broj1 - broj2;
printf("%d %c %d = %.4f\n", broj1, operator1, broj2, rezultat);
break;

case '*':
rezultat = broj1 * broj2;
printf("%d %c %d = %.4f\n", broj1, operator1, broj2, rezultat);
break;

case '/':
if (broj2 == 0)
{
printf("Greska: dijeljenje sa nulom!\n");
break;
}

else
{
rezultat = (float)broj1 / broj2;

42
printf("%d %c %d = %.4f\n", broj1, operator1, broj2, rezultat);
break;
}

default:
printf("Nepoznata operacija!\n");
break;
}

getchar();
getchar();
}

Zadatak 4.2. Napišite program koji od korisnika traži da unese dva cijela broja, te zatim ispisuje tri
broja koja se nalaze između njih. Ako je udaljenost brojeva manja od tri, program treba ispisati
odgovarajuću poruku.

Rješenje:

#include <stdio.h>

void main ()
{
int x, y, i;

printf("Unesite dva cijela broja: ");


scanf("%d %d", &x, &y);

oznaka:
if (y >= x)
{
if ((y - x) < 4)
{
printf("Brojevi su nedovoljno udaljeni!\n");
}

else
{
printf("Brojevi unutar zadanih granica: ");
for (i = x + 1; i < x + 4; i++)
printf("%d ", i);
}
}

else
{

43
// ako je y > x zamijenimo im vrijednosti
int t = x;
x = y;
y = t;

goto oznaka;
}

getchar();
getchar();
}

Zadatak 4.3. Napišite program u kojem korisnik unosi deset cijelih brojeva (koristite for petlju), a
program vraća njihovu aritmetičku sredinu.

Rješenje:

#include <stdio.h>

void main()
{
int broj = 0;
int brojac = 10;
int suma = 0;
int i;
float prosjek = 0;

for (i = 0; i < brojac; i++)


{
printf("Unesite broj: ");
scanf ("%d", &broj);
suma += broj;
}

prosjek = (float)suma/brojac;

printf("Prosjecna vrijednost ovih deset unesenih brojeva iznosi: %f\n", prosjek);

getchar();
getchar();
}

44
Zadatak 4.4. Napišite program koji, uz pomoć petlji, na ekran ispisuje:

a) b)

* ABBB
** AABB
*** AAAB
**** AAAA

Rješenje (a):

#include <stdio.h>

void main()
{
char znak = '*';
int i, j;

for (i = 4; i > 0; i--)


{
for (j = i-1; j < 4; j++)
{
printf("%c", znak);
}

printf("\n");
}

getchar();
}

Rješenje (b):

#include <stdio.h>

void main()
{
char a = 'A';
char b = 'B';
int i, j, k;

for (i = 0; i < 4; i++)


{
for (j = i; j >= 0; j--)
printf("%c", a);

for (k = 3-i; k > 0; k--)

45
printf("%c", b);

printf("\n");
}

getchar();
}

Zadatak 4.5. Napišite program koji, uz pomoć naredbe getchar(), broji ukupan broj riječi koje unese
korisnik. Prekid unosa znakova neka bude pritisak na tipku enter. Napomena: da bi izbjegli
višestruke praznine, za definiciju riječi uzmite znak ili niz znakova kojima prethodi praznina.

Rješenje:

#include <stdio.h>

#define EOF '\n'

void main()
{

int znak, prethodniZnak = ' ';


int brojac = 0, i = 0;

while ((znak = getchar()) != EOF)


{
if ((znak != ' ') && (prethodniZnak == ' '))
brojac++;

prethodniZnak = znak;
}

printf("Broj upisanih rijeci: %d.\n", brojac);

getchar();
}

46
DODATNI ZADACI

Zadatak 4.6. Napišite program koji računa n-tu faktorijelu. Napomena: n se unosi pomoću scanf()
funkcije, i ne može biti veći od 12.

Zadatak 4.7. Napišite program koji ispisuje sve vrijednosti funkcije y = 15 * x + 76, za sve cijele
parne brojeve x iz intervala [-7, 7].

Zadatak 4.8. Napišite program koji, pomoću petlji, generira i ispisuje:

1
232
34543
4567654
567898765
67890109876
7890123210987
890123454321098
90123456765432109

DOMAĆI RAD

Zadatak 4.9. Napišite program koji zadanu vrijednost duljine u centimetrima pretvara u inche.
(x(in) = x(cm) / 2,54).

Zadatak 4.10. Napišite program koji za učitanu ocjenu ispisuje njezin opis. Na primjer, ako korisnik
unese 5, program ispisuje "Izvrstan". Ako korisnik unese broj izvan intervala [1,5], program treba
ispisati odgovarajuću poruku. Koristite switch-case naredbu.

Zadatak 4.11. Napišite program koji ispisuje sve parne brojeve iz intervala od 0 do 100.

47
VJEŽBA 5

Nizovi

Kolekcija varijabli istog tipa i zajedničkog imena zove se polje ili niz (engl. array). Niz u memoriji
zauzima kontinuirani niz memorijskih lokacija [2], a deklaracijom niza rezervira se memorija
potrebna za njegove članove. Nizovi mogu biti višedimenzionalni, a ime bilo kojeg niza predstavlja
adresu prvog elementa njegovog elementa.

Opći oblik glasi: tip ime_niza[izraz], gdje je izraz pozitivni cijeli broj.

Primjer deklaracije niza:

int x[100]; // niz od 100 cijelih brojeva


char text[80]; // niz od 80 znakova
float n[12]; // niz od 12 realnih brojeva

Primjer inicijalizacije niza:

int znamenke[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9};


float x[6] = {0, 0.25, 0, -0.50, 0, 0};
char boja[5] = {'P', 'L', 'A', 'V', 'A'};

Polja ili nizovi u programiranju su slični vektorima i matricama u matematici. Ako se želi pristupiti
članu nekog niza, to se radi pomoću indeksiranja.

Primjer:

#include <stdio.h>

void main()
{
int a[] = {1, 4, 7, 8, 17};

printf("%d ", a[0]); // ispisujemo vrijednost prvog člana niza


printf("%d", a[4]); // ispisujemo vrijednost posljednjeg člana niza

getchar();
}

ISPIS PROGRAMA:
1 17

48
Niz znakova

Niz znakova (engl. string) je polje koje se sastoji od niza znakova i koje završava oznakom kraja niza
'\0' (engl. string terminator).

Primjer (niz znakova): Program pohranjuje znakovni niz "Dalmacija" u jednodimenzionalni


znakovni niz X. Budući da riječ "Dalmacija" ima devet slova, znakovni niz mora imati mjesta za
deset znakova. Oznaka kraja niza se računa kao jedan znak.

Ovako to izgleda u memoriji:

D a l m a c i j a \0

X[0] = 'D'
X[1] = 'a'
X[2] = 'l'
X[3] = 'm'
X[4] = 'a'
X[5] = 'c'
X[6] = 'i'
X[7] = 'j'
X[8] = 'a'
X[9] = '\0'

Programski kod:

#include <stdio.h>

void main()
{
char X[10] = "Dalmacija";
printf("Znakovni niz glasi: %s.\n", X);
getchar();
}

ISPIS PROGRAMA:
Znakovni niz glasi: Dalmacija.

49
Višedimenzionalni nizovi

Višedimenzionalni nizovi su skupovi jednodimenzionalnih nizova. Primjer nekog


višedimenzionalnog niza bila bi matrica.

Grafički prikaz dvodimenzionalnog niza:

Tablica 5.1. Grafički prikaz dvodimenzionalnog niza

X stupac 0 stupac 1 stupac 2 stupac 3 stupac 4 stupac 5 stupac 6


redak 0 X[0][0] X[0][1] X[0][2] X[0][3] X[0][4] X[0][5] X[0][6]
redak 1 X[1][0] X[1][1] X[1][2] X[1][3] X[1][4] X[1][5] X[1][6]
redak 2 X[2][0] X[2][1] X[2][2] X[2][3] X[2][4] X[2][5] X[2][6]
redak 3 X[3][0] X[3][1] X[3][2] X[3][3] X[3][4] X[3][5] X[3][6]

Opći oblik:

tip_niza ime_niza [dimenzija_1] [dimenzija_2] ... [dimenzija_n]


tip_niza ime_ niza [broj_redaka] [broj_stupaca] ... [dodatne_dimenzije]

Primjer deklaracije niza:

float tablica[50][50];
char stranica[24][80];
static double zapisi [x][y][z];

Primjer inicijalizacije niza:

int a[2][3] = {{1, 2, 3}, {4, 5, 6}};

Primjer (dvodimenzionalni niz): Program ispisuje dvodimenzionalni niz od tri retka i četiri stupca.

#include <stdio.h>

void main()
{
int niz[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int i, j;

for (i = 0; i < 3; i++)


for (j = 0; j < 4; j++)
printf("Niz [%d][%d] = %d\n", i, j, niz[i][j]);
getchar();

50
}

ISPIS PROGRAMA:

51
ZADACI

Zadatak 5.1. Napišite program koji jednodimenzionalni niz od sedam članova inicijalizira na nulu.

Rješenje:

#include <stdio.h>

void main()
{
int i;
int niz[7];

for (i = 0; i < 7; i++)


{
niz[i] = 0;
printf("niz[%d] = %d\n", i, niz[i]);
}

getchar();
}

Zadatak 5.2. Napišite program koji učitava niz od deset cijelih brojeva, te ih ispisuje na ekran
korištenjem for petlje.

Rješenje:

#include <stdio.h>

void main()
{
int i = 0;
int a;
int niz[10];

for (i = 0; i < 10; i++)


{
printf("Unesite %d. broj: ", i+1);
scanf("%d", &a);
niz[i] = a;
}

printf("\n");

//ispisujemo originalni niz

52
for (i = 0; i < 10; i++)
printf("%d. broj: %d\n", i+1, niz[i]);

getchar();
getchar();
}

Zadatak 5.3. Napišite program koji učitava znakovni niz sa tipkovnice i zatim ga ispisuje na ekran.

Rješenje:

#include <stdio.h>

void main()
{
char niz[80];

printf("Unesite znakovni niz: ");


scanf("%s", niz); // alternativno: gets(niz);

printf("Upisali ste niz: %s.\n", niz);

getchar();
getchar();
}

Zadatak 5.4. Napišite program u kojemu korisnik unosi niz od 10 cijelih brojeva. Program od tog
niza napravi dva druga niza: jedan koji sadrži samo parne brojeve iz originalnog niza, te drugi koji
sadrži samo neparne brojeve iz originalnog niza.

Rješenje:

#include <stdio.h>

void main()
{
int i = 0;
int a;
int niz[10];
int parni[10];
int neparni[10];
int brojac_parni = 0;
int brojac_neparni = 0;

for (i = 0; i < 10; i++)

53
{
printf("Unesite %d. broj: ", i+1);
scanf("%d", &a);
niz[i] = a;
}

printf("\n");

// ispisujemo originalni niz


for (i = 0; i < 10; i++)
printf("%d. broj: %d\n", i+1, niz[i]);

// parne i neparne brojeve dijelimo u dva niza


for (i = 0; i < 10; i++)
{
if ((niz[i] % 2) == 0) // parni
{
parni[brojac_parni] = niz[i];
brojac_parni++;
}

else // neparni
{
neparni[brojac_neparni] = niz[i];
brojac_neparni++;
}
}

printf("\nNiz koji sadrzi parne brojeve: ");

// ispisujemo originalni niz


for (i = 0; i < brojac_parni; i++)
printf("%d ", parni[i]);

printf("\nNiz koji sadrzi neparne brojeve: ");

// ispisujemo originalni niz


for (i = 0; i < brojac_neparni; i++)
printf("%d ", neparni[i]);

getchar();
getchar();
}

Zadatak 5.5. Napišite program za zbrajanje matrica dimenzija 3x3. Matrice inicijalizirajte na
proizvoljne vrijednosti unutar programskog koda.

54
Primjer zbrajanja matrica [4]:

    
1 3 2 0 0 5 10 30 25 1 3 7
1 0 0  7 5 0 = 17 05 00 = 8 5 0
1 2 2 2 1 1 12 21 21 3 3 3

Rješenje:

#include <stdio.h>

void main()
{
int A[3][3] = {{1, 3, 2}, {1, 0, 0}, {1, 2, 2}};
int B[3][3] = {{0, 0, 5}, {7, 5, 0}, {2, 1, 1}};
int C[3][3];
int i, j;

// zbrajanje matrica
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
C[i][j] = A[i][j] + B[i][j];

printf("Rezultat zbrajanja matrica:\n");

for (i = 0; i < 3; i++)


for (j = 0; j < 3; j++)
{
printf("[%d][%d] = %d", i, j, C[i][j]);
printf("\n");
}

getchar();
getchar();
}

ISPIS PROGRAMA:

55
Zadatak 5.6. Napišite program za množenje dviju matrica. Neka prva matrica ima dimenzije 2x3, a
druga 3x2. Matrice inicijalizirajte na proizvoljne vrijednosti unutar programskog koda.

Primjer množenja matrica [4]:

 
3 1
 1 0 2⋅
−1 3 1
2 1 =
1 0
1⋅30⋅22⋅1 1⋅10⋅12⋅0 = 5 1
−1⋅33⋅21⋅1 −1⋅13⋅11⋅0 4 2  
Rješenje:

#include <stdio.h>

void main()
{
int A[2][3] = {{1, 0, 2}, {-1, 3, 1}};
int B[3][2] = {{3, 1}, {2, 1}, {1, 0}};
int C[2][2] = {{0, 0}, {0, 0}};
int i, j, k;

// mnozenje matrica
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
{
for (k = 0; k < 3; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}

printf("Rezultat mnozenja matrica:\n");

for (i = 0; i < 2; i++)


for (j = 0; j < 2; j++)
{
printf("[%d][%d] = %d", i, j, C[i][j]);
printf("\n");
}

getchar();
}

ISPIS PROGRAMA:

56
Zadatak 5.7. Napišite program u kojem korisnik unosi elemente kvadratne matrice dimenzija 5x5.
Program treba ispisati sve elemente matrice koji se nalaze ispod glavne dijagonale, te zatim te
elemente prebaciti u jednodimenzionalni niz i onda ispisati i taj niz.

Rješenje:

#include <stdio.h>

void main()
{
int i, j, k = 0;
int const n = 5;
int niz[n][n];
int novi_niz[10];

// korisnik unosi elemente matrice


for (i = 0; i < n; i++)
{
printf("Unesite %d elemenata %d. retka: ", n, i+1);

for (j = 0; j < n; j++)


scanf("%d", &niz[i][j]);
}

printf("\n");

// ispisujemo unesenu matricu


for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%d ", niz[i][j]);

printf("\n");
}

printf("\n");

// ispisujemo elemente ispod glavne dijagonale matrice


for (i = 0; i < n; i++)
{
for (j = 0; j < i; j++)
{
printf("%d ", niz[i][j]);
novi_niz[k] = niz[i][j];
k++;
}

57
printf("\n");
}

printf("\n");

// ispisujemo novi niz


for (i = 0; i < k; i++)
printf("%d ", novi_niz[i]);

printf("\n");

getchar();
getchar();
}

58
DODATNI ZADACI

Zadatak 5.8. Napišite program koji učitava dva niza znakova i ispituje da li su ti nizovi jednaki. Kraj
učitavanja niza određen je oznakom za prijelaz u novi redak ('\n').

Zadatak 5.9. Napišite program koji učitava redak teksta i pretvara mala slova u velika. Redak mora
biti ograničen na 80 znakova. Napomena: za pretvaranje malih slova u velika koristite funkciju
toupper() iz biblioteke <ctype.h>, a za unošenje retka funkciju gets().

DOMAĆI RAD

Zadatak 5.10. Napišite program koji učitava ime i prezime korisnika, dob i godinu rođenja, te
ispisuje te informacije na ekran.

Zadatak 5.11. Napišite program u kojem korisnik unosi niz od deset cijelih brojeva, a program
ispisuje njihovu aritmetičku sredinu.

Zadatak 5.12. Napišite program za zbrajanje matrica. Elemente matrice unosi korisnik, a svaka
matrica može imati najviše 20 redaka i stupaca. Napomena: zbrajati se mogu samo matrice istih
dimenzija.

59
VJEŽBA 6

Bubble sort algoritam

Bubble sort algoritam je algoritam za sortiranje članova nekog niza. Ovo je jedan od
najjednostavnijih, ali ujedno i najsporijih, algoritama za sortiranje.

U slijedećem primjeru prikazan je način rada bubble sort algoritma. Algoritam u svakom koraku
uspoređuje dva susjedna broja, i u slučaju da je prvi broj veći od drugog, zamjenjuje im mjesta.
Napomena: podebljani brojevi su oni koji se trenutno uspoređuju.

Ulazni niz brojeva: (0 8 1 3 2).

1. prolaz algoritma:
• (0 8 1 3 2) --> (0 8 1 3 2) // 0 < 8 --> nema zamjene
• (0 8 1 3 2) --> (0 1 8 3 2) // 8 > 1 --> zamjena
• (0 1 8 3 2) --> (0 1 3 8 2) // 8 > 3 --> zamjena
• (0 1 3 8 2) --> (0 1 3 2 8) // 8 > 2 --> zamjena

2. prolaz algoritma:
• (0 1 3 2 8) --> (0 1 3 2 8) // 0 < 1 --> nema zamjene
• (0 1 3 2 8) --> (0 1 3 2 8) // 1 < 3 --> nema zamjene
• (0 1 3 2 8) --> (0 1 2 3 8) // 3 > 2 --> zamjena
• (0 1 2 3 8) --> (0 1 2 3 8) // 3 < 8 --> nema zamjene

3. prolaz algoritma:
• (0 1 2 3 8) --> (0 1 2 3 8) // 0 < 1 --> nema zamjene
• (0 1 2 3 8) --> (0 1 2 3 8) // 1 < 2 --> nema zamjene
• (0 1 2 3 8) --> (0 1 2 3 8) // 2 < 3 --> nema zamjene
• (0 1 2 3 8) --> (0 1 2 3 8) // 3 < 8 --> nema zamjene

Iako je niz bio sortiran na kraju drugog prolaza algoritma, algoritam se je morao još jednom izvršiti
da bi "znao" da je niz sortiran. Drugim riječima, algoritmu je potreban jedan prolaz bez ijedne
zamjene da bi bio siguran da je algoritam sortiran.

Analiza bubble sort algoritma

Pod analizom algoritma podrazumijeva se procjena vremena izvršavanja tog algoritma. Vrijeme se
poistovjećuje s brojem operacija koje odgovarajući program treba obaviti [5], i izražava se kao
funkcija oblika O(n) (engl. Order(n)). Na primjer, za ulazni niz brojeva (0 8 1 3 2), n bi bio jednak pet.
Da bi bubble sort algoritam uspio sortirati taj niz, u najboljem slučaju bi mu bilo potrebno O(n)
operacija (u ovom slučaju 5), a u najgorem slučaju O(n2) operacija (u ovom slučaju 25). Kako se n
povećava, najgore vrijeme izvršavanja algoritma eksponencijalno raste. Upravo zbog ovog

60
problema, bubble sort algoritam nije dobar za sortiranje nizova sa velikim brojem podataka. Drugi
algoritmi kao što su heap sort i mergesort imaju puno bolje vrijeme izvršavanja – u najboljem
slučaju O(n), u najgorem slučaju O(nlogn) – ali su ipak nešto kompliciraniji.

61
ZADACI

Zadatak 6.1. Napišite program koji u niz sprema maksimalno 20 cijelih brojeva koje unosi korisnik.
Program sortira brojeve po veličini i ispisuje sortirani niz. Koristite bubble sort algoritam.

Rješenje:

#include <stdio.h>

void main ()
{
int niz[20];
int n;
int temp;
int i, j;

printf("Koliko brojeva zelite unijeti? ");


scanf("%d", &n);

if ((n <= 0) || (n > 20))


printf("Morate unijeti broj u rasponu od 1 do 20.\n");
else if (n == 1)
printf("Nije potrebno sortirati niz od samo jednog clana.\n");
else
{
printf("\nUpisite clanove niza:\t ");

for (i = 0; i < n; i++)


scanf("%d", &niz[i]);

for (i = 0; i < n-1; i++)


for (j = i+1; j < n; j++)
{
if (niz[i] > niz[j])
{
temp = niz[i];
niz[i] = niz[j];
niz[j] = temp;
}
}

printf("\nSortirani niz:\t ");

for (i = 0; i < n; i++)


printf("%d ", niz[i]);
}

62
printf("\n");

getchar();
getchar();
}

ISPIS PROGRAMA:

Zadatak 6.2. Pomoću for petlje unesite prosječne mjesečne temperature za jednu godinu. Ispišite
maksimalnu, minimalnu i prosječnu godišnju temperaturu.

Rješenje:

#include <stdio.h>

void main()
{
float godina[12];
int i;
float prosjecnaTemperatura = 0;
float max, min;

for (i = 0; i < 12; i++)


{
printf("Temperatura za mjesec broj %d: \t", i+1);
scanf("%f", &godina[i]);
}

printf("\n");

for (i = 0; i < 12; i++)


{
printf("Temperatura za mjesec broj %d: \t %.2f\n", i, godina[i]);
}

for (i = 0; i < 12; i++)


prosjecnaTemperatura = prosjecnaTemperatura + godina[i];

63
prosjecnaTemperatura = prosjecnaTemperatura / 12;

printf("Prosjecna temperatura: \t %.2f\n", prosjecnaTemperatura);

max = godina[0];

for (i = 1; i < 12; i++)


{
if (max < godina[i])
max = godina[i];
}

min = godina[0];

for (i = 1; i < 12; i++)


{
if (min > godina[i])
min = godina[i];
}

printf("Maksimalna temperatura: \t %.2f\n", max);


printf("Minimalna temperatura: \t %.2f\n", min);

getchar();
getchar();
}

Zadatak 6.3. Napišite program koji učitava proizvoljan broj znakova, te ispisuje koliko ima slova,
brojeva i ostalih znakova. Kraj učitavanja niza određen je oznakom za prijelaz u novi redak ('\n'). Za
unos znakova koristite funkciju getchar().

Rješenje:

#include <stdio.h>

void main()
{
int slova = 0;
int brojevi = 0;
int ostaliZnakovi = 0;
int znak;

puts("Unesite neki niz znakova:");

while ((znak = getchar()) != '\n')


{

64
if ((znak >= 'a' && znak <= 'z') || (znak >= 'A' && znak <= 'Z'))
slova++;
else if (znak >= '0' && znak <= '9')
brojevi++;
else
ostaliZnakovi++;
}

printf("Slova: %d\n", slova);


printf("Brojevi: %d\n", brojevi);
printf("Ostali znakovi: %d\n", ostaliZnakovi);

getchar();
}

Zadatak 6.4. Zadatak je sličan prethodnome. Napišite program koji učitava proizvoljni broj znakova,
te ispisuje koliko ima slova, brojeva i ostalih znakova. Koristite funkcije getchar(), isdigit(), isupper()
i islower(). Uključite biblioteku <ctype.h>.

Rješenje:

#include <stdio.h>
#include <ctype.h>

void main()
{
int slova = 0;
int brojevi = 0;
int ostaliZnakovi = 0;
int znak;

puts("Unesite neki niz znakova:");

while ((znak = getchar()) != '\n')


{
if ((islower(znak)) || (isupper(znak)))
slova++;
else if (isdigit(znak))
brojevi++;
else
ostaliZnakovi++;
}

printf("Slova: %d\n", slova);


printf("Brojevi: %d\n", brojevi);
printf("Ostali znakovi: %d\n", ostaliZnakovi);

65
getchar();
}

66
DODATNI ZADACI

Zadatak 6.5. Napišite program koji za neku predefiniranu riječ broji koliko ona ima samoglasnika, te
tu informaciju ispisuje na ekran.

Zadatak 6.6. Napišite program koji dozvoljava unos proizvoljnog broja znakova (koristite while
petlju i funkciju getchar() za unos znakova). Kraj unosa određen je oznakom za prijelaz u novi redak
('\n'). Program treba ispisati ukupan broj unesenih znakova. Napomena: prazna mjesta se također
broje kao znakovi.

DOMAĆI RAD

Zadatak 6.7. Napišite program koji učitava niz od deset cijelih brojeva, te ih u obrnutom redoslijedu
sprema u novi niz. Program treba ispisati taj novi niz.

Zadatak 6.8. Napišite program koji učitava niz od deset cijelih brojeva, te ispisuje samo one koji su
parni. Ako u nizu ne postoji nijedan parni broj, program treba ispisati odgovarajuću poruku.

67
VJEŽBA 7

Funkcije

Funkcija je programski modul koji obavlja neke specifične, točno definirane zadaće.
Svaki C program sastoji se od jedne ili više funkcija, pri čemu se jedna mora zvati main(). Od main()
funkcije program počinje obradu. Sve se ostale funkcije, posredno ili neposredno, pozivaju iz
funkcije main().
Funkcija izvede programiranu radnju svaki put kad je "pozvana" iz bilo kojeg dijela programa. Po
povratku iz funkcije programski tok nastavlja se tamo odakle je funkcija bila pozvana. U pravilu,
funkcija prihvaća skup argumenata (jedan ili više), a vraća samo jednu vrijednost.

Opći oblik:

tip_povratne_informacije ime_funkcije (tip1 argument1, tip2 argument2, ...)


{
...
}

Napomena: lista argumenata može biti i prazna, a tip povratne informacije može biti void.

Argumenti se unutar funkcije nazivaju i formalnim argumentima, jer predstavljaju samo preslike
podataka koji su u funkciju poslani iz pozivnog dijela programa. Također, koristi se i naziv parametri.
Argumente koji su u funkciju poslani nazivamo stvarnim argumentima ili parametrima.

Informacija se iz funkcije vraća u pozivni dio programa preko naredbe return. Ta naredba također
vraća programski tok na mjesto odakle je funkcija pozvana.

Ako se iz funkcije main() poziva neka druga funkcija, onda se ta funkcija mora ili definirati prije
funkcije main(), ili se prije funkcije main() mora nalaziti prototip te funkcije (tijelo funkcije se onda
može nalaziti poslije funkcije main()).

Kako funkcija prenosi podatke?

Kada se pozove neka funkcija, ona će napraviti kopije argumenata koji su joj predani, tj. od stvarnih
argumenata (parametara) će napraviti formalne. U isto vrijeme funkcija će osigurati memorijski
prostor za eventualnu povratnu vrijednost.

Prijenos argumenata u funkciju

Kada se šalje neka varijabla kao stvarni argument u funkciju, njena vrijednost se preslika u formalni
argument u pozvanoj funkciji. Takav način proslijeđivanja argumenata funkciji nazivamo
proslijeđivanjem preko vrijednosti (engl. call by value). Ovakav način proslijeđivanja ima svoje
prednosti i nedostatke. Prednost je u tome što argument kroz funkciju ne mijenja svoju vrijednost,

68
a nedostatak je u tome što se na ovaj način preko argumenata ne može prenijeti informacija natrag
iz funkcije.

Kada se šalje niz kao stvarni argument u funkciju, njegova vrijednost se preslika u formalni
argument u pozvanoj funkciji. Kako je niz predstavljen početnom adresom niza, preslikana
vrijednost početne adrese pristupa istim podacima. Ovakav način proslijeđivanja argumenta
funkciji nazivamo proslijeđivanjem preko adrese (engl. call by reference). Ovakav način
proslijeđivanja podrazumijeva da je svaka promjena argumenta u funkciji vidljiva i u dijelu
programa koji je funkciju pozvao.

Ukratko, ako se koristi proslijeđivanje preko vrijednosti, stvarni argumenti ostaju nepromijenjeni.
Ako se pak koristi proslijeđivanje preko adrese, stvarni argumenti mogu biti promijenjeni.

Slika 7.1. Grafički prikaz prijenosa argumenata u funkciju.

69
ZADACI

Zadatak 7.1. Napišite program koji iz funkcije main() poziva funkciju zbroji() i prosljeđuje joj dva
proizvoljna cijela broja. Funkcija zbroji() mora vratiti rezultat zbrajanja ta dva broja.

Rješenje (1. način):

#include <stdio.h>

int zbroji (int, int); // prototip funkcije zbroji()

void main()
{
int a;
int b;
int rezultat;

printf("Unesite 1. broj: ");


scanf("%d", &a);
printf("Unesite 2. broj: ");
scanf("%d", &b);

rezultat = zbroji(a, b);

printf("%d + %d = %d\n", a, b, rezultat);


getchar();
getchar();
}

int zbroji (int x, int y)


{
int z;
z = x + y;
return z;
}

Rješenje (2. način):

#include <stdio.h>

int zbroji (int x, int y) // definicija funkcije zbroji()


{
int z;
z = x + y;
return z;

70
}

void main()
{
int a;
int b;
int rezultat;

printf("Unesite 1. broj: ");


scanf("%d", &a);
printf("Unesite 2. broj: ");
scanf("%d", &b);

rezultat = zbroji(a, b);

printf("%d + %d = %d\n", a, b, rezultat);

getchar();
getchar();
}

Zadatak 7.2. Napišite program koji učitava niz od deset cijelih brojeva, te zatim proslijeđuje taj niz
funkciji koja vraća aritmetičku sredinu članova niza.

Rješenje:

#include <stdio.h>

float aritmetickaSredina(int a[])


{
float aritmeticka_sredina = 0;
int brojac;

for (brojac = 0; brojac < 10; brojac++)


aritmeticka_sredina = aritmeticka_sredina + a[brojac];

aritmeticka_sredina = aritmeticka_sredina / 10;

return aritmeticka_sredina;
}

void main()
{
int niz[10], i;
float rezultat;

71
for (i = 0; i < 10; i++)
{
printf("Unesite %d. clan niza: \t", i+1);
scanf("%d", &niz[i]);
}

printf("\n");

rezultat = aritmetickaSredina(niz);

printf("Aritmeticka sredina clanova niza je %.4f.\n", rezultat);

getchar();
getchar();
}

Zadatak 7.3. Napišite program koji učitava malo slovo, te ga pretvara u veliko slovo pomoću
funkcije malo_u_veliko().

Rješenje:

#include <stdio.h>

int malo_u_veliko (char x)


{
int rezultat;

// velika i mala slova su u ASCII tablici udaljeni za 32 znaka


rezultat = x - 32;

return rezultat;
}

void main()
{
char maloSlovo, velikoSlovo;

printf("Unesite neko malo slovo: ");


scanf("%c", &maloSlovo);

if ((maloSlovo >= 'a') && (maloSlovo <= 'z'))


{
velikoSlovo = malo_u_veliko(maloSlovo);
printf("Veliko slovo: %c\n", velikoSlovo);
}

72
else
printf("Niste unijeli malo slovo.\n");

getchar();
getchar();
}

73
DODATNI ZADACI

Zadatak 7.4. Napišite program u kojem korisnik unosi broj sekundi, a program preračunave
sekunde u sate, minute i sekunde. Na primjer, ako korisnik unese 3670, program treba ispisati: 1
sat, 1 minuta i 10 sekundi.

DOMAĆI RAD

Zadatak 7.5. Napišite program u kojem korisnik unosi brojčani iznos u kunama, a program
preračunava kune u eure (1 euro = 7.26 kuna). Preračunavanje se mora obaviti u posebnoj funkciji.

Zadatak 7.6. Napišite program koji za deset predefiniranih brojeva računa aritmetičku sredinu, te
traži najveći broj u nizu.

74
VJEŽBA 8

Doseg funkcije

Kada govorimo o dosegu funkcije, govorimo o imenima varijabli koje koristimo. Doseg je dio
programa unutar kojeg se neka varijabla može koristiti.

Varijable se mogu podijeliti na:

• lokalne (automatske)
• globalne (vanjske)
• statičke
• registarske

Lokalne (automatske) varijable

Lokalne (automatske) varijable su prijavljene unutar neke funkcije i vidljive su jedino u toj funkciji.
Ako im se pokuša pristupiti iz neke druge funkcije, program će javiti grešku.
Dvije lokalne varijable u različitim funkcijama s istim imenima nezavisne su jedna od druge.
Sve varijable su lokalne ako se to drugačije ne navede.
Lokalne varijable ne zadržavaju vrijednost nakon što programski tok ode iz funkcije u kojoj je
varijabla definirana.

Globalne (vanjske) varijable

Suprotno lokalnim varijablama, globalne varijable nisu vezane za neku funkciju. Njihov doseg seže
od mjesta definicije kroz ostatak programa. Čak štoviše, katkad povezuju ne samo funkcije nego i
cjelokupni program.
Promjena globalne varijable u bilo kojoj funkciji biti će vidljiva u svakom dijelu programa.
Inicijalizacija globalne varijable mora biti inicijalizirana konstantom, a nikako izrazom.

Statičke varijable

Doseg statičkih varijabli, kao i doseg lokalnih varijabli, seže samo unutar funkcije u kojoj su
definirane. Ako programski tok izađe iz funkcije, pa se opet vrati u nju, statička će varijabla dobiti
onu vrijednost koju je imala na izlazu iz funkcije. To znači da se statičke varijable ne uništavaju
nakon izlaska programskog toka iz neke funkcije, već ostaju sačuvane u memoriji.
Statičke varijable se označavaju sa ključnom riječi static.

Registarske varijable

Registarske varijable se najčešće koriste za ubrzavanje programskog koda. To su varijable koje se ne

75
moraju spremati i čitati iz memorije, već tijekom čitavog izvođenja programa ostaju u registrima.
Označavaju se sa ključnom riječi register.

Lokalne varijable definirane unutar programskog bloka

Ako se lokalne varijable definiraju unutar nekog programskog pod-bloka, biti će dostupne samo u
tome pod-bloku. Pokušaj pristupa nekoj od njih izvan tog programskog bloka uzrokovati će grešku.

Primjer 1.

#include <stdio.h>

void main()
{
int a = 0;

do
{
int b = 1;
...programski kod...
} while(...);

// da pokušamo ovdje ispisati vrijednost varijable b, program bi javio grešku


// varijabla b ovdje više ne postoji
}

Primjer 2.

#include <stdio.h>

void main ()
{
int brojac1 = 1; // deklariran u VANJSKOM bloku

do
{
int brojac2 = 0; // deklariran u UNUTARNJEM bloku
++brojac2;
printf("\nbrojac1 = %d brojac2 = %d", brojac1, brojac2);
} while (++brojac1 <= 8);

// brojac2 vise ne postoji

printf("\nbrojac1 = %d\n", brojac1);

getchar();

76
}

ISPIS PROGRAMA:

Primjer 3.

#include <stdio.h>

void main()
{
int brojac = 0; // deklariran u VANJSKOM bloku

do
{
int brojac = 0; // ovo je druga varijabla nazvana brojac
++brojac; // ovo se odnosi na UNUTARNJI brojac
printf("brojac = %d\n", brojac);
} while (++brojac <= 8); // ovo mijenja VANJSKI brojac

printf("brojac = %d\n", brojac);

getchar();
}

ISPIS PROGRAMA:

77
ZADACI

Zadatak 8.1. (Lokalne varijable) Proučite i objasnite kako radi slijedeći program:

#include <stdio.h>

void test()
{
// funkcija test() ne vidi varijablu a
// ako se varijabla a pokuša koristiti u ovoj funkciji, program će javiti grešku

printf("Funkcija test(): ovdje ne postoji varijabla a\n");


}

void main()
{
int a; // a je lokalna varijabla u funkciji main()
a = 2;
printf("Funkcija main(): %d\n", a);
test();
getchar();
}

ISPIS PROGRAMA:
Funkcija main(): 2
Funkcija test(): ovdje ne postoji varijabla a

Zadatak 8.2. (Globalne varijable) Proučite i objasnite kako radi slijedeći program:

#include <stdio.h>

int x = 7; // x je globalna varijabla, vidljiva u svim funkcijama

void test()
{
printf("Funkcija test(): %d\n", x);
}

void main()
{
printf("Funkcija main(): %d\n", x);
test();
getchar();
}

78
ISPIS PROGRAMA:
Funkcija main(): 7
Funkcija test(): 7

Zadatak 8.3. (Statičke varijable) Proučite i objasnite kako radi slijedeći program:

#include <stdio.h>

int brojac = 1; // globalna varijabla brojac

void test()
{
static int a = 0; // statička varijabla a
a = a + 2;
printf("%d. poziv funkcije test(). \t a = %d\n", brojac, a);
brojac++;
}

void main()
{
int i; // lokalna varijabla i
for (i = 0; i < 10; i++)
test();
getchar();
}

ISPIS PROGRAMA:

79
DODATNI ZADACI

Zadatak 8.4. Napišite program koji ispisuje prvih 10 znamenki Fibonaccijevog niza (koristite while
ili for petlju). Napomena: Fibonaccijev niz je niz brojeva koji započinje sa nulom i jedinicom, a svaki
slijedeći broj je zbroj prethodna dva. Prvih nekoliko znamenki Fibonaccijevog niza: 0 1 1 2 3 5 8 13
21 34 55 89 144 ...

DOMAĆI RAD

Zadatak 8.5. Napišite program u kojem korisnik unosi dva cijela broja, a program ispisuje sve proste
brojeve koji se nalaze unutar zadanog intervala. Napomena: prosti brojevi ili prim-brojevi su svi
prirodni brojevi djeljivi bez ostatka samo sa brojem 1 i sami sa sobom, a veći od broja 1.

Zadatak 8.6. Napišite program koji računa sumu svih brojeva od 1 do 100 koji su djeljivi sa 5.

80
VJEŽBA 9

Bitznačajni operatori

Bit je najmanja jedinica informacije, ili 0 ili 1, a bitznačajni operatori (engl. bitwise operators) se
koriste za manipulaciju bitovima (odnosno za programiranje na najnižoj mogućoj razini). Bitznačajni
operatori se najčešće koriste u kriptografiji i u sažimanju podataka.

Bitznačajni operatori:
• & binarno I (AND)
• | binarno ILI (OR)
• ^ binarno ekskluzivno ILI (XOR)
• ~ jedinični komplement (NOT)
• << pomak u lijevo (SHIFT LEFT)
• >> pomak u desno (SHIFT RIGHT)

Tablica 9.1. Tablica istine za &, ^ i | operatore

a b a&b a^b a|b


0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 0 1

Tablica 9.2. Tablica istine za ~ operator

a ~a
0 1
1 0

Tablica 9.3. Primjeri primjene AND, OR i XOR operatora

Primjer (AND): Primjer (OR): Primjer (XOR):


0010 0010 0010
& 1010 | 1010 ^ 1010
0010 1010 1000

Jedinični komplement (~) je unarni operator koji se koristi za inverziju bitova nekog operanda
(jedinice postaju nule, a nule jedinice). Operand se najčešće predstavlja u oktalnoj ili u
heksadecimalnoj formi, iako ovo nije formalno pravilo [6].

81
Primjer:

a = 0110 1101 1011 0111 (dekadski brojevni sustav – 28087)


~a = 1001 0010 0100 1000 (dekadski brojevni sustav – 37448)

Bitznačajni pomak u lijevo odgovara množenju operanda sa potencijama broja dva. Na primjer,
ako operand pomaknemo za jedno mjesto u lijevo dobiti ćemo isti rezultat kao da smo ga
pomnožili sa 2.

Primjeri:

a = 0110 1101 1011 0111 (dekadski brojevni sustav – 28087)


a << 6 = 0110 1101 1100 0000 (dekadski brojevni sustav – 28096)

a = 0000 0010 (dekadski brojevni sustav – 2)


a << 1 = 0000 0100 (dekadski brojevni sustav – 4)
a << 2 = 0000 1000 (dekadski brojevni sustav – 8)
a << 3 = 0001 0000 (dekadski brojevni sustav – 16)
a << 4 = 0010 0000 (dekadski brojevni sustav – 32)

Bitznačajni pomak u desno odgovara cjelobrojnom dijeljenju operanda sa potencijama broja dva.
Na primjer, ako operand pomaknemo za jedno mjesto u desno dobiti ćemo isti rezultat kao da smo
ga podijelili sa 2.

Primjeri:

a = 0110 1101 1011 0111 (dekadski brojevni sustav – 28087)


a >> 6 = 0000 0001 1011 0110 (dekadski brojevni sustav – 438)

a = 0100 0000 (dekadski brojevni sustav – 64)


a >> 1 = 0010 0000 (dekadski brojevni sustav – 32)
a >> 2 = 0001 0000 (dekadski brojevni sustav – 16)
a >> 3 = 0000 1000 (dekadski brojevni sustav – 8)
a >> 4 = 0000 0100 (dekadski brojevni sustav – 4)

Maskiranje bitova

Bitznačajni operator I (AND) se najčešće koristi za maskiranje bitova. Maskiranje bitova je proces
važan za računalnu sigurnost, grafiku i kriptografiju.

Primjer:

a = 0110 1101 1011 0111 (dekadski brojevni sustav – 28087)


maska = 0000 0000 0000 1111 (dekadski brojevni sustav – 15)
rezultat = 0000 0000 0000 0111 (dekadski brojevni sustav – 7)

82
#include <stdio.h>

void main()
{
unsigned n = 0x6db7; // dekadski brojevni sustav - 28087
unsigned maska = 0xF; // dekadski brojevni sustav – 15

// korištenje znaka '#' uzrokuje pojavu znakova '0x' ispred keksadecimalnog broja
printf("Vrijednost od n (n = %#x), maskirana sa %#x, je: %#x\n", n, maska, n & maska);

getchar();
}

83
ZADACI

Zadatak 9.1. Napišite program u kojem korisnik unosi neki cijeli broj, a program ispisuje njegov
binarni ekvivalent.

Rješenje:

#include <stdio.h>

void main()
{
int x, i, n, b;

printf ("Unesite jedan cijeli broj: ");


scanf ("%d", &x);

// sizeof(int) vraća broj bajtova koje zauzima int


// 8 * sizeof(int) vraća broj bitova koje zauzima int
n = 8 * sizeof(x);

printf ("Binarni kod je: ");

for (i = n-1; i >= 0; i--) // od MSB do LSB (od 31. do 0. bita)


{
b = (x & (01 << i)) != 0;
printf ("%d", b);
}

printf("\n");

getchar();
getchar();
}

Pretpostavimo da korisnik unese broj 2 (binarno 00000000 00000000 00000000 00000010).


Promotrimo što točno radi linija koda:

b = (x & (01 << i)) != 0;

U prvom prolazu for petlje, i = 31.

Dakle: b = (00000000 00000000 00000000 00000010 & (01 << 31)) != 0;

Kada se broj 01 pomakne za 31 mjesto ulijevo, ostaje samo 00.

Dakle: b = (00000000 00000000 00000000 00000010 & (00)) != 0;

84
Ako je bilo koji od operanada jednak nuli, rezultat logičke operacije AND je također jednak nuli:
00000000 00000000 00000000 00000010 & 00 = 0.

Dakle: b = (0) != 0;

0 != 0 nije točno, pa je čitav izraz jednak logičkoj nuli. MSB bit ima vrijednost nula.

Napomena: != ima veći prioritet od =. Zato se u izrazu "b = (0) != 0;" prvo izvrši usporedba (0) != 0,
pa se tek onda rezultat usporedbe dodijeli varijabli b.

U predzadnjem prolazu for petlje, i = 1.

Dakle: b = (00000000 00000000 00000000 00000010 & (01 << 1)) != 0;

Kada se broj 01 pomakne za 1 mjesto ulijevo, ostane 10.

Dakle: b = (00000000 00000000 00000000 00000010 & (10)) != 0;

Budući da je izraz (00000000 00000000 00000000 00000010 & (10)) != 0 istinit, bit sa težinskom
vrijednošću jedan jednak je jedinici.

Zadatak 9.2. Napišite program u kojemu su definirana dva cjelobrojna niza. Elementi nizova mogu
biti samo binarne znamenke, tako da čitavi niz zapravo predstavlja neki binarni broj. Pokažite
djelovanje AND, OR i XOR operatora nad članovima tih nizova.

Rješenje:

#include <stdio.h>

void main()
{
int a[4] = {1,1,0,1}; // 13
int b[4] = {1,0,1,0}; // 10
int rezultat[4];
int i;

// AND
for (i = 0; i < 4; i++)
rezultat[i] = a[i] & b[i];

// ispisujemo rezultat logickog AND


printf("Rezultat AND operacije: ");
for (i = 0; i < 4; i++)
printf("%d", rezultat[i]);

// OR

85
for (i = 0; i < 4; i++)
rezultat[i] = a[i] | b[i];

// ispisujemo rezultat logickog OR


printf("\nRezultat OR operacije: ");
for (i = 0; i < 4; i++)
printf("%d", rezultat[i]);

// XOR
for (i = 0; i < 4; i++)
rezultat[i] = a[i] ^ b[i];

// ispisujemo rezultat logickog XOR


printf("\nRezultat XOR operacije: ");
for (i = 0; i < 4; i++)
printf("%d", rezultat[i]);

getchar();
getchar();
}

Zadatak 9.3. Napišite program i definirajte neki cijeli broj u heksadecimalnom obliku. Korisnik
unosi redni broj bita čiju vrijednost želi saznati, i program vraća nulu ili jedinicu, ovisno o tome koji
se bit nalazi na mjestu kojeg je specificirao korisnik.

Rješenje:

#include <stdio.h>

void main ()
{
int x = 0x2; // dekadski isto 2
int n;

printf("Unesite oznaku bita ciju vrijednost zelite procitati: \n");


scanf ("%d", &n);

if ((n < 0) || (n >= 32))


printf("Odabrali ste nepostojeci bit!!!\n");
else
printf("Bit na %d. mjestu ima vrijednost: %d \n", n, ((x & (01 << n)) != 0));

getchar();
getchar();
}

86
DODATNI ZADACI

Zadatak 9.4. Napišite program u kojem korisnik unosi neki cijeli broj, a program ispisuje njegov
binarni ekvivalent. Binarni ekvivalent se sprema u niz binarni_ekvivalent[32]. Postavite sve bitove
binarnog ekvivalenta na nulu (koristite XOR operaciju).

DOMAĆI RAD

Zadatak 9.5. Napišite program koji za predefinirani cijeli broj ispisuje težinsku vrijednost svakog
bita koji je jednak jedinici. Na primjer, za cijeli broj 11 (binarno 1011), program bi trebao ispisati 1,
2 i 8.

1 0 1 1
2 1 0
23=8 2 =4 2 =2 2 =1

87
DODATAK

Pretvaranje iz dekadskog brojevnog sustava u binarni brojevni sustav

15610=? 2

Prvi način (broj u dekadskom brojevnom sustavu se dijeli sa 2, a ostatak dijeljenja se zapisuje u
poseban stupac):

156 : 2 = 78 0
78 : 2 = 39 0
39 : 2 = 19 1
19 : 2 = 9 1
9:2=4 1
4:2=2 0
2:2=1 0
1:2=0 1

Rješenje se dobije tako da se ostaci dijeljenja sa 2 napišu obrnutim redoslijedom. Rješenje bi bilo:
1001 1100.

Drugi način (promatraju se potencije broja 2):

156 – 128 = 28 1 (128 je najveća potencija broja 2 koja "stane" u broj 156)
28 – 64 = -36 0 (64 je iduća niža potencija broja 2, ali 64 ne "stane" u 28)
28 – 32 = -4 0 (32 je iduća niža potencija broja 2, ali 32 ne "stane" u 28)
28 – 16 = 12 1 (16 je iduća niža potencija broja 2)
12 – 8 = 4 1 (8 je iduća niža potencija broja 2)
4–4=0 1 (4 je iduća niža potencija broja 2)
0 – 2 = -2 0 (2 je iduća niža potencija broja 2)
0 – 1 = -1 0 (1 je iduća niža potencija broja 2)

Napomena: ako je rezultat oduzimanja negativan, za binarnu znamenku se uzima nula. Ako je
rezultat pozitivan, uzima se jedinica.

Pretvaranje iz binarnog brojevnog sustava u dekadski brojevni sustav

100111002 =?10

MSB LSB
1 0 0 1 1 1 0 0
7 6 5 4 3 2 1
2 =128 2 =64 2 =32 2 =16 2 =8 2 =4 2 =2 2 0=1

1⋅1280⋅640⋅321⋅161⋅81⋅40⋅20⋅1=1281684=156

88
Pretvaranje iz dekadskog brojevnog sustava u oktalni brojevni sustav

15610=? 8

156 najprije podijelimo sa najvećom potencijom broja 8 koja "stane" u broj 156 (a to je 64).

156 : 64 = 2 (ostatak 28) 64=8


2

28 : 8 = 3 (ostatak 4) 8=81
4:1=4 (ostatak 0) 1=8
0

Rezultat: 234.

Pretvaranje iz oktalnog brojevnog sustava u dekadski brojevni sustav

234 8=? 10

2 1 0
2∗8 3∗8 4∗8 =128244=156

Pretvaranje iz dekadskog brojevnog sustava u heksadecimalni brojevni sustav

15610=? 16

156 najprije podijelimo sa najvećom potencijom broja 16 koja "stane" u broj 156 (a to je 16).

156 : 16 = 9 (ostatak 12) 16=16


1

12 : 1 = 12 (C) (ostatak 0) 1=16


0

Rezultat: 9C.

Pretvaranje iz heksadecimalnog brojevnog sustava u dekadski brojevni sustav

9C16=? 10

1 0
9∗16 12∗16 =14412=156

89
VJEŽBA 10

MATLAB

MATLAB (engl. MATrix LABoratory) je aplikacija i programski jezik (sličan C-u) za znanstvena
istraživanja. MATLAB korisniku pruža velik broj funkcija, grupiranih tematski u “toolbox-ove”, te
namijenjenih rješavanju problema vezanih za kontrolu i optimizaciju sustava, kao i za obradu
signala.

Neki od MATLAB-ovih toolbox-ova:


• Partial Differential Equation Toolbox
• Statistics Toolbox
• Neural Network Toolbox
• Aerospace Toolbox
• Image Processing Toolbox
• Fuzzy Logic Toolbox
• ...

Pokretanje MATLAB-a

Na Windows Desktop-u kliknite na Start --> All Programs --> Matlab --> Matlab. Otvoriti će se
osnovni prozor MATLAB-a (Slika 10.1) koji po default-u sadrži naredbeni prozor (engl. Command
Window), prozor povijesti naredbi (engl. Command History), prozora tekućih datoteka (engl.
Current Directory) i prozor sa sadržajem radnog prostora (engl. Workspace).

Osnovne operacije

MATLAB koristi jednostavnu sintaksu. Naredbe u MATLABu se upisuju u posljednju, aktivnu liniju
naredbenog prozora koja počinje sa oznakom '>>'.

Nardbe (i operacije) koje se upisuju u komandnu liniju izvršavaju se nakon pritiska na <enter>. Na
primjer:

>> (3^2+4*5)/ (9/2-8^3) <enter>

izračunava vrijednost izraza

324⋅5
9 3 .
−8
2

Pretraživanje i preuređivanje prethodno izvršenih izraza radimo sa 'tipkama-strelicama': gore,


dolje, lijevo i desno. Na primjer, prethodni izraz pozivamo tipkom gore.

90
Slika 10.1. Osnovni prozor MATLAB-a

Primijetili ste da se rezultat ispisuje na pod nazivom ans (engl. answer). Ukoliko želimo vrijednosti
dodijeliti ime (ime konstante), ispred izraza napišemo ime i stavljamo znak jednakosti.

Primjer: pozovimo prethodni izraz i dodijelimo ga konstanti k:

>> k = (3^2+4*5)/ (9/2-8^3) <enter>


>> k =
-0.0571

Ukoliko ne želimo konstantu ispisati na ekran, na kraju izraza upisujemo točka-zarez ;.

>> k = (3^2+4*5)/ (9/2-8^3);


>>

Na taj način konstanta k se ne ispisuje na ekranu, ali ostaje definirana u programu dok joj se ne
dodijeli nova vrijednost, odnosno izraz.

91
Matrice i operacije sa matricama

Rješavanje nekih problema (pogotovo onih vezanih za matrice i općenito za matematiku), puno je
jednostavnije i brže u Matlabu nego u nekim drugom programskim jezicima (npr. C-u).
Matrica je dvodimenzionalno polje brojeva, i usput osnovni podatak za rad u MATLAB-u. Matrica
dimenzija [1,1] naziva se skalar, a matrica koja sadrži samo jedan stupac ili samo jedan redak
naziva se vektor.

Matrica se definira navođenjem njezinih redaka. Elementi redaka se razdvajaju zarezom ili praznim
mjestom. Dva retka se razdvajaju simbolom ; na kraju retka.

Primjer definiranja matrice u MATLAB-u:

A = [16 3 2 13; 5 10 11 8; 9 6 7 12; 4 15 14 1];

ili

A = [16, 3, 2, 13; 5, 10, 11, 8; 9, 6, 7, 12; 4, 15, 14, 1];

Ovime smo definirali matricu:

 
16 3 2 13
5 10 11 8
A=
9 6 7 12
4 15 14 1

Napomena: matrice je uobičajeno označavati velikim slovima.

Matrične operacije i funkcije

Nad matricama se primjenjuju matematičke operacije kao što su zbrajanje (oznaka je +),
oduzimanje (-), množenje (*) i dijeljenje (množenje jedne matrice sa inverznom drugom matricom)
(/). Napomena: prilikom množenja ili dijeljenja matrica treba voditi računa o uzajamnoj
usklađenosti veličine matrica.

MATLAB poznaje standardne matrične operacije i funkcije kao što su transponiranje, potenciranje,
nalaženje inverzne matrice i određivanje determinante. Na primjer, slijedeće naredbe

>> B'
>> B^2
>> inv(B)
>> det(B)

određuju odgovarajuću transponiranu matricu B, kvadrat matrice B, inverznu matricu B (inverzna


matrica se može odrediti i sa B^(-1)) i determinantu matrice B, respektivno.

92
Posebne operacije sa matricama

Ako su matrice A i B istih dimenzija, i ukoliko je ⊕ binarna operacija, tada je . ⊕ posebna operacija
koja se može primijeniti na matrice.

Karakteristične posebne operacije (element sa elementom) su: množenje redaka (.*), dijeljenje
redaka (./) i potenciranje redaka (.^).

Primjer:

>> A = [2 4 6; 1 2 3];
>> B = [1 1 1; 2 2 2];
>> A.*B % A * B bi generiralo grešku

U gornjem smo primjeru definirali matrice A i B, te izračunali njihov umnožak.

Izdvajanje stupaca (redaka) matrice

Indeksiranje matrica, odnosno izdvajanje vektora redka ili vektora stupca ili pojedinih elemenata
vrši se korištenjem simbola dvotočke ':'. Prvi indeks se odnosi na redak, a drugi indeks na stupac.

Primjer:

>> D = [9 8 7; 6 5 4; 3 2 1]; % definiramo matricu D


>> e = D(:, 3) % izdvajamo treći stupac matrice D
>> f = D(1, :) % izdvajamo prvi redak matrice D
>> g = D(1:2, 2) % izdvajamo prva dva elementa drugog stupca
>> h = D(3, 2:3) % izdvajamo drugi i treći element trećeg retka

Napomene

MATLAB razlikuje velika i mala slova.

Bilo koja linija napisana iza znaka '%' predstavlja komentar.

Informacije o pojedinim naredbama se mogu dobiti primjenom naredbe help. Na primjer:

>> help zeros

prikazuje opis naredbe zeros.

Varijable se iz MATLAB-ove memorije brišu naredbama clear ime_varijable ili clear all. Naredbom
clc se isprazni komandni ekran.

93
Vektori

Matrica sa jednim retkom ili stupcem predstavlja vektor. Na primjer:

>> v1 = [1 2 3 4]; % matrica sa jednim retkom


>> v2 = [1; 2; 3; 4]; % matrica sa jednim stupcem

MATLAB omogućava definiranje vektora čiji elementi imaju konstantan međusoban razmak. Na
primjer, definirajmo vektor na intervalu [0, 100] sa korakom 10.

>> x = 0 : 10 : 100;

Dakle, rezultat je [0 10 20 30 40 50 60 70 80 90 100] i u konkretnom primjeru, 0 je početni element


vektora, 10 je srednji element koji predstavlja korak između dva elementa vektora, dok je 100
zadnji element. Pa možemo zaključiti da je sintaksa ovakvog definiranja vektora:

ime_vektora = prvi_element : korak : zadnji_element;

Ako se korak eksplicitno ne navede, po defaultu iznosi jedan.

Polinomi

Polinomi se definiraju preko vektora koeficijenata polinoma, od koeficijenta ispred najvišeg stupnja
polinoma do slobodnog elementa. Na primjer, polinom 2x3 − x 23 se u MATLAB-u definira na
slijedeći način:

>> a = [2 -1 0 3]

Napomena: primijetite da u zadanom polinomu koeficijent uz x ima iznos 0.

Korijeni polinoma se mogu odrediti primjenom naredbe roots. Na primjer:

>> roots([1 5 6])

pronalazi korijene polinoma x 2 5x6.

Inverzna naredba roots naredbe je poly. Naime, ukoliko znamo korijene polinoma, primjenom
naredbe poly, dobivamo koeficijente polinoma. Na primjer:

>> poly([-2 -3])

čime iz zadanih korijena x1 = -2 i x2 = -3 dobivamo polinom x 2 5x6.

94
Rješavanje sustava linearnih jednadžbi

Rješavanje sustava jednadžbi obavlja se preko operacija sa matricama.

Pretpostavimo da tražimo rješenje Ax=B sustava.

Ax=B se može zapisati i na slijedeći način:

Rješenje sustava Ax=B bilo bi jednako x =A−1 B .

Na primjer, rješenje sustava jednadžbi x + 3y = 7 i 2x – 5y = 8 bilo bi:

>> A = [1 3; 2 -5]
>> B = [7; -8]
>> X = inv(A)*B

Crtanje funkcija

MATLAB posjeduje različite funkcije za grafički prikaz dobivenih rezultata. Najčešće korištena
naredba za grafički prikaz funkcija je plot, sa sintaksom:

plot(x, y, 'opcije')

Na primjer:

>> x = -1 : 0.01 : 1;
>> plot(x, exp(x)+1)

crta funkciju e x 1 za −1 ≤ x ≤ 1 u posebnom prozoru. Korak u definiranju vektora elemenata je u


ovom konkretnom slučaju 0.01, i s ovim određujemo finoću i preciznost prikaza funkcije.

Alternative MATLAB-u

Besplatne alternative MATLAB-u su Octave (http://sourceforge.net/projects/octave/files/) i Scilab


(http://www.scilab.org/products/scilab/download).

95
ZADACI

Zadatak 10.1. Definirajte matrice:

     
−2 3 1 2 4 8 1 1 1
M= 1 5 6 N = −1 2 9 O= 2 2 2
7 4 1 2 3 2 3 3 3

Izdvojite:
a) posljednji stupac matrice M,
b) prva dva elementa drugog reda matrice N
c) drugi i treći element prvog stupca matrice O
d) drugi redak matrice M
e) prva dva elementa trećeg stupca zbroja matrica M + N

Rješenje:

>> M = [-2 3 1; 1 5 6; 7 4 1];


>> N = [2 4 8; -1 2 9; 2 3 2];
>> O = [1 1 1; 2 2 2; 3 3 3];

>> a = M(:, 3);


>> b = N(2, 1:2);
>> c = O(2:3, 1);
>> d = M(2, :);
>> E = M + N;
>> e = E(1:2, 3);

Zadatak 10.2. Riješite sustav jednadžbi:

1. x 2y=3
2. −x y4z=7
3. 2x3y−z=5

Rješenje:

A = [1 2 0; -1 1 4; 2 3 -1];
B = [3; 7; 5];
x = inv(A) * B

ISPIS PROGRAMA:
15
-6
7

96
Zadatak 10.3. Riješite sustav jednadžbi:

4. −x 1x 3=1
5. x 1− x 2=−1
6. x 2 x 3=1
7. x 1 x 4=3

Rješenje:

A = [-1 0 1 0; 1 -1 0 0; 0 1 1 0; 1 0 0 1];
B = [1; -1; 1; 3];
x = inv(A) * B

ISPIS PROGRAMA:
-0.50000
0.50000
0.50000
3.50000

Zadatak 10.4. Pronađite korijene polinoma y=−3x 44x3 −x3.

Rješenje:

y = [-3 4 0 -1 3];
roots(y)

ISPIS PROGRAMA (Octave):


1.48680 + 0.00000i
0.34243 + 0.82767i
0.34243 – 0.82767i
-0.83832 + 0.00000i

Zadatak 10.5. Na istoj slici iscrtati grafove funkcija y 1=x 32x 2−4 i y 2=−5x 23, na intervalu (-
5,5), sa korakom 0.01. Neka graf funkcije y 1 bude iscrtan žutom bojom, a graf funkcije y 2 zelenom
bojom.

Rješenje:

x = -5 : 0.01 : 5;
y1 = x.^3 + 2.*x – 4;
y2 = -5.*x.^2 + 3;
plot(x, y1, 'y', x, y2, 'g')

97
ex
Zadatak 10.6. Nacrtajte graf funkcije y= 1 , na intervalu (-5,5), sa korakom 0.02.
1 x
1e

Rješenje:

x = -5 : 0.02 : 5;
y = exp(x)./(1 + exp(1./(1 + x)));
plot(y)

ex
Zadatak 10.7. Nacrtajte graf funkcije y= 1 , na intervalu (-5,5), sa korakom 0.5. Neka graf
1e 1 x
bude zelene boje, i neka sve točke na grafu budu označeve kružićima. Napomena: dodatne opcije
za crtanje grafa funkcije objašnjene su u dodatku.

Rješenje:

x = -5 : 0.5 : 5;
y = exp(x)./(1 + exp(1./(1 + x)));
plot(y, '-og')

98
DOMAĆI RAD

Zadatak 10.8. Pronađite korijene polinoma y=7x 4 4x 2−6x3.

sinx cosx
Zadatak 10.9. Na istoj slici iscrtati grafove funkcija y 1= i y 2= , na intervalu (0,10), sa
x x
korakom 0.01. Neka graf funkcije y 1 bude iscrtan žutom bojom, a graf funkcije y 2 zelenom bojom.

99
DODATAK VJEŽBI 10

Grafovi

U MATLAB-u se može specificirati tip linije kojom se iscrtava graf, te se mogu prikazati oznake za
željene točke na grafu.

Tablica 10.1. Tipovi linija u MATLAB-u [7]

Oznaka u MATLAB-u Tip linije


'-' solid line (default)
'--' dashed line
':' dotted line
'-.' dash-dot line
'none' no line

Tablica 10.2. Oznake točaka na grafovima u MATLAB-u [7]

Oznaka u MATLAB-u Tip točke


'+' plus sign
'o' circle
'*' asterisk
'.' point
'x' cross
'square' ili 's' square
'diamond' ili 'd' diamond
'^' upward-pointing triangle
'v' downward-pointing triangle
'>' right-pointing triangle
'<' left-pointing triangle
'pentagram' ili 'p' five-pointed star (pentagram)
'hexagram' ili 'h''' six-pointed star (hexagram)
'none' no marker (default)

100
Boje grafova

U MATLAB-u postoji osam predefiniranih boja za grafove. Sve su prikazane u tablici 10.3.

Tablica 10.3. Predefinirane boje grafova u MATLAB-u [7]

Oznaka u MATLAB-u Boja


r red
g green
b blue
c cyan
m magenta
y yellow
k black
w white

Na primjer, naredbom plot(x, y, '-.or') bi se iscrtao graf sa linijom tipa '-.' (engl. dash-dot line), a
točke na grafu bi bile označeve kružićima ('o'). I graf i kružići bi bili crvene boje ('r') [7].

101
POPIS OZNAKA I KRATICA

ASCII – American Standard Code for Information Interchange


BCPL - Basic Combined Programming Language
CR – Carriage Return
DEC - Digital Equipment Corporation
EOF - End-of-File
LF – Line Feed
LSB – Least Significant Bit
MATLAB – MATrix LABoratory
MIT – Massachusetts Institute of Technology
MSB – Most Significant Bit
PDP - Programmed Data Processor

102
LITERATURA

[1] "Dennis Ritchie", http://en.wikipedia.org/wiki/Dennis_Ritchie, web stranica posjećena 15. rujna


2010.
[2] Lavicki-Šatović, N.; Vrba, Ž.: "Library funkcije za slučajne brojeve", 2004,
http://zvrba.net/writings/C-srand.pdf, web stranica posjećena 18. rujna 2010.
[3] Vulin, R.: "Zbirka riješenih zadataka iz C-a", Školska knjiga, Zagreb, 2003.
[4] "Matrica (matematika)", http://hr.wikipedia.org/wiki/Matrica_(matematika), web stranica
posjećena 05. listopada 2010.
[5] Manger, R.; Marušić, M.: "Strukture podataka i algoritmi", skripta, treće izdanje, Prirodoslovno
matematički fakultet, Sveučilište u Zagrebu, Zagreb, 2007,
http://web.math.hr/nastava/spa/files/skripta.pdf, web stranica posjećena 20. rujna 2010.
[6] Gottfried, B.: "Schaum's Outline Series: Programming with C", Second Edition, McGraw-Hill,
1996.
[7] "LineSpec (Line Specification)", http://www.mathworks.com/help/techdoc/ref/linespec.html,
web stranica posjećena 23. rujna 2010.

103
Петар Спалевић
Бранимир Јакшић
Стефан Панић

ЗБИРКА РЕШЕНИХ ЗАДАТАКA

ИЗ ПРОГРАМСКОГ ЈЕЗИКА C
I ДЕО

Косовска Митровица, 2011.


Збирка решених задатака из програмског језика С, I део
Прво издање

Аутори: Петар Спалевић, ванредни професор Факултета техничких наука у Косовској Митровици
Бранимир Јакшић, асистент на Факултету техничких наука у Косовској Митровици
Стефан Панић, доцент Природно-математичког факултета у Косовској Митровици

Рецензенти: Градимир Миловановић, редовни професор Мегатренд универзитета и


члан Српске академије наука и уметности
Братислав Мирић, редовни професор Државног универзитета у Новом Пазару

Технички уредници: Аутори

Издавач:

Штампа:

Тираж: 100 примерака

НАПОМЕНА: Фотокопирање или умножавање на било који начин или поновно објављивање
ове књиге – у целини или деловима – није дозвољено без претходне сагласности и писменог одобрења
издавача.
Предговор
Ова збирка задатака је помоћни уџбеник за учење програмирања на језику С. Задаци прате
градиво које одговара предмету Програмирање 2 којег слушају студенти у оквиру студијског
програма Електротехничко и рачунарско инжењерство на Факултету техничких наука у Косовској
Митровици. Збирку могу користити и студенти других факултета који у оквиру својих предмета
изучавају језик С, као и ученици средњих школа.
Збирка је тако конципирана да је могу користити и почетници у програмирању. Задаци су у
свакој области изложени по тежини, од најлакших ка тежим. Кроз задатке, поред елемената самог
језика, приказане су најчешће коришћени поступци у програмирању: претраживање и уређивање
низова, обрада знаковних података, рад са показивачима и структурама, као и рад са датотекама.
Решења свих задатака су потпуна у смислу да се дати програмски кодови могу ивршавати на
рачунари. Сви задаци су урађени, проверени и тестирани коришћењем програма DEV C/C++. Поред
самих програмских кодова дати су изгледи на екрану након тестирања програма. За сложене задатке
дата су објашњења у виду текста или пропратног кометара у програмском коду.
Збирка је подељена у два дела. Први део обухвата основне елементе и конструкције језика С:
просте линијске структуре, грањање у програму, петље, скокови, улаз-излаз, функције, низови и
матрице.
Други део је наставак градива из претходног дела, који обухвата и нешто сложеније задатке:
стрингови, показивачи (обухватајући и рад са показивачима кроз све елементе језика из првог дела
збирке), динамичка зона меморије, структуре и рад са датотекама.

У Косовској Митровици, Аутори


септембар, 2011.
САДРЖАЈ

1 ОСНОВНЕ КОНСТРУКЦИЈЕ ПРОГРАМСКОГ ЈЕЗИКА С ....... 1


1.1 Типови података, декларације и константе ............................................. 1
1.2 Оператори ................................................................................................... 4
2 ПРОГРАМИ СА ПРОСТОМ ЛИНИЈСКОМ СТРУКТУРОМ ..... 8
2.1 Улазна и излазна конверзија ..................................................................... 8
2.1 Креирање програма са простом линијском структуром ........................ 15
3 ГРАЊАЊЕ У ПРОГРАМУ ....................................................................... 27
4 FOR ПЕТЉА .................................................................................................. 40
5 WHILE ПЕТЉА ............................................................................................ 61
6 DO...WHILE ПЕТЉА .................................................................................. 73
7 СКОКОВИ ....................................................................................................... 79
7.1 BREAK ........................................................................................................ 79
7.2 CONTINUE ................................................................................................. 83
7.3 GOTO .......................................................................................................... 85
7.4 SWITCH ... CASE ....................................................................................... 88
8 КАРАКТЕРИ – ЗНАКОВНИ УЛАЗ И ИЗЛАЗ .................................... 94
9 ФУНКЦИЈЕ .................................................................................................... 105
9.1 Рекурзивне функције ................................................................................. 123
10 НИЗОВИ ........................................................................................................... 129
10.1 Основне конструкције програма са низовима ...................................... 129
10.2 Операције са низовима и разврставање елемената ............................... 132
10.3 Низови и функције ................................................................................... 139
10.4 Претраживање низова ............................................................................. 145
10.5 Уређивање и сортирање низова .............................................................. 151
11 МАТРИЦЕ .................................... .................................................................. 160
ЛИТЕРАТУРА ............................................................................................... 178
Збирка решених задатака из Програмског језика С – I део

1 ОСНОВНЕ КОНСТРУКЦИЈЕ
ПРОГРАМСКОГ ЈЕЗИКА С

1.1 Типови података, декларације и константе

Табела 1.1: Знакови који се користе у програмском језику С


велика и мала слова енглеске абецеде A – Z, a – z
(Ц прави разлику између великих и малих слова)
цифре: 0 1 2 3 4 5 6 7 8 9
бели знакови: размак (space), хоризонтални табулатор, вертикални табулатор, нови ред
специјални знакови:
+ - * / = % & # ! ? ^ " ' ~ \
| < > ( ) [ ] { } : ; . , _

Табела 1.2: Неки знакови који имају строго дефинисано значење


Знак Значење
/* Почетак коментара (коментар се мора завршити са знаком */)
*/ Крај коментара
# Макро улази (декларација константи, команде превођења, ...)
; Крај програмске линије
, Набрајање
\ Специјални знак за контролу излаза
0х Следи приказ хексадецималног броја
'' Почетак или крај променљиве типа string
' Почетак или крај променљиве типа char

Табела 1.3: Резервисане речи у програмском језику С


auto break case char continue const default
do double else enum extern float for
goto if int long register return short
sizeof static struct switch signed typedef union
unsigned void volatile while

1
Збирка решених задатака из Програмског језика С – I део

Табела 1.4: Типови података


ознака значење
int целобројни податак
char знаковни податак
float реални податак једноструке тачности
double реални податак двоструке тачности
short int "кратки" целобројни податак; у меморији заузума мање
меморијског простора од податка типа int па може приказати
мањи распон целих бројева.
long int "дуги" целобројни податак; у меморији заузума више
меморијског простора од податка типа int па може приказати
већи и распон целих бројева.
long double реални податак вишеструке тачности
unsigned int
unsigned short int неозначене (само позитивне) вредности целобројних података
unsigned long int
void тип податка који не садржи вредност

Декларација променљивих: tip_podatka ime_promenljive;


нпр: int a;

Иницијализација променљивих: ime_promenljive = vrednost;


нпр: a=5;

Истовремена декларација и иницијализација променљивих:


tip_podatka ime_promenljive = vrednost;
нпр: int a=5;

Дефинисање нових типова података: typedef tip_podatka ime_tipa;


typedef float duzina;

Декларација константи:
const tip_podatka ime_promenljive = vrednost_konstante;
нпр: const double e=2.71828182845905;

Дефинисање симболичке константе: #define IME_KONSTANTE vrednost_konstante


нпр: #define MAX 50

Декларација наброjaних константи:


enum ime_nabrajanja { IME_KONSTANTE = vrednost,
IME_KONSTANTE = vrednost, …}
нпр: enum podaci {MIN=10, MAX=100, POZELJNO=30}

1.1. Koји су од следећих коментара коректно записани:


a) /*Ovo je programski jezik C.*/
б) /*Prva oblast /*Tipovi podataka i operatori*/ */
в) /*Prva oblast
Tipovi podataka i operatori*/
г) */Programski jezik C.*/

2
Збирка решених задатака из Програмског језика С – I део

a) Коректно.
б) Некоректно, не могу да се коментари гнезде један унутар другог.
в) Коректно.
г) Некоректно, коментар треба започети са /* и завршити са */.

1.2. Koји су од следећих идентификатора правилно написани:


а) "x" г) broj е) float
б) Ime_i_prezime д) a21 ж) r
в) a+b ђ) 3n

а) Неправилно, недозвољени знак ".


б) Правилно.
в) Неправилно, оператор није дозвољен.
г) Прваилно.
д) Правилно.
ђ) Неправилно, први знак не сме да буде цифра.
е) Неправилно, резервисане речи нису дозвољене.
ж) Правилно.

1.3. Које су од следећих целобројних константи коректно записане:


а) 543 г) 650L е) 03928
б) 0123 д) 0xFFFFU ж) 3ab22
в) 0ХF7А5 ђ) 152UL з) 1.555

а) Коректно, децимална константа типа int.


б) Коректно, октална константа почиње са 0, типа int.
в) Коректно, хексадецимална константа почиње са 0Х или 0х, типа int.
г) Коректно, децимална константа типа long int, пошто се завршава са L (или l).
д) Коректно, хексадецимална константа типа unsigned int, пошто се завршава са U (или u).
ђ) Коректно, децимална константа типа unsigned long int,
пошто се завршава са UL (или ul).
е) Некоректно, 8 и 9 нису окталне цифре.
ж) Некоректно, a и b нису децималне цифре.
з) Тачка означава реалну константу.

1.4. Које су од следећих реалних константи коректно записане:


а) 1.24 г) 211.25F е) 1ab.34
б) .065 д) 1.65L ж) 423.
в) 1.34Е2 ђ) 5,45 з) 2.E11

а) Коректно, реална константа типа double.


б) Коректно, реална константа типа double.
в) Коректно, реална константа типа double.
г) Коректно, реална константа типа float.
д) Коректно, реална константа типа long double.
ђ) Некоректно, не користи се децимални зарез.
е) Некоректно, слова нису дозвољена.

3
Збирка решених задатака из Програмског језика С – I део

ж) Коректно, реална константа типа double.


з) Коректно, реална константа типа double.

1.5. Које су од следећих декларација и иницијализација коректно записане:


а) int a, b, c; г) const double pi 3.14; ж) typedef float duzina;
б) int a=7; д) #define MAX =10 duzina a=5.2;
в) char slovo=’d’; ђ) const int a=5;

Kоректно а), б), в), ђ), ж)

1.6. Декларисати константе за следеће вредности:


а) број дана у недељи; в) сала са 200 места;
б) особа тешка 80.5 kg; г) број дана у сваком месецу за преступну годину.

а) const int nedelja=7;


б) const double tezina=80.5;
в) const int sala=200;
г) enum meseci {ЈАN=31, FEB=29, MAR=31, APR=30, MAJ=31, JUN=30,
JUL=31, AVG=31, SEP=30, OKT=31, NOV=30, DEC=31};

1.2 Оператори

Табела 1.5: Аритметички оператори и оператори доделе


оператор пример Значење
= х=у Додела
+ х+у Сабирање
- х-у Одузимање
* х*у Множење
/ х/у дељење (уколико се примени над целим бројевима има функцију
целобројног дељења)
% х%у остатак при целобројном дељењу
++ ++х пре инкрементирање (х=х+1), повећа вредност променљиве х за 1 па се
таква променљива користи
++ х++ пост инкрементирање (х=х+1), упореби се променљива х, па се тек онда
увећа за 1
-- --х пре декрементирање (х=х-1), смањи вредност променљиве х за 1 па се
таква променљива користи
-- х-- пост декрементирање (х=х-1), упореби се променљива х, па се тек онда
смањи за 1
+= х+=у (х = х + у) додаје вредност операнда са десне стране оператора вредности
операнда са леве стране и то постаје нова вредност левог операнда
-= х-=у (х = х - у) одузима вредност операнда са десне стране оператора од
вредности операнда са леве стране и то постаје нова вредност левог
операнда

4
Збирка решених задатака из Програмског језика С – I део

*= х*=у (х = х * у) вредност операнда са десне стране оператора се множи са


вредношћу операнда са леве стране и то постаје нова вредност левог
операнда
/= х/=у (х = х / у) вредност операнда са леве стране оператора се дели са
вредношћу операнда са десне стране и то постаје нова вредност левог
операнда
%= х%=у (х = х % у) вредност операнда са леве стране оператора се дели са
вредношћу операнда са десне стране и остатак тог дељења постаје нова
вредност левог операнда

Taбела 1.6: Релацијски оператори Taбела 1.7: Логички оператори


оператор пример значење оператор пример значење
> х>у веће && х&&у логичко И (AND)
< х<у мање || x||у логичко ИЛИ (OR)
>= х>=у веће или једнако ! !х логичка негација (NOT)
<= х<=у мање или једнако
== х==у једнако
!= х!=у различито

Taбела 1.8: Оператори над битовима


оператор пример значење
<< х<<у померање у лево, померање х за у битова у лево
>> х>>у померање у десно, померање х за у битова у десно
& х&у логичко И за низ битова
| х|у логичко ИЛИ за низ битова
^ х^у искључиво логичко ИЛИ за низ битова
~ ~х комплемент
<<= х<<=у х=х<<у
>>= х>>=у х=х>>у
&= х&=у извршава се логичко И над одговарајућим битовима операнада са леве
и десне стране оператора и резултат се додељује левом операнду
|= х|=у извршава се логичко ИЛИ над одговарајућим битовима операнада са
леве и десне стране оператора и резултат се додељује левом операнду

Taбела 1.9: Оператори специјалне намене


оператор значење
[] индексирање
() позив функције
. приступ пољу (елементу) структуре
-> приступ пољу (елементу) структуре помоћу показивача
* (унарни) приступ податку помоћу показивача (индексно
адресирање)
& (унарни) адреса податка
?: условни оператор, (х<у)?х:у
, ланчање израза
sizeof величина променљиве, sizeof(х)
величина типа, sizeof(int)
(tip) сast оператор, (double) а

5
Збирка решених задатака из Програмског језика С – I део

1.7. Који је резултат после извршавања следећих аритметичких операција:


а) 2+3*4 г) 9%3 е) 7*3/4
б) 7/4 д) 7/4*3 ж) 7.*3./4.
в) 7%4 ђ) 7./4.*3.

а) 24 г) 0 е) 5
б) 1 д) 3 ж) 5.25
в) 3 ђ) 5.25

1.8. Ако је а=5, колике ће бити вредности променљивих а и b након израчунавања израза:
а) b=++a б) b=a++ в) b=--a г) b=a--

а) a=6, b=6 б) a=6, b=5 в) a=4, b=4 г) a=4, b=5

1.9. Написати следеће изразе у проширеном облику:


а) a%=3; б) a*=10+b; в) a+=++b+20;

а) a=a%3; б) a=a*10+b; в) a=a+b+1+20;

1.10. Приказати процес конверзије типа у следећим изразима:


а) 3+4. б) 5/4*3. в) 3.*5/4

а) 3+4. → 3.+4. → 7.
б) 5/4*3. → (5/4)*3. → 1*3. → 1.*3. → 3.
в) 3.*5/4 → (3.*5)/4 → (3.*5.)/4 → 15./4 → 15./4. → 3.75

1.11. Коју вредност ће имати променљива y после извршавања следећег блока наредби:
а) int y; б) float y; в) float y;
float x=3.14; y=10/4; y=(float)10/4;
y=x;

а) 3 б) 2 в) 2.5

1.12. Која вредност се добија после извршавања следећих операција:


а) 5>7 в) 8==13>5 д) а<b<5
б) 10<=20 г) 14>5<3

а) 5>7 → 0
б) 10<=20 → 1
в) 8==13>5 → 8==(13>5) → 8==1 → 0
г) 14>5<3 → (14>5)<3 → 1<3 → 1
д) а<b<5 → (а<b)<5 → (0 ili 1)<5 → 1

6
Збирка решених задатака из Програмског језика С – I део

1.13. Написати следеће изразе у програмском језику С:


а) (a AND b)<(c OR d) б) (x OR y)=z в) a≠b

а) (a && b)<(c || d) б) (x || y)==z в) a != b

1.14. Које се вредности добијају након извршавања следећих операција над битовима за случај
када су подаци типа int и имају 16 битова:
а) 0x1234 & 0x5678 г) ! 0x1234 е) 000001 << 5
б) 0x1234 | 0x5678 д) 022222 & 055555 ж) 0х3801 << 4
в) 0x1234 ^ 0x5678 ђ) 022222 && 055555 з) 0xff56 >> 4
г) ~ 0x1234

а) 0x1230 г) 0 е) 000040
б) 0x567с д) 000000 ж) 0х8010 (прекорачење!)
в) 0x444с ђ) 1 з) 0xfff5
г) 0xedcb

7
Збирка решених задатака из Програмског језика С – I део

2 ПРОГРАМИ СА ПРОСТОМ
ЛИНИЈСКОМ СТРУКТУРОМ

2.1 Улазна и излазна конверзија

Табела 2.1: Специјални карактери након backslash црте \


карактер Значење
\n прелазак у нови ред
\t хоризонтални табулатор
\v вертикални табулатор
\b повратак за један карактер уназад
\r прелазак на почетак текућег реда
\f прелазак на нову страницу
\a звучни сигнал
\’ једноструки наводник
\’’ двоструки наводник
\\ коса црта
\? Упитник
\ddd исписује знак са кодом ddd октално
\0xdd исписује знак са кодом dd
хексадецимално
\0 нул знак

Табела 2.2: Конверзије за унос података


знак конверзије тип податка који се учитава
%c један знак (char)
%i децимални, хексадецимални или октални цели број (int),
зависно од облика прочитаног броја према правилима
писања целобројних константи
%d децимални цеo број (int)
%u цео број без предзнака (unsigned int)
%o октални цео број (int)
%x хексадецимални цео број (int)
%hi, %hd, кратак цео број (short int) за одговарајући децимални,
%hu, %ho, %hx хексадецимални или октални цели број

8
Збирка решених задатака из Програмског језика С – I део

%li, %ld, дугачак цео број (long int) за одговарајући децимални,


%lu, %lo, %lx хексадецимални или октални цели број
%e, %f, %g број типа float
%le, %lf, %lg број типа double
%Le, %Lf, %Lg број типа long double
%s Стринг
%p Показивач

Табела 2.3: Конверзије за испис података


знак конверзије тип податка који се исписује
%c један знак (char)
%d, %i децимални цеo број (int)
%u цео број без предзнака (unsigned int)
%o октални цео број без предзнака (unsigned int)
%x, %X хексадецимални цео број без предзнака (unsigned
int)
%hi, %hd, %hu, кратак цео број (short int) за одговарајући
%ho, %hx, %hX децимални, хексадецимални или октални цели број
%li, %ld, %lu, дугачак цео број (long int) за одговарајући
%lo, %lx, %lX децимални, хексадецимални или октални цели број
%e, %f, %g број типа float
%e, %f, %g број типа double
%Le, %Lf, %Lg број типа long double
%s Стринг
%p Показивач

Табела 2.4: Допунски параметри конверзије код исписа података


знак конверзије Значење
%- податак ће да се равна уз леву ивицу поља ширине n знакова, тј. да се
допунски знакови размака додају иза, а не испред података
%+ знак + биће исписан испред позитивног броја
%0 код нумеричких конверзија означава да, у случају равнања уз десну
ивицу, број треба да се допуни нулама уместо знакова размака
% (размак) један размак ће претходити сваком позитивном броју
%# (уз o или x коверзију) осигурава да ће октални или хексадецимални
бројеви бити исписани с водећом 0 или 0х
%# (уз e, f или g конверзију) осигурава да ће децимална тачка бити
исписана и да ће нуле на крајњој десној страни броја бити исписане

2.1. Саставити програм који на екрани исписује текст: Od danas programiramo u jeziku
C.
#include <stdio.h>

main()
{
printf("Od danas programiramo u jeziku C.");
getche();
return 0;
}

9
Збирка решених задатака из Програмског језика С – I део

#include<stdio.h> значи да
укључујемо стандарну улазно-
излазну библиотеку података.

main() је почетак главног програма.


Испис на екрану
{ означава почетак блока података.

printf(); је функција која исписује текст на екрану, тј. конзоли. Текст који се исписује
ставља се под наводницима.

getche(); чека знак са тастатуре, а тек након тога излази из програма. Ово нам користи да
видимо шта исиписује наш програм.

return 0; враћа оперативном систему како је извршавање протекло без проблема. У случају
да се врати вредност 1 ОС зна да је дошло до грешке.

} означава крај блока наредби. Број отворених заграда мора бити једнак броју затворених.

2.2. Шта се исписује након извршавања следећих програмских кодова:


а) б)
#include <stdio.h> #include <stdio.h>

main() main()
{ {
printf("Pozdrav svima!"); printf("\nPozdrav svima!\n");
getche(); getche();
return 0; return 0;
} }

в) г)
#include <stdio.h> #include <stdio.h>

main() main()
{ {
printf("\nPozdrav\nsvima!\n"); printf("\nDobrodosli ");
getche(); printf("u jezik C\n\n");
return 0; getche();
} return 0;
}

д) ђ)
#include <stdio.h> #include <stdio.h>

main() main()
{ {
printf("\nDobrodosli \n\n\tu jezik C\n\n"); printf("\nABCDEF\n");
getche(); printf("A");
return 0; printf("BC");
} printf("DEF");
printf("\nA\nBC\nDEF\n");
getche();
return 0;
}

10
Збирка решених задатака из Програмског језика С – I део

а) б)

Испис на екрану
Испис на екрану

в) г)

Испис на екрану Испис на екрану

д) ђ)

Испис на екрану
Испис на екрану

2.3. Ако су декларисане следеће променљиве


int a, b;
long int i, j;
double x, y;
char f;
написати функцију која учитава вредности са тастатуре за следеће променљиве:
а) a, b, x
б) i, f, j
в) x, y, f
г) i, f

а) scanf("%d %d %lf ", &a, &b, &x);


б) scanf("%ld %c %ld ", &i, &f, &j);
в) scanf("%lf %lf %c ", &x, &y, &f);
г) scanf("%ld %c ", &i, &f);

2.4. Написати наредбу којом се штампају:


а) променљива х у декадном систему;
б) реалне променљиве х и у;
в) промељива х у декадном, окталном и хексадецималном систему;
г) штампа вредност променљиве х типа char.

11
Збирка решених задатака из Програмског језика С – I део

а) printf("%d", x);
б) printf("%f %f", x, y);
в) printf("%d %o %x", x, x, x);
г) printf("%c", x);

2.5. Саставити програм којим се учитавају и приказују један цео и један реалан број.
#include <stdio.h>

main()
{
int ceo;
float realan;
printf("Unesite jedan ceo broj: ");
scanf("%d",&ceo);
printf("Unesite jedan realan broj: ");
scanf("%f",&realan);
printf("\nCeo broj: %d", ceo);
printf("\nRealan broj: %f", realan);
getche();
return 0;
}

Испис на екрану

2.6. Саставити програм којим се реални број унет са тастатуре заокружује на две децимале.
#include <stdio.h>

main()
{
float a;
printf("Unesite jedan realan broj: ");
scanf("%f",&a);
printf("\nBroj zaokruzen na dve decimale je: %.2f", a);
getche();
return 0;
}

Испис на екрану

12
Збирка решених задатака из Програмског језика С – I део

2.7. Саставити програм који омогућује унос целог броја са тастатуре и његов приказ у
децималном, окталном и хексaдецималном облику.
#include <stdio.h>

main()
{
int a;
printf("Unesite ceo broj: ");
scanf("%d",&a);
printf("\nDecimalni oblik: %d", a);
printf("\nOktalni oblik: %o", a);
printf("\nHeksadecimalni oblik: %x", a);
getche(); Испис на екрану
return 0;
}

2.8. Саставити програм који омогућује унос реалног броја са тастатуре и његов приказ у
различитим облицима.
#include <stdio.h>

main()
{
double a;
printf("Unesite jedan realan broj: ");
scanf("%lf",&a);
printf("\nOblik sa decimalnom tackom: %f", a);
printf("\nOblik sa eksponentom: %e", a);
printf("\nU naucnoj notaciji: %g", a);
getche();
return 0;
}

Испис на екрану

2.9. Како изгледа испис на екрану после извршавања следећег програмског кода:
#include <stdio.h>

main()
{
const int a=987;
const double b=1.2345;
printf("%10d\n", a);
printf("%-10d\n\n", a);
printf("%10f\n", b);
printf("%-10f\n", b);
printf("%10.2f\n", b);
printf("%.2f\n", b); Испис на екрану
getche();
return 0;
}
13
Збирка решених задатака из Програмског језика С – I део

2.10. Саставити програм којим се на екрану исписује распоред слова као што је приказано на
слици.
#include <stdio.h>

main()
{
printf("%c\n%2c\n%3c\n%4c\n%5c", 'A', 'B', 'C', 'D', 'E');
getche();
return 0;
}

Испис на екрану

2.11. Саставити програм који омогућује унос три знаковне променљиве са тастатуре, а затим
приказује њихове вредности и њихов одговарајући АSCII код.
#include <stdio.h>

main()
{
char x, y, z;
printf("Unesite tri znaka:\n");
scanf("%c %c %c",&x,&y,&z);
printf("Promenljiva\t ASCII kod\n");
printf("%c\t\t %d\n",x, x);
printf("%c\t\t %d\n",y, y);
printf("%c\t\t %d\n",z, z); Испис на екрану
getche();
return 0;
}

2.12. Саставити програм који омогућује унос једне знаковне променљиве, приказује њену вредност
и њен ASCII код, а затим у следећа три реда приказује променљиве чији је код за један већи од
претходне.
#include <stdio.h>

main()
{
char x;
char ch;
printf("Unesite znak: ");
scanf("%c",&x);
printf("\n\nZnak\tASCII kod\n");
printf("%c \t %d \n", x, x);
printf("%c \t %d \n", x+1, x+1);
printf("%c \t %d \n", x+2, x+2); Испис на екрану
printf("%c \t %d \n", x+3, x+3);
getche();
return 0;
}

14
Збирка решених задатака из Програмског језика С – I део

2.13. Саставити програм који приказује величину у бајтовима следећих типова података: char,
unsigned char, int, unsigned int, long, unsigned long, float, double.

#include <stdio.h>

main()
{
printf("\nTip CHAR = %d B memorije.", sizeof(char));
printf("\nTip UNSIGNED CHAR = %d B memorije.", sizeof(unsigned char));
printf("\nTip INT = %d B memorije.", sizeof(int));
printf("\nTip UNSIGNED INT = %d B memorije.", sizeof(unsigned int));
printf("\nTip LONG = %d B memorije.", sizeof(long));
printf("\nTip UNSIGNED LONG = %d B memorije.", sizeof(unsigned long));
printf("\nTip FLOAT = %d B memorije.", sizeof(float));
printf("\nTip DOUBLE = %d B memorije.", sizeof(double));
getche();
return 0;
}

Испис на екрану

2.1 Креирање програма са простом линијском структуром

Табела 2.5: Неке од функција за рад са целобројним променљивима


дефинисане у библиотеци <stdlib.h>
функција вредност функције
abs(n) Вредност функције типа int, једнака је апсолутној вредности
аргумента n типа int.
labs(n) Вредност функције типа long int, једнака је апсолутној
вредности аргумента n типа long int.
rand() Вредност функције, типа int, је псеудослучајан број са
равномерном расподелом у опсегу [0, RAND_MAX]. RAND_MAX је
симболичка константа чија се вредност мења од рачунара до
рачунара, али која не сме да буде мања од 32767.
srand(n) Ова функција поставља почетне вредности секвенце
псеудослучајних бројева, коју даје функција rand(), на вредност
аргумента n. Подразумевана почетна вредност секвенце је 1. Тип
аргумента n је unsigned int. Функција не даје никакав резултат.
* n означава целобројну променљиву

15
Збирка решених задатака из Програмског језика С – I део

Табела 2.6: Неке од математичких функција дефинисане у библиотеци <math.h>


функција вредност функције
sin(x) sin x
cos(x) cos x
tan(x) tg x
asin(x) arc sin x, x ∈ [-1, 1]
acos(x) arc cos x, x ∈ [-1, 1]
atan(x) arc tg x, у опсегу [-π/2, π/2]
atan2(x,y) arc tg x/y, у опсегу [-π, π]
sinh(x) sh x
cosh(x) ch x
tanh(x) th x
exp(x) ex
log(x) loge x, x>0
log10(x) log10 x, x>0
pow(x,y) xy, ако је х=0, мора да буде у>0; ако је х<0, у мора да буде цео број
sqrt(x) ,
ceil(x) вредност функције је најмања целобројна вредност која није мања од х
floor(x) вредност функције је највећа целобројна вредност која није већа од х
fabs(x) |x|
ldexp(x,n) х·2n
* х ,y и n означавају променљиве

2.14. Саставити програм којим се замењују вредности два унета цела броја.

#include <stdio.h>

main()
{
int a, b, pomocna;
printf("Unesite prvi broj a= ");
scanf("%d", &a);
printf("Unesite drugi broj b= ");
scanf("%d", &b);
printf("\nPre zamene:\ta=%d, b=%d",a,b);
pomocna = a;
Испис на екрану
a = b;
b = pomocna;
printf("\nPosle zamene:\ta=%d, b=%d\n\n", a, b);
getche();
return 0;
}

16
Збирка решених задатака из Програмског језика С – I део

2.15. Саставити програм који учитава два цела броја са тастатуре и исписује њихов збир.

Први начин:
#include <stdio.h>

main()
{
int a, b, c;
printf("Unesite prvi broj: ");
scanf("%d", &a);
printf("Unesite drugi broj: ");
scanf("%d", &b); Испис на екрану
c = a + b;
printf("Zbir unetih brojeva je: %d\n", c);
getche();
return 0;
}

Други начин:
#include <stdio.h>

main()
{
int a, b;
printf("Unesite prvi broj: ");
scanf("%d", &a);
printf("Unesite drugi broj: ");
scanf("%d", &b);
printf("Zbir unetih brojeva je: %d\n", a+b);
getche();
return 0;
}

2.16. Саставити програм који учитава два цела броја и исписује њихов збир, разлику, производ,
целобројни количник, реални количник и остатак при целобројном дељењу.

#include <stdio.h>

main()
{
int a, b;
printf("Unesite prvi broj: ");
scanf("%d", &a);
printf("Unesite drugi broj: ");
scanf("%d", &b);
printf("Zbir a+b je: %d\n", a+b);
printf("Razlika a-b je: %d\n", a-b);
printf("Proizvod a*b je: %d\n", a*b);
printf("Celobrojni kolicnik a/b je: %d\n", a/b);
printf("Realni kolicnik a/b je: %f\n", (float)a/(float)b);
printf("Ostatak pri deljenju a/b je: %d\n", a%b);
getche();
return 0;
}

17
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

2.17. Саставити програм који за унете странице правоугаоника исписује његов обим и површину.

#include <stdio.h>

main()
{
float a, b, o, p;
printf("Stranica a= ");
scanf("%f", &a);
printf("Stranica b= ");
scanf("%f", &b); Испис на екрану
o=2*a+2*b;
p=a*b;
printf("\nObim: %.2f",o);
printf("\nPovrsina: %.2f",p);
getche();
return 0;
}

2.18. Саставити програм који за унети полупречник круга исписује његов обим и површину.

#include <stdio.h>
#define PI 3.14

main()
{
double r;
printf("Unesite poluprecnik kruga: ");
scanf("%lf", &r);
printf("Obim: %.3f\n", 2*r*PI);
printf("Povrsina: %.3f\n", r*r*PI); Испис на екрану
getche();
return 0;
}

18
Збирка решених задатака из Програмског језика С – I део

2.19. Саставити програм који за унети полупречник основице и висине ваљка исписује његову
површину и запремину. (Површина: P=2*r*π*(r+h) , Запремина: V=r2*π*h)

#include <stdio.h>
#define PI 3.14

main()
{
double p,r,h,v;
printf("Unesite visinu valjka: ");
scanf("%lf",&h);
printf("Unesite poluprecnik valjka: ");
scanf("%lf",&r);
p = 2*r*PI*(r+h);
v = r*r*PI*h;
printf("Povrsina valjka: %.4f\n", p);
printf("Zapremina valjka: %.4f\n",v);
getche();
return 0;
}

Испис на екрану

2.20. Саставити програм којим се вредност темепературе унете у Фаренхајтима приказује у


Целзијусима.
#include <stdio.h>

main()
{
int temp;
double fahr, celsius;
printf("\nUnesite T u stepenima F <ceo broj od 0 do 300>: ");
scanf("%d",&temp);
fahr=(double)temp;
celsius=(5.0/9.0)*(fahr-32.0);
printf("\n%d F = %.2f C\n\n", temp, celsius);
getche();
return 0;
}

Испис на екрану

19
Збирка решених задатака из Програмског језика С – I део

2.21. Саставити програм за решавање линеарне једначине AX+B=0, где се коефицијенти А и В


уносе са тастатуре (А≠0).

#include <stdio.h>

main()
{
float X, A, B;
printf("A = ");
scanf("%f", &A);
printf("B = ");
scanf("%f",&B);
Испис на екрану
X=-B/A;
printf("Jednacina ima oblik %.2fX + %.2f = 0\n", A, B);
printf("Resenje X= %.2f\n", X);
getche();
return 0;
}

2.22. Саставити програм за рачунање израза y = x + x 2 + x 3 за унету вредност х.


Први начин: Други начин:

#include <stdio.h> #include <stdio.h>


#include <math.h> #include <math.h>

main() main()
{ {
float x, y; Испис на екрану float x, y;
printf("Unesite x: "); printf("Unesite x: ");
scanf("%f", &x); scanf("%f", &x);
y=sqrt(x+ x*x + x*x*x); y=sqrt(x+ pow(x,2) + pow(x,3));
printf("\y = %.2f", y); printf("\y = %.2f", y);
getche(); getche();
return 0; return 0;
} }

2.23. Саставити програм који исписује вредност модула комплексног броја z = a + bi за унете
вредности а и b. Модул се рачуна по формули z = a 2 + b 2 .

#include <stdio.h>
#include <math.h>

main()
{
float a, b, m;
printf("a= "); scanf("%f",&a);
printf("b= "); scanf("%f",&b);
m=sqrt(a*a+b*b); Испис на екрану
printf("Modul kompleksnog broja %.2f+%.2fi je %.2f ", a, b, m);
getche();
return 0;
}

20
Збирка решених задатака из Програмског језика С – I део

2.24. Саставити програм који за унете реалне и имагинарне делове два комплексна броја исписује
та да два броја у облику z1 = a + bi и z 2 = c + di , а затим рачуна њихов збир и разлику
z1 ± z 2 = (a + c) ± i(b + d ) .

#include <stdio.h>
#include <math.h>

main()
{
float a1,b1,a2,b2,rz,rr,iz,ir;
printf("a1 = "); scanf("%f",&a1);
printf("b1 = "); scanf("%f",&b1);
printf("a2 = "); scanf("%f",&a2);
printf("b2 = "); scanf("%f",&b2);
rz=a1+a2;
rr=a1-a2;
iz=b1+b2;
ir=b1-b2;
printf("\nz1 = %.2f + %.2fi \nz2 = %.2f + %.2fiИспис
\n",a1,b1,a2,b2);
на екрану
printf("\nz1+z2 = %.2f + %.2fi", rz, iz);
printf("\nz1-z2 = %.2f + %.2fi", rr, ir);
getche();
return 0;
}

2.25. Саставити програм за исписивање растојања између две тачке у тродимензионалном


простору на основу унетих координата тачака.
#include <stdio.h>
#include <math.h>

main()
{
double x1, x2, y1, y2, z1, z2, d;
printf("Unesite koordinate prve tacke <x1,y1,z1>: \n");
scanf("%lf %lf %lf",&x1,&y1,&z1);
printf("Unesite koordinate druge tacke <x2,y2,z2>: \n");
scanf("%lf %lf %lf",&x2,&y2,&z2);
d=sqrt(pow(x2-x1,2)+pow(y2-y1,2)+pow(z2-z1,2));
printf("\nRastojanje d = %.2f\n", d);
getche();
return 0;
}

Испис на екрану

21
Збирка решених задатака из Програмског језика С – I део

2.26. Саставити програм за исписивање површине троугла ако су задате координате његових
темена. Површину троугла рачунати помоћу следећих формула:
( xB − xC ) − ( yB − yC ) , ( xC − x A ) − ( yC − y A ) , a = ( xA − xB ) − ( y A − yB )
2 2
a= b=
2 2 2 2

a+b+c P = S ( S − a )( S − b )( S − c )
S= ,
2
#include<stdio.h>
#include <math.h>

main()
{
double xA, yA, xB, yB, xC, yC, a, b, c, s, P;
printf("Koordinate temena trougla\n");
printf("- prvo teme <xA,yA>: "); scanf("%lf%lf",&xA,&yA);
printf("- drugo teme <xB,yB>: "); scanf("%lf%lf",&xB,&yB);
printf("- trece teme <xC,yC>: "); scanf("%lf%lf",&xC,&yC);
a=sqrt(pow(xB-xC,2)+pow(yB-yC,2));
b=sqrt(pow(xC-xA,2)+pow(yC-yA,2));
c=sqrt(pow(xA-xB,2)+pow(yA-yB,2));
s=(a+b+c)/2;
P=sqrt(s*(s-a)*(s-b)*(s-c));
printf("\nPovrsina trougla: %.2f\n", P);
getche();
return 0;
}

Испис на екрану

2.27. Саставити програм који за унети троцифрени број исписује његове цифре и суму цифара.

#include <stdio.h>

main()
{
int xyz, x, y, z;
printf("Unesite trocifreni broj: ");
scanf("%d",&xyz);
x=xyz/100;
y=(xyz/10)%10; Испис на екрану
z=xyz%10;
printf("\nCifre broja %d su %d, %d, %d", xyz,x,y,z);
printf("\nSuma cifara je: %d", x+y+z);
getche();
return 0;
}

22
Збирка решених задатака из Програмског језика С – I део

2.28. Саставити програм који учитава вредност производа у динарима, а затим израчунава и
приказује колико је потребно новчаница од 500 дин., 100 дин. и 1 дин. за плаћање тог производа.

#include<stdio.h>

main()
{
int n, n500, n100, n1;
printf("Unesite cenu proizvoda: ");
scanf("%d",&n);
n500=n/500;
n100=(n%500)/100; Испис на екрану
n1=(n%500)%100;
printf("\nBr.novcanica od 500: %d",n500);
printf("\nBr.novcanica od 100: %d",n100);
printf("\nBr.novcanica od 1: %d",n1);
getche();
return 0;
}

2.29. Саставити програм који за унети временски интервал у секундама и исписује га у облику
дани : часови : минуте : секунде.

#include<stdio.h>

main()
{
long sec, d, h, m, s;
printf("Unesite vreme u sekundama: ");
scanf("%ld",&sec);
s=sec%60;
Испис на екрану
m=sec/60;
h=m/60;
m=m%60;
d=h/24;
h=h%24;
printf("\n(d:h:m:s) %ld:%ld:%ld:%ld\n",d,h,m,s);
getche();
return 0;
}

2.30. Саставити програм који одређује и исписује број степени, минута и секунди у углу који је
задат у радијанима.

#include<stdio.h>
#define PI 3.141592

main()
{
double x;
int stepen,minut,sekund;
printf("Unesite ugao u radijanima: ");
scanf("%lf",&x);
x*=180/PI; /*konverzija u stepene*/
23
Збирка решених задатака из Програмског језика С – I део

stepen=(int)x; /*zaokruzivanje broja stepeni*/


x-=stepen; /*izracunavanje koliko delova stepena je preostalo*/
x*=60; /*izracunavanje broja minuta*/
minut=(int)x; /*zaokruzivanje broja minuta*/
x-=minut; /*koliko delova minuta je ostalo*/
x*=60; /*izracunavanje broja sekundi*/
sekund=(int)x; /*zaokruzivanje broja sekundi*/
printf("\nstepena, minuta, sekundi [%d,%d,%d]\n", stepen, minut, sekund);
getche();
return 0;
}

Испис на екрану

2.31. Шта се исписује на екрану након извршавaња следећег програмског кода:


#include<stdio.h>

main()
{
int x, y;
int a=0, b=0;
printf("Na pocetku : \na = %d\nb = %d\n", a, b);
a++;
++b;
printf("\nPosle : a++; ++b; \na = %d\nb = %d\n", a, b);
x = ++a;
y = b++;
printf("\nPosle : x = ++a; \na = %d\nx = %d\n", a, x);
printf("\nPosle : y = b++; \nb = %d\ny = %d\n", b, y);
getche();
return 0;
}

Испис на екрану

24
Збирка решених задатака из Програмског језика С – I део

2.32. Шта се исписује на екрану након извршавања следећег програмског кода:


#include<stdio.h>

main()
{
int a = 3, b = 3;
printf("\n a b \n");
printf("\n %d %d\n", a--, --b);
printf("\n %d% d\n", a--, --b);
printf("\n %d% d\n\n", a--, --b);
getche();
return 0;
}
Испис на екрану

2.33. Који је резултат извршавања следећег програмског кода:

#include<stdio.h>

main()
{
int x=1, y=2, z=3;
printf("Vrednost izraza x==1 je logicka %d.\n", x==1);
printf("Vrednost izraza y!=2 je logicka %d.\n", y!=2);
printf("Vrednost izraza x<=y je logicka %d.\n", x<=1);
printf("Vrednost izraza x>=z je logicka %d.\n", x>=1);
printf("Vrednost izraza x+y==z je logicka %d.\n", x+y==z);
printf("Vrednost izraza x>y*z je logicka %d.\n", x>y*z);
getche();
return 0;
}

Испис на екрану

2.34. Који је резултат извршавања следећег програмског кода:


#include<stdio.h>

main()
{
int a = 5<3, b = 5>3, c = 3==5, d = 3!=5;
printf("5<3 - %d\n5>3 - %d\n3==5 - %d\n3!=5 - %d\n", a, b, c, d);
printf("Konjunkcija : 3>5 && 5>3 - %d\n", a && b);
printf("Disjunkcija : 3>5 || 5>3 - %d\n", a || b);
printf("Negacija : !(3>5) - %d\n", !a);
getche();
return 0;
}

25
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

2.35. Саставити програм који тестира операторе над битовима за два унета броја у
хексадецималном облику и броја помераја.
#include<stdio.h>

main()
{
int x, y, n;
printf("Unesite dva heksadecimalna broja: ");
scanf("%i %i", &x, &y);
printf("Unesite broj pomeraja: ");
scanf("%d", &n);
printf("%#x & %#x = %#x\n", x, y, x&y);
printf("%#x | %#x = %#x\n", x, y, x|y);
printf("%#x ^ %#x = %#x\n", x, y, x^y);
printf("%#x << %d = %#x\n", x, n, x<<n);
printf("%#x >> %d = %#x\n", y, n, y>>n);
getche();
return 0;
}

Испис на екрану

26
Збирка решених задатака из Програмског језика С – I део

3 ГРАЊАЊЕ У ПРОГРАМУ

3.1. Саставити програм који исписује обавештење да ли је унети цео број паран или непаран.

Први начин:
#include <stdio.h>

main()
{
int broj;
printf("Unesite broj: ");
scanf("%d", &broj);
if (broj%2 == 0) Испис на екрану
printf("\nUneti broj je paran.\n");
else
printf("\nUneti broj je neparan.\n");
getche();
return 0;
}

Други начин (условни оператор):


#include <stdio.h>

main()
{
int broj;
printf("Unesite broj: "); scanf("%d", &broj);
(broj%2 == 0) ? printf("\nUneti broj je paran.\n")
: printf("\nUneti broj je neparan.\n");
getche();
return 0;
}

27
Збирка решених задатака из Програмског језика С – I део

3.2. Саставити програм који исписује обавештење да ли је унети број позитиван, негативан или је
једнак нули.

Први начин:
#include <stdio.h>

main()
{
int a;
printf("Unesite ceo broj: ");
scanf("%d", &a);
if(a < 0) Испис на екрану
printf("\nBroj je negativan.\n");
else if(a > 0)
printf("\nBroj je pozitivan.\n");
else
printf("\nBroj je nula.\n");
getche();
return 0;
}

Други начин (условни оператор):


#include <stdio.h>

main()
{
int a;
printf("Unesite ceo broj: "); scanf("%d", &a);
if(a == 0)
printf("\nBroj je nula.\n");
else
(a > 0) ? printf("\nBroj je pozitivan.\n")
: printf("\nBroj je negativan.\n");
getche();
return 0;
}

3.3. Саставити програм који за два унета цела броја исписује какав постоји релациони однос
између њих (једнаки су, први већи од другог или први је мањи од другог).

Први начин:
#include <stdio.h>

main()
{
int a, b;
printf("Unesite broj a= ");
scanf("%d", &a);
printf("Unesite broj b= ");
scanf("%d", &b); Испис на екрану
if(a == b)
printf("Brojevi su jednaki.\n");
28
Збирка решених задатака из Програмског језика С – I део

else if (a > b)
printf("Broj a je veci od b.\n");
else
printf("Broj a je manji od b.\n");
getche();
return 0;
}

Други начин (условни оператор):


#include <stdio.h>

main()
{
int a, b;
printf("Unesite broj a= ");
scanf("%d", &a);
printf("Unesite broj b= ");
scanf("%d", &b);
if(a == b)
printf("Brojevi su jednaki.\n");
else
(a > b) ? printf("Broj a je veci od b.\n")
: printf("Broj a je manji od b.\n");
getche();
return 0;
}

3.4. Саставити програм који за три унета цела броја исписује највећи.
#include <stdio.h>

main()
{
int a, b, c, max;
printf("Unesite tri cela broja: ");
scanf("%d%d%d", &a, &b, &c); Испис на екрану
max=a;
if(b>max)
max=b;
if(c>max)
max=c;
printf("Najveci je %d\n", max);
getche();
return 0;
}

29
Збирка решених задатака из Програмског језика С – I део

3.5. Саставити програм који три унета реална броја уређује у неопадајућем редоследу.

#include <stdio.h>

main()
{
double x, y, z, p;
printf("Unesite tri realna broja: ");
scanf("%lf%lf%lf", &x, &y, &z);
if(x>y)
{
p=x; x=y; y=p;
}
if(x>z)
{
p=x; x=z; z=p;
}
if(y>z)
{
Испис на екрану
p=y; y=z; z=p;
}
printf("Uredjeni brojevi: %.2f %.2f %.2f\n", x, y, z);
getche();
return 0;
}

3.6. Саставити програм који проверава и исписује да ли се на k-том месту унетог броја n налази
бит који има вредност 1 или 0.
#include <stdio.h>

main()
{
int n,k;
printf(" Unesite broj: ");
scanf("%d",&n);
printf(" Unesite poziciju tog broja koju zelite da proverite: ");
scanf("%d",&n);
if((n & (1 << k))!=0)
printf(" Bit je 1\n");
else
printf(" Bit je 0\n");
getche();
return 0;
}

Испис на екрану

30
Збирка решених задатака из Програмског језика С – I део

3.7. Саставити програм који ће на основу унетих броја поена (од нула до 100) исписати
одговарајућу оцену (0-50 пет, 51-60 шест, 61-70 седам, 71-80 осам, 81-90 девет, 91-100 десет).

#include <stdio.h>

main()
{
int a;
printf("Unesite broj bodova: ");
scanf ("%d", &a); Испис на екрану
if (a>90)
printf("Ocena je 10\n");
else if (a>80)
printf("Ocena je 9\n");
else if (a>70)
printf("Ocena je 8\n");
else if (a>60)
printf ("Ocena je 7\n");
else if (a>50)
printf("Ocena je 6\n");
else
printf("Ocena je 5\n");
getche();
return 0;
}

3.8. Саставити програм који ће за унети опсег позитивних целих бројева од а до b исписати да ли
се у задатом опсегу налази квадрат броја х (број х се уноси са тастатуре).

Први начин:
#include <stdio.h>

main()
{
int a, b, x;
printf("Unesite donju i gornju granicu opsega: ");
scanf("%d %d", &a, &b);
printf("Unesite ceo broj x= ");
scanf("%d", &x);
if((a <= x*x) && (x*x <= b))
printf("\nx*x=%d pripada oblasti [%d,%d]", x*x, a, b);
else
printf("\nx*x=%d ne pripada oblasti [%d,%d]", x*x, a, b);
getche();
return 0;
}

Испис на екрану

31
Збирка решених задатака из Програмског језика С – I део

Други начин (условни оператор):


#include <stdio.h>

main()
{
int a, b, x;
printf("Unesite donju i gornju granicu opsega: ");
scanf("%d %d", &a, &b);
printf("Unesite ceo broj x= ");
scanf("%d", &x);
((a <= x*x) && (x*x <= b))
? printf("\nx*x=%d pripada oblasti [%d,%d]", x*x, a, b)
: printf("\nx*x=%d ne pripada oblasti [%d,%d]", x*x, a, b);
getche();
return 0;
}

3.9. Саставити програм који ће учитати два броја и од већег одузети мањи и приказати резултат.

Први начин:
#include <stdio.h>

main()
{
int x, y;
printf("Unesite dva cela broja: ");
scanf("%d %d", &x, &y);
if(x<y) Испис на екрану
printf("\nRezultat = %d", y-x);
else
printf("\nRezultat = %d", x-y);
getche();
return 0;
}

Други начин (условни оператор):


#include <stdio.h>

main()
{
int x, y;
printf("Unesite dva cela broja: ");
scanf("%d %d", &x, &y);
printf("\nRezultat = %d", (x<y)? y-x : x-y);
getche();
return 0;
}

32
Збирка решених задатака из Програмског језика С – I део

3.10. Саставити програм за одређивање сигнум функције и исписивање резултата за унети реалан
−1 , x<0

број х. y = sgn( x ) = 0 , x=0
1 , x>0

Први начин: Други начин (условни оператор):
#include <stdio.h> #include <stdio.h>

main() main()
{ {
float x; float x;
int y; int y;
printf("Unesite x= "); printf("Unesite x= ");
scanf("%f", &x); scanf ("%f", &x);
if(x==0) y = (x>0)? 1 : (x<0)? -1 : 0;
y=0; printf("\ny= %d", y);
else if(x>0) getche();
y=1; return 0;
else }
y=-1;
printf("\ny= %d", y);
getche();
return 0;
}

Испис на екрану

3.11. Саставити програм за израчунавање функције у за унето х. Функција у је дефинисана на


следећи начин:
 2 x, -2<x ≤ 2 main()

y = 3 x − 1, 5 ≤ x < 7 {
1/ x, ostalo
float x, y;
 printf ("Unesite x= "); scanf("%f", &x);
if((x<=2) && (x>-2))
y=2*x;
else if((x<7) && (x>=5))
y=3*x-1;
else
y=1/x;
printf("\ny= %.2f", y);
getche();
Испис на екрану return 0;
}

3.12. Саставити програм за израчунавање функције z за унето х и y. Функција z је дефинисана на


 min( x, y ), y>0
следећи начин: z = 
 max( x , y ), y ≤ 0
2 2

#include <stdio.h>

main()
{
33
Збирка решених задатака из Програмског језика С – I део

int x, y, z;
printf("Unesite x= "); scanf("%d", &x);
printf ("Unesite y= "); scanf("%d", &y);
if(y < 0)
{
if((x*x)<(y*y)) z=y*y;
else z=x*x;
}
else
{
if(x<y) z=x; Испис на екрану
else z=y;
}
printf("\nz= %.d\n", z);
getche();
return 0;
}

3.13. Саставити програм који исписује обавештење да ли унете променљиве а, b и c које


означавају дужине страница формирају троугао. Уколико формирају троугао израчунати површину
троугла користeћи следеће формуле:
a+b+c
S= , P = S ( S − a )( S − b )( S − c ) .
2

#include <stdio.h>

main()
{
float a,b,c,p,s;
printf("Unesi stranice trougla \na= "); scanf("%f",&a);
printf("b= "); scanf("%f",&b);
printf("c= "); scanf("%f",&c);
if (a+b>c && a+c>b && b+c>a)
{
s=(a+b+c)/2;
p=sqrt(s*(s-a)*(s-b)*(s-c));
printf("Ѕtranice formiraju trougao povrsine p= %.2f\n", p);
}
else printf("Ѕtranice ne formiraju trougao.\n");
getche();
return 0;
}

Испис на екрану

34
Збирка решених задатака из Програмског језика С – I део

3.14. Саставити програм који исписује дужину страница и величину углова троугла на основу
унетих координата темена. Уколико се троугао не може формитати штампати одговарајуће
обавештење.
( xB − xC ) − ( y B − yC ) , b= ( xC − xA ) − ( yC − yA )
2 2
Користити следеће формуле: a =
2 2
,
a+b+c
c= ( x A − xB ) − ( y A − y B ) P = S ( S − a )( S − b )( S − c )
2 2
, S= ,
2
#include <stdio.h>
#include <math.h>
#define PI 3.141592

main()
{
double xa, ya, xb, yb, xc, yc, a, b, c, alfa, beta, gama;
printf("Unesite koordinate tacke A(x,y): ");
scanf("%lf%lf",&xa,&ya);
printf("Unesite koordinate tacke B(x,y): ");
scanf("%lf%lf",&xb,&yb);
printf("Unesite koordinate tacke C(x,y): ");
scanf("%lf%lf",&xc,&yc);
a = sqrt(pow(xb-xc,2) + pow(yb-yc,2));
b = sqrt(pow(xa-xc,2) + pow(ya-yc,2));
c = sqrt(pow(xa-xb,2) + pow(ya-yb,2));
printf("\nStranice:\n");
printf("a= %f\n", a);
printf("b= %f\n", b);
printf("c= %f\n", c);
if(a+b>c && a+c>b && b+c>a)
{
alfa = acos( (b*b+c*c-a*a) / (2*b*c) );
beta = acos( (c*c+a*a-b*b) / (2*c*a) );
gama = acos( (a*a+b*b-c*c) / (2*a*b) );
alfa *= 180/PI;
beta *= 180/PI;
gama *= 180/PI;
printf("\nUglovi:\n");
printf("Alfa = %.2f stepeni\n", alfa);
printf("Beta = %.2f stepeni\n", beta);
printf("Gama = %.2f stepeni\n", gama);
}
еlse printf("Ne moze se kreirati trougao.\n");
getche();
return 0;
}

35
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

3.15. Саставити програм којим се испитује да ли се секу праве y = a1 ⋅ x + b1 и y = a2 ⋅ x + b2 . Ако


се секу одредити координате пресека. Коефицијенти а1, b1, a2 и b2 се уносе са тастатуре
#include <stdio.h>

main()
{
double a1, a2, b1, b2, x, y;
printf("Unesite koeficijente:\na1= "); scanf("%lf", &a1);
printf("b1= "); scanf("%lf", &b1);
printf("a2= "); scanf("%lf", &a2);
printf("b2= "); scanf("%lf", &b2);
printf("\nPrave:\ny=%.2fx+%.2f\ny=%.2fx+%.2f\n", a1, b1, a2, b2);
if(a1==a2)
{
if(b1==b2) printf("\nPrave su podudarne.");
else printf("\nPrave su paralelne.");
}
else
{
x=(b2-b1)/(a1-a2);
y=a1*x+b1;
printf("\nTacka preseka je x= %.2f, y= %.2f\n", x, y);
}
getche();
return 0;
}

Испис на екрану (Задатак16)

Испис на екрану (Задатак 15)

36
Збирка решених задатака из Програмског језика С – I део

3.16. Саставити програм којим се решава нелинеарна једначина a ⋅ x + b ↔ 0 где је ↔ знак < или >,
и а≠0. Коефицијенти а и b и знак се уносе са тастатуре.
#include <stdio.h>

main()
{
char z;
double a, b, x;
printf("Unesite znak [<,>]: "); scanf("%c", &z);
printf("Unesite koeficijente:\na= "); scanf("%lf", &a);
printf("b= "); scanf("%lf", &b);
printf("\nNejednacina ima oblik: %.2fx+%.2f%c0\n", a, b, z);
x=-b/a;
if(a>0) printf("\nResenje x%c%.2f", z, x);
else printf("\nResenje .2f%c%x", z, x);
getche(); return 0;
}

3.17. Саставити програм за решавање система од две линеарне једначине: a1 x + b1 y = c1 и


a2 x + b2 y = c2 . Коефицијенти a1, a2, b1, b2, c1 и c2 се уносе са тастатуре. За решавање система
користити методу детерминанти: D = a1 b1
= a1b2 − a2b1 , Dx =
c1 b1
= c1b2 − c2b1 и
a2 b2 c2 b2
a1 c1
Dy = = a1c2 − a2 c1 .
a2 c2
Систем има три решења:
Dy
1) D ≠ 0 : x=
Dx
, y=
D D
2) D = Dx = Dy = 0 : неодређено (бесконачно решења)
3) остали случајеви: нема решења.

#include <stdio.h>

main()
{
double a1, b1, c1, a2, b2, c2, D, Dx, Dy, x, y;
printf ("Unesite koeficijente prve jednacine:\na1= ");
scanf("%lf", &a1);
printf("b1= "); scanf("%lf", &b1);
printf("c1= "); scanf("%lf", &c1);
printf("Unesite koeficijente druge jednacine:\na2= ");
scanf("%lf", &a2);
printf("b2= "); scanf("%lf", &b2);
printf("c2= "); scanf("%lf", &c2);
D = a1 * b2 - a2 * b1;
Dx = c1 * b2 - c2 * b1;
Dy = a1 * c2 - a2 * c1;
if(D != 0)
{
x=Dx/D;
y=Dy/D;
printf ("\nResenje sistema:\nx= %.2f\n", x);

37
Збирка решених задатака из Програмског језика С – I део

printf ("y= %.2f\n", y);


}
else
if(Dx==0 && Dy==0)
printf ("Sistem ima beskonacno resenja.\n");
else printf ("Sistem nema resenja.\n");
getche();
return(0);
}

Испис на екрану

3.18. Саставити програм за решавање квадратне једначине ax 2 + bx + c = 0 . У зависности од


коефицијента а и дискриминанте D = b 2 − 4ac имамо следећа решења:
1) а≠0 и D>0: два различита и реална ( x1,2 = −b ± d ),
2a
−b
2) а≠0 и D=0: два једнака реална ( x1,2 = ),
2a
3) а≠0 и D<0: два коњуговано комплексна ( x1,2 = −b ± i d ),
2a
− c
4) а=0 и b≠0: линеарна једначиина, решење ( x = ),
b
5) а=0 и b=0: нема решења.

#include <stdio.h>
#include <math.h>

main()
{
double a, b, c, D, x1, x2;
printf("Unesite koeficijente:\na= "); scanf("%lf",&a);
printf("b= "); scanf("%lf",&b);
printf("c= "); scanf("%lf",&c);
if(a!=0)
{
D=b*b-4*a*c;
if(D>0)
{
x1=(-b+sqrt(D))/(2*a);
x2=(-b-sqrt(D))/(2*a);
38
Збирка решених задатака из Програмског језика С – I део

printf("n\Resenja:\nx1=%.2f, x2=%.2f",x1,x2);
}
else if(D==0)
{
x1=(-b/(2*a));
printf("\nResenje:\nx1=x2=%.2f",x1);
}
else
{
x1=-b/(2*a);
x2=sqrt(-D)/(2*a);
printf("\nKompleksna resenja:\n");
printf("x1=%.2f+i%.2f, x2=%.2f-i%.2fi",x1,x2,x1,x2);
}
}
else
{
if(b!=0)
{
x1=-c/b;
printf("\nResenje:\nx=%.2f",x1);
}
else printf("Sistem nema resenja.");
}
getche();
return 0;
}

Испис на екрану

39
Збирка решених задатака из Програмског језика С – I део

4 FOR ПЕТЉА

4.1. Саставити програм који ће пет пута исписати реченицу Pozdrav svima! употребом FOR
петље.
#include <stdio.h>

main()
{
int i;
for(i=1; i<6; i++)
printf("Pozdrav svima!\n");
getche();
return 0;
} Испис на екрану

4.2. Саставити програм који употребом FOR петље исписује:


а) све бројеве прве десетице,
б) само непарне бројеве прве десетице
в) све бројеве прве десетице у обрнутом редоследу.

а) #include <stdio.h>

main()
{
int i;
for(i=1; i<=10; i=i+1)
printf("%d\n", i);
getche();
return 0;
} Испис на екрану б)

б) #include <stdio.h>
Испис на екрану а)
main()
{
int i;
for (i=1; i<=10; i=i+2)
printf("%d\n", i);
getche();
return 0;
}

40
Збирка решених задатака из Програмског језика С – I део

в)
#include <stdio.h>

main()
{
int i;
for(i=10; i>=1; i=i-1)
printf("%d\n", i);
getche();
return 0;
}

Испис на екрану в)

4.3. Које вредности i и j имају након сваке промене унутар FOR петље у следећем програмском
коду:
#include <stdio.h>

main()
{
int i, j;
for(i=1; i<3; i++)
for(j=1; j<4; j++)
printf("i=%d, j=%d\n", i, j);
printf("\n");
for(i=1; i<4; i++)
for(j=1; j<3; j++)
printf("i=%d, j=%d\n", i, j);
getche();
return 0;
}
Испис на екрану

4.4. Саставити програм који за унето n исписује збир првих n целих позитивних бројева.

#include <stdio.h>

main()
{
int n, s, i;
printf("Unesite n= ");
scanf("%d", &n);
s=0; Испис на екрану
for(i=1; i<=n; i++)
s+=i;
printf("Suma= %d\n", s);
getche();
return 0;
}

41
Збирка решених задатака из Програмског језика С – I део

4.5. Саставити програм који за унето n учитава n реалних бројева и приказује њихов збир и
аритметичку средину.

#include <stdio.h>

main()
{
int n, i;
float a, s, ars;
s=0;
printf("n= ");
scanf("%d",&n);
printf(" Unesite %d brojeva:\n", n);
for(i=1; i<=n; i++)
{
scanf("%f",&a);
s+=a;
}
ars=s/n;
printf("\n Suma zadatih brojeva je %.2f", s);
printf("\n Aritmeticka sredina zadatih brojeva je %.2f", ars);
getche();
return 0;
}

Испис на екрану

4.6. Саставити програм који за унети цео број n приказује његов факторијел.

#include <stdio.h>

main()
{
int i,n;
long faktorijel=1;
printf("n= ");
scanf("%d",&n); Испис на екрану
for(i=1;i<=n;i++)
faktorijel=faktorijel*i;
printf("Faktorijel = %ld\n", faktorijel);
getche();
return 0;
}

42
Збирка решених задатака из Програмског језика С – I део

4.7. Саставити програм којим се за унети природан број n израчунава суму: S =1!+2!+3!+...+n!.
#include <stdio.h>

main()
{
int i,n;
long f=1, s=0;
printf("n= ");
scanf("%d",&n); Испис на екрану
for(i=1; i<=n; i++)
{
f*=i;
s+=f;
}
printf("\ns= %ld\n", s);
getche();
return 0;
}

4.8. Саставити програм којим се, за дате природне бројеве m и n, израчунава израз:
а) S = n ( n + m )( n + 2 m ) ... ( n + m ⋅ m )
1 1 1 1
− ... ( −1)
m +1
б) S = − +
n + m n + 2m n + 3m n + m⋅m
а) #include <stdio.h> б) #include <stdio.h>

main() main()
{ {
int i, m, n; int i, m, n, znak;
long s; float s;
printf("n= "); printf("n= ");
scanf("%d",&n); scanf("%d",&n);
printf("m= "); printf("m= ");
scanf("%d",&m); scanf("%d",&m);
s=1; s=0;
for(i=0;i<=m;i++) znak=1;
s=s*(n+i*m); for(i=1;i<=m;i++)
printf("\ns= %ld\n", s); {
getche(); s=s+(float)znak/(n+i*m);
return 0; znak=-znak;
} }
printf("\ns= %.5f\n", s);
getche();
return 0;
}

Испис на екрану а) Испис на екрану б)

43
Збирка решених задатака из Програмског језика С – I део

4.9. Саставити програм којим се, за дати природни n израчунава израз:


а) S = + 2! +
1! 3!
+ ... +
n!
1 1 1 1 1 1 1 1 1
+ + + + + ... +
2 2 3 2 3 4 2 3 n +1
1+ 2 1+ 2 + 3 n −1 1 + 2 + 3 + .. + n
б) S = 1 − + − ... ( −1)
2! 3! n!
cos (1) cos (1) + cos ( 2 ) cos (1) + cos ( 2 ) + ... + cos ( n )
в) S = * *...*
sin (1) sin (1) + sin ( 2 ) sin (1) + sin ( 2 ) + ... + sin ( n )

а) #include <stdio.h> б) #include <stdio.h>

main() main()
{ {
int i, n, fakt; int i, n, fakt, znak;
float s, q; float s, q;
printf("n= "); printf("n= ");
scanf("%d",&n); scanf("%d",&n);
s=0; s=0;
q=0; q=0;
fakt=1; fakt=1;
for(i=1; i<=n; i++) znak=1;
{ for(i=1; i<=n; i++)
fakt=fakt*i; {
q=q+1./(1+i); fakt=fakt*i;
s=s+fakt/q; q=q+i;
} s=s+znak*q/(float)fakt;
printf("\ns= %.5f\n", s); znak=-znak;
getche(); }
return 0; printf("\ns= %.5f\n", s);
} getche();
return 0;
}

в) #include <stdio.h>
#include <math.h>

main()
{
int i, n;
float s, p, q;
printf("n= ");
scanf("%d",&n);
s=1;
p=0; Испис на екрану а) Испис на екрану б)
q=0;
for(i=1; i<=n; i++)
{
p=p+cos(i);
q=q+sin(i);
s=s*p/(float)q;
}
printf("\ns= %.5f\n", s);
getche();
return 0;
}
Испис на екрану в)

44
Збирка решених задатака из Програмског језика С – I део

4.10. Саставити програм којим се, за дати природни број n и реалан број х, израчунава израз:
а) S = sin ( x ) + sin 2 ( x ) + ... + sin n ( x )

( ) ( )
б) S = cos ( x ) + cos x 2 + ... + cos x n

а) #include <stdio.h> б) #include <stdio.h>


#include <math.h> #include <math.h>

main() main()
{ {
int i, n; int i, n;
float s, p, x; float s, p, x;
printf("n= "); printf("n= ");
scanf("%d",&n); scanf("%d",&n);
printf("x= "); printf("x= ");
scanf("%f",&x); scanf("%f",&x);
s=0; s=0;
p=1; p=1;
for(i=1; i<=n; i++) for(i=1; i<=n; i++)
{ {
p=p*sin(x); p=p*x;
s=s+p; s=s+cos(p);
} }
printf("\ns= %.5f\n", s); printf("\ns= %.5f\n", s);
getche(); getche();
return 0; return 0;
} }

Испис на екрану а) Испис на екрану б)

4.11.Саставити програм којим се, за дати природни број n, израчунава израз:


1 1 1 1
S= ⋅ ⋅ ⋅ ... ⋅ #include <stdio.h>
2 2+ 2 2+ 2+ 2 2 + 2 + ... + 2
#include <math.h>

main()
Код последњег фактора квадратни корен је {
примењен n пута. int i, n;
float s, p;
printf("n= "); scanf("%d",&n);
s=1; p=0;
for(i=1; i<=n; i++)
{
p=sqrt(p+2);
s=s/(float)p;
}
Испис на екрану printf("\ns= %.5f\n", s);
getche();
return 0;
}

45
Збирка решених задатака из Програмског језика С – I део

4.12. Саставити програм који ће учитати n реалних бројева и исписати највећи.

#include <stdio.h>

main()
{
int i, n;
float br, max;
printf("\nn= ");
scanf("%d",&n);
printf("\nUnesite 1. broj: ");
scanf("%f",&br);
max=br;
for(i=2; i<=n; i++)
{ Испис на екрану
printf("Unesite %d. broj: ",i);
scanf("%f",&br);
if(br>max) max=br;
}
printf("\nNajveci: %.2f", max);
getche();
return 0;
}

4.13. Саставити програм који ће исписати све бројева прве стотине који су дељиви са 6 и њихову
суму.

#include <stdio.h>

main()
{
int i, s=0;
printf("Brojevi deljivi sa 6:\n");
for(i=1; i<=100; i++)
{
if(i%6 == 0)
{
s=s+i;
printf("\n%d", i);;
}
}
printf("\n\nSuma: %d\n", s);
getche();
return 0;
}

Испис на екрану

46
Збирка решених задатака из Програмског језика С – I део

4.14. Саставити програм који исписује све троцифрене бројеве код којих је друга цифра за 2 већа
од прве, а трећа за 1 већа од друге.
#include <stdio.h>

main()
{
int a, b, c;
for(a=1; a<=9; a++)
for(b=3; b<=9; b++)
for(c=4; c<=9; c++)
if(b == a+2 && c == b+1)
printf("%d%d%d\n", a, b, c);
getche(); Испис на екрану
return 0;
}

4.15. Саставити програм којим се исписују сви троцифрени Амстронгови бројеви. Троцифрени
број је Амстронгов ако је једнак збиру кубова својих цифара.
#include <stdio.h>
#include <math.h>

main()
{
int a, b, c, broj;
printf("Amstrongovi brojevi:\n");
for(a=1; a<=9; a++)
for(b=0; b<9; b++) Испис на екрану
for(c=0; c<9; c++)
{
broj=100*a+10*b+c;
if(broj == pow(a,3)+pow(b,3)+pow(c,3))
printf("\n%d", broj);
}
getche();
return 0;
}

4.16. Саставити програм којим се исписују сви троцифрени бројеви АВС који имају својство
(АВС)= (АВ)2-С2, где су непознате цифре 1 ≤ A ≤ 9 , 0 ≤ B ≤ 9 , 0 ≤ C ≤ 9 . На пример: 147=142-72.
#include <stdio.h>
main()
{
int a, b, c, broj;
for(a=1; a<=9; a++)
for(b=0; b<9; b++)
for(c=0; c<9; c++) Испис на екрану
{
broj=100*a+10*b+c;
if(broj == ((10*a+b)*(10*a+b)-c*c))
printf("\n%d", broj);
}
getche(); return 0;
}

47
Збирка решених задатака из Програмског језика С – I део

4.17. Саставити програм којим се исписују сви троцифрени бројеви који имају особину да су
дељиви бројем који се добија избацивањем средње цифре.

#include <stdio.h>

main()
{
int a, b, c, broj, dvocif;
for(a=1;a<=9;a++)
for(b=0;b<9;b++)
for(c=0;c<9;c++)
{
broj=100*a+10*b+c;
dvocif=10*a+c;
if(broj%dvocif == 0)
printf("%d, ", broj);
}
getche();
return 0;
}

Испис на екрану

4.18. Саставити програм који рачуна суму троцифрених природних бројева чији је збир цифара
једнак 5. Исписати и обавештење колико бројева има такву особину.

#include <stdio.h>

main()
{
int a, b, c, s=0, br, n=0;
for(a=1; a<=9; a++)
for(b=0; b<9; b++)
for(c=0; c<9; c++) Испис на екрану
{
br=100*a+10*b+c;
if (a+b+c == 5)
{
n++;
s+=br;
}
}
printf("Suma: %d\n", s);
printf("Ukupno brojeva: %d\n", n);
getche();
return 0;
}

48
Збирка решених задатака из Програмског језика С – I део

4.19. Саставити програм који ће исписати све делиоце унетог броја n.


#include <stdio.h>

main()
{
int i, n;
printf("n= ");
scanf("%d",&n);
printf("\nDelioci:");
for(i=1; i<=n; i++)
{
if(n%i == 0)
printf("\n%d ", i);
}
getche();
return 0; Испис на екрану
}

4.20. Саставити програм који ће исписати обавештење да ли је унети број n савршен. Број је
савршен ако је једнак суми својих делиоца искључујући њега самог. На пример, 28=1+2+4+7+14.
#include <stdio.h>

main()
{
int n, i, suma=0;
printf("n= ");
scanf("%d",&n);
for(i=1; i<n; i++)
{ Испис на екрану
if(n%i==0)
suma+=i;
}
if(suma==n)
printf("Broj %d jeste savrsen broj.\n",n);
else
printf("Broj %d nije savrsen broj.\n",n);
getche();
return 0;
}

4.21. Саставити програм који ће учитати оцене за n ученика и исписати просечну оцену свих
ученика и број ученика који имају оцену 1.
#include <stdio.h>

main()
{
int i, br=0, n, ocena;
float s,srednja;
printf("Broj ucenika n= ");
scanf("%d",&n);
for(i=1; i<=n; i++)
49
Збирка решених задатака из Програмског језика С – I део

{
printf("Unesi ocenu %d. ucenika: ",i);
scanf("%d",&ocena);
s+=ocena;
if(ocena==1) br++;
}
srednja=s/n;
printf("\nSrednja ocena: %.2f", srednja);
printf("\nBroj negativnih: %d", br);
getche();
return 0;
}

Испис на екрану

4.22. Електронски сат показује време у сатима, минутима и секундама. Саставити програм који ће
исписати све моменте времена у току једног дана такве да је сума цифара на сату једнака датом броју
n. Испис треба да је у облику (n=33):
0 sat 11 min 31 sec
1 sat 32 min 0 sec .

#include <stdio.h>

main()
{
int sat, min, sec, n;
printf("n= ");
scanf("%d",&n);
for(sat=0; sat<=23; sat++)
for(min=0; min<=59; min++)
for(sec=0; sec<=59; sec++)
{
if(n==(sat/10+sat%10+min/10+min%10+sec/10+sec%10))
printf("\n%d sat %d min %d sec", sat, min, sec);
}
getche();
return 0;
}

50
Збирка решених задатака из Програмског језика С – I део

Испис на екрану (Задатак 23)

Испис на екрану (Задатак 22)

2x +1
4.23. Саставити програм за табелирање функције y = у опсегу од xmin до xmax са кораком
x2 − 1
dx.
#include <stdio.h>

main()
{
double xmin, xmax, dx, x, y;
printf("xmin= ");
scanf("%lf", &xmin);
printf("xmax= ");
scanf("%lf", &xmax);
printf("dx= ");
scanf("%lf", &dx);
printf("\n x y\n ===================\n");
for(x=xmin; x<=xmax; x+=dx)
{
y=(2*x+1)/(x*x-1);
printf ("%10.3f%10.3f\n", x, y);
}
getche();
return 0;
}

4.24. ( ) ( )
Саставити програм за табелирање функције y = (1 + x ) ⋅ 1 + x 2 ⋅ ... ⋅ 1 + x n у опсегу од xmin
до xmax са кораком dx. Степен функције n се уноси са тастатуре.

51
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h>

main()
{
double xmin, xmax, dx, x, y=1, p=1;
int i, n;
printf("n= ");
scanf("%d", &n);
printf("xmin= ");
scanf("%lf", &xmin);
printf("xmax= ");
scanf("%lf", &xmax);
printf("dx= ");
scanf("%lf", &dx);
printf("\n x y\n");
printf("===================\n");
for(x=xmin;x<=xmax;x+=dx)
{
for(i=1; i<=n; i++)
{
p*=x;
y*=(1+p);
} Испис на екрану
printf("%10.6f %11.6f\n",x,y);
p=1;
y=1;
}
getche();
return 0;
}

4.25. Саставити програм којим се за све углове од 0 до 90 степени са кораком промене


(дефинисаним у степенима) израчунава и исписује вредност синусне функције. Функција sin као
улазни параметар захтева угао у радијанима.

#include <stdio.h>
#include <math.h>
#define PI 3.141592

main()
{
double dx=0, UgaoRad, UgaoSte;
printf("Unesite korak u stepenima: ");
scanf("%lf",&dx);
printf("\n x sin(x)");
printf("\n=======================\n");
for(UgaoSte=0; UgaoSte<=90; UgaoSte+=dx)
{
UgaoRad = (PI*UgaoSte)/180.0;
printf("%f \t%f\n",UgaoSte, sin(UgaoRad));
}
getche();
return 0;
} Испис на екрану

52
Збирка решених задатака из Програмског језика С – I део

4.26. Саставити програм који за унети позитиван цео број n исцртава облик приказан на слици, на
слици је n=5.
a) **********
б) 0123456789
********** 0123456789
********** 0123456789
********** 0123456789
********** 0123456789

а) б)
#include <stdio.h> #include <stdio.h>
main() main()
{ {
int i, j, n; int i, j, n;
printf(" n= "); printf(" n= ");
scanf("%d", &n); scanf("%d", &n);
printf("\n"); printf("\n");
for(i=0; i<n; i++) for(i=0; i<n; i++) Испис на екрану а)
{ {
for(j=0; j<2*n; j++) for(j=0; j<2*n; j++)
printf("*"); printf("%d", j);
printf("\n"); printf("\n");
} }
getche(); getche();
return 0; return 0;
} }

Испис на екрану б)

4.27. Саставити програм који за унете позитивне целе бројеве m и n исцртава правоугаоник
формиран од знака чији се ASCII код уноси са тастатуре.
#include <stdio.h>

main()
{
int i, j, m, n, a;
printf(" m= ");
scanf("%d", &m);
printf(" n= ");
scanf("%d", &n);
printf(" ASCII= ");
scanf("%d", &a);
printf("\n");
Испис на екрану
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
printf("%c", a);
printf("\n");
}
getche();
return 0;
}

53
Збирка решених задатака из Програмског језика С – I део

4.28. Саставити програм који за унети позитиван цео број n исцртава облик приказан на слици, на
слици је n=5.
а) б) в) г)

* * * * * ***** * *
* * * * * * * * * **
* * * * * * * * ** * *
* * * * * * * * *** * *
* * * * * ***** * **** *****

д) ђ) е) ж)

* **** ***** * *****


* *** * * ** ****
* ** * * *** ***
* * ** **** **
* * ***** *

а) #include <stdio.h> в) #include <stdio.h>

main() main()
{ {
int i, j, n; int i, j, n;
printf(" n= "); printf(" n= ");
scanf("%d", &n); scanf("%d", &n);
printf("\n"); printf("\n");
for(i=1; i<=n; i++) for(i=1; i<=n; i++)
{ {
for(j=1; j<=n; j++) for(j=1; j<=i; j++)
printf("* "); printf("* ");
printf("\n"); printf("\n");
} }
getche(); getche();
return 0; return 0;
} }

Испис на екрану а) Испис на екрану б) Испис на екрану в) Испис на екрану г)

54
Збирка решених задатака из Програмског језика С – I део

б) #include <stdio.h> г) #include <stdio.h>

main() main()
{ {
int i, j, n; int i, j, n;
printf(" n= "); printf(" n= ");
scanf("%d", &n); scanf("%d", &n);
printf("\n"); printf("\n");
for(i=1; i<=n; i++) for(i=1; i<=n; i++)
{ {
for(j=1; j<=n; j++) for(j=1; j<=i; j++)
{ {
if(i==1 || i==n) if(i==n)
printf("* "); printf("* ");
else if (j==1 || j==n) else if (j==1 || j==i)
printf("* "); printf("* ");
else printf(" "); else printf(" ");
} }
printf("\n"); printf("\n");
} }
getche(); getche();
return 0; return 0;
} }

д) #include <stdio.h> ђ) #include <stdio.h>

main()
main()
{
{
int i, j, n;
int i, j, n;
printf(" n= ");
printf(" n= ");
scanf("%d", &n); scanf("%d", &n);
printf("\n"); printf("\n");
for(i=1; i<=n; i++)
for(i=1; i<=n; i++)
{ {
for(j=n; j>=i; j--)
for(j=n; j>=i; j--)
{
printf("* ");
if(i==1) printf("* ");
printf("\n");
else if(j==n || j==i)
}
printf("* ");
getche();
return 0; else printf(" ");
} }
printf("\n");
}
getche();
return 0;
}

Испис на екрану д) Испис на екрану ђ) Испис на екрану е) Испис на екрану ж)

55
Збирка решених задатака из Програмског језика С – I део

е) #include <stdio.h> ж) #include <stdio.h>

main() main()
{ {
int i, j, n, k; int i, j, n, k;
printf(" n= "); printf(" n= ");
scanf("%d", &n); scanf("%d", &n);
printf("\n"); printf("\n");
for(i=1; i<=n; i++) for(i=n; i>=1; i--)
{ {
for(k=n; k>i; k--) for(k=n; k>i; k--)
printf(" "); printf(" ");
for(j=1; j<=i; j++) for(j=1; j<=i; j++)
printf("* "); printf("* ");
printf("\n"); printf("\n");
} }
getche(); getche();
return 0; return 0;
} }

4.29. Саставити програм који за унети позитивни цео број n исцртава облик приказан на слици, на
слици је n=5.
#include <stdio.h>

main()
{
int n, i, j, k;
printf("n= "); scanf("%d", &n);
printf("\n");
for(i=1; i<=n; i++)
{
for(k=n; k>i; k--)
printf(" ");
for(j=0; j<i; j++)
printf("* ");
printf("\n");
} Испис на екрану
for(i=n-1; i>0; i--)
{
for(k=n; k>i; k--)
printf(" ");
for(j=0; j<i; j++)
printf("* ");
printf("\n");
}
getche(); return 0;
}

56
Збирка решених задатака из Програмског језика С – I део

4.30. Саставити програм који за унети позитиван цео број n (од 1 до 9) исцртава облик приказан на
слици, на слици је n=5.
#include <stdio.h>

main()
{
int n, i, j, k, m;
printf("n= "); scanf("%d",&n);
printf("\n");
for(i=n; i>0; i--)
{
m=i;
for(k=n; k>i; k--)
printf(" ");
for(j=0; j<i; j++)
printf("%d ", m);
printf("\n");
Испис на екрану
}
for(i=2; i<=n; i++)
{
m=i;
for(k=n; k>i; k--)
printf(" ");
for(j=0; j<i; j++)
printf("%d ", m);
printf("\n");
}
getche();
return 0;
}

4.31. Саставити програм који за унети цео позитиван број n исцртава облик приказан на слици, на
слици је n=7. Подразумева се да се уноси непаран број.

#include <stdio.h>

main()
{
int i, j, n;
printf("n= ");
scanf("%d", &n);
printf("\n");
for(i=1; i<=n; i++)
{
if(i%2==0) printf(" ");
if(i%4==3) printf(" ");
for(j=1; j<=n; j++)
printf("* ");
printf("\n");
}
getche();
return 0;
}

Испис на екрану

57
Збирка решених задатака из Програмског језика С – I део

4.32. Саставити програм који за унети позитиван цео број n исцртава облик приказан на слици, на
слици је n=5.
#include <stdio.h>

main()
{
int n, i, j, nzv, nrz, kor=1;
printf(" n= ");
scanf("%d", &n);
printf("\n");
nzv=n,
nrz=n-1;
for(i=1; i<=2*n-1; i++)
{
for(j=1; j<=nrz; j++)
printf(" ");
for(j=1; j<=nzv; j++)
printf("* ");
printf("\n");
if(i==n) kor = -1;
nzv += kor;
nrz -= kor;
}
getche();
return 0;
}
Испис на екрану

4.33. Саставити програм који за унето непарно и позитивно n исцртава стрелицу приказану на
слици, на слици је n=3.
#include <stdio.h>

main()
{
int n, i, j, nzv=0, kor=1;
char rep = ' ';
printf(" n= ");
scanf("%d", &n);
printf("\n");
for(i=1; i<=3*n; i++)
{
nzv+=kor;
for(j=1; j<=3*n; j++)
printf("%c", rep);
for(j=1; j<=nzv; j++)
printf("*");
printf("\n");
if(i==n) rep='*';
if(i==3*n/2+1) kor=-1;
if(i==2*n) rep = ' ';
}
getche();
return 0;
}

Испис на екрану

58
Збирка решених задатака из Програмског језика С – I део

4.34. Саставити програм који за унети цео позитиван и непаран број n исцртава облик приказан на
слици, на слици је n=7. Укупна ширина je 2n-1.
#include <stdio.h>

main()
{
int i, j, n;
printf(" n= "); scanf("%d", &n);
printf("\n");
for(i=0;i<2*n-1;i++)
{
if(i==0 || i==n-1 || i==2*n-2)
printf("+");
else printf("-");
}
printf("\n");
for(j=0;j<n-2;j++)
{
for(i=0; i<2*n-1; i++)
{
if(i==0 || i==n-1 || i==2*n-2)
printf("|");
else printf(" ");
}
printf("\n");
}
for(i=0;i<2*n-1;i++)
Испис на екрану
{
if(i==0 || i==n-1 || i==2*n-2)
printf("+");
else printf("-");
}
printf("\n");
getche();
return 0;
}

4.35. Саставити програм који за унети цео позитиван и непаран број n исцртава облик приказан на
слици, на слици је n=9.

#include <stdio.h>

main()
{
int i, j, n;
printf(" n= ");
scanf("%d", &n);
printf ("\n");
printf("+");
for(i=0;i<n-2;i++)
printf("-");
printf("+\n");
for(i=1; i<n-1; i++)
{
printf("|");
for(j=1; j<n-1; j++)
if(i==n/2 && j==n/2) printf("+");
59
Збирка решених задатака из Програмског језика С – I део

else if(j==n/2 ) printf("|");


else if(i==n/2 ) printf("-");
else printf(" ");
printf("|\n");
}
printf("+");
for(i=0; i<n-2; i++)
printf("-");
printf("+\n");
getche();
return 0;
}

Испис на екрану

4.36. Саставити програм који за унети цео позитиван и непаран број n исцртава облик приказан на
слици, на слици је n=7.
#include <stdio.h>

main()
{
int i, j, n;
printf(" n= ");
scanf("%d", &n);
printf("\n");

printf("+");
for(i=0; i<n-2; i++)
printf("-");
printf ("+\n");

for(j=0; j<n-2; j++)


{
printf("|");
for(i=0;i<n-2;i++)
{
if(i==j) printf("\\");
else printf(" ");
}
printf("|\n");
}

printf ("+");
Испис на екрану for(i=0; i<n-2; i++)
printf ("-");
printf("+\n");

getche();
return 0;
}

60
Збирка решених задатака из Програмског језика С – I део

4.37. Саставити програм који за унети цео позитиван и непаран број n исцртава облик приказан на
слици, на слици је n=7.

#include <stdio.h>

main()
{
int n, i, j;
printf(" n= ");
scanf("%d", &n);
printf("\n");

printf("+");
for(i=0;i<n-2;i++)
printf("-");
printf("+\n");

for(i=1; i<n-1; i++)


{
printf("|");
for(j=1; j<n-1; j++)
if(i==n/2 && j==n/2) printf("X");
else if(i==j) printf("\\");
else if(i==n-1-j) printf("/");
else printf(" ");
printf("|\n");
}

printf("+");
for(i=0; i<n-2; i++)
printf("-");
Испис на екрану
printf("+\n");
getche();
return 0;
}

61
Збирка решених задатака из Програмског језика С – I део

5 WHILE ПЕТЉА

5.1. Саставити програм који ће пет пута исписати реченицу Pozdrav svima! употребом
WHILE петље.

#include <stdio.h>

main()
{
int i;
i=1;
while(i<=5)
{
printf("Pozdrav svima!\n");
Испис на екрану
i++;
}
getche();
return 0;
}

5.2. Саставити програм који употребом WHILE петље исписује:


а) све бројеве прве десетице,
б) само парне бројеве прве десетице
в) све бројеве прве десетице у обрнутом редоследу.

а) #include <stdio.h> б) #include <stdio.h>

main() main()
{ {
int i; int i;
i=1; i=2;
while(i<=10) while(i<=10)
{ {
printf("%d\n", i); printf("%d\n", i);
i++; i+=2;
} }
getche(); getche();
return 0; return 0;
} }

62
Збирка решених задатака из Програмског језика С – I део

Испис на екрану б)

Испис на екрану a)

в) #include <stdio.h>

main()
{
int i;
i=10;
while(i<=10 & i>0)
{
printf("%d\n", i);
i--;
}
getche();
return 0;
Испис на екрану в)
}

5.3. Саставити програм за исписивање суме природних бројева од 1 до n. Број n се уноси са


тастатуре.

#include <stdio.h>

main()
{
int n, i=1, suma=0;
printf("n= ");
scanf("%d",&n);
while(i <= n)
{ Испис на екрану
suma+= i;
i++;
}
printf("Suma prirodnih brojeva od 1 do %d je: %d\n", n, suma);
getche();
return 0;
}

63
Збирка решених задатака из Програмског језика С – I део

5.4. Саставити програм за исписивање суме сваког трећег природног броја од 1 до n. Број n се
уноси са тастатуре.

#include <stdio.h>

main()
{
int i=1, suma=0, n;
printf(" n= ");
scanf("%d",&n);
while(i<=n)
{ Испис на екрану
suma=suma+i;
i=i+3;
}
printf(" Suma svakog treceg broja, od 1 do %d, je %d\n", n,suma);
getche();
return 0;
}

5.5. Саставити програм којим се за дати природни број n израчунава сума:


1 1 1 1
S = 2 + 2 + 2 + ... +
( 2n + 1)
2
3 5 7

#include <stdio.h>
#include <math.h>

main()
{
int i=1, n;
float s=0;
printf(" n= "); scanf("%d", &n);
while(i<=n)
Испис на екрану
{
s+=1./pow(2*i+1,2);
i++;
}
printf("\n s= %f\n", s);
getche();
return 0;
}

5.6. Саставити програм за израчунавање суме s квадрата парних и кубова непарних природних
бројева од n до m (n<m).

#include <stdio.h>
#include <math.h>

main()
{
int i, n, m;
long s=0;
64
Збирка решених задатака из Програмског језика С – I део

printf(" n= "); scanf("%d", &n);


printf(" m= "); scanf("%d", &m);
i=n;
while(i<=m)
{
if(i%2==0) s=s+pow(i,2);
else s=s+pow(i,3);
i++;
}
printf("\n s= %ld\n", s);
getche();
return 0;
} Испис на екрану

5.7. Саставити програм којим се:


а) исписује n елемената Фибоначијевог низа;
б) израчунава и исписује сума првих n елемената Фибоначијевог низа.
Фибоначијев низ: f1=1, f2=1, fi=fi-1+fi-2, i=3, 4, 5, ...

а) #include <stdio.h> б) #include <stdio.h>

main() main()
{ {
int i=3, n, fpp=1, fp=1, fn; int i=3, n, fpp=1, fp=1, fn,s=2;
printf(" n= "); printf(" n= ");
scanf("%d", &n); scanf("%d", &n);
printf("\n f1= 1\n f2= 1\n"); while(i<=n)
while(i<=n) {
{ fn=fp+fpp;
fn=fp+fpp; s=s+fn;
fpp=fp; fpp=fp;
fp=fn; fp=fn;
printf(" f%d= %d\n", i, fn); i++;
i++; }
} printf("\n s= %d\n", s);
getche(); getche();
return 0; return 0;
} }

Испис на екрану б)

Испис на екрану а)

65
Збирка решених задатака из Програмског језика С – I део

5.8. Саставити програм за исписивање n-тог степена броја а. Оба броја се уносе са тастатуре.

#include <stdio.h>

main()
{
int a, n, i=1, stepen=1;
printf(" a= ");
scanf("%d",&a);
printf(" n= ");
scanf("%d",&n);
Испис на екрану
while(i<=n)
{
stepen*=a;
i++;
}
printf("\n Broj %d na %d-ti stepen je: %d\n",a,n,stepen);
getche();
return 0;
}

5.9. Саставити програм за израчунавање средње вредности унетих реалних бројева. Користити
број 0 као STOP кôд за крај учитавања.
#include <stdio.h>
#define STOP 0

main()
{
int n=0;
float x, suma=0;
printf("\n Unesite niz realnih brojeva (0 za kraj):\n\n");
scanf("%f",&x);
while(x!=STOP)
{
suma += x;
n++;
scanf("%f",&x);
}
if (n==0)
printf("\n Nije zadat niz realnih brojeva.\n\n");
else
printf("\n Aritmeticka sredina zadatog niza je %.3f\n",suma/n);
getche();
return 0;
}

Испис на екрану

66
Збирка решених задатака из Програмског језика С – I део

5.10. Саставити програм који ће учитавати један за другим низ бројева. Крај уноса означен је
нулом. Наћи и исписати аритметичку средину учитаних бројева узимајући у обзир само оне бројеве
који су већи или једнаки 2 и мањи или једнаки 6.
#include <stdio.h>

main()
{
int i=0;
float x, suma=0, sredina;
printf("\n Unesite niz realnih brojeva (0 za kraj):\n\n");
while(1)
{
scanf("%f",&x);
if(x==0)
{
sredina=suma/i;
printf(" Aritmeticka sredina: %.3f\n", sredina);
}
if(x>=2 && x<=6)
{
suma+=x;
i++;
}
}
getche();
return 0;
}

Испис на екрану

5.11. Саставити програм који ће учитати природне бројеве m и n (m>n). Уколико услови приликом
уноса нису испуњени поновити учитавање. Наћи и исписати биномни коефицијент:
m m!
b= 
  ( − n )!
n n ! m

#include <stdio.h>

main()
{
int m=0, n, i, brojilac=1, imenilac=1;
while(m<1 || n<1 || n>m)
{
printf("\n Unesite m i n: ");
scanf("%d%d",&m,&n);
}
for(i=m;i>m-n;i--)
brojilac=brojilac*i;
for(i=1;i<=n;i++) Испис на екрану
imenilac=imenilac*i;
brojilac=brojilac/imenilac;
printf("\n Binomni koeficijent b= %d \n ", brojilac);
getche();
return 0;
}

67
Збирка решених задатака из Програмског језика С – I део

5.12. Саставити програм који ће учитати два броја m и n. Оба броја треба да буду природна. Ако
тај услов није испињен, учитавање треба поновити. Ако је n<m, заменити m са n. Наћи и исписати
суму квадратних корена свих непарних бројева од m до n.
#include <stdio.h>
#include <math.h>

main()
{
int m=0, n, pomoc, i;
float suma=0, koren;
printf("\n Unesite m i n [0<m<n]: ");
while(m<1 || n<1)
scanf("%d%d",&m,&n);
if(m>n)
{
pomoc=n;
n=m;
m=pomoc;
}
if(m%2==0) m++;
for(i=m;i<=n;i=i+2)
{
koren=sqrt(i); Испис на екрану
suma+=koren;
}
printf("\n Suma korena je %.3f\n", suma);
getche();
return 0;
}

1 1 1 n −1 1
5.13. Саставити програм којим се за унето n рачуна сума: S = 1 − + − + ... + ( −1)
2 3 4 n
#include <stdio.h>

main()
{
int znak=1, i=1, n;
float suma=0;
printf("\n n= ");
scanf("%d",&n);
while(i<=n) Испис на екрану
{
suma+=(float)znak/i;
i++;
znak=-znak;
}
printf("\n S= %.3f\n", suma);
getche();
return 0;
}

68
Збирка решених задатака из Програмског језика С – I део


1 1 1 1
5.14. Саставити програм којим се приближно рачуна сума: S = 2
+ 2 + 2 + ... = ∑ 2
1 2 3 n =1 n
Сумирање вршити све док је општи члан већи од 10-4.

#include <stdio.h>

main()
{
int n=1;
float suma=0, clan;
clan=1/(n*n);
while(clan>1e-4) Испис на екрану
{
suma=suma+clan;
n++;
clan=1.0/(n*n);
}
printf("\n S= %.3f\n", suma);
getche();
return 0;
}

x x2 n x
n
5.15. Саставити програм којим за унто х приближно рачуна сума: S = 1 − + − ... + ( −1) + ...
1! 2! n!
Сумирање вршити до члана (укључујући и њега) који је по апсолутној вредности мањи од задатог
броја ерѕ. Исписати и колико је елемената сумирано.

#include <stdio.h>

main()
{
double suma=1.0, x, eps, clan;
int n=1, i;
printf("\n x= ");
scanf("%lf",&x);
printf("\n eps= ");
scanf("%lf",&eps);
clan=x;
Испис на екрану
while(abs(clan)>=eps)
{
suma+=clan;
clan=x;
n++;
for(i=2;i<=n;i++)
clan=-clan*(-x/i);
}
printf("\n S= %lf", suma);
printf("\n Br.elemenata= %d\n", n);
getche();
return 0;
}

69
Збирка решених задатака из Програмског језика С – I део

5.16. Саставити програм којим се за унето х приближно рачуна сума:


a ( a − 1) a ( a − 1) ... ( a − n + 1)
S = 1 + ax + x 2 + ... + x n + ...
2! n!
где је а реалан број (уноси се са тастатуре). Сумирати до члана који је по апсолутној вредноси мањи
од задатог броја ерѕ.
#include <stdio.h>

main()
{
double suma=1.0, x, a, eps, clan;
int i=0;
printf("\n x= ");
scanf("%lf",&x);
printf("\n a= ");
scanf("%lf",&a);
printf("\n eps= ");
scanf("%lf",&eps); Испис на екрану
clan=x;
while(fabs(clan)>=eps)
{
i++;
clan=clan*(a-i+1)*x/i;
suma=suma+clan;
}
printf("\n S= %lf\n", suma);
getche();
return 0;
}

5.17. Саставити програм којим се исписује највећи заједнички делилац (NZD) бројева a и b
помоћу Еуклидовог алгоритма:
- ако је a=b, тада је NZD=a и то је крај алгоритма;
- ако је а≠b, тада од већег броја одузимамо мањи и враћамо се на први корак.

#include <stdio.h>

main()
{
int a, b;
printf(" a= ");
scanf("%d",&a);
printf(" b= ");
scanf("%d", &b); Испис на екрану
while(a!=b)
{
if(a>b) a-=b;
else b-=a;
}
printf("\n NZD=: %d\n",a);
getche();
return 0;
}

70
Збирка решених задатака из Програмског језика С – I део

5.18. Саставити програм који испитује да ли је унети број Нивенов. Нивенов број је број који је
дељив са сумом својих цифара.

#include <stdio.h>

main()
{
int n, k, suma=0;
printf(" n= ");
scanf("%d", &n);
k=n;
while(k > 0)
{ Испис на екрану
suma+=k%10;
k /= 10;
}
if(k%suma==0)
printf("\n Broj %d jeste Nivenov\n", n);
else
printf("\n Broj %d nije Nivenov\n", n);
getche();
return 0;
}

5.19. Саставити програм који за унети природни број исписује број чије су цифре у обрнутом
редоследу унетог броја.

#include <stdio.h>

main()
{
int n, obrnuti=0;
printf(" n= ");
scanf("%d", &n);
while(n > 0)
Испис на екрану
{
obrnuti = obrnuti*10 + n%10;
n /= 10;
}
printf("\n Obruti: %d\n", obrnuti);
getche();
return 0;
}

5.20. Саставити програм којим се дати природни број раставља на просте факторе. На пример, за
28 треба исписати: 2 2 7.
#include <stdio.h>

main()
{
int m, n, k;
printf(" n= ");

71
Збирка решених задатака из Програмског језика С – I део

scanf("%d",&n);
printf("\n\n Prosti faktori:");
m=n/2;
for (k=2;k<=m;k++)
{
while(n%k==0)
{
printf("\n%3d", k);
n/=k;
}
}
getche(); Испис на екрану
return 0;
}

5.21. Саставити програм којим се исписују сви Питагорини бројеви а, b и c за 1 ≤ a ≤ 20 ,


1 ≤ b ≤ 20 . Бројеви су Питагорини ако важи: a2+b2=c2.

#include <stdio.h>

main()
{
int a, b, c, zbir;
printf(" Pitagorini brojevi:\n");
for(a=1;a<=20;a++)
{
for(b=1;b<=20;b++)
{
zbir=a*a+b*b;
c=1;
while(c*c<=zbir)
{
if(c*c==zbir)
printf(" a=%2d b=%2d c=%2d\n", a,b,c);
c++;
}
}
}
getche();
return 0;
}

Испис на екрану

72
Збирка решених задатака из Програмског језика С – I део

6 DO...WHILE ПЕТЉА

6.1. Саставити програм који ће пет пута исписати реченицу Pozdrav svima! употребом DO
WHILE петље.
#include <stdio.h>

main()
{
int i;
i=1;
do
{
printf("Pozdrav svima!\n");
i++;
} Испис на екрану
while(i<=5);
getche();
return 0;
}

6.2. Саставити програм који употребом DO WHILE петље исписује:


а) све бројеве прве десетице,
б) само парне бројеве прве десетице
в) све бројеве прве десетице у обрнутом редоследу.

а) #include <stdio.h>

main()
{
int i;
i=1;
do
{
printf("%d\n", i);
i++;
}
while(i<=10);
getche();
return 0; Испис на екрану а) Испис на екрану в)
}

73
Збирка решених задатака из Програмског језика С – I део

б) в)
#include <stdio.h> #include <stdio.h>

main() main()
{ {
int i; int i;
i=2; i=10;
do do
{ {
printf("%d\n", i); printf("%d\n", i);
i+=2; Испис на екрану б) i--;
} }
while(i<=10); while(i<=10 & i>0);
getche(); getche();
return 0; return 0;
} }

6.3. Саставити програм који омогућује унос целих бројева све док препозна број чији квадрат
припада првој стотини.

#include <stdio.h>

main()
{
int n;
do
{
printf(" n= ");
scanf("%d", &n);
}
Испис на екрану
while(n*n<=0 || n*n>100);
printf("\n Kvadrat broja %d [%d] pripada prvoj stotini.\n", n, n*n);
getche();
return 0;
}

6.4. Саставити програм којим се исписују сви степени броја 2 који нису већи од унете вредности
променљиве границе, а која је већа од броја 2.
#include <stdio.h>

main()
{
int stepen,granica;
printf(" Unesite granicu: ");
scanf("%d",&granica);
stepen=1;
do
{
printf(" %d\n",stepen);
stepen*=2; Испис на екрану
}
while(stepen <= granica);
getche();
return 0;
}
74
Збирка решених задатака из Програмског језика С – I део

6.5. Саставити програм којим се израчунава број π=3.1415926... коришћењем формуле:


π 1 1 1
= 1 − + − + ... Рачунање прекинути када се добије члан суме чија је апсолутна вредност мања
4 3 5 7
од позитивног задатог броја ерѕ.

#include <stdio.h>
#include <math.h>

main()
{
float znak=-1.0;
int i=1;
float clan=1.0, suma=1.0, eps;
Испис на екрану
printf(" eps= ");
scanf("%f", &eps);
do
{
clan=(float)znak/(2*i+1);
suma+=clan;
znak=-znak;
i++;
}
while(fabs(clan) > eps);
printf("\n Pi= %f", 4*suma);
getche();
return 0;
}

1 1 1
6.6. Саставити програм којим се међу бројевима 1, 1+ , 1+ + , ... проналази први већи од
2 2 3
задатог броја а.

#include <stdio.h>

main()
{
float a, i=0, s=0;
printf(" a= ");
scanf("%f",&a);
do
Испис на екрану
{
i++;
s=s+1/i;
}
while(s<a);
printf("\n S=%.3f", s);
getche();
return 0;
}

75
Збирка решених задатака из Програмског језика С – I део

6.7. Саставити програм који ће израчунати квадратни корен Њутновом методом са задатом
1 x
тачношћу. Њутнова формула гласи: yi +1 =  yi +  , где је х број чији се тражи корен, а почетна
2 yi 
итерација y0 = x + 1 .
#include <stdio.h>
#include <math.h>

main()
{
float x, y, z, eps;
printf(" Unesite broj x= ");
scanf("%f", &x);
printf(" Unesite tacnost eps= "); Испис на екрану
scanf("%f", &eps);
y=x+1;
do
{
z=y;
y=0.5*(y+x/y);
}
while(fabs(z-y) > eps);
printf("\n Koren iz %.3f je %.3f", x, y);
getche();
return 0;
}

6.8. Саставити програм који на основу задатог опсега унутар прве стотине исписује бројеве
дељиве са 4. Уколико се не зада коректна граница програм треба да захтева поновни унос. У сваком
реду исписати по десет бројева.
#include <stdio.h>

main()
{
int x, a, b, brojac=0;
do
{
printf(" Unesite granice opsega [cele brojeve od 1 do 100]: ");
scanf("%d%d",&a,&b);
}
while(a<1 || a>b || b<=a || b>100);
printf("\n Brojevi u opsegu od %d do %d deljivi sa 4:\n", a, b);
for(x=a;x<=b;x++)
{
if(x%4==0)
{
printf(" %d ", x);
brojac++;
}
if(brojac%10==0)
printf("\n");
}
getche();
return 0;
}

76
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

6.9. Саставити програм којим се врши сабирање и исписује сума свих троцифрених бројева
дељивих са 64. Колико има таквих бројева?

#include <stdio.h>

main()
{
int i=100,s=0,br=0;
do
{
if(i%64==0) Испис на екрану
{
s+=i;
br++;
}
i++;
}
while (i<=999);
printf("\n Suma= %d", s);
printf("\n Brojeva= %d", br);
getche();
return 0;
}

6.10. Саставити програм који ће прво да учита број m. Тај број мора бити већи од 0 и мањи од 10.
Ако тај услов није испуњен учитавање поновити. Програм треба даље да учитава низ бројева, а унос
се завршава са нулом. Програм треба наћи и исписати број n који показује колико међу учитаним
бројевима има оних код којих је прва цифра m.

Испис на екрану

77
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h>
#include<math.h>

main()
{
int m, n, k, br=0;
float x;
do
{
printf("\n m= ");
scanf("%d", &m);
}
while (m<=0 || m>=10);
printf ("\n Unesite cele brojeve [0 za kraj]:\n");
scanf("%d",&k);
do
{
n=log10 (k); /*Nadji prvu cifru.*/
/*Moze i ovako: n=k; while(n>9) n/=10;.....*/
n=k/pow(10,n); /*... n je prva cifra*/
if(n==m) br++;
scanf("%d",&k);
}
while(k!=0);
printf("\n %d brojeva ima prvu cifru %d ", br, m);
getche();
return 0;
}

78
Збирка решених задатака из Програмског језика С – I део

7 СКОКОВИ

7.1 BREAK

7.1. Шта се исписује на екрану након извршавања следећег програмског кода:


а)
#include <stdio.h>

main()
{
int i;
for(i=1;i<=10;i++)
{
if(i==5) break;
printf(" i=%d \n",i); Испис на екрану а)
}
getche();
return 0;
}

б) #include <stdio.h>

main()
{
int i, j;
for(i=1;i<=5;i++)
for(j=1;j<=10;j++)
{
if(j==3) break;
printf("i=%d j=%d\n",i,j);
}
getche();
return 0; Испис на екрану б)
}

79
Збирка решених задатака из Програмског језика С – I део

7.2. Саставити програм који ће учитавати позитивне целе бројеве и исписивати њихове квадрате
све док не причита негативни број.

#include <stdio.h>

main()
{
int i;
while(1)
{
printf(" i= "); scanf("%d",&i);
if (i<0) break;
printf(" i*i= %d\n\n", i*i);
}
getche();
return 0;
}
Испис на екрану

7.3. Саставити програм који са тастатуре копира на екран низ целих бројева све док се не унесе
100 или број 0 као STOP код.
#include <stdio.h>
#define STOP 0

main()
{
int i,x;
printf(" Unesite cele brojeve [100 njih ili 0 za kraj unosa]:\n\n");
for(i=0; i<=100; i++)
{
scanf("%d",&x);
if(x==STOP)
break;
printf("\n% d",x);
}
getche();
return 0;
}

Испис на екрану

80
Збирка решених задатака из Програмског језика С – I део

7.4. Саставити програм који ће исписати први број (ако постоји) који је мањи од 500, а дељив са
бројевим 3, 4, 5 и 7.
#include <stdio.h>

main()
{
int i;
for(i=1; i<=500; i++) Испис на екрану
if(i%3==0 && i%4==0 && i%5==0 && i%7==0)
{
printf("%d\n", i);
break;
}
getche();
return 0;
}

n
1
7.5. Саставити програм који за унето n рачуна суму s = ∑i
i =1
2
. Програм треба да ради за

произвољан број уноса n све док за његову вредност не прочита нулу или негативни број..
#include <stdio.h>

main()
{
int n, i;
float s;
while(1)
{
printf(" n= ");
scanf("%d", &n);
if(n <= 0) break;
s=0;
for(i=1; i<=n; i++)
s+=1./(i*i);
printf (" S= %.6f\n\n", s);
}
getche();
return 0; Испис на екрану
}

7.6. Саставити програм који ће прво учитати број n који означава број елемената низа, а затим
учитава елементе низа. Када прочита елементе треба израчунати и исписати аритметичку средњу
1 n 1 n 2 2
вредност s = ∑
n i =1
ai и стандардну девијацију d = ∑ ai − si . Програм треба да обрађује
n i =1
произвољан број комплета све док за број елемената низа не прочита нулу или негативни број.

81
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h>

main()
{
while(1)
{
double a, s, d;
int n,i;
printf("\n n= ");
scanf("%d", &n); Испис на екрану
if(n <= 0) break;
printf(" Elementi: ");
s=0, d=0;
for(i=1; i<=n; i++)
{
scanf("%lf",&a);
s+=a;
d+=a*a;
}
s/=n;
d=sqrt(d/n-s*s);
printf(" s= %.4f\n", s);
printf(" d= %.4f\n", d);
}
getche();
return 0;
}

7.7. Саставити програм који ће исписати све просте бројеве од 1 до 100. Број је прост ако је
дељив само са 1 и самим собом.
#include <stdio.h>

main()
{
int i,j,m;
float x;
for(i=1; i<=100; i=i+1)
{
x=i;
m=sqrt(x);
for(j=2; j<=m; j++)
if(i%j==0) break;
if(i==2 || i%j!=0)
printf(" %2d",i);
}
getche();
return 0;
}

Испис на екрану

82
Збирка решених задатака из Програмског језика С – I део

7.2 CONTINUE

7.8. Шта се исписује на екрану након извршавања следећег програмског кода:


а)
#include <stdio.h>

main()
{
int i;
for(i=1;i<=10;i++)
{
if(i==5) continue;
printf(" i=%d \n",i);
}
getche();
return 0;
} Испис на екрану а)

б) #include <stdio.h>

main()
{
int i, j;
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
{
if(j==2) continue;
printf("i=%d j=%d\n",i,j);
}
getche();
return 0;
}
Испис на екрану б)

7.9. Саставити програм користећи наредбу continue који ће исписати парне бројеве прве
десетице.

#include <stdio.h>

main()
{
int i;
for(i=1;i<10; i++)
{
if((i%2)!=0) continue;
printf(" %d\n", i); Испис на екрану
}
getche();
return 0;
}

83
Збирка решених задатака из Програмског језика С – I део

7.10. Које вредности променљиве х се исписују на екран након извршавања следећег програма:
а)
#include <stdio.h>

main()
{
int i, x=0;
for(i=1; i<20; i++)
{
if(i%5==0) continue;
x++;
if(i==10) break;
printf("\n x=%d", x);
}
getche();
return 0;
}

Испис на екрану а)

б) #include <stdio.h>

main()
{
int i,x=0;
for(i=1; i<20; i++)
{
if(i%8==0) continue;
x++;
if(i==8||i==12||i==16) break;
printf ("\n x=%d", x);
}
getche();
Испис на екрану б)
return 0;
}

7.11. Саставити програм који исписује све бројеве мање од 20 који нису дељиви са бројем 3.
#include <stdio.h>

main()
{
int i;
for(i=1; i<=20; i++)
{
if(i%3==0) continue;
printf(" %d\n", i);
}
getche();
return 0;
}

Испис на екрану

84
Збирка решених задатака из Програмског језика С – I део

n
1
7.12. Саставити програм за рачунање суме s = ∑i
i =1
2
за позитивне вредности n. За сваки негативни

број n тражи нову вредност, а за n=0 прекида извршавање.

#include <stdio.h>

main()
{
int n, i;
float s;
while(1)
{
printf ("\n n= ");
scanf("%d", &n);
if(n == 0) break;
if(n < 0) continue;
s=0;
for(i=1; i<=n; i++)
s+=1./(i*i);
printf (" s= %.6f\n", s);
}
getche();
return 0;
}
Испис на екрану

7.3 GOTO

7.13. Шта ће се исписати на екрану, уколико се унесу бројеви 5, 7 и 3 након извршавања следећег
програма: #include <stdio.h>
main()
{
int opcija;
start: printf(" Birati opciju od 1 do 3: ");
scanf("%d", &opcija);
if(opcija<1 || opcija>3)
goto start;
else if(opcija==1)
goto Num1;
else if(opcija==2)
goto Num2;
else if(opcija==3)
goto Num3;
Num1: printf(" Izabrana je opcija A.\n");
goto End;
Num2: printf(" Izabrana je opcija B.\n");
goto End;
Num3: printf(" Izabrana je opcija C.\n");
goto End;
End:;
getche();
return 0;
}

85
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

7.14. Саставити програм који ће понављати захтев за уношење броја све док се број не унесе у
задатом опсегу, и који ће цртати хистограм вредности ако је у задатом опсегу.

#include <stdio.h>

main()
{
int i, n;
start: printf(" Unesite ceo broj od 0 do 10: ");
scanf("%d", &n);
if(n<0 || n>10)
goto start;
else if (n==0)
goto Loc0;
else
goto Loc1;
Loc0: printf("\n Izabran je broj 0 za KRAJ.\n\n");
goto End;
Loc1: for(i=0;i<n;i++)
printf("X");
printf("\n\n");
goto start;
End: ;
getche();
return 0;
}

Испис на екрану

86
Збирка решених задатака из Програмског језика С – I део

7.15. Саставити програм који ће исписати бројеве прве десетице помоћу goto наредбе.

#include <stdio.h>

main()
{
int i=1;
poc: printf(" %d", i); Испис на екрану
i++;
if(i<=10)
goto poc;
getche();
return 0;
}

7.16. Саставити програм који ће за унети природан број n исписати производ његових цифара.
#include <stdio.h>

main()
{
int n, a, p=1;
printf(" n= ");
scanf("%d",&n); Испис на екрану
poc: a=n%10;
p=p*a;
n=n/10;
if(n!=0)
goto poc;
printf(" p= %d", p);
getche();
return 0;
}

7.17. Саставити програм којим се дати природни број раставља на просте факторе. На пример, за
28 треба исписати: 2 2 7.
#include <stdio.h> else
{
main() f++;
{ goto poc;
int n, f=2; }
printf(" n= "); }
scanf("%d",&n); getche();
printf(" %d=1",n); return 0;
poc: if(n!=1) }
{
if(n%f==0)
{
printf("*%d",f);
n=n/f;
goto poc;
} Испис на екрану

87
Збирка решених задатака из Програмског језика С – I део

7.18. Саставити програм који ће учитавати реалне бројеве све док се не учита нула. Затим треба
исписати колико је бројева учитано, колико је међу учитаним бројевима позитивно, а колико
негативно и аритметичку средину учитаних бројева.

#include <stdio.h>

main()
{
float n, br=0, poz=0, neg=0, s=0, as;
poc: printf("\ Ucitaj broj: ");
scanf("%f",&n);
if(n!=0)
{
br++;
s=s+n;
if(n>0) poz++;
else neg++;
goto poc;
} Испис на екрану
as=s/br;
printf("\n Ucitano: %.0f brojeva.", br);
printf("\n Pozitivnih: %.0f brojeva. ", poz);
printf("\n Negativnih: %.0f brojeva. ", neg);
printf("\n Aritmeticka sredina: %.3f", as);
getche();
return 0;
}

7.4 SWITCH ... CASE

7.19. Саставити програм који за унету редни број од 1 до 7 исписати одговрајући дан у недељи.
#include <stdio.h> case 5:
printf("\n petak");
main() break;
{ case 6:
int x; printf("\n subota");
printf(" n= "); break;
scanf("%d",&x); case 7:
switch(x) printf("\n nedelja");
{ break;
case 1: default:
printf("\n ponedeljak"); printf("\n GRESKA");
break; break;
case 2: }
printf("\n utorak"); getche();
break; return 0;
case 3: }
printf("\n sreda");
break;
case 4:
printf("\n cetvrtak");
break; Испис на екрану

88
Збирка решених задатака из Програмског језика С – I део

7.20. Саставити програм који исписује на екрану да ли је унето слова самогласник или сугласник.

#include <stdio.h>

main()
{
char x;
printf(" Unesite slovo: ");
Испис на екрану
scanf("%c",&x);
switch (x)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
printf(" %c je samoglasnik",x);
break;
default:
printf(" %c je suglasnik",x);
}
getche();
return 0;
}

7.21. Шта се исписује на екрану након извршавање следећег програма:


#include <stdio.h>

main()
{
int a=6, b=4;
switch (a%b)
{ Испис на екрану
case 0:
a++;
b++;
case 1:
a++;
b++;
break;
case 2:
a--;
b--;
case 3:
a--;
b++;
break;
}
printf (" a=%d, b=%d", a, b);
getche();
return 0;
}
89
Збирка решених задатака из Програмског језика С – I део

7.22. Саставити програм који за унети знак операције (+, -, *, /) и два реална операнда исписује
резултат операција.
#include <stdio.h>

main()
{
float op1,op2;
char op;
printf(" Operator: ");
scanf ("%c", &op);
printf(" Operand1: ");
scanf ("%f", &op1);
printf(" Operand2: ");
scanf ("%f", &op2); Испис на екрану
switch(op)
{
case '+':
printf("Vrednost: %.2f\n", op1 + op2);
break;
case '-':
printf("Vrednost: %.2f\n", op1 - op2);
break;
case '*':
printf("vrednost: %.2f\n", op1 * op2);
break;
case '/':
if (op2 == 0)
printf("Greska! Deljenje nulom!\n");
else
printf("\n Rezultat: %.2f\n", op1 / op2);
break;
default:
printf(" Greska! Pogresan operator\n");
}
getche();
return 0;
}
Испис на екрану

7.23. Саставити програм који ће учитати дужине страница правоугаоника, а затим на основу
избора опција, рачуна и исписује обим O = 2(a + b) , површину P = ab или дужину дијагонале
d = a 2 + b 2 тог правоугаоника.
#include <stdio.h>
#include <math.h>

main()
{
int i;
float a, b, O, P, d;
printf("\n a= ");
scanf("%f", &a);
printf(" b= ");
scanf("%f", &b);
if(a>0 && b>0)
{
printf("\n\n Zelite da izracunate:");

90
Збирка решених задатака из Програмског језика С – I део

printf("\n 1 - Obim\n 2 - Povrsinu\n 3 - duzinu dijagonale");


printf("\n Izaberite opciju: ");
scanf("%d",&i);
switch(i)
{
case 1:
O=2*(a+b);
printf("\n Obim= %.2f", O);
break;
case 2:
P=a*b;
printf("\n Povrsina= %.2f", P);
break;
case 3:
d=sqrt(a*a+b*b);
printf("\n Dijagonala= %.2f", d); Испис на екрану
break;
default:
printf("Izabrali ste pogresan broj.");
break;
}
}
else printf ("GRESKA!!!");
getche();
return 0;
}

7.24. Саставити програм који за унету годину и редни број месеца у години исписује број дана у
том месецу. Узети у обзир преступне године.
#include <stdio.h>

main()
{
int mesec, godina, BrDana;
printf(" Unesite godinu: ");
scanf("%d", &godina);
printf(" Unesite redni broj meseca u godini: ");
scanf("%d", &mesec);
switch(mesec)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
BrDana=31;
break;
case 4: case 6: case 9: case 11:
BrDana=30;
break;
case 2:
BrDana=28+(godina%4==0 && godina%100!=0 || godina%400==0);
break;
default:
BrDana=0;
break;
}
if(BrDana!=0)
printf(" Mesec ima %d dana.\n", BrDana);
getche();
return 0;
}

91
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

7.25. Саставити програм за исписивање наредног датума у односу на задати дан. Програм треба да
чита датуме и исписује резултате све док за једну компоненту датума не прочита нулу.

#include <stdio.h>

main()
{
int dan, mesec, godina, d;
while (1)
{
printf(" Danasnji dan: ");
scanf("%d%d%d", &dan, &mesec, &godina);
if(dan==0 || mesec==0 || godina==0) break;
switch (mesec)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
d=31;
break;
case 4: case 6: case 9: case 11:
d=30;
break;
case 2:
d=28+(godina%4==0 && godina%100!=0 || godina%400==0);
break;
}
if(dan<d) dan++;
else
{
dan=1;
if(mesec<12) mesec++;
else
{
mesec=1;
godina++;
}
}
printf(" Sutrasnji dan: %2.2d %2.2d %d\n\n", dan, mesec, godina);
}
getche();
return 0;
}

92
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

7.26. Дато је n инструкција кретања учитавањем n вредности променљиве a ∈ {1, 2,3, 4} . Ако 1
представља кретање на север, 2 на исток, 3 на југ, 4 на запад, саставити програм који исписује
позиције тачке која полази из координатног почетка. Свака инструкција задаје кретање за дужину d.

#include <stdio.h>

main()
{
int i, n, a;
float x=0, y=0, d;
printf(" n= ");
scanf("%d", &n);
printf(" d= ");
scanf("%f", &d);
printf(" Unesite kod pravca kretanja");
printf("\n 1-sever, 2-istok, 3-jug, 4-zapad\n");
for(i=1;i<=n;i++)
{
printf (" Kod= ");
scanf ("%d", &a);
switch (a)
{
case 1:
y=y+d;
break;
case 2:
x=x+d;
break;
case 3:
y=y-d;
break;
case 4:
x=x-d; Испис на екрану
break;
}
}
printf (" Polozaj: x= %2.2f y= %2.2f\n", x, y);
getche();
return 0;
}

93
Збирка решених задатака из Програмског језика С – I део

8 КАРАКТЕРИ –
ЗНАКОВНИ УЛАЗ И ИЗЛАЗ

Табела 8.1: Функције за читање и писање знакова без конверзије дефинисане у библиотеци <stdio.h>
функција значење
getchar() Функција чита следећи знак, укључујући и беле знакове са главног улаза
рачунара (тастатуре). Вредност функције је кôд прочитаног знака или
симболичка константа EOF (end of file) уколико је прочитани сигнал за крај
датотеке као и у случају грешке у току читања. Резултат је типа int. Сигнал
за крај датотеке преко тастатуре под оперативним системом MS-DOS се
задаје управљачким знаком ctrl+Z.
putchar(c) Функција исписује знак с на главном излазу рачунара (екрану). Тип
аргумента је int. Вредност функције је кôд исписаног знака или
симболичка константа EOF у случају грешке. Резултат је типа int.
gets(s) Функција чита ред текста (до знака за прелазак у нови ред \n) са главног
улаза рачунара (тастатуре) и смешта га, као бочни ефекат у ниску s (типа
char[], односно char*). Уместо знака \n у низ s се поставља знак \0.
Вредност функције у случају наилска на крај датотеке, или у случају
откривања грешке у току читања, једнака је симболичкој константи NULL,
односно почетној адреси низа ѕ у случају успешног читања.
puts(s) Функција исписује ред ниске s (типа char[], односно char*) до
завршног знака \0 као ред текста на главном излазу рачунара (екрану),
додајући знак за прелазак у нови ред (\n) иза последњег знака. Ако текст у
низу s садржи и знакове \n, резултат ће бити више исписаних редова.
Вредност функције (типа int) је не-негативни број, односно симболичка
константа EOF у случају откривања грешке у току испитивања.
* Функције gets(s)и puts(s)применићемо у област о стринговима.

Табела 8.2: Функције за испитивање знакова дефинисане у библиотеци <ctype.h>


функција значење
isalnum(c) Да ли је c слово или цифра?
isalpha(c) Да ли је c слово?
islower(c) Да ли је c мало слово?
isupper(c) Да ли је c велико слово?
isdigit(c) Да ли је c децимална цифра?
isxdigit(c) Да ли је c хексадецимална цифра?

94
Збирка решених задатака из Програмског језика С – I део

isspace(c) Да ли је c бели знак?


isgraph(c) Да ли је c штампајући знак, али није размак?
isprint(c) Да ли је c штампајући знак (укључујући и размак)?
ispunct(c) Да ли је c специјални знак (штампајући али није слово ни цифра)?
iscntrl(c) Да ли је c управљачки знак?
tolower(c) Ако је c велико слово, вредност функције је кôд одговарајућег малог слова,
а иначе вредност функције је с.
toupper(c) Ако је c мало слово, вредност функције је кôд одговарајућег великог слова,
а иначе вредност функције је с.
* Вредност свих функција је типа logical, а тип аргумента c је int (вредност треба да је кôд неког знака). За
логичку неистину дају неку ненулту вредност, а не обавезно вредност 1, као што дају релацијски и логички
оператори.

8.1. Шта се исписује на екрану након извршавања следећег програмског кода:

#include <stdio.h>

main()
{
putchar('\n');
putchar('a');
putchar('\n'); Испис на екрану
putchar(97); (Задатак 2а)
putchar('\n'); Испис на екрану Са тастатуре је унето: А
putchar('A'+ 10); (Задатак 1)
putchar('\n');
putchar('a'+ 3);
getche();
return 0;
}

Испис на екрану
(Задатак 2б)
Са тастатуре је унето:
Programski jezik C

8.2. Саставити програм који:


а) чита са тастатуре један знак и исписује га на екрану.
б) чита са тастатуре неограничени број каректера све док се не учита EOF и исписује унете
карактере на екрану.

а) #include <stdio.h> б) #include <stdio.h>

main() main()
{ {
int c; int c;
c=getchar(); while(c!=EOF)
putchar(c); {
getche(); c=getchar();
return 0; putchar(c);
} }
getche();
return 0;
}

95
Збирка решених задатака из Програмског језика С – I део

8.3. Саставити програм за:


а) унос текста са тастатуре све док се не унесе тачка (.) и приказује број карактера до тачке.
б) унос текста са тастатуре све док се не учита EOF и приказује укупан број карактера.

а)
#include <stdio.h>

main()
{
int c, n=0;
c=getche();
while(c != '.')
{ Испис на екрану а)
Са тастатуре је унето:
c=getche(); Programski jezik C.
n++;
}
printf("\n Broj karaktera %d.\n", n);
getche();
return 0;
}

б) #include <stdio.h>

main()
{
int c, n=0;
while((c=getchar()) != EOF)
n++;
printf("\n Broj karaktera: %d.\n",n);
getche(); Испис на екрану б)
return 0; Са тастатуре је унето:
} Programski jezik C.

8.4. Саставити програм који броји децималне цифре у улазном тексту до ознаке за крај уноса
ЕОF.

Први начин: Други начин:


#include <stdio.h> #include <stdio.h>
#include <ctype.h>
main()
{ main()
int c, n=0; {
while((c=getchar()) != EOF) int c, n=0;
if(c>='0'&& c<='9') while((c=getchar()) != EOF)
n++; if(isdigit(c))
printf("\n Broj cifara: %d.\n", n); n++;
getche(); printf("\n Broj cifara: %d.\n",n);
return 0; getche();
} return 0;
}

96
Збирка решених задатака из Програмског језика С – I део

Испис на екрану
Са тастатуре је унето:
Broj 1 i broj 156

8.5. Саставити програм који броји празне знакове (размак, хоризонтални табулатор и нови ред),
слова, децималне цифре као и све знакове улазног текста до ознаке за крај уноса ЕОF.

Први начин:
#include <stdio.h>

main()
{
int c, nk=0, nr=0, nb=0, ns=0;
while((c=getchar()) != EOF)
{
if ((c==' ') || (c=='\t') || (c=='\n')) nr++;
if (c>='0' && c<='9') nb++;
if ((c>='a' && c<='z') || (c>='A' && c<='Z')) ns++;
nk++;
}
printf(" Razmaci: %d\n", nr);
printf(" Cifre: %d\n", nb);
printf(" Slova: %d\n", ns);
printf(" Ukupno: %d\n",nk);
getche();
return 0;
}

Други начин:
#include <stdio.h>
#include <ctype.h>

main()
{
int c, nk=0, nr=0, nb=0, ns=0;
while((c=getchar()) != EOF)
{
if (isspace(c)) nr++;
if (isdigit(c)) nb++;
if (isalpha(c)) ns++;
Испис на екрану
nk++;
}
printf(" Razmaci: %d\n", nr);
printf(" Cifre: %d\n", nb);
printf(" Slova: %d\n", ns);
printf(" Ukupno: %d\n",nk);
getche();
return 0;
}

97
Збирка решених задатака из Програмског језика С – I део

8.6. Саставити програм за одређивање броја самогласника и сугласника у улазном тексту. Унос
текста се завршава сигналом ЕОF.

#include <stdio.h>

main()
{
int c, sugl=0, samog=0;
while((c=getchar()) != EOF)
{
if((c>='a' && c<='z') || (c>='A' && c<='Z'))
if(c=='a' || c=='e' || c=='i' || c=='o' || c=='u'
|| c=='A' || c=='E' || c=='I' || c=='O' || c=='U')
samog++;
else
sugl++;;
}
printf("Samoglasnika: %d\n", samog);
printf("Suglasnika: %d\n", sugl);
getche();
return 0;
} Испис на екрану
Са тастатуре је унето:
Programski jezik C

8.7. Саставити програм за одређивање броја великих слова, малих слова и цифара у улазном
тексту. Унос текста се завршава сигналом ЕОF.
Први начин:
#include <stdio.h>

main()
{
int c, veliko=0, malo=0, cifra=0;
while((c = getchar()) != EOF)
{
if(c >= 'A' && c <= 'Z') veliko++;
if(c >= 'a' && c <= 'z') malo++;
if(c >= '0' && c <= '9') cifra++; Испис на екрану
} Са тастатуре је унето:
printf(" Velika: %d\n", veliko); 1 Programski jezik C 33
printf(" Mala: %d\n", malo);
printf(" Cifre: %d\n", cifra);
getche();
return 0;
}
Други начин:
#include <stdio.h>
#include <ctype.h>

main()
{
int c, veliko=0, malo=0, cifra=0;
while((c = getchar()) != EOF)
{
veliko += isupper(c) != 0;
malo += islower(c) != 0;
cifra += isdigit(c) != 0;
98
Збирка решених задатака из Програмског језика С – I део

}
printf(" Velika: %d\n", veliko);
printf(" Mala: %d\n", malo);
printf(" Cifre: %d\n", cifra);
getche();
return 0;
}

8.8. Саставити програм за одређивање броја појављивања слова А у улазном тексту и изразити ту
вредност процентуално у односу на све унете знаке. Унос текста се завршава сигналом ЕОF.
#include <stdio.h>

main()
{
int c, n=0, u=0;
float p;
while((c = getchar()) != EOF)
{
u++;
if(c=='A') n++;
}
Испис на екрану
p=(float)n/u*100;
Са тастатуре је унето:
printf("\n Ukupno znakova: %d", u); Slova A A A
printf("\n Ukupno slovo A: %d", n);
printf("\n U procentima: %.2f%\n", p);
getche();
return 0;
}

8.9. Саставити програм за одређивање броја празних карактера, као и броја знакова: тачка, зарез,
двотачка и тачка-зарез. Унос текста се завршава сигналом ЕОF.
#include <stdio.h>

main()
{
int c, razmak=0, n=0;
while((c=getchar())!=EOF)
switch(c)
{
case ' ':
razmak++;
break;
case '.':
case ',':
case ':':
case ';':
n++; Испис на екрану
break; Са тастатуре је унето:
Razni znakovi: ; , .
default:
break;
}
printf("\nRazmaci: %d", razmak);
printf("\nOstali trazeni: %d", n);
getche();
return 0;
}

99
Збирка решених задатака из Програмског језика С – I део

8.10. Саставити програм који броји карактере улазног текста до прве децималне цифре. Унос
текста се завршава сигналом EOF.
#include <stdio.h>
#include <ctype.h>

main()
{
int c, n=0;
while((c=getchar()) != EOF)
Испис на екрану
{ Са тастатуре је унето:
if(isdigit(c)) break; Petak je 5-ti dan u sedmici.
n++;
}
printf("Broj znakova: %d\n", n);
getche();
return 0;
}

8.11. Саставити програм који броји карактере улазног текста различите од децималних цифара.
Унос текста се завршава сигналом EOF.
#include <stdio.h>
#include <ctype.h>

main()
{
int c, n=0;
while((c=getchar()) != EOF)
{
if(isdigit(c)) continue; Испис на екрану
Са тастатуре је унето:
n++; Ovo je broj 5, a ovo 33.
}
printf("Broj znakova koji nisu cifre: %d\n", n);
getche();
return 0;
}

8.12. Саставити програм који испитује да ли су у унетом тексту заграде“(“ и “ )“ добро упарене.
Унос текста се завршава сигналом ЕОF.
#include <stdio.h>

main()
{
int c;
int otv=0;
while((c=getchar()) != EOF)
{
switch(c)
{ Испис на екрану
case '(': Са тастатуре је унето:
otv++; Danas je petak ((osamnaesti).
break;

100
Збирка решених задатака из Програмског језика С – I део

case ')':
otv--;
if (otv<0)
{
printf("Visak zatvorenih zagrada\n");
break;
}
}
}
if (otv==0)
printf("Zagrade su u redu\n");
else
printf("Visak otvorenih zagrada\n");
getche();
return 0;
}

8.13. Саставити програм који врши конверзију унетих великих слова у мала. Унос текста се
завршава сигналом ЕОF.
Први начин: Други начин:
#include <stdio.h>
#include <stdio.h>
main() #include <ctype.h>
{
int c; main()
while((c=getchar()) != EOF) {
{ int c;
if(c >= 'A' && c <= 'Z') while((c=getchar()) != EOF)
c = c -'A' + 'a'; putchar(tolower(c));
putchar(c); getche();
} return 0;
getche(); }
return 0;
}

Испис на екрану
Са тастатуре је унето:
Jezik C

101
Збирка решених задатака из Програмског језика С – I део

8.14. Саставити програм који врши конверзију унетих малих слова у велика. Унос текста се
завршава сигналом ЕОF.

Први начин: Други начин:


#include <stdio.h> #include <stdio.h>
#include <ctype.h>
main()
{ main()
int c; {
while((c=getchar()) != EOF) int c;
{ while((c=getchar()) != EOF)
if(c >= 'a' && c <= 'z') putchar(toupper(c));
c = c -'a' + 'A'; getche();
putchar(c); return 0;
} }
getche();
return 0;
}

Испис на екрану
Са тастатуре је унето:
Jezik C

8.15. Саставити програм који врши конверзију првог слова у велико, а сва остала у мала унете
реченице. Унос текста се завршава сигналом ЕОF.

#include <stdio.h>
#include <ctype.h>

main()
{
int c, prvi=0;
while((c=getchar()) != EOF)
{ Испис на екрану
if(isalpha(c))
{
if(prvi==0)
putchar(toupper(c));
else putchar(tolower(c));
}
else putchar(c);
prvi=1;
}
getche();
return 0;
}

102
Збирка решених задатака из Програмског језика С – I део

8.16. Саставити програм којим се копира улазни текст на екран уз раздвајање речи по једним
знаком размака. Речи су на улазу раздвојене произвољним бројем знакова размака и/или табулације.
Текст се завршава сигналом ЕОF.

#include <stdio.h>
#define NIJE_PRAZNO 'a'
#define PRAZNO ' '
#define HOR_TAB '\t'

main()
{
int c, predh_c=NIJE_PRAZNO; Испис на екрану
while((c=getchar()) != EOF)
{
if(c==HOR_TAB)
c=PRAZNO;
if(c != PRAZNO || predh_c != PRAZNO)
putchar(c);
predh_c=c;
}
getche();
return 0;
}

8.17. Саставити програм који копира улазни текст на екран, где сваку реч приказује у једној
линији. Унос текста се завршава сигналом ЕОF.
#include <stdio.h>
#define U_RECI 1
#define VAN_RECI 0

main()
{
int c, poz=VAN_RECI;
while((c=getchar()) != EOF)
{
if(c==' ' || c=='\n' || c=='\t')
Испис на екрану
{
if(poz==U_RECI)
{
putchar('\n');
poz=VAN_RECI;
}
}
else
{
poz=U_RECI;
putchar(c);
}
}
getche();
return 0;
}

103
Збирка решених задатака из Програмског језика С – I део

8.18. Саставити програм који учитава текст са улаза, и при том броји речи. Под речју се
подразумева низ не-бланко карактера (бланко карактери су ' ', '\n' и '\t').

#include <stdio.h> case U_RECI:


#define U_RECI 1 switch(c)
#define VAN_RECI 0 {
case ' ':
main() case '\t':
{ case '\n':
int c, n=0, stanje=VAN_RECI; stanje=VAN_RECI;
while ((c=getchar()) != EOF) break;
{ default:
switch(stanje) break;
{ }
case VAN_RECI: break;
switch(c) }
{ }
case ' ': printf ("Broj reci: %d\n", n);
case '\t': getche();
case '\n': return 0;
break; }
default:
n++;
stanje=U_RECI;
break;
}
break;
Испис на екрану

104
Збирка решених задатака из Програмског језика С – I део

9 ФУНКЦИЈЕ

9.1. Саставити функцију која врши сабирање два цела броја, а затим саставити програм који
тестира функцију и исписује резултат.

Први начин: Други начин (скраћени запис):


#include <stdio.h> #include <stdio.h>

/*Deklaracija i definicija funkcije*/ /*Deklaracija i definicija funkcije*/


int zbir(int a, int b) int zbir(int a, int b)
{ {
int rezultat; return (a+b);
rezultat=a+b; }
return rezultat;
} /*Glavni program*/
main()
/*Glavni program*/ {
main() /*Poziv funkcije*/
{ printf("\n%d\n", zbir(5,3));
int c; getche();
c=zbir(5,3); /*Poziv funkcije*/ return 0;
printf("\n%d\n", c); }
getche();
return 0;
}
Испис на екрану

9.2. Саставити функције за рачунање збира, производа и количника два реална броја, као и
функције за израчунавање квадрата и куба реалног броја. Затим саставити програм за израчунавање
x
израза z1 = x + y 2 , z 2 = x 3 − и z3 = ( x * y ) + ( 5 − y ) , користећи претходно формиране функције.
y
Променљиве х и у се уносе са тастатуре. Исписати резултате.

105
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h> /*Funkcija kuba*/


float kub(float a)
/*Funkcija zbira*/ {
float zbir(float a, float b) return(a*a*a);
{ }
return(a+b);
} /*Glavni program*/
main()
/*Funkcija razlike*/ {
float razlika(float a, float b) float x, y, z1, z2, z3;
{ printf(" x= ");
return(a-b); scanf("%f", &x);
} printf(" y= ");
scanf("%f", &y);
/*Funkcija proizvoda*/ z1=zbir(x,kvadrat(y));
float proizvod(float a, float b) z2=razlika(kub(x),kolicnik(x,y));
{ z3=zbir(proizvod(x,y),razlika(5,y));
return(a*b); printf("\n z1=%.2f\n", z1);
} printf("\n z2=%.2f\n", z2);
printf("\n z3=%.2f\n", z3);
/*Funkcija kolicnika*/ getche();
float kolicnik(float a, float b) return 0;
{ }
if(b==0) return 0;
else return(a/b);
}

/*Funkcija kvadrata*/
float kvadrat(float a)
{
return(a*a);
}
Испис на екрану

9.3. Саставити функцију за одређивање максимума два цела броја, а затим саставити програм
који ће за унета четири цела броја одредити највећи користећи претходну функцију, а затим
исиписати резултат.
#include <stdio.h>

int max(int a, int b)


{
if(a==b) return 0;
else if(a>b) return a;
else return b;
}
Испис на екрану
main()
{
int a, b, c, d, m;
printf("Unesite cetiri broja:\n");
scanf("%d %d %d %d", &a, &b, &c, &d);
m=max(max(a,b),max(c,d));
if(m==0) printf("Zadati brojevi su isti.");
else printf("\nMaximum= %d\n", m);
getche();
return 0;
}

106
Збирка решених задатака из Програмског језика С – I део

9.4. Шта се исписује на екрану након извршавања следећих програма.

а)
#include <stdio.h>

void fun1(int a)
{
scanf("%d", &a);
printf("\n a= %d\n", a);
}

main() Испис на екрану a)


{
int x=0; Пример приказује демонстрацију преноса
printf(" Unesite broj: "); параметара по вредности, где се пренети
fun1(x); параметри не могу мењати. Функција
printf(" x= %d\n", x); покушава да учита цео број. Због преноса
getche(); параметара по вредности ово не успева.
return 0;
}

б) в)
#include <stdio.h> #include <stdio.h>

void fun2(int x) int fun3(int x)


{ {
x*=2; return ++x;
x++; }
}
main()
main() {
{ int x=3;
int x=3; printf(" x= %d\n", x);
fun2(x); printf(" f(x)= %d\n", fun3(x));
printf(" x= %d\n", x); getche();
getche(); return 0;
return 0; }
}

Испис на екрану б)
Испис на екрану в)

9.5. Саставити програм за израчунавање површине и запремине лопте и исписивање резултата на


основу унете вредности полупречника r. За рачунање запремине и површине, као и за испис
резултата формирати одговарајуће функције.
#include <stdio.h>
#define PI 3.14

double Povrsina(double r)
{
return(4*r*r*PI);
}

107
Збирка решених задатака из Програмског језика С – I део

double Zapremina(double r)
{
return((4./3.)*r*r*r*PI);
}

void Ispis(double p, double v)


{
printf("\n Povrsina: %.2f", p);
printf("\n Zapremina: %.2f\n", v);
}

main()
{
double r, p, v;
printf(" r= ");
scanf("%lf", &r);
p=Povrsina(r);
v=Zapremina(r);
Ispis(p,v);
getche(); Испис на екрану
return 0;
}

9.6. Саставити програм за израчунавање површине троугла ако су задате координате његовог
темена. Површину троугла рачунати помоћу следећих формула:
a= ( xB − xC ) − ( yB − yC ) b= ( xC − xA ) − ( yC − y A ) c= ( x A − xB ) − ( y A − y B )
2 2 2 2 2 2
, ,
a+b+c
S= , P = S ( S − a )( S − b )( S − c ) . За израчунавање дужине страница a, b и c
2
формирати одговарајућу функцију.
#include <stdio.h>
#include <math.h>

double Stranica(double x1, double x2, double y1, double y2)


{
return(sqrt(pow(x1-x2,2)+pow(y1-y2,2)));
}

main()
{
double xA, yA, xB, yB, xC, yC, a, b, c, s, P;
printf("Koordinate temena trougla\n");
printf("- prvo teme <xA,yA>: ");
scanf("%lf%lf",&xA,&yA);
printf("- drugo teme <xB,yB>: ");
scanf("%lf%lf",&xB,&yB);
printf("- trece teme <xC,yC>: ");
scanf("%lf%lf",&xC,&yC);
a=Stranica(xB,xC,yB,yC);
b=Stranica(xC,xA,yC,yA);
c=Stranica(xA,xB,yA,yB);
s=(a+b+c)/2; Испис на екрану
P=sqrt(s*(s-a)*(s-b)*(s-c));
printf("\nPovrsina trougla: %.2f\n", P);
getche();
return 0;
}

108
Збирка решених задатака из Програмског језика С – I део

9.7. Саставити програм за израчунавање и исписивање суме квадрата свих бројева, само парних и
само непарних за унете границе интервала. Користити функције за израчунавање збира квадрата.
#include <stdio.h>

int ZbirKv(int a, int b)


{
int i, suma=0;
for(i=a; i<=b; i++)
suma+=i*i;
return suma;
}

int ZbirKvP(int a, int b)


{
int i, suma=0;
for(i=a; i<=b; i++)
{
if(i%2==0)
suma+=i*i;
}
return suma;
}

int ZbirKvN(int a, int b)


{
int i, suma=0;
for(i=a; i<=b; i++)
{
if(i%2 == 1)
suma += i*i;
}
return suma;
}

main() Испис на екрану


{
int a, b;
printf(" Donja granica: "); scanf("%d", &a);
printf(" Gornja granica: "); scanf("%d", &b);
printf("\n Zbir kvadrata svih brojeva: %d", ZbirKv(a, b));
printf("\n Zbir kvadrata parnih brojeva: %d", ZbirKvP(a, b));
printf("\n Zbir kvadrata neparnih brojeva: %d", ZbirKvN(a, b));
getche();
return 0;
}

9.8. Саставити програм који исписује суму цифара за унете границе интервала. За рачунање суме
цифара формирати одговарајућу функцију.

#include <stdio.h>
#include <math.h>

int Suma(int a)
{
int s=0;
while (a!=0)
{
109
Збирка решених задатака из Програмског језика С – I део

s+=a%10;
a/=10;
}
return s;
}

main()
{
int i, d, g;
printf(" Donja granica= ");
scanf("%d", &d);
printf(" Gornja granica= ");
scanf("%d", &g);
for(i=d; i<=g; i++)
printf("\n%4d\t%3d", i, Suma(fabs(i)));
getche();
return 0;
} Испис на екрану

9.9. Саставити програм који коришћењем функција одређује највећи заједнички делилац и
најмањи заједнички садржалац два природна броја. Програм треба да захтева унос све док не
прочита нулу за један од два унета природна броја.
#include <stdio.h>

unsigned nzd (unsigned a, unsigned b)


{
unsigned c;
while(b != 0)
{
c=b;
b=a%b;
a=c;
}
return a;
}

unsigned nzs (unsigned a, unsigned b)


{
return a*b/nzd(a,b);
} Испис на екрану

main()
{
unsigned a, b;
while(1)
{
printf ("\n a= "); scanf ("%u", &a);
printf (" b= "); scanf ("%u", &b);
if (a==0 || b==0) break;
printf (" nzd= %u", nzd(a,b));
printf ("\n nzs= %u", nzs(a,b));
printf ("\n\n");
}
getche();
return 0;
}

110
Збирка решених задатака из Програмског језика С – I део

9.10. Саставити функцију за рачунање факторијела, затим саставити програм који рачуна и
n n!
исписује број комбинација Cn ,k =   = , за дато n и k помоћу функције за рачунање
k  k !( n − k ) !
факторијела.
#include <stdio.h>

long Fakt(int n)
{
long i, f=1;
for(i=1; i<=n; i++)
f *= i;
return f;
} Испис на екрану

main()
{
int n, k, c;
printf(" n= ");
scanf("%d", &n);
printf(" k= ");
scanf("%d", &k);
c=Fakt(n)/(Fakt(k)*Fakt(n-k));
printf("\n c= %d", c);
getche();
return 0;
}

9.11. Саставити програм који за дато n рачуна и исписује суму S = 1! + 2! + 3! + ... + n!. За
рачунање факторијела користити одговарајућу функцију.
#include <stdio.h>

long Fakt(int n)
{
long i, f=1;
for(i=1; i<=n; i++)
f *= i;
return f;
} Испис на екрану

main()
{
long n, s=0;
int i;
printf(" n= ");
scanf("%ld",&n);
for(i=1; i<=n; i++)
s+=Fakt(i);
printf("\n S= %ld\n", s);
getche();
return 0;
}

111
Збирка решених задатака из Програмског језика С – I део

9.12. Саставити програм којим се исписују сви троцифрени бројеви (ако их има) који су једнаки
суми факторијела својих цифара.
#include <stdio.h>

long Fakt(int n)
{
long i, f=1;
for(i=1; i<=n; i++)
f *= i;
return f;
}

main()
{
int a, b, c; Испис на екрану
for(a=1; a<=9; a++)
for(b=0; b<=9; b++)
for(c=0; c<=9; c++)
{
if((a*100+b*10+c)==(Fakt(a)+Fakt(b)+Fakt(c)))
printf("\n %d", a*100+b*10+c);
}
getche();
return 0;
}

9.13. Саставити функцију за степеновање бројева. Затим саставити програм који помоћу
формиране функције врши рачунање за дати број и степен и исписује резултат.

#include <stdio.h>

double Stepen(double x, int n)


{
int i, negative;
double s=1.0;
negative = n<0;
if(negative) n=-n;
for(i=0; i<n; i++)
s*=x;
Испис на екрану
if(negative) return(1/s);
else return(s);
}

main()
{
int n;
double x, s;
printf("\n Osnova: ");
scanf("%lf", &x);
printf("\n Stepen: ");
scanf("%d", &n);
s=Stepen(x,n);
printf("\n Rezultat= %.2f", s);
getche();
return 0;
}

112
Збирка решених задатака из Програмског језика С – I део

9.14. Саставити програм за рачунање и исписивање месечне рате за отплату кредита по формули
A⋅ p ⋅ k
r= , где је A = (1 + k ) , р – позајмица (износ кредита), k – месечна камата (нпр, за 6% уноси
m

A −1
се 0.06), m – број месечних рата. За рачунање вредности А формирати одговарајућу функцију.
#include <stdio.h>

double Stepen(double x, int n)


{
int i;
double s=1.0;
for(i=0; i<n; i++)
s*=x;
return(s);
}

main()
{ Испис на екрану
int m;
double p, k, r, A;
printf("\n Iznos kredita: "); scanf("%lf", &p);
printf("\n Mesecna kamata: "); scanf("%lf", &k);
printf("\n Broj mesecnih rata: "); scanf("%d", &m);
A=Stepen(1+k,m);
r=(A*p*k)/(A-1);
printf("\n Mesecna rata= %.2f", r);
getche();
return 0;
}

9.15. Саставити програм који исписује све просте бројеве мање од 500. Користити функцију за
одређивање простих бројева.

#include <stdio.h>
Пошто у С-у не постоји логички тип
int Prost(int broj)
података, уколико се ради о некој функцији која
{
int i; треба да врати вредност тачно или нетачно, као
for(i=2; i<broj; i++) што је случај са овом, тада је она типа int и
if(broj%i == 0) враћа 1 ако треба да врати тачно, а 0 ако треба
return 0;
return 1; да врати нетачно. Из тог разлога ова функција је
} типа int и у зависности од (не)испуњења
услова враћа се вредност 0 или вредност 1.
main()
{
int i;
for(i=1; i<=500; i++)
if(Prost(i) == 1)
printf("%d\t", i);
getche();
return 0;
}

113
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

9.16. Саставити програм који рачуна и исписује вредност Ојлерове функције позитивног целог
броја унетог са улаза. Под Ојлеровом функцијом φ(n) подразумевамо број бројева m, таквих да је
1≤m<n и да су m и n узајамно прости. Ојлерова функција, као и NZD(m,n) рачунати у посебним
функцијама.

#include <stdio.h> int Ojler(int n)


{
int nzd (int a, int b) int br=0, m;
{ /*Prolazimo kroz sve prirodne brojeve m
int c; koji su manji od n, i za svaki koji je
while(b != 0) uzajamno prost sa n uvecavamo brojac*/
{ for(m = 1; m < n; m++)
c=b; if(nzd(n,m) == 1) br++;
b=a%b; /*Vracamo broj uzajamno prostih brojeva
sa brojem n*/
a=c;
return br;
}
}
return a;
}
main()
{
int n;
printf(" n= ");
scanf("%d", &n);
printf(" Euler(%d)= %d\n", n, Ojler(n));
getche();
return 0;
Испис на екрану
}

9.17. Саставити програм којим се исписују сви троцифрени Амстронгови бројеви. Троцифрени
број је Амстронгов ако је једнак суми кубова својих цифара. Формирати две функције, једна за
рачунање суме кубова, а друга за одређивање да ли је дати број Амстронгов (ако јесте враћа 1, ако
није враћа 0).

#include <stdio.h>
#include <math.h>

int SumaKubova(int n)
{
int suma=0 ;
for( ; n>0; n/=10)
suma += pow(n%10,3);
return suma;
}

114
Збирка решених задатака из Програмског језика С – I део

int Amstrongov(int n)
{
if(n==SumaKubova(n))
return 1;
return 0;
}
Испис на екрану
main()
{
int i;
for(i=100; i<=999; i++)
if(Amstrongov(i))
printf("%d\t", i);
getche();
return 0;
}

9.18. Саставити програм којим се исписују сви Нивенови бројеви друге стотице. Нивенов број је
број који је дељив са сумом својих цифара. Формирати две функције, једна за рачунање суме цифара,
а друга за одређивање да ли је дати број Нивенов (ако јесте враћа 1, ако није враћа 0).
#include <stdio.h> main()
#include <math.h> {
int i;
int SumaCifara(int n) for(i=101; i<=200; i++)
{ if(Nivenov(i))
int suma=0 ; printf("%d\t", i);
for( ; n>0; n/=10) getche();
suma += n%10; return 0;
return suma; }
}

int Nivenov(int n)
{
if(n % SumaCifara(n) == 0)
return 1;
return 0;
}

Испис на екрану

9.19. Кондензатор капацитета C се пуни из једносмерног извора напона U0 преко отпорника


 −
t

отпора R. Напон на кондензатору временски расте по релацији uc ( t ) = U 0 1 − e RC
 док напон на
 
отпорнику опада по изразу ur ( t ) = U 0 − uc ( t ) . Саставити програм који ће учитати вредност
капацитета C у микрофарадима, отпора R у килоомима и напона U0 у волтима и израчунати и
исписати вредности напона на кондензатору и отпорнику за t од 0 до R*C са кораком R*C/10.

115
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h>
#include <math.h>

float R, C, U0;

float uc(float t)
{
return U0*(1-exp(-t/(R*C)));
}

float ur(float t)
{
return U0-uc(t);
}

main()
{
float t;
printf("\n R[kOhm]= ");
scanf("%f",&R); Испис на екрану
printf("\n C[uF]= ");
scanf("%f",&C);
printf("\n U0[V]= ");
scanf("%f",&U0);
R*=1e3;
C*=1e-6;
printf("\n Vreme N a p o n n a ");
printf("\n [ms] kondenzatoru otporniku");
for(t=0; t<=R*C; t=t+R*C/10)
printf("\n%7.2f %9.3f %9.3f",t*1e3,uc(t),ur(t));
getche();
return 0;
}

sin ( x )
9.20. Саставити програм који ће табеларно приказати вредности функција f1 ( x ) = и
x
 sin ( x ) 
2

f2 ( x ) =   = ( f1 ( x ) ) . Променљива x треба да узима вредности од 1 до учитаног xmin


2

 x 
(xmin<1) тако да се свако наредно x смањи за учитану вредност корака dx (dx <0.1).

#include <stdio.h>
#include <math.h>

float x, xmin, dx;

float f1(float x)
{
return sin(x)/x;
}

float f2(float x)
{
return f1(x)*f1(x);
}
Испис на екрану
main()
116
Збирка решених задатака из Програмског језика С – I део

{
printf("\n xmin[xmin<1] = ");
scanf("%f",&xmin);
printf("\n dx[xkor<0.1] = ");
scanf("%f",&dx);
printf("\n x f1(x) f2(x)");
for(x=1; x>=xmin; x-=dx)
printf("\n%5.2f%9.5f%9.5f",x,f1(x),f2(x));
getche();
return 0;
}

9.21. Трапезна метода за рачунање површине:


Површина испод криве y = f ( x ) у интервалу f(x)
од x1 до x2 може се приближно израчунати трапезном
методом тако, да се цела површина апроксимира
одређеним бројем трапеза (као што је приказано на
слици). Површина појединачног трапеза је
f ( xi ) + f ( xi + dx )
Pi = ⋅ dx .
2
Када се површине свих n трапеза саберу добија се
 f ( x1 ) f ( x2 )  0 x1 xi xi+1 x2 x
укупна површина P =  + + S  ⋅ dx
 2 2 
где је S сума ордината y ( xi ) за свакo xi од x1+dx до x2-dx. То произлази због тога што се при
рачунању свих површина ординате f ( xi ) узимају два пута, као задња страница i-тог трапеза и прва
страница i+1-ог трапеза, док су f ( x2 ) и f ( x2 ) странице првог и последњег трапеза.
Саставити програм који ће трапезном методом наћи и ишисати површину испод криве
y = a ⋅ x ⋅ sin ( b ⋅ x ) у интервалу од задатог х1 до задатог х2. Апроксимирати површину помоћу n
трапеза. Параметре a и b учитати као реалне бројеве, а број трапеза n као цели број.

#include <stdio.h>
#include <math.h>

float a, b;

float f(float x)
{
return(a*x*fabs(sin(b*x)));
}

main()
{ Испис на екрану
int n;
float x, x1, x2, dx, S, P;
printf(" Parametar a= "); scanf("%f",&a);
printf(" Parametar b= "); scanf("%f",&b);
printf(" Broj tacaka n= "); scanf("%d",&n);
printf(" Pocetak intervala x1= "); scanf("%f",&x1);
printf(" Kraj intervala x2= "); scanf("%f",&x2);
dx=(x2-x1)/n;
S=(f(x1)+f(x2))/2;

117
Збирка решених задатака из Програмског језика С – I део

for(x=x1+dx; x<=x2-dx; x+=dx)


S+=f(x);
P=S*dx;
printf("\n Povrsina= %.4f",P);
getche();
return 0;
}

9.22. Напон на неком потрошачу се мења временски по функцији u ( t ) = e − b⋅t ⋅ sin ( a ⋅ t ) док отпор
 u 
потрошача зависи од напона по функцији r ( u ) = r0 + ln 1 +  . Саставити програм који ће учитати
 10 
параметре a, b и r0, као и почетно и крајње време t1 и t2 и наћи и исписати енергију утрошену на
потрошачу у временском интервалу од t1 до t2.
Енергија је временски интеграл напона и струје, па треба наћи површину испод криве
(u (t ))
2

f (t ) = у интервалу од t1 до t2.
r (t )
#include <stdio.h>
#include <math.h>

float a, b, r0;

float u(float t)
{
return exp(-b*t)*sin(a*t);
}

float r(float t)
{ Испис на екрану
return r0+log(1+fabs(u(t)/10));
}

float f(float t)
{
return u(t)*u(t)/r(t);
}

main()
{
int n;
float t1, t2, t, dt, E;
printf(" Parametar a= "); scanf("%f",&a);
printf(" Parametar b= "); scanf("%f",&b);
printf(" Parametar r0= "); scanf("%f",&r0);
printf(" Vremenski interval [t1,t2]= "); scanf("%f%f",&t1,&t2);
printf(" Broj tacaka n= "); scanf("%d",&n);
dt=(t2-t1)/n;
E=f(t1)+f(t2);
for(t=t1+dt; t<=t2-dt; t+=dt)
E+=2*f(t);
E=2*E*dt;
printf("\n Energija= %.4f",E);
getche();
return 0;
}

118
Збирка решених задатака из Програмског језика С – I део

9.23. Саставити функцију која израчунава еx на основу првих неколико (n) чланова Тејлоровог

xi x1 x2 x3 x4
реда e x = ∑ i ! = 1 + 1! + 2! + 3! + 4! + ... , а затим саставити главни програм који за дато n и х
i =0
користећи претходну функцију рачуна и исписује вредност израза, а затим одређује апсолутну
грешку између добијене вредности и тачне вредности (за тачну вредност користити уграђену
функцију exp() за исто х).
#include <stdio.h>
#include <math.h>

double Ekspon (double x, int n)


{
double ex=1, clan=1;
int i;
for(i=1; i<n; i++)
{
clan *= x/i;
ex += clan;
}
return ex;
}

main() Испис на екрану


{
double x, ex, ext, apsgr;
int n;
printf (" x= ");
scanf ("%lf", &x);
printf (" n= ");
scanf ("%d", &n);
ex=Ekspon(x,n); /*Izracunata vrednost*/
ext=exp(x); /*Tacna vrednost*/
apsgr = fabs(ex-ext);
printf("\n Izracunato= %.4f", ex);
printf("\n Tacno= %.4f", ext);
printf("\n APSGR= %.4f", apsgr);
getche();
return 0;
}

n  n   n  t  n 
9.24. Саставити програм за рачунање суме S =   −  +  − ... + ( −1)  и
 k   k + 1  k + 2  k +t
n
исписивање њене вредности за дато n, k и t употребом функције за рачунање комбинација   .
k 
#include <stdio.h>

int Komb(int n, int m)


{
int i, p=1;
for(i=1; i<=m; i++)
p *= (n-i+1)/i;
return p;
}

119
Збирка решених задатака из Програмског језика С – I део

main()
{
float s;
int n, k, i, t, znak=1;
printf (" n= ");
scanf ("%d", &n);
printf (" k= ");
scanf ("%d", &k);
printf (" t= ");
scanf ("%d", &t);
for(i=0; i<t; i++)
{
s += znak*Komb(n,k);
znak=-znak; Испис на екрану
}
printf("\n S= %.2f", s);
getche();
return 0;
}

1 1 1
9.25. Саставити програм којим се рачуна сума S = 1 + − + − ... рачунајући до члана који
2!! 3!! 4!!
је по апсолутној вредности мањи од ерѕ. Двоструки факторијел рачунати коришћењем функције:
n ⋅ ( n − 2 ) ⋅ ... ⋅ 3 n непарно
dfakt ( n ) = n !! = 
n ⋅ ( n − 2 ) ⋅ ... ⋅ 4 ⋅ 2 n парно

#include <stdio.h>

int DFakt(int n)
{
int p=1;
while(n>=2)
{
p=p*n;
n=n-2;
}
return p; Испис на екрану
}

main()
{
int i=2, znak=1;
float s=1, clan=1, eps;
printf (" eps= ");
scanf ("%f", &eps);
printf("\n");
while(fabs(clan)>=eps)
{
clan=(float)znak/DFakt(i);
s=s+clan;
i++;
znak=-znak;
}
printf(" S= %.4f", s);
getche();
return 0;
}

120
Збирка решених задатака из Програмског језика С – I део

9.26. Саставити програм који помоћу функције исцртава правоугаоник дужине а и ширине b од
знакова чији је ASCII код 254. После цртања правоугаоника поставља се питање '' Da li zelite
novo crtanje?[D/N]:'' и понавља исти поступак.

#include <stdio.h>

void Crtaj(int a,int b)


{
int i, j;
for(i=0; i<b; i++)
{
for(j=0; j<a; j++)
printf("%c",254);
printf("\n");
}
}

main()
{
int a, b, ch;
ch='D';
while(ch=='D') Испис на екрану
{
printf(" a= ");
scanf("%d",&a);
printf(" b= ");
scanf("%d",&b);
Crtaj(a,b);
printf("\n\n Da li zelite novo crtanje?[D/N]: ");
ch=getchar();
ch=toupper(ch);
while(ch!='D'&& ch!='N')
{
ch=getchar();
ch=toupper(ch);
}
}
getche();
return 0;
}

9.27. Саставити програм који ће исцртати оквир приказан на слици за унету дужину и ширину. За
цртање вертикалних и хоризонталних делова оквира формирати одговарајуће функције. На слици је
приказан оквир дужине 6 и ширине 2.

121
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h>
#define HLIN '-'
#define VLIN '|'
#define UGAO '+'
#define PRAZNO ' '

void Znakovi(int n, char c)


{
while(n>0)
{
n--;
putchar(c);
}
}

void Hokvir(int k)
{
putchar(UGAO);
Znakovi(k, HLIN); Испис на екрану
putchar(UGAO);
putchar('\n');
}

void Vokvir(int k)
{
putchar(VLIN);
Znakovi(k, PRAZNO);
putchar(VLIN);
putchar('\n');
}

main()
{
int i, duzina, sirina;
do
{
printf(" Unesite duzinu okvira (od 1 do 20): ");
scanf("%d", &duzina);
}
while(duzina<1 || duzina>20);
do
{
printf(" Unesite sirinu okvira (od 1 do 20): ");
scanf("%d", &sirina);
}
while(sirina<1 || sirina>20);
Hokvir(duzina); /*Stampanje gornjeg dela okvira*/
for(i=0; i<sirina; i++)
Vokvir(duzina); /*Stampanje srednjeg dela okvira*/
Hokvir(duzina); /*Stampanje donjeg dela okvira*/
getche();
return 0;
}

122
Збирка решених задатака из Програмског језика С – I део

9.28. а) Саставити функцију која врши конверзију малих слова у велика. Затим тестирати
функцију за унети текст. Унос текста се завршава сигналом EOF.
б) Саставити функцију која врши конверзију великих слова у мала. Затим тестирати
функцију за унети текст. Унос текста се завршава сигналом EOF.

а) #include <stdio.h> б) #include <stdio.h>

char UVeliko(char c) char UMalo(char c)


{ {
if ('a'<=c && c<='z') if ('A'<=c && c<='Z')
return c-'a'+'A'; return c-'A'+'a';
return c; return c;
} }

main() main()
{ {
int c; int c;
while((c=getchar()) != EOF) while((c=getchar()) != EOF)
putchar(UVeliko(c)); putchar(UMalo(c));
getche(); getche();
return 0; return 0;
} }

Испис на екрану
Испис на екрану

9.1 Рекурзивне функције

9.29. Саставити рекурзивну функцију за одређивање факторијела целог броја, а затим је тестирати
у главном програму за унети цео број n и исписати добијени резултат.
#include <stdio.h>

int Faktorijel(int n)
{
if(n == 1) return 1;
return n*Faktorijel(n-1);
} Испис на екрану
main()
{
int n;
printf("n= ");
scanf("%d", &n);
printf("%d!= %d", n, Faktorijel(n));
getche();
return 0;
}

123
Збирка решених задатака из Програмског језика С – I део

9.30. Саставити рекурзивну функцију која степеновање целог броја на целобројни изложилац, а
затим тестирати функцију за дати природни број и изложилац и исписати добијени резултат.
#include <stdio.h>

int Stepen(int a, int k)


{
if(k==0)
return 1;
else
return a*Stepen(a,k-1);
}
Испис на екрану
main()
{
int a,k;
printf(" a= ");
scanf("%d", &a);
printf(" k= ");
scanf("%d", &k);
printf("\n %d^%d= %d", a, k, Stepen(a,k));
getche();
return 0;
}

9.31. Саставити рекурзивну функцију која врши сабирање првих n бројева, а затим тестирати
функцију за дато n и исписати добијени резултат.
#include <stdio.h>

int Suma(int n)
{
if(n==0)
return 0;
else
return(n + Suma(n-1));
} Испис на екрану

main()
{
int s,n;
printf(" n= ");
scanf("%d", &n);
s=Suma(n);
printf("\n s= %d\n",s);
getche();
return 0;
}

124
Збирка решених задатака из Програмског језика С – I део

9.32. Саставити рекурзивну функцију која исписује првих n бројева у обрнутом редолседу, а затим
тестирати функцију за дато n.

#include <stdio.h>

void Stampaj(unsigned int n)


{
if(n == 0) return;
printf(" %d", n);
Stampaj(n-1);
}

main() Испис на екрану


{
int n;
printf(" n= ");
scanf("%d",&n);
Stampaj(n);
getche();
return 0;
}

9.33. Саставити рекурзивну функцију за одређивање највећег заједничког делилаца за два цела
броја. Затим тестирати функцију у главном програму и исписати добијени резултат.
#include <stdio.h>

int NZD(int x, int y)


{
if(x%y == 0) return y;
return NZD(y, x%y);
}

main() Испис на екрану


{
int n, m, t;
printf("\n Unesite dva cela broja: ");
scanf("%d %d",&n, &m);
if(n<m)
{
t=n;
n=m;
m=t;
}
printf("\n NZD(%d,%d) = %d\n", n, m,NZD(n,m));
getche();
return 0;
}

125
Збирка решених задатака из Програмског језика С – I део

9.34. Саставити рекурзивну функцију која сабира декадне цифре целог броја. Затим тестирати
функцију у главном програму за унети цео број и исписати добијени резултат.

#include <stdio.h>
#include <stdlib.h>

int SaberiCifre(int x)
{
if(x<0) x=abs(x);
if(x<10) return x;
return(x%10 + SaberiCifre(x/10));
} Испис на екрану

main()
{
int n;
printf("\n Unesite ceo broj: ");
scanf("%d",&n);
printf("\n Suma cifara broja %d je %d\n", n, SaberiCifre(n));
getche();
return 0;
}

9.35. Саставити рекурзивну функцију која одређује и исписује n-ти члан Фибоначијевог низа, а
затим тестирати функцију за дато n. Фибоначијев низ: f1=1, f2=1, fi=fi-1+fi-2, i=3, 4, 5, ...

#include <stdio.h>

int Fib(int n)
{
if((n==0)||(n==1))
return 1;
else
return(Fib(n-1)+Fib(n-2)); Испис на екрану
}

main()
{
int n;
printf(" n= ");
scanf("%d", &n);
printf(" Fib[%d]= %d", n, Fib(n-1));
getche();
return 0;
}

9.36. Саставити рекурзивну функцију за рачунање биномног


коефицијента. Затим саставити програм који користећи претходну
функцију исписује Паскалов троугао за унети цео број n.
Изглед Паскаловог троугла за n=7 је приказан на следећој слици:

126
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h>

/*Rekurzivna funkcija za racunanje binomnog koeficijenta.*/


int BinKoefREK(int n, int k)
{
return (0<k && k<n) ? BinKoefREK(n-1, k-1)+BinKoefREK(n-1, k) : 1;
}

/*Iterativna funkcija za racunanje binomnog koeficijenta.*/


int BinKoefIT(int n, int k)
{
int i, j, b;
for(b=i=1, j=n; i<=k; b=b*j--/i++);
return b;
}

/*Glavni program.*/
main ()
{
int n, i, j, k;
printf("\n n= ");
scanf("%d", &n);
for(i=0; i<=n; i++) Испис на екрану
{
for(j=0; j<n-i; j++)
printf (" ");
for(k=0; k<=i; k++)
printf ("%4d", BinKoefREK(i, k));
printf("\n");
}
getche();
return 0;
}

9.37. Ханојске куле: Дата су три штапа, и на једном од њих n дискова различитих пречника,
поређаних тако да мањи диск лежи на већем. Потребно је преместити све дискове на трећи штап у
истом поретку, тако што се премешта један по један диск, коришћењем сва три штапа, и у сваком
тренутку на сваком од штапова диск може да лежи само на већем диску.
Саставити рекурзивну функцију која омогућује пребацивање дискова по горе наведеном
правилу, а затим тестирати функцију за унети број (n) дискова.

#include <stdio.h>

void Prebaci(int n, int i, int j)


{
int k;
/*Odrediti pomocni stap k*/
switch(i+j)
{
case 3: k=3; break;
case 4: k=2; break;
case 5: k=1; break;
}
if(n==1)
printf(" Prebaceno sa %d na %d\n", i, j);
else
{
127
Збирка решених задатака из Програмског језика С – I део

Prebaci(n-1,i,k);
Prebaci(1,i,j);
Prebaci(n-1,k,j);
}
return;
}

main()
{
int broj;
printf(" Unesite broj diskova: ");
scanf("%d", &broj);
Prebaci(broj, 1, 3); Испис на екрану
getche();
return 0;
}

128
Збирка решених задатака из Програмског језика С – I део

10 НИЗОВИ

10.1 Основне конструкције програма са низовима

10.1. а) Која је разлика између следећа два низа:


int a[15] = {1,2,3};
int b[] = {1,2,3};
б) На који други начин можемо доделити вредности елементима низа?
в) Колико елемената и које вредности ће имати ти елементи низова а и b након извршавања
следећег дела програма:
int а [10];
int b [10] = {0};

а) Променљиве (низови) a и b се разликују у дужини. Низ a има 15 елемената где прва три имају
вредности 1, 2 и 3, док су остали имају вредности нуле. Низ b има три елемента са вредностима 1, 2 и
3.

б)
int a[17], b[3], i;
a[0]=1; a[1]=2; a[2]=3;
for(i=3;i<15;i++) a[i]=0;
b[0]=1; b[1]=2; b[2]=3;

в) Низ а има 10 елемената чије су вредности непознате (цели бројеви). Низ b има 10 елемената и сви
имају вредности нула.

10.2. Шта се исписује на екрану након извршавања следећег програма:


#include <stdio.h>
#define MAX 10

main()
{
int i, n, niz[MAX];
printf(" n= ");
scanf("%d", &n);
for(i=0; i<n; i++)
{
printf(" %d. element niza: ", i+1);
129
Збирка решених задатака из Програмског језика С – I део

scanf("%d", &niz[i]);
}
for(i=0; i<n; i++)
printf("\n %d. element niza: %d", i+1, niz[i]);
getche();
return 0;
}

Испис на екрану

10.3. Шта се исписује на екрану након извршавања следећег програма:


#include <stdio.h>
#define MAX 5

main()
{
int i, j, niz[]={15,3,9,7,11};
printf("\nR.Br.\tIndeks\tVrednost\n");
for(i=0; i<MAX; i++)
printf("\n%d\t%d\t%d", i+1, i, niz[i]);
getche();
return 0; Испис на екрану
}

10.4. Саставити програм који ће учитати низ од n елемената и исписати их оним редоследом којим
су учитани.
#include <stdio.h>
#define MAX 100

main()
{
int niz[MAX], i,n;
printf(" n= ");
scanf("%d", &n);
printf(" Unesite %d elemenata: ",n); Испис на екрану
for(i=0 ; i<n ; i++)
scanf("%d", &niz[i]);
printf("\n Uneti niz: ");
for(i=0 ; i<n ; i++)
printf(" %d", niz[i]);
getche();
return 0;
}

130
Збирка решених задатака из Програмског језика С – I део

10.5. Саставити програм који ће учитати низ од n елемената и исписати их обрнутим редоследом.
#include <stdio.h>
#define MAX 100

main()
{
int niz[MAX];
int i,n;
printf(" n= "); Испис на екрану
scanf("%d", &n);
printf(" Unesite %d elemenata: ",n);
for(i=0; i<n; i++)
scanf("%d", &niz[i]);
printf("\n Obrnuto: ");
for(i=n-1; i>=0; i--)
printf(" %d", niz[i]);
getche();
return 0;
}

10.6. Шта се исписује на екрану након извршавања следећих програма:


а) #include <stdio.h>
#define MAX 10

main()
{
int niz[MAX];
printf("\n Niz zauzima %d bajtova.", sizeof(niz));
getche();
return 0;
}

б)
#include <stdio.h>

main()
{
int i, BrElem;
int niz[] = {1, 2, 3, 4, 5, 6};
BrElem = sizeof(niz)/sizeof(int);
for(i=0; i<BrElem; i++)
printf(" niz[%d]=%d\n",i, niz[i]);
getche();
return 0;
}

Испис на екрану а) Испис на екрану

131
Збирка решених задатака из Програмског језика С – I део

10.2 Операције са низовима и разврставање елемената

10.7. Саставити програм за израчунавање и исписивање аритметичке средине задатог низа (дужине
n) целих бројева.

#include <stdio.h>
#define MAX 100

main()
{
int i, n, niz[MAX], suma=0;
printf(" Broj elemenata: ");
scanf("%d", &n);
printf(" Elementi niza: "); Испис на екрану
for(i=0; i<n; i++)
{
scanf ("%d", &niz[i]);
suma+=niz[i];
}
printf(" SRV= %.2f\n", (float)suma/n);
getche();
return 0;
}

10.8. Саставити програм који за унети низ (дужине n) целих бројева израчунава и исписуеј
аритметичку средину оних елемената низа који су дељиви са 3.
#include <stdio.h>
#define MAX 100

main()
{
int i, n, k=0, niz[MAX];
double suma=0;
printf(" Broj elemenata: ");
scanf("%d", &n); Испис на екрану
printf(" Elementi niza: ");
for(i=0; i<n; i++)
{
scanf("%d", &niz[i]);
if(niz[i]%3 == 0)
{
suma+=niz[i];
k++;
}
}
printf(" SRV= %.3f\n", suma/k);
getche();
return 0;
}

132
Збирка решених задатака из Програмског језика С – I део

10.9. Саставити програм који ће за унети низ (дужине n) целих бројева одредити и исписати:
а) суму парних и суму непарних бројева;
б) суму елемената са парним индексима и суму елемената са непарним индексима.

а) #include <stdio.h>
#define MAX 100

main()
{
int i, n, niz[MAX], sumap=0, suman=0;
printf(" Broj elemenata: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
{
scanf("%d", &niz[i]);
if(niz[i]%2==0)
sumap += niz[i];
else
suman += niz[i]; Испис на екрану
}

б)
#include <stdio.h>
#define MAX 100

main()
{
int i, n, niz[MAX], sumap=0, suman=0;
printf(" Broj elemenata: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
{
scanf("%d", &niz[i]);
if(i%2==0)
sumap += niz[i];
else
suman += niz[i]; Испис на екрану
}

10.10. Саставити програм који прочита два низа, дужине n, са реалним компонентама,
n −1
A = ( A1 , A2 ,..., An ) и B = ( B1 , B2 ,..., Bn ) израчунава њихов скаларни производ s = ∑ Ai Bi и
i=0
исписује добијени резултат.

133
Збирка решених задатака из Програмског језика С – I део

#include <stdio.h>
#define MAX 100

main()
{
int i, n;
double proizvod=0, niz1[MAX], niz2[MAX];
printf(" Broj elemenata: ");
scanf("%d", &n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
scanf("%lf", &niz1[i]);
printf(" Elementi niza B: ");
for(i=0; i<n; i++)
scanf("%lf", &niz2[i]);
for(i=0; i<n; i++) Испис на екрану
proizvod+=niz1[i]*niz2[i];
printf (" Skalarni proizvod= %.3f\n", proizvod);
getche();
return 0;
}

10.11. Саставити програм који учита елементе низа A = ( A1 , A2 ,..., An ) дужине n и низа
B = ( B1 , B2 ,..., Bm ) дужине m и спаја у један низ C = ( A1 , A2 ,..., An , B1 , B2 ,..., Bm ) дужине n+m.
Исписати новокреирани низ.
#include <stdio.h>
#define MAX 100

main()
{
int i, n, m, nizA[MAX], nizB[MAX], nizC[MAX];
printf(" Broj elemenata niza A: ");
scanf("%d", &n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
scanf("%d", &nizA[i]);
printf(" Broj elemenata niza B: ");
scanf("%d", &m);
printf(" Elementi niza B: ");
for(i=0; i<m; i++)
scanf("%d", &nizB[i]);
printf(" Elementi niza C: ");
for(i=0; i<(n+m); i++)
{
if (i<n) nizC[i]=nizA[i];
else nizC[i]=nizB[i-n];
printf("%d ",nizC[i]);
}
getche(); Испис на екрану
return 0;
}

134
Збирка решених задатака из Програмског језика С – I део

10.12. Саставити програм који учита елементе два низа низа дужине n A = ( A1 , A2 ,..., An ) и
B = ( B1 , B2 ,..., Bn ) и формира и исписује нови низ чији су елементи
C = ( A1 + B1 , A2 + B2 ,..., An + Bn ) .
#include <stdio.h>
#define MAX 100

main()
{
int i, n, nizA[MAX], nizB[MAX], nizC[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
scanf("%d", &nizA[i]);
printf(" Elementi niza B: ");
for(i=0; i<n; i++)
scanf("%d", &nizB[i]);
printf(" Elementi niza C: ");
for(i=0; i<n; i++)
{
nizC[i]=nizA[i]+nizB[i];
printf("%d ",nizC[i]);
}
getche();
return 0;
} Испис на екрану

10.13. Саставити програм за формирање низа С од два задата низа реалних бројева А и В (сваки
(A )
3

дужине 5) на следећи начин Ci = i + 2 Ai Bi . Исписати низ С.


3
#include <stdio.h>
#define MAX 5

main()
{
float nizA[MAX], nizB[MAX], nizC[MAX];
int i;
printf (" Elementi niza A: ");
for(i=0; i<MAX; i++)
scanf ("%f", &nizA[i]);
printf (" Elementi niza B: ");
for(i=0; i<MAX; i++)
scanf ("%f", &nizB[i]);
printf ("\n Elementi niza C: ");
for(i=0; i<MAX; i++)
{
nizC[i]=pow(nizA[i],3)/3+2*nizA[i]*nizB[i];
printf ("%.2f ", nizC[i]);
}
getche();
return 0;
}

135
Збирка решених задатака из Програмског језика С – I део

Испис на екрану

10.14. Саставити програм за формирање низа С од два задата низа целих бројева А и В (сваки
дужине 5) на следећи начин: А[0]+B[4],…,A[4]+B[0]. Исписати низ С.
#include <stdio.h>
#define MAX 5

main()
{
int nizA[MAX], nizB[MAX], nizC[MAX], i;
printf (" Elementi niza A: ");
for(i=0; i<MAX; i++)
scanf ("%d", &nizA[i]);
printf (" Elementi niza B: ");
for(i=0; i<MAX; i++)
scanf ("%d", &nizB[i]);
printf (" Elementi niza C: ");
for(i=0; i<MAX; i++)
{
nizC[i]=nizA[i]+nizB[MAX-1-i];
printf ("%d ", nizC[i]);
}
getche();
return 0;
} Испис на екрану

10.15. Саставити програм који учита елементе низа A = ( A1 , A2 ,..., An ) дужине n и низа
B = ( B1 , B2 ,..., Bm ) дужине m, а затим формира и исписује низ С који се састоји од парних елемената
низа А и низа В.
#include <stdio.h>
#define MAX 100

main()
{
int i, n, m, k=0, nizA[MAX], nizB[MAX], nizC[MAX];
printf(" Broj elemenata niza A: ");
scanf("%d", &n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
scanf("%d", &nizA[i]);
printf(" Broj elemenata niza B: ");
scanf("%d", &m);
printf(" Elementi niza B: ");
for(i=0; i<m; i++)
scanf("%d", &nizB[i]);
printf("\n Elementi niza C: ");
for(i=0; i<n; i++)
if(nizA[i]%2==0)
136
Збирка решених задатака из Програмског језика С – I део

{
nizC[k]=nizA[i];
k++;
}
for(i=0; i<m; i++)
if(nizB[i]%2==0)
{
nizC[k]=nizB[i];
k++;
}
for(i=0; i<k; i++) Испис на екрану
printf("%d ",nizC[i]);
getche();
return 0;
}

10.16. Саставити програм који ће учитати два низа целих бројева А и В једнаких дужина n и на
основу њих формирати низ С тако да i-ти елемент низа С буде једнак мањем од i-тих елемената низа
А и В. Ако су i-ти елементи низа А и В једнаки онда i-ти елемент низа С треба да добије вредност
нула. Исписати низ С.
#include <stdio.h>
#define MAX 100

main()
{
int i, n, nizA[MAX], nizB[MAX], nizC[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
scanf("%d", &nizA[i]);
printf(" Elementi niza B: ");
for(i=0; i<n; i++)
scanf("%d", &nizB[i]);
printf("\n Elementi niza C: ");
for(i=0; i<n; i++) Испис на екрану
{
if (nizA[i]<nizB[i]) nizC[i]=nizA[i];
else if(nizA[i]>nizB[i]) nizC[i]=nizB[i];
else nizC[i]=0;
printf("%d ",nizC[i]);
}
getche();
return 0;
}

10.17. Саставити програм који за учитани низ целих бројева А дужине n формира и исписује два
низа: низ В који садржи негативне елементе низа А и низ С који садржи позитивне елементе и нуле
низа А.
#include <stdio.h>
#define MAX 100

main()
{
int nizA[MAX], nizB[MAX], nizC[MAX];
int n, i, j=0 ,k=0;
printf(" Broj elemenata niza A: ");

137
Збирка решених задатака из Програмског језика С – I део

scanf("%d", &n);
printf(" Elemneti A: ");
for(i=0; i<n; i++)
scanf ("%d", &nizA[i]);
for(i=0; i<n; i++)
{
if (nizA[i]<0)
{
nizB[j]=nizA[i];
j++;
}
else
{
nizC[k]=nizA[i];
k++;
}
}
printf("\n Elementi B: ");
for(i=0; i<j; i++)
printf ("%d ", nizB[i]);
printf("\n Elementi C: ");
for(i=0; i<k; i++)
printf ("%d ", nizC[i]);
getche(); Испис на екрану
return 0;
}

10.18. Саставити програм који за унети низ реланих бројева А дужине n формира и исписује нови
низ В кога чине елементи низа А који су већи од аритемтичке средине свих елемената низа А.
#include <stdio.h>
#define MAX 100

main()
{
float s=0, as, nizA[MAX], nizB[MAX];
int i, j=0, n;
printf(" Broj elemenata niza A: ");
scanf("%d", &n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
{
scanf("%f", &nizA[i]);
s+=nizA[i];
}
as=s/n;
printf("\n Sredina= %.2f", as);
printf("\n Elementi niza B: ");
for(i=0; i<n; i++)
{
if (nizA[i]>as)
{
nizB[j]=nizA[i];
printf("%.2f ",nizB[j]);
j++;
}
}
getche();
return 0; Испис на екрану
}

138
Збирка решених задатака из Програмског језика С – I део

10.19. Саставити програм који за унети низ целих бројева А, дужине n, формира и исписује нови
низ В чији се елементи формирају по следећем принципу: В0=А0, В1=А0+А1, В2=А0+А1+А2, ...,
Bi=A0+A1+A2+...+Ai.
#include <stdio.h>
#define MAX 100

main()
{
int i, n, s=0, nizA[MAX], nizB[MAX];
printf(" Broj elemenata niza A: ");
scanf("%d", &n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
{
scanf("%d", &nizA[i]);
s+=nizA[i];
nizB[i]=s;
}
printf("\n Elementi niza B: ");
for(i=0; i<n; i++)
printf("%d ",nizB[i]);
getche();
return 0; Испис на екрану
}

10.3 Низови и функције

10.20. Шта се исписује извршавањем следећег програмског кода:


#include <stdio.h>

void StampaNiz(int a[], int n)


{
int i;
for(i=0; i<n; i++)
printf("%d ",a[i]);
printf("\n");
printf("sizeof(a) - u okviru fje : %d\n", sizeof(a));
}

main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("sizeof(a) - u okviru main : %d\n", sizeof(a));
StampaNiz(a, sizeof(a)/sizeof(int));
getche();
return 0;
}

139
Збирка решених задатака из Програмског језика С – I део

Низови се преносе тако што се пренесе адреса


њиховог почетка. Низове је неопходно
преносити заједно са димензијом низа (осим
ниски карактера), јер тамо важи конвенција
да се крај низа обележава знаком '\0'.
Испис на екрану

10.21. Саставити функцију за израчунавање скаларног производа два низа реалних бројева
n −1
s = ∑ Ai Bi , а затим саставити главни програм који ће учитати два низа једнаких дужина n и
i=0
применом формирани функције исписати скаларни производ два низа.

#include <stdio.h>
#define MAX 100

double SkalPro(double a[], double b[], int n)


{
double zbir=0;
int i;
for(i=0;i<n;i++)
zbir+=a[i]*b[i];
return zbir;
}

main()
{ Испис на екрану
double nizA[MAX],nizB[MAX];
int i, n;
printf(" Broj elemenata niza: ");
scanf("%d",&n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
scanf("%lf",&nizA[i]);
printf(" Elementi niza B: ");
for(i=0; i<n; i++)
scanf("%lf",&nizB[i]);
printf("\n A*B= %.2f", SkalPro(nizA,nizB,n));
getche();
return 0;
}

10.22. Саставити функцију којом се одређује број различитих елемената у задатом целобројном
низу. Затим саставити програм који чита низ целих бројева, и одређује број различитих елемената
користећи претходну функцију и исписује резултат.
#include <stdio.h>
#define MAX 100

int Razliciti(const int niz[], int n)


{
int i, j, brojac=0;
140
Збирка решених задатака из Програмског језика С – I део

for(i=0; i<n; i++)


{
for(j=0; j<i && niz[j]!=niz[i]; j++);
if(j==i) brojac++;
}
return brojac;
}

main()
{
int niz[MAX], n, i;
printf(" Broj elemenata niza: ");
Испис на екрану
scanf("%d", &n);
printf(" Elementi niza: ");
for (i=0; i<n; i++)
scanf ("%d",&niz[i]);
printf ("\n Broj razl. elemenata je %d", Razliciti(niz,n));
getche();
return 0;
}

10.23. Саставити програм за израчунавање статистике полагања испита која обухвата следеће
функције: израчунавање укупне просечне оцене (сви који су полгали испит), израчунавање просечне
оцене оних који су положили (оцена већа од 5), израчунавање броја који су положили испит,
израчунавање броја који нису положили испит и израчунавање броја који имају оцену већу од
просечне. У главном програму се уноси број студената и оцене студената у облику низа. Исписати
добијене резултате

#include <stdio.h>
#define MAX 100

/*Izracunavanje prosecne ocene*/


float Prosek(int x[], int n)
{
int i;
float suma =0;
for(i=0; i<n; i++)
suma+=x[i];
return(suma/n);
}

/*Izracunavanje proseka polozenih*/


float ProsekPolozenih(int x[], int n)
{
int i, j=0;
float suma=0;
for(i=0;i<n;i++)
if(x[i]>5)
{
suma+=x[i];
j++;
}
return(suma/j);
}

/*Izracunavanje broja polozenih na ispitu*/


int BrojPolozenih (int x[], int n)
{

141
Збирка решених задатака из Програмског језика С – I део

int i, broj=0;
for(i=0; i<n; i++)
if(x[i]>5)
broj++;
return broj;
}

/*Izracunavanje broja nepolozenih na ispitu*/


int BrojNepolozenih (int x[], int n)
{
int i, broj=0;
for(i=0; i<n; i++)
if(x[i] == 5)
broj++;
return broj;
}

/*Izracunavanje broja studenata iznad proseka*/


int BrojNadprosecnih (int x[], int y[], int n, float m)
{
int i, j=0;
for(i=0; i<n; i++)
{
if(x[i] > m)
{
y[j]=i;
j++;
}
}
return j;
}

/*Glavni program*/
main()
{
int student[MAX], ocena[MAX];
int i, n;
Испис на екрану
printf(" Broj studenata: ");
scanf("%d",&n);
printf(" Ocene studenata [5 do 10]: \n");
for(i=0; i<n; i++)
{
printf(" Ocena studenta %d = ",i);
scanf("%d",&ocena[i]);
}
printf("\n Ukupno polozenih na ispitu: %d\n",
BrojPolozenih(ocena,n));
printf(" Ukupno nepolozenih na ispitu: %d\n",
BrojNepolozenih(ocena,n));
printf(" Prosek ocena na ispitu: %.2f\n", Prosek(ocena,n));
printf(" Prosek ocena polozenih na ispitu: %.2f\n",
ProsekPolozenih(ocena,n));
printf(" Broj studenata iznad proseka: %d\n",
BrojNadprosecnih(ocena, student, n, Prosek(ocena,n)));
getche();
return 0;
}

142
Збирка решених задатака из Програмског језика С – I део

10.24. Саставити функцију која генерише првих n чланова Фибоначијевог низа и функцију која
исписује чланове низа, а затим те функције тестирати у главном програму.
Фибоначијев низ: f1=1, f2=1, fi=fi-1+fi-2, i=3, 4, 5, ...

#include <stdio.h>
#define MAX 100

void Fibonaci(int niz[], int n)


{
int i;
for(i=0; i<n; i++)
if(i<2) niz[i]=1;
else niz[i]=niz[i-1]+niz[i-2];
}

void Prikazi(int niz[], int n)


{
int i;
for(i=0; i<n; i++)
printf("%d ", niz[i]);
}

main() Испис на екрану


{
int niz[MAX], n;
printf(" Broj Fibonacijevih brojeva: ");
scanf("%d", &n);
printf("\n");
Fibonaci(niz, n);
Prikazi(niz, n);
getche();
return 0;
}

10.25. Саставити рекурзивну функцију за израчунавање скаларног производа два низа реалних
n −1
бројева s = ∑ A B , а затим саставити главни програм који ће учитати два низа једнаких дужина n и
i=0
i i

применом формирани функције исписати скаларни производ два низа.


#include <stdio.h>
#define MAX 100

float SkalPro (const float a[], const float b[], int n)


{
return (n>0) ? a[0]*b[0]+SkalPro(a+1,b+1,n-1) : 0;
}

main()
{
float nizA[MAX],nizB[MAX];
int i, n;
printf(" Broj elemenata niza: ");
scanf("%d",&n);
printf(" Elementi niza A: ");
for(i=0; i<n; i++)
scanf("%f",&nizA[i]); Испис на екрану
printf(" Elementi niza B: ");
143
Збирка решених задатака из Програмског језика С – I део

for(i=0; i<n; i++)


scanf("%f",&nizB[i]);
printf("\n A*B= %.2f", SkalPro(nizA,nizB,n));
getche();
return 0;
}

10.26. Саставити рекурзивну функцију која исписује све пермутације скупа {1, 2, …, n}. Затим
тестирати функцију у главном програму за унету дужину пермуатција n.

#include <stdio.h>
#define MAX 100

/*Funkcija koja ispisuje elemente niza*/


void IspisiNiz(int a[], int n)
{
int i;
for(i=1; i<=n; i++)
printf(" %d", a[i]);
printf("\n");
}

/*Funkcija koja proverava da li se x vec nalazi


u permutaciji na prethodnih 1...n mesta*/ Испис на екрану
int Koriscen(int a[], int n, int x)
{
int i;
for(i=1; i<=n; i++)
if(a[i]==x) return 1;
return 0;
}

/*Funkcija koja ispisuje sve permutacije od skupa {1,2,...,n}.


a[] - je niz u koji smesta permutacije,
m - oznacava da se na m-tu poziciju u permutaciji
smesta jedan od preostalih celih brojeva,
n - je velicina skupa koji se permutuje,
Funkciju pozivamo sa argumentom m=1 jer krecemo da
formiramo permutaciju od 1. pozicije.*/
void Permutacija(int a[], int m, int n)
{
int i;
/*Ako je pozicija na koju treba smestiti broj premasila
velicinu skupa, onda se svi brojevi vec nalaze u
permutaciji i ispisujemo permutaciju.*/
if(m>n) IspisiNiz(a,n);
for(i=1; i<=n; i++)
{
/*Ako se broj i nije do sada pojavio u permutaciji
od 1 do m-1 pozicije, onda ga stavljamo na poziciju m
i pozivamo funkciju da napravi permutaciju za jedan
vece duzine, tj. m+1. Inace nastavljamo dalje, trazeci
broj kojis e nije pojavio do sada u permutaciji.*/
if(! Koriscen(a,m-1,i))
{
a[m]=i;
Permutacija(a,m+1,n);
}
}
}

144
Збирка решених задатака из Програмског језика С – I део

main()
{
int n, a[MAX];
printf("\n Unesite duzinu permutacije: ");
scanf("%d", &n);
if(n < 0 || n >= MAX)
{
printf("Duzina permutacije mora biti broj od 0 dо %d!\n", MAX);
return 1;
}
printf(" Permutacije: \n");
Permutacija(a,1,n);
getche();
return 0;
}

10.4 Претраживање низова

10.27. Саставити програм који за унети низ реалних бројева, дужине n, исписује елемент највеће
вредности, као и његове позиције у низу.
#include <stdio.h>
#define MAX 100

main()
{
double niz[MAX], max;
int n, i, imax=0;
printf(" Broj elemenata niza: ");
scanf("%d", &n);
Испис на екрану
printf (" Elementi niza: ");
for (i=0; i<n; i++)
scanf ("%lf", &niz[i]);
max=niz[0];
for(i=1; i<n; i++)
if(niz[i] > max)
{
max=niz[i];
imax=i;
}
printf ("\n MAX= %.2f", max);
printf ("\n Pozicija= %d", imax+1);
getche();
return 0;
}

145
Збирка решених задатака из Програмског језика С – I део

10.28. Саставити програм који учита низ реалних бројева, дужине n, налази најмањи и највећи члан
низа, xmin и xmax, и исписује све елементе низа који су мањи од xmax/2 и већи од xmin*2.

#include <stdio.h>
#define MAX 100

main()
{
int n, i;
float x[MAX], xmin, xmax;
printf(" Broj elemenata niza: ");
scanf("%d",&n);
printf(" Elementi niza: ");
for(i=0; i<n; i++) Испис на екрану
scanf("%f",&x[i]);
xmin=x[0];
xmax=x[0];
for(i=1; i<n; i++)
{
if(x[i]<xmin) xmin=x[i];
if(x[i]>xmax) xmax=x[i];
}
printf("\n Elementi [xmin*2<x<xmax/2]: ");
for(i=0; i<n; i++)
if(x[i]<xmax/2 && x[i]>xmin*2) printf("\n %.2f ",x[i]);
getche();
return 0;
}

10.29. Саставити програм који за унети низ целих бројева, дужине n, исписује елемент најмање
вредности међу парним бројевима.
#include <stdio.h>
#define MAX 100

main()
{
int niz[MAX], i, n, min;
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: "); Испис на екрану
for(i=0; i<n; i++)
scanf ("%d",&niz[i]);
for(i=0; i<n; i++)
if(niz[i]%2==0)
{
min=niz[i];
break;
}
if(i==n) printf("\n Nema parnih brojeva!");
else
{
for(i=0; i<n; i++)
if(niz[i]%2==0 && niz[i]<min) min=niz[i];
printf("\n Najmanji parni element: %d", min);
}
getche();
return 0;
}

146
Збирка решених задатака из Програмског језика С – I део

10.30. Саставити програм који за унети низ целих бројева, дужине n, проналази и на екрану
исписује елементе на парним позицијама и међу њима проналази онај који има максималну
вредност. Минимална дужина низа је 2.
#include <stdio.h>
#define MAX 100

main()
{
int niz[MAX], i, n, max;
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf ("%d",&niz[i]);
max=niz[1];
printf("\n Parne pozicije: ");
for(i=0; i<n; i++)
if(i%2!=0 )
{
printf("%d ",niz[i]);
if(niz[i]>max) max=niz[i];
}
printf("\n MAX= %d", max);
getche();
return 0;
} Испис на екрану

10.31. Саставити програм који исписује обавештење да ли учитани низ бројева одговара
Фибоначијевом низу. Низ бројева који се уноси мора имати најмање три елемента.
Фибоначијев низ: f1=1, f2=1, fi=fi-1+fi-2, i=3, 4, 5, ...

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, pom=2, niz[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: "); Испис на екрану
while(n>=3 && n<=MAX)
{
for(i=1; i<=n; i++)
{
scanf("%d", &j);
niz[i-1]=j;
}
for(i=2; i<n; i++)
{
if(niz[i]==(niz[i-1]+niz[i-2]))
pom++;
else
{
printf("\n Niz nije Fibonacijev!");
break;
}

147
Збирка решених задатака из Програмског језика С – I део

}
if(pom==n)
printf("\n Niz jeste Fiboacijev!");
break;
}
getche();
return 0;
}

10.32. Саставити програм који за унети низ целих бројева, дужине n, проналази позицију траженог
елемента или исписује обавештење да тражени елемент не постоји у низу. Користити методу
Линеарног претраживања:
а) без употреба функција;
б) коршћењем функције која линеарно претражује низ.

а) #include <stdio.h>
#define MAX 100

main()
{
int i, n, broj, nadjen=0, niz[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf("%d", &niz[i]);
printf(" Trazena vrednost: ");
scanf("%d", &broj);
for(i=1; i<n; i++)
if(niz[i] == broj)
{ Испис на екрану
nadjen=1;
printf ("\n Vrednost %d ima %d. element niza.", broj, i+1);
}
if(!nadjen)
printf ("\n Vrednost %d nije nadjena u nizu.", broj);
getche();
return 0;
}

б)
#include <stdio.h>
#define MAX 100

/*Funkcija proverava da li se dati broj nalazi u datom nizu celih brojeva.


Funkcija vraca poziciju u nizu na kojoj broj pronadjen
odnosno -1 ukoliko trazenog broja nema.*/
int Trazi(int niz[], int n, int broj)
{
int i;
for(i=0; i<n; i++)
if(niz[i]==broj) return i;
return -1;
}
main()
{
int i, n, broj, niz[MAX];
printf(" Broj elemenata niza: ");
148
Збирка решених задатака из Програмског језика С – I део

scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf("%d", &niz[i]);
printf(" Trazena vrednost: ");
scanf("%d", &broj);
i=Trazi(niz, n, broj);
if(i==-1)
printf("\n Vrednost %d nije nadjena u nizu.", broj);
else
printf("\n Vrednost %d ima %d. element niza.", broj, i+1);
getche();
return 0;
}

10.33. Саставити програм који за унети низ целих бројева, дужине n, проналази позицију траженог
елемента или исписује обавештење да тражени елемент не постоји у низу. Претпоставља се да је низ
уређен у растућем поретку. Користити методу Бинарног претраживања:
а) без употреба функција;
б) коршћењем функције која бинарно претражује низ;
в) коршћењем рекурзивне функције која бинарно претражује низ.

Метода Бинарне претраге:


Нека је дат низ a[0], a[1], …, a[n-1] и вредност елемента који се тражи b. Најпре се b са
средњим елементом низа (или елементом око средине). Ако су једнаки, претраживање је завршено.
Ако је b мање од средњег елемента, тада се претраживање наставља у левој половини низа, а
супротно у десну. У изабраној половини се примењује исти алгоритам.

а)
#include <stdio.h>
#define MAX 100

main()
{
int i, iSrednji, iMin=0, iMax;
int n, broj, nadjen=0, niz[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf("%d", &niz[i]);
printf(" Trazena vrednost: ");
scanf("%d", &broj);
iMax=n-1;
while(iMin<=iMax)
{
iSrednji = (iMin+iMax)/2;
if(broj==niz[iSrednji])
{
nadjen=1;
printf("\n Vrednost %d je %d. element.", broj, iSrednji+1);
break;
}
else if(broj<niz[iSrednji])
iMax=iSrednji-1;
else
iMin=iSrednji+1;

149
Збирка решених задатака из Програмског језика С – I део

}
if(!nadjen)
printf ("\n Vrednost %d nije nadjena u nizu.", broj);
getche();
return 0;
}

б)
#include <stdio.h>
#define MAX 100

/*Funkcija proverava da li se trazeni broj nalazi


unutar niza celih brojeva a.
Funkcija vraca poziciju na kojoj je element nadjen
odnosno -1 ako ga nema.*/
int Trazi(int niz[], int n, int broj)
{
/*Pretrazujemo interval [iMin, iMax]*/
int iMin=0, iMax=n-1;
/*Sve dok interval [iMin, iMax] nije prazan*/
while(iMax<=iMax)
{
/*Srednja pozicija intervala [iMin, iMax]*/
int iSrednji=(iMin+iMax)/2;
/* Ispitujemo odnos trazenog broja i srednjeg elementa*/
if(broj==niz[iSrednji])
return iSrednji; /*Element je pronadjen*/
else if(broj<niz[iSrednji])
iMax=iSrednji-1; /*Pretrazujemo interval [iMin,iSrednji-1]*/
else
iMin=iSrednji+1; /*Pretrazujemo interval [iSrednji+1,iMax]*/
}
return -1; /*Element je nadjen*/
}

main()
{
int i, n, broj, niz[MAX];
printf (" Broj elemenata niza: ");
scanf ("%d", &n);
printf (" Elementi niza: ");
for(i=0; i<n; i++) Испис на екрану
scanf ("%d", &niz[i]);
printf (" Trazena vrednost: ");
scanf ("%d", &broj);
i=Trazi(niz, n, broj);
if(i==-1)
printf("\n Vrednost %d nije nadjena u nizu.", broj);
else
printf("\n Vrednost %d ima %d. element niza.", broj, i+1);
getche();
return 0;
}

150
Збирка решених задатака из Програмског језика С – I део

в)
#include <stdio.h>
#define MAX 100

/*Funkcija proverava da li se trazeni broj nalazi unutar niza celih brojeva a.


Funkcija vraca poziciju na kojoj je element nadjen odnosno -1 ako ga nema.*/
int Trazi(int niz[], int iMin, int iMax, int broj)
{
/*Ukoliko je interval prazan, elementa nema*/
if(iMin>iMax) return -1;
/*Srednja pozicija intervala [iMin, iMax]*/
int iSrednji=(iMin+iMax)/2;
/*Ispitujemo odnos trazenog broja i srednjeg elementa*/
if(broj==niz[iSrednji])
return iSrednji; /*Element je pronadjen*/
else if(broj<niz[iSrednji])
/*Pretrazujemo interval [iMin, iSrednji-1]*/
return Trazi(niz, iMin, iSrednji-1, broj);
else
/*Pretrazujemo interval [iSrednji+1, iMax] */
return Trazi(niz, iSrednji+1, iMax, broj);
return -1; /*Element je nadjen*/
}

main()
{
int i, n, broj, niz[MAX];
printf (" Broj elemenata niza: ");
scanf ("%d", &n);
printf (" Elementi niza: ");
for(i=0; i<n; i++)
scanf ("%d", &niz[i]);
printf (" Trazena vrednost: ");
scanf ("%d", &broj);
i=Trazi(niz, 0, n-1, broj);
if(i==-1)
printf("\n Vrednost %d nije nadjena u nizu.", broj);
else
printf("\n Vrednost %d ima %d. element niza.", broj, i+1);
getche();
return 0;
}

10.5 Уређивање и сортирање низова

Табела 10.1: Облици сортирања низова


поредак изглед низа
опадајући а[0] > а[1] > ... > а[i] > а[i+1] > ... > а[n-1]
растући а[0] < а[1] < ... < а[i] < а[i+1] < ... < а[n-1]
неопадајући а[0] ≤ а[1] ≤ ... ≤ а[i] ≤ а[i+1] ≤ ... ≤ а[n-1]
нерастући а[0] ≥ а[1] ≥ ... ≥ а[i] ≥ а[i+1] ≥ ... ≥ а[n-1]

151
Збирка решених задатака из Програмског језика С – I део

10.34. Саставити програм који од унетог низа А целих бројева дужине n формира и исписује низ В
са обрнутим распоредом елемената.
#include <stdio.h>
#define MAX 100

main()
{
int a[MAX], i, n;
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza A: "); Испис на екрану
for(i=0; i<n; i++)
scanf("%d",&a[i]);
printf("\n Elementi niza B: ");
for(i=n-1; i>=0; i--)
printf("%d ", a[i]);
getche();
return 0;
}

10.35. Саставити програм за циклично премештање елемената задатог низа целих бројева дужине n
за једно место у лево и исписивање новодобијеног низа.

#include <stdio.h>
#define MAX 100

main()
{
int niz[MAX], i, n, pom;
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf("%d",&niz[i]);
pom=niz[0];
for(i=0; i<n-1; i++)
niz[i]=niz[i+1];
niz[n-1]=pom;
printf("\n Novi niz: ");
for(i=0; i<n; i++)
printf("%d ", niz[i]);
getche();
return 0; Испис на екрану
}

10.36. Саставити програм који за унети низ целих бројева дужине n врши ротирање чланова низа за
x места у лево и исписује новодбијени низ.
#include <stdio.h>
#define MAX 100

void CitajNiz(int a[],int n)


{

152
Збирка решених задатака из Програмског језика С – I део

int i;
for(i=0; i<n; i++)
scanf("%d",&a[i]);
}

void PisiNiz(int a[],int n)


{
int i;
for(i=0; i<n; i++)
printf("%d ", a[i]); Испис на екрану
}

void Rotiraj(int a[], int n)


{
int pom, i;
pom=a[0];
for(i=1; i<n; i++)
a[i-1]=a[i];
a[n-1]=pom;
}

main()
{
int i, x, n, a[MAX];
printf(" Broj elemenata niza: ");
scanf("%d",&n);
printf(" Elementi niza: ");
CitajNiz(a, n);
printf(" Broj mesta za rotaciju: ");
scanf("%d",&x);
for(i=0; i<x; i++)
Rotiraj(a, n);
printf("\n Rotirani niz za %d mesta: ", x);
PisiNiz(a, n);
getche();
return 0;
}

10.37. Саставити програм који за унети низ целих бројева дужине n врши замену суседних
елемената низа на парним и непарним позицијама и исписује новодобијени низ.
#include <stdio.h>
#define MAX 100

void CitajNiz(int a[],int n)


{
int i;
for(i=0; i<n; i++)
scanf("%d",&a[i]);
}

void PisiNiz(int a[],int n)


{
int i;
for(i=0; i<n; i++)
printf("%d ", a[i]);
}

void Zameni(int a[], int n)


{
153
Збирка решених задатака из Програмског језика С – I део

int i, pom;
for(i=0; i<n-1; i+=2)
{
pom=a[i];
a[i]=a[i+1];
a[i+1]=pom;
}
}
Испис на екрану
main()
{
int i, x, n, a[MAX];
printf(" Broj elemenata niza: ");
scanf("%d",&n);
printf(" Elementi niza: ");
CitajNiz(a, n);
Zameni(a, n);
printf("\n Novi niz: ");
PisiNiz(a, n);
getche();
return 0;
}

10.38. Саставити програм који за унети низ целих бројева дужине n формира и приказује нови низ
који је састављен од елемената без понављања унетог низа.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, nadjeniIsti, a[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf ("%d", &a[i]);
printf("\n Novi niz: ");
for(i=0; i<n-1; i++)
{
nadjeniIsti=0;
for(j=i+1; j<n; j++)
if(a[i] == a[j])
{
nadjeniIsti=1;
break;
}
if(!nadjeniIsti)
printf ("%d ",a[i]);
}
printf ("%d ",a[n-1]);
getche();
return 0;
} Испис на екрану

154
Збирка решених задатака из Програмског језика С – I део

10.39. Саставити програм за сортирање унетог низа целих бројева дужине n у неопадајући поредак
методом избора (Selection Sort). Исписати сортирани низ.
Selection Sort подразумева да минимални елемент низа размени са a[0], минимални елемент
одсечка a[1], a[2], …, a[n-1] разменити са a[1], минимални елемент одсечка a[2], a[3], …, a[n-1]
разменити са a[2]; исти поступак применити на преостале елементе осим последњег који се налази на
свом месту.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, pom, niz[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf ("%d", &niz[i]);
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(niz[i] > niz[j])
{
pom=niz[i];
niz[i]=niz[j];
niz[j]=pom;
}
printf(" Sortirani niz: ");
for(i=0; i<n; i++)
printf ("%d ",niz[i]);
getche();
return 0; Испис на екрану
}

10.40. Саставити програм за сортирање унетог низа целих бројева дужине n у неопадајући поредак
методом уметања (Insert Sort). Исписати сортирани низ.
Insert Sort: Нека је првих k елемената већ уређено у неопадајућем поретку, тада се узима
(k+1)-ви елемент и умеће на одговарајуће место међу првих k елемената тако да првих k+1
елемената буде уређено. Овај се метод примењује за k од 0 до n-2.

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, pom, niz[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf("%d", &niz[i]);
for(i=1; i<n; i++)
{
pom=niz[i];
for(j=i-1; j>=0; j--)
if (niz[j] > pom)
niz[j+1]=niz[j];
else break;
155
Збирка решених задатака из Програмског језика С – I део

niz[j+1]=pom;
}
printf (" Sortirani niz: ");
for(i=0; i<n; i++)
printf ("%d ",niz[i]);
getche();
return 0;
} Испис на екрану

10.41. Саставити програм за сортирање унетог низа целих бројева дужине n у неопадајући поредак
методом мехурића (Bubble Sort). Исписати сортирани низ.
Bubble Sort: Пролазимо кроз низ редом поредећи суседне елементе, и при том их замењујући
ако су у погрешном поретку. Овим се највећи елемент попут мехурића истискује на "површину", тј.
на крајњу десну позицију. Након тога је потребно овај поступак поновити над низом а[0],...,а[n-2], тј.
над првих n-1 елемената низа без последњег који је постављен на праву позицију. Након тога се исти
поступак понавља над све краћим и краћим префиксима низа, чиме се један по један истискују
елемененти на своје праве позиције.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, pom, niz[MAX];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf("%d", &niz[i]);
for(i=n-1; i>0; i--)
for(j=0; j<i; j++)
if(niz[j] > niz[j+1])
{
pom=niz[j];
niz[j]=niz[j+1];
niz[j+1]=pom;
}
printf(" Sortirani niz: ");
for(i=0; i<n; i++)
printf("%d ",niz[i]);
getche();
return 0; Испис на екрану
}

10.42. Саставити програм којим се у уређени низ бројева умеће нови број тако да низ и даље буде
уређен. Исписати новодобијени низ.
#include <stdio.h>
#define MAX 100

main()
{
int i, n, b, niz[MAX+1];
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
156
Збирка решених задатака из Програмског језика С – I део

for(i=0; i<n; i++)


scanf("%d", &niz[i]);
printf(" Element koji treba umetnuti: ");
scanf("%d", &b);
for(i=n-1; i>=0 && niz[i]>b; i--)
niz[i+1]=niz[i];
niz[i+1]=b;
n++;
printf("\n Novi niz: ");
for(i=0; i<n; i++)
printf("%d ", niz[i]);
getche();
return 0;
Испис на екрану
}

10.43. Саставити програм који учитава два низа целих бројева који су уређени по неопадајућем
редоследу (различитих дужина) и исписује њихову фузију која је такође неопадајућа.
#include <stdio.h> else
#define MAX 100 {
for(ic=0; ic<nc; ic++)
main() {
{ if(nizA[ia]<=nizB[ib])
int nizA[MAX], nizB[MAX], nizC[2*MAX]; {
int na, nb, nc, ia, ib, ic; nizC[ic]=nizA[ia];
printf(" Broj elemenata niza A: "); ia++;
scanf("%d", &na); }
printf(" Elemneti A: "); else
for(ia=0; ia<na; ia++) {
scanf ("%d", &nizA[ia]); nizC[ic]=nizB[ib];
printf(" Broj elemenata niza B: "); ib++;
scanf("%d", &nb); }
printf(" Elemneti B: "); }
for(ib=0; ib<nb; ib++) }
scanf("%d", &nizB[ib]); printf("\n Elementi niza C: ");
nc=na+nb; for(ic=0; ic<nc; ic++)
ia=0; printf("%d ", nizC[ic]);
ib=0; getche();
if(na==0) return 0;
{ }
for(ic=0; ic<nc; ic++)
nizC[ic]=nizB[ic];
}
else if (nb==0)
{
for(ic=0; ic<nc; ic++)
nizC[ic]=nizA[ic];
}

Испис на екрану

157
Збирка решених задатака из Програмског језика С – I део

10.44. Саставити програм који исписује број који се највећи број пута појављује у низу целих
бројева, као и број појављивања. Прво сортирати низ у растућем поретку, а затим пронаћи најдужу
секвенцу једнаких елемената. Низ се уноси са тастатуре.

#include <stdio.h>
#define MAX 100

void Sortiraj(int a[], int n)


{
int i, j, pom, min;
for(i=0; i<n-1; i++)
{
min=i;
for(j=i+1; j<n; j++)
if(a[j]<a[min])
min=j;
if(min!=i)
{
pom=a[i];
a[i]=a[min];
a[min]=pom;
}
}
}

main()
{
int a[MAX], i, j, n, indeks=-1, duzina=-1, brojac;
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++)
scanf("%d", &a[i]);
Sortiraj(a,n);
printf("\n Sortiran niz: ");
for(i=0; i<n; i++)
printf("%d ", a[i]);
for(i=0; i<n; i++)
{
brojac=1;
for(j=i+1; j<n && a[i]==a[j]; j++)
brojac++;
if(brojac > duzina)
{
duzina=brojac;
indeks=i;
}
}
printf("\n Najveci broj puta se pojavljuje broj %d i to %d puta.",
a[indeks], duzina);
getche();
return 0;
}

Испис на екрану

158
Збирка решених задатака из Програмског језика С – I део

10.45. Саставити програм који испистује да ли у унетом низу целих бројева постоје два елемента
чији је збир једнак датом броју. Користити бинарну претрагу за проналажење допуне до датог броја.
Елементи низа се уносе са тастатуре.
#include <stdio.h>
#define MAX 100

void Sortiraj(int a[], int n)


{
int i, j, pom, min;
for(i=0; i<n-1; i++)
{
min=i;
for(j=i+1; j<n; j++)
if(a[j]<a[min])
min=j;
if(min!=i)
{
pom=a[i];
a[i]=a[min];
a[min]=pom;
}
}
} Испис на екрану
int BinarnaPretraga(int a[], int n, int x)
{
int s, l=0, d=n-1;
while(l<=d)
{
s=(l+d)/2;
if(a[s]==x) return s;
if(a[s]>x) d=s-1;
else l=s+1;
}
return -1;
}

main()
{
int a[MAX], n, i, zbir, drugi, nadjen =0;
printf(" Broj elemenata niza: ");
scanf("%d", &n);
printf(" Elementi niza: ");
for(i=0; i<n; i++) scanf("%d", &a[i]);
Sortiraj(a, n);
printf(" Vrednost zbir dva elementa: ");
scanf("%d", &zbir);
/*Uslov drugi>i stoji samo da bi se izbegla nepotreban ponavljanja u ispisu.*/
for(i=0; i< n; i++)
if((drugi=BinarnaPretraga(a, n, zbir-a[i])) != -1 && drugi>i)
{
printf("\n Trazeni zbir se moze formirati od elemenata: %d i %d",
a[i], a[drugi]);
nadjen++;
}
if(!nadjen) printf(" Trazeni zbir se ne moze dobiti!\n");
getche();
return 0;
}

159
Збирка решених задатака из Програмског језика С – I део

11 МАТРИЦЕ

11.1. Саставити програм који учитава, а затим исписује елементе матрице mxn. Елементи матрице
су цели бројеви.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, m, n, mat[MAX][MAX];
printf(" Vrsta m= ");
scanf("%d", &m);
printf(" Kolona n= ");
scanf("%d", &n);
/*Citanje matrice sa tastature*/
for(i=0; i<m; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ",i,j);
scanf("%d", &mat[i][j]);
}
/*Prikaz matrice*/
printf("\n Uneta matrica:\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
printf(" %d", mat[i][j]);
printf("\n"); Испис на екрану
}
getche();
return 0;
}

160
Збирка решених задатака из Програмског језика С – I део

11.2. Саставити програм који за унету матрицу димензија nxn врши сабирање њених елеменета и
исписује добијени резултат. Елементи су цели бројеви.

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, s=0, mat[MAX][MAX];
printf(" n= ");
scanf("%d", &n);
printf(" Elementi:\n");
for(i=0; i<n; i++)
for(j=0; j<n; j++)
scanf("%d", &mat[i][j]);
for(i=0; i<n; i++) Испис на екрану
for(j=0; j<n; j++)
s+=mat[i][j];
printf("\n suma= %d", s);
getche();
return 0;
}

11.3. Саставити програм који учита матрицу димензија mхn, а затим врши сабирање елемената
који су парни бројеви. На крају исписати суму парних бројева и број елемената који су једнаки нули.
Елементи матрице су цели бројеви од 0 до 9.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, m, n, s=0, nule=0, mat[MAX][MAX];
printf(" m= ");
scanf("%d",&m);
printf(" n= ");
scanf("%d", &n);
printf("\n Uneta matrica:\n");
for(i=0; i<m; i++)
for(j=0; j<n; j++)
scanf("%d",&mat[i][j]);
for(i=0; i<m; i++)
for(j=0; j<n; j++)
{
if(mat[i][j]%2==0) s+=mat[i][j];
if(mat[i][j]==0) nule++;
} Испис на екрану
printf("\n Suma parnih elemenata: %d", s);
printf("\n Broj elemenata jednakih nuli: %d", nule);
getche();
return 0;
}

161
Збирка решених задатака из Програмског језика С – I део

11.4. Саставити програм који учита две матрице целих бројева, a и b, обе димензија mхn, а затим
врши сабирање ове две матрице и исписује нову матрицу с. Матрице се сабирају тако што се
сабирају елементи матрица са истим индексима.
 a11 a12 K a1n   b11 b12 L b1n 
a a22 K a2 n   b21 b22 L b2 n 
c = a + b =  21 + =
 M   M 
   
am1 am 2 K amn  bm1 bm 2 L bmn 

 a11 + b11 a12 + b12 K a1n + b1n   c11 c12 L c1n 


a + b a22 + b22 K a2 n + b2 n   c21 c22 L c2 n 
 21 21 =
 M   M 
   
am1 + bm1 am 2 + bm 2 K amn + bmn  cm1 cm 2 L cmn 

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, m, mat1[MAX][MAX], mat2[MAX][MAX];
printf(" m= ");
scanf("%d", &m);
printf(" n= ");
scanf("%d", &n);
printf("\n Elementi prve matrice: \n");
for(i=0; i<m; i++)
for(j=0; j<n; j++)
scanf("%d", &mat1[i][j]);
printf("\n Elementi druge matrice: \n");
for(i=0; i<m; i++)
for(j=0; j<n; j++)
scanf("%d", &mat2[i][j]);
printf("\n Zbir dve matrice:\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
printf(" %d", mat1[i][j]+mat2[i][j]);
printf("\n");
}
getche(); Испис на екрану
return 0;
}

11.5. Саставити програм који ће учитати матрицу димензија nxn, а затим исписати матрицу у
облику таблице, исписати све елементе на главној и споредној дијагонали, као и суме елемената на
главној и споредној дијагонали. Елементи матрице су цели бројеви.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, sgd=0, ssd=0, mat[MAX][MAX];
printf(" n= ");
scanf("%d", &n);

162
Збирка решених задатака из Програмског језика С – I део

printf(" Elementi:\n");
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &mat[i][j]);
}
printf("\n Uneta matrica:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %d",mat[i][j]);
printf("\n");
}
printf("\n Elementi glavne dijagonale: ");
for(i=0; i<n; i++)
{
printf("%d ",mat[i][i]);
sgd+=mat[i][i];
}
printf("\n Suma glavne dijagonale = %d", sgd);
printf("\n Elementi sporedne dijagonale: ");
for(i=0; i<n; i++)
{
printf("%d ",mat[i][n-i-1]);
ssd+=mat[i][n-i-1];
}
printf("\n Suma sporedne dijagonale = %d", ssd);
getche();
return 0;
}

Испис на екрану

163
Збирка решених задатака из Програмског језика С – I део

11.6. Саставити програм који учита матрицу димензија nxn, а затим је исписује у облику таблице и
израчунава и исписује суму елемената у свакој врсти. Елементи матрице су цели бројеви.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, s=0, mat[MAX][MAX];
printf(" n= ");
scanf("%d", &n);
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &mat[i][j]);
}
printf("\n Uneta matrica:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %d", mat[i][j]);
printf("\n"); Испис на екрану
}
printf("\n Suma elememenata vrste:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
s+=mat[i][j];
printf(" %d", s);
}
getche();
return 0;
}

11.7. Саставити програм који учита матрицу димензија mxn, а затим је исписује у облику таблице
и на основу унетог редног броја врсте врши сабирање елемената у тој врсти. Елементи матрице су
цели бројеви.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, m, vrsta, s=0, mat[MAX][MAX];
printf(" m= ");
scanf("%d", &m);
printf(" n= ");
scanf("%d", &n);
for(i=0; i<m; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &mat[i][j]);
}
printf("\n Uneta matrica:\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
printf(" %d", mat[i][j]);
164
Збирка решених задатака из Програмског језика С – I део

printf("\n");
}
printf("\n Redni broj vrste ciji zbir elemenata zelite: ");
scanf("%d",&vrsta);
for(j=0; j<n; j++)
s=s+mat[vrsta-1][j];
printf("\n Zbir elememenata %d. vrste: %d", vrsta, s);
getche();
return 0;
}

Испис на екрану

11.8. Саставити програм који учита матрицу целих бројева А димензија mxn, а затим исписује
њене елементе у редоследу као што је приказано на следећој слици:

#include <stdio.h>
#define MAX 100

main()
{
int i, j, m, n, a[MAX][MAX];
printf(" m= ");
scanf("%d", &m);
printf(" n= ");
scanf("%d", &n);
printf(" Matrica:\n");
for(i=0; i<m; i++)
for(j=0; j<n; j++)
scanf("%d", &a[i][j]);
165
Збирка решених задатака из Програмског језика С – I део

printf("\n Elementi:\n");
for(j=0;j<n;j++)
{
if(j%2==0)
for(i=0; i<m; i++)
printf(" %d",a[i][j]);
else
for(i=m-1; i>=0; i--)
printf(" %d",a[i][j]);
}
getche();
return 0;
} Испис на екрану

11.9. Саставити програм који учита матрицу реалних бројева А димензија nxn, а затим формира
нову матрицу тако што све чланове врсте (укључујући и дијагонални) дели са дијагоналним чланом.
Уколико је дијагонални члан једнак нули, све чланове у том реду поставља на нулу, осим
дијагоналног који поставља на 1. Исписати добијену матрицу.

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n;
float a[MAX][MAX], t;
printf(" n= ");
scanf("%d", &n);
printf(" Matrica:\n");
for(i=0; i<n; i++)
for(j=0; j<n; j++)
scanf("%f",&a[i][j]);
for(i=0; i<n; i++)
if(a[i][i]!=0)
{ Испис на екрану
t=a[i][i];
for(j=0; j<n; j++)
a[i][j]/=t;
}
else
{
for(j=0; j<n; j++)
a[i][j]=0;
a[i][i]=1;
}
printf("\n Nova matrica:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %.2f",a[i][j]);
printf("\n");
}
getche();
return 0;
}

166
Збирка решених задатака из Програмског језика С – I део

11.10. Саставити програм који учита један цео број х и матрицу целих бројева А димензија nxn, а
затим формира нову матрицу тако што све елементе испод главне дијагонала увећа за вредност х, а
елементе изнад главне дијагонале увећава за 2х. Елементи на главној дијагонали се не мењају.
Исписати добијену матрицу.

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, x, a[MAX][MAX];
printf(" x= ");
scanf("%d",&x);
printf(" n= ");
scanf("%d", &n);
printf("\n Uneta matrica: \n");
for(i=0; i<n; i++)
for(j=0; j<n; j++)
scanf("%d",&a[i][j]);
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{
if(i>j) a[i][j]+=x; Испис на екрану
if(i<j) a[i][j]+=2*x;
}
printf("\n Nova matrica:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %d",a[i][j]);
printf("\n");
}
getche();
return 0;
}

11.11. Саставити програм који учита матрицу целих бројева А димензија mxn, а затим исписује
матрицу у облику таблице и врши замену места двема колонама на основу унета два цела броја који
представљају редне бројеве колона.

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, m, k1, k2, pom, a[MAX][MAX];
printf(" m= ");
scanf("%d", &m);
printf(" n= ");
scanf("%d", &n);
for(i=0; i<m; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
printf("\n Zadata matrica:\n");
167
Збирка решених задатака из Програмског језика С – I део

for(i=0; i<m; i++)


{
for(j=0; j<n; j++)
printf(" %d", a[i][j]);
printf("\n");
}
do
{
printf("\n Redni broj kolona za zamenu: ");
scanf("%d%d", &k1, &k2);
}
while(k1<1 || k1>n || k2<1 || k2>n);
for(i=0; i<n; i++)
{
pom=a[i][k1-1];
a[i][k1-1]=a[i][k2-1];
a[i][k2-1]=pom;
}
printf("\n Nova matrica:\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
printf(" %d", a[i][j]);
printf("\n");
}
getche();
return 0;
}

Испис на екрану

168
Збирка решених задатака из Програмског језика С – I део

11.12. Саставити програм који учита матрицу целих бројева А димензија nxn, а затим исписује
матрицу у облику таблице и врши њено транспоновање. Танспонована матрица је матрица која се
добија када се врсте почетне матрице поређају по колонама.
а) без употребе функција;
б) употребом функција за учитавања, исписивање и транспоновање матрице.
Исписати транспоновану матрицу.

а)
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, pom, mat[MAX][MAX];
printf(" n= ");
scanf("%d", &n);
printf("\n");
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &mat[i][j]);
}
printf("\n Zadata matrica: \n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %d",mat[i][j]);
printf("\n");
}
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
{
pom=mat[i][j];
mat[i][j]=mat[j][i];
mat[j][i]=pom;
}
printf ("\n Transponovana matrica:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %d",mat[i][j]);
printf("\n");
}
getche();
return 0;
}

б)
#include <stdio.h>
#define MAX 100

void Citaj(int mat[MAX][MAX], int n)


{
int i, j;
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &mat[i][j]);
169
Збирка решених задатака из Програмског језика С – I део

}
}

void Pisi(int mat[MAX][MAX], int n)


{
int i, j;
for (i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %d",mat[i][j]);
printf("\n");
}
}

void Transp(int mat[MAX][MAX], int n)


{
int i, j, pom;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
{
pom=mat[i][j];
mat[i][j]=mat[j][i];
mat[j][i]=pom;
} Испис на екрану
}

main()
{
int i, j, n, pom, mat[MAX][MAX];
printf(" n= ");
scanf("%d", &n);
printf("\n");
Citaj(mat,n);
printf("\n Zadata matrica: \n");
Pisi(mat,n);
Transp(mat,n);
printf ("\n Transponovana matrica:\n");
Pisi(mat,n);
getche();
return 0;
}

11.13. Саставити програм који учита матрицу целих бројева А димензија nxn, а затим исписује
матрицу у оквиру таблице. Програм треба да одређује највећи и најмањи елемент у свакој врсти и
колони, а добијене елементе сместити у једнодимензионалне низове. Исписати формиране низове.

#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, a[MAX][MAX];
int maxv[MAX], minv[MAX], maxk[MAX], mink[MAX];
printf(" n= ");
scanf("%d", &n);
printf("\n");
for(i=0; i<n; i++)
for(j=0; j<n; j++)

170
Збирка решених задатака из Програмског језика С – I део

{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
printf("\n Zadata matrica: \n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %d",a[i][j]);
printf("\n");
}
for(i=0; i<n; i++)
{
minv[i]=a[i][0];
maxv[i]=a[i][0];
mink[i]=a[0][i];
maxk[i]=a[0][i];
for(j=1; j<n; j++)
{
if(a[i][j]<minv[i]) minv[i]=a[i][j];
if(a[i][j]>maxv[i]) maxv[i]=a[i][j];
if(a[j][i]<mink[i]) mink[i]=a[j][i];
if(a[j][i]>maxk[i]) maxk[i]=a[j][i]; Испис на екрану
}
}
printf("\n Najveci u vrstama: ");
for(i=0; i<n; i++)
printf("%d ", maxv[i]);
printf("\n Najmanji u vrstama: ");
for(i=0; i<n; i++)
printf("%d ", minv[i]);
printf("\n Najveci u kolonama: ");
for(i=0; i<n; i++)
printf("%d ", maxk[i]);
printf("\n Najmanji u kolonama: ");
for(i=0; i<n; i++)
printf("%d ", mink[i]);
getche();
return 0;
}

11.14. Саставити програм који учита две матрице целих бројева, А димензија nxm, и матрицу B
димензија mxk, а затим формира и исписује матрицу C добијену множењем матрица А и В.

 a11 a12 K a1m   b11 b12 L b1k 


a a22 K a2 m   b21 b22 L b2 k 
c = a ⋅ b =  21 ⋅ =
 M   M 
   
an1 an 2 K anm  bm1 bm 2 L bmk 

 a11b11 + a12 b21 + K + a1m bm1 L a11b1k + a12 b2 k + K + a1m bmk   c11 c12 L c1n 
a b + a b + K + a b L a 21b1k + a 22 b2 k + K + a 2 m bmk   c 21 c 22 L c 2 n 
 21 11 22 21 2 m m1
=
 M   M 
   
a n1b11 + a n 2 b21 + K + a nm bm1 K a n1b1k + a n 2 b2 k + K + a nm bmk  c m1 cm2 L c mn 

171
Збирка решених задатака из Програмског језика С – I део

Две матрице могу да се множе ако је број врсти друге матрице једнак броју колона прве
матрице.

#include <stdio.h>
#define MAX 100

void Citaj(int mat[MAX][MAX], int n, int m)


{
int i, j;
for(i=0; i<n; i++)
for(j=0; j<m; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &mat[i][j]);
}
}

void Pisi(int mat[MAX][MAX], int n, int m)


{
int i, j;
for (i=0; i<n; i++)
{
for(j=0; j<m; j++)
printf(" %3d",mat[i][j]);
printf("\n");
}
}

main()
{
int a[MAX][MAX], b[MAX][MAX];
int c[MAX][MAX], d[MAX][MAX];
int i, j, n, m, k, t;
printf(" Broj vrsta matrice A: ");
scanf("%d",&n);
printf(" Broj kolona matrice A: ");
scanf("%d",&m);
printf(" Broj kolona matrice B: ");
scanf("%d",&k);
printf("\n Matrica A:\n");
Citaj(a,n,m);
printf("\n Matrica B:\n");
Citaj(b,m,k);
for(i=0; i<n; i++)
for(j=0; j<k; j++)
{
c[i][j]=0; Испис на екрану
for(t=0; t<m; t++)
c[i][j]=c[i][j]+a[i][t]*b[t][j];
}
printf("\n Matrica A:\n");
Pisi(a,n,m);
printf("\n Matrica B:\n");
Pisi(b,m,k);
printf("\n Matrica C:\n");
Pisi(c,n,k);
getche();
return 0;
}

172
Збирка решених задатака из Програмског језика С – I део

11.15. Саставити програм који учита матрицу целих бројева A димензија nxn, а затим исписује
матрицу која представља производ АхА.
#include <stdio.h>
#define MAX 100

main()
{
int i, j, n, k;
int a[40][40],b[40][40];
printf("\n n= ");
scanf("%d",&n);
printf("\n Matrice %dx%d\n", n,n);
for(i=0; i<n; i++)
for(j=0; j<n; j++)
scanf("%d",&a[i][j]);
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{ Испис на екрану
b[i][j]=0;
for(k=0; k<n; k++)
b[i][j]+=a[i][k]*a[k][j];
}
printf("\n Matrica AxA:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf(" %4d ", b[i][j]);
printf("\n");
}
getche();
return 0;
}

11.16. Саставити програм који учита матрицу целих бројева A димензија mxm и цео број n, а затим
исписује матрицу која представља n-ти производ матрице А (n-ти степен матрице А).

#include <stdio.h>
#define MAX 100

main()
{
int i, j, m, n, k, p;
int a[MAX][MAX], b[MAX][MAX], c[MAX][MAX];
printf("\n Stepen n= ");
scanf("%d",&n);
printf(" Dimanzija m= ");
scanf("%d",&m);
printf("\n Matrica %dx%d:\n", m,m);
for(i=0; i<m; i++)
for(j=0; j<m; j++)
{
scanf("%d",&a[i][j]);
b[i][j]=a[i][j];
}

173
Збирка решених задатака из Програмског језика С – I део

/*Stepenovanje matrice mnozeci je sa samom sobom n-1 puta*/


for(p=1; p<n; p++)
{
for(i=0; i<m; i++)
for(j=0; j<m; j++)
{
c[i][j]=0;
for(k=0; k<m; k++)
c[i][j]+=a[i][k]*b[k][j];
}
/*Prenos matrice C u matricu B*/
for(i=0; i<m; i++)
for(j=0; j<m; j++)
b[i][j]=c[i][j];
}

/*Ispis matrice*/
printf("\n Rezultujuca matrica:\n");
for(i=0; i<m; i++) Испис на екрану
{
for(j=0; j<m; j++)
printf("%6d ",c[i][j]);
printf("\n");
}
getche();
return 0;
}

11.17. Саставити програм који учита матрицу реалних бројева A димензија nxn и, а затим дату
матрицу своди на горњу десну троугласту. Исписати новодобијену матрицу.

#include <stdio.h>
#define MAX 100

main()
{
float a[MAX][MAX], z, xm;
int n, i, j, k, s=1;
printf("\n n= ");
scanf("%d",&n);
printf("\n Matrica %dx%d:\n",n,n);
for(i=0; i<n; i++)
for(j=0; j<n; j++)
scanf("%f",&a[i][j]);
/*Iteracija za svaku kolonu: svodjenje na nulu clanova ispod dijagonale*/
for(k=0; k<n-1; k++)
{
if(a[k][k]==0)
/*Potrebno je izvrsiti zamenu vrsti; nadji clan u k-toj koloni razlicit
od nule; ako ga nema, ispisi poruku*/
{
for(i=k+1; i<n-1 && a[i][k]==0; i++)
if(i==n-1 && a[i][k]==0)
{
printf("\n Matrica se ne moze svesti na gornju trouglastu.");
return 1;
}
/*Zameniti i-tu i k-tu vrstu*/

174
Збирка решених задатака из Програмског језика С – I део

for(j=k; j<n; j++)


{
z=a[k][j];
a[k][j]=a[j][k];
a[j][k]=z;
}
s=-s;
}
/*Svodjenje na nulu clanova ispod dijagonale */
for(i=k+1; i<n; i++)
{
xm=a[i][k]/a[k][k];
for(j=k; j<n; j++)
a[i][j]-=xm*a[k][j];
}
}
if(a[n][n]==0)
{
printf("\n Matrica se ne moze svesti na gornju trouglastu.");
return 1;
}
a[n][n]=a[n][n]*s; /*Postavi ispravni predznak*/

/*Ispis rezultata*/
printf("\n Gornja trouglasta matrica:\n");
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
printf("%7.2f",a[i][j]);
printf("\n");
}
getche();
return 0;
}

Испис на екрану

Решење се своди на итеративни поступак у петљи у којој се повећва варијабла k. Свођење


чланова на нулу обавља се за све врсте испод дијагонале и то у свакој колони од прве до
предпоследње (k иде од 0 до n-2) јер у последњој колони више нема чланова испод дијагоналног.
Ако је дијагонални члан једнак нули па није могуће с њим делити, проналази се врста испод
дијагонале која у тој (k-тој) колони има вредност различиту од нуле па се ти елементи замене и
варијабли ѕ се промени предзнак. Ако таква врста не постоји и замена није могућа, матрица се не
може свести на горњу троугласту па се исписује одговарајућа порука и завршава даље рачунање. За
дијагонални члан различит од нуле обавља се множење и умањење да би се добиле нуле у свим
врстама испод дијагонале. При томе се не узимају колоне лево од дијагонале (j иде од k до n-1) јер су
ти чланови већ сведени на нулу у претходним итерацијама. Након обављене итерације по k (до
предпоследње колоне), може се догодити да је последњи дијагонални члан једнак нули. Тада се
матрица опет не може свести на горњу троугласту па се исписује одговарајућа порука.

175
Збирка решених задатака из Програмског језика С – I део

11.18. Саставити програм који учита матрицу целих бројева димензија mxn, а затим врши
уређивање колона матрице по неопадајућем редоследу збирова елемената по колонама. Исписати
новодобијену матрицу.

#include <stdio.h>
#define MAX 100

main()
{
int mat[MAX][MAX], s[MAX], p;
int m, n, i, j, min;
printf(" m= ");
scanf("%d", &m);
printf(" n= ");
scanf("%d", &n);
for(i=0; i<m; i++)
for(j=0; j<n; j++)
{
printf(" element[%d][%d] = ", i, j);
scanf("%d", &mat[i][j]);
}

/*Ispisivanje zadate matrice*/


printf("\n Zadata matrica: \n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
printf(" %d",mat[i][j]);
printf("\n");
}
Испис на екрану
/*Racunanje zbirova elemenata po kolonama*/
for(j=0; j<n; j++)
for(s[j]=i=0; i<m; i++)
s[j]+=mat[i][j];

/*Uredjivanje kolona po velicinama zbirova*/


for(i=0; i<n-1; i++)
{
/*Тrazenje najmanjeg zbira*/
for(min=i, j=i+1; j<n; j++)
if(s[j]<s[min]) min=j;
if(min != i)
{
p=s[i];
s[i]=s[min];
s[min]=p;
/*Zamena kolona*/
for(j=0; j<n; j++)
{
p=mat[j][i];
mat[j][i]=mat[j][min];
mat[j][min]=p;
}
}
}

/*Ispisivanje uredjene matrice*/


printf("\n Uredjena matrica:\n");
for(i=0; i<m; i++)

176
Збирка решених задатака из Програмског језика С – I део

{
for(j=0; j<n; j++)
printf(" %d", mat[i][j]);
printf("\n");
}
printf("\n Suma po kolonama:\n");
for(j=0; j<n; j++)
printf("% d", s[j]);
getche();
return 0;
}

177
ЛИТЕРАТУРА

[1] Brian W. Kernighan, Dennis M. Ritchie: The C Programming Language, New Jersey, 1988.

[2] Laslo Kraus: Programski jezik C sa rešenim zadacima, Akademska misao, Beograd, 2006.

[3] Laslo Kraus: Rešeni zadaci iz programskog jezika C, Akademska misao, Beograd, 2005.

[4] Ivo Mateljan: Programiranje C jezikom, Split, 2005/2006.

[5] Jozo J. Dujmović: Programski jezici i metode programiranja, Naučna knjiga, Beograd,
1990.

[6] B. S. Gottfired: Theory and Problems of Programming with C, Schaum’s outline series,
McGraw-Hill, 1996.

[7] Clovis Tondo, Scott Gimpel: Programski jezik C – rešenja zadataka, CET, Beograd, 2004.

[8] A.Hansen: Programiranje na jeziku C – potpuni vodič za programski jezik C,


Mikroknjiga, Beograd, 2000.

[9] Igor ðurović, Slobodan ðukanović, Vesna Popović: Programski jezik C sa zbirkom
riješenih zadataka, ETF Podogorica, Podgorica, 2006.

[10] Milan Čabarkapa: C osnovi programiranja, Krug, Beograd, 1996.

[11] Milan Čabarapa, Stanka Matković: C/C++ zbirka zadataka, Krug, Beograd, 2003.

[12] Milan Čabarkapa, Nevenka Spalević: Metodička zbirka zadataka iz programiranja, Sova,
Novi Beograd, 1997.

[13] Абрамов С.А., Гнездилова Г.Г., Капустина Е.Н., Селљун М.И.: Задачи по
программированию, Наука, Москва, 1988.

[14] Абрамов В.Г., Тирфонов Н.П, Трифонава Г.Н., Введение в язык Паскалъ, Наука,
Москва, 1988.
Osnovi programiranja
Programski jezik C
— Zadaci sa vežbi —

Milena Vujošević - Janičić 2005/2006


2

2
Sadržaj

1 Programski jezik C 5
1.1 Zdravo svete! . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Imena promenljivih . . . . . . . . . . . . . . . . . . . 6
1.3 Deklaracije . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Tipovi i veličina podataka . . . . . . . . . . . . . . . 6
1.5 Funkcije printf i scanf . . . . . . . . . . . . . . . . . . 7
1.6 Aritmetički operatori . . . . . . . . . . . . . . . . . . 9
1.7 Operatori i izrazi dodeljivanja vrednosti . . . . . . . 11
1.8 Inkrementacija i dekrementacija . . . . . . . . . . . . 12
1.9 Relacioni i logički operatori . . . . . . . . . . . . . . 13
1.10 Kontrola toka — if, while, do - while, for . . . . . . . 14
1.10.1 if . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.10.2 Else-if . . . . . . . . . . . . . . . . . . . . . . 15
1.10.3 while . . . . . . . . . . . . . . . . . . . . . . . 17
1.10.4 do-while . . . . . . . . . . . . . . . . . . . . . 17
1.10.5 for . . . . . . . . . . . . . . . . . . . . . . . . 17
1.11 Switch . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.12 Uslovni izraz . . . . . . . . . . . . . . . . . . . . . . . 19
1.13 Simboličke konstante . . . . . . . . . . . . . . . . . . 20
1.14 Enumeracija . . . . . . . . . . . . . . . . . . . . . . . 21
1.15 Funkcije . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.16 Nizovi . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.17 Konstante . . . . . . . . . . . . . . . . . . . . . . . . 27
1.18 Konverzija . . . . . . . . . . . . . . . . . . . . . . . . 28
1.18.1 Automatska konverzija . . . . . . . . . . . . . 28
1.18.2 Eksplicitna konverzija . . . . . . . . . . . . . 28
1.18.3 Funkcije koje vrše konverziju . . . . . . . . . . 29
1.19 Operator sizeof() . . . . . . . . . . . . . . . . . . . 30
1.20 Znakovni ulaz i izlaz . . . . . . . . . . . . . . . . . . 31
1.21 Nizovi . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.22 Dvostruka for petlja . . . . . . . . . . . . . . . . . . 39
1.23 Formiranje HTML dokumenta . . . . . . . . . . . . . 40

3
4 SADRŽAJ

1.24 Funkcije — prenos parametara po vrednosti . . . . . 42


1.25 Break i continue . . . . . . . . . . . . . . . . . . . . . 45
1.26 Rad sa niskama karaktera . . . . . . . . . . . . . . . 45
1.27 Makroi . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.28 Bitski operatori . . . . . . . . . . . . . . . . . . . . . 53
1.29 Linearna i binarna pretraga . . . . . . . . . . . . . . 61
1.30 Razni zadaci . . . . . . . . . . . . . . . . . . . . . . . 63

4
Glava 1

Programski jezik C

1.1 Zdravo svete!


Primer 1.1.1 Program štampa poruku ”hello, world”.
#include <stdio.h>

main()
/*iskazi f-je main su zatvoreni u zagrade */
{
/*poziv f-je printf da odstampa poruku*/
printf("hello, world\n");
}
Primer 1.1.2 Program štampa poruku ”hello, world”
#include <stdio.h>

main()
{
printf("hello, ");
printf("world");
printf("\n");
}
Specijalni znaci:
\n novi red
\t tabulator
\\ kosa crta
\" navodnici
\a zvuk
\’ jednstruki navodnik

5
6 Milena Vujošević–Janičić

1.2 Imena promenljivih


Postoje ograničenja: u imenu se mogu pojaviti slova i cifre, potcrta
” ” se smatra slovom.
Velika i mala slova se razlikuju.
int x, X; /*To su dve razlicite promenljive!!!*/
Ključne reči kao što su if, else, for, while, se ne mogu koristiti za
imena promenljivih.

1.3 Deklaracije
Da bi se promenljiva mogla upotrebljavati ona se mora na početku
programa deklarisati. Prilikom deklaracije može se izvršiti i početna
inicijalizacija.

int broj; /*Deklaracija celog broja*/


int vrednost=5; /*Deklaracija i inicijalizacija celog broja*/

Kvalifikator const može biti dodeljen deklaraciji bilo koje promenljive


da bi označio da se ona neće menjati
const double e=2.71828182845905

1.4 Tipovi i veličina podataka


Osnovni tipovi podataka:
int ceo broj
char znak, jedan bajt
float realan broj
double realan broj dvostruke tacnosti

char jedan bajt, sadrzi jedan znak


int celobrojna vrednost,2 ili 4 bajta
float realan broj, jednostruka tacnost
double dvostruka tacnost

Postoje kvalifikatori koje pridružujemo osnovnim tipovima short(16)


i long(32):
short int kratak_broj;
long int dugacak_broj;
short kratak;
long dugacak;

6
1.5 Funkcije printf i scanf 7

Važi

broj bajtova(short) <= broj bajtova(int) <= broj bajtova(long)

Postoje kvalifikatori signed i unsigned koji se odnose na označene


i neoznačene cele brojeve. Npr.
signed char: -128 do 127
dok je
unsigned char: od 0 do 255.
Float, double i long double.

Primer 1.4.1 Uvo enje promenljivih u program.


#include <stdio.h>

main()
{
/*deklaracija vise promenljivih
istog tipa */
int rez,pom1,pom2;
pom1=20;
pom2=15;
rez=pom1-pom2;

/*ispisivanje rezultata*/
printf("Rezultat je %d-%d=%d\n",pom1,pom2,rez);
}
Izlaz iz programa:
Rezultat je 20-15=5

Iskaz dodele:
pom1=20;
pom2=15;
Individualni iskazi se zavrsavaju sa ;

1.5 Funkcije printf i scanf


printf("%d\t%d\n", broj1, broj2);
uvek je prvi argument izmedju " "
%d ceo broj
\t tab izmedju
\n novi red
Svaka % konstrukcija je u paru sa argumentom koji sledi.

7
8 Milena Vujošević–Janičić

Primer 1.5.1
#include <stdio.h>
main()
{
printf("Slova:\n%3c\n%5c\n", ’z’ , ’Z’);
}
Izlaz iz programa:
Slova:
z
Z
%c je za stampanje karaktera
%3c je za stampanje karaktera na tri pozicije
Isto tako smo mogli i %3d za stampanje broja na tri pozicije ili %6d
za stampanje broja na 6 pozicija.
Pravila:
%d stampaj kao ceo broj
%6d stampaj kao ceo broj sirok najvise 6 znakova
%f stampaj kao realan broj
%6f stampaj kao realan broj sirok najvise 6 znakova
%.2f stampaj kao realan broj sa dve decimale
%6.2f stampaj kao realan broj sirok najvise 6 znakova a od toga 2
iza decimalne tacke
%c karakter
%s string
%x heksadecimalni broj
%% je procenat

Primer 1.5.2 Prikazuje unos celog broja koristeci scanf("%d", &x)


#include <stdio.h>

main()
{
int x;
printf("Unesi ceo broj : ");

/* Obratiti paznju na znak &


(operator uzimanja adrese)
pre imena promenljive u funkciji
scanf */
scanf("%d",&x);

8
1.6 Aritmetički operatori 9

/* U funkciji printf nije


potrebno stavljati & */
printf("Uneli ste broj %d\n", x);
}

Primer 1.5.3 Program sabira dva uneta cela broja


#include <stdio.h>

main()
{
int a, b, c;
printf("Unesi prvi broj : ");
scanf("%d", &a);
printf("Unesi drugi broj : ");
scanf("%d", &b);
c = a + b;
printf("%d + %d = %d\n", a, b, c);
}
Ulaz:
Unesi prvi broj : 2 <enter>
Unesi drugi broj : 3 <enter>
Izlaz:
2 + 3 = 5

1.6 Aritmetički operatori


+ - * /
% (samo za celobrojne vrednosti)
unarno + i -

Asocijativnost sleva na desno, prioritet kao u matematici.

Primer 1.6.1 Program ilustruje neke od aritmetičkih operacija.


#include <stdio.h>
main()
{
int a, b;
printf("Unesi prvi broj : ");
scanf("%d",&a);

printf("Unesi drugi broj : ");

9
10 Milena Vujošević–Janičić

scanf("%d",&b);

/* Kada se saberu dva cela broja, rezultat je ceo broj*/


printf("Zbir a+b je : %d\n",a+b);
/* Kada se oduzmu dva cela broja, rezultat je ceo broj*/
printf("Razlika a-b je : %d\n",a-b);
/* Kada se pomnoze dva cela broja, rezultat je ceo broj*/
printf("Proizvod a*b je : %d\n",a*b);
/* Kada se podele dva cela broja, rezultat je ceo broj!!!*/
printf("Celobrojni kolicnik a/b je : %d\n", a/b);
/* Rezultat je ceo broj, bez obzira sto ga ispisujemo kao realan*/
printf("Pogresan pokusaj racunanja realnog kolicnika a/b je : %f\n", a/b)
/* Eksplicitna konverzija, a i b pretvaramo u relane brojeve kako
bi deljenje bilo realno*/
printf("Realni kolicnik a/b je : %f\n", (float)a/(float)b);
/* Ostatak pri deljenju se moze izvrsiti samo nad celim brojevima*/
printf("Ostatak pri deljenju a/b je : %d\n", a%b);
}

Ulaz:
Unesi prvi broj : 2 <enter>
Unesi drugi broj : 3 <enter>
Izlaz:
Zbir a+b je : 5
Razlika a-b je : -1
Proizvod a*b je : 6
Celobrojni kolicnik a/b je : 0
Progresan pokusaj racunanja realnog kolicnika a/b je : 0.000000
Realni kolicnik a/b je : 0.666667
Ostatak pri deljenju a/b je : 2
Primer 1.6.2 Program ilustruje celobrojno i realno deljenje.
#include <stdio.h>

main()
{
int a = 5;
int b = 2;
int d = 5/2; /* Celobrojno deljenje - rezultat je 2 */
float c = a/b; /* Iako je c float, vrsi se celobrojno
deljenje jer su i a i b celi */

/* Neocekivani rezultat 2.000000 */

10
1.7 Operatori i izrazi dodeljivanja vrednosti 11

printf("c = %f\n",c);
printf("Uzrok problema : 5/2 = %f\n", 5/2);
printf("Popravljeno : 5.0/2.0 = %f\n", 5.0/2.0);
printf("Moze i : 5/2.0 = %f i 5.0/2 = %f \n", 5/2.0, 5.0/2);
printf("Za promenljive mora kastovanje : %f\n", (float)a/(float)b);

Izlaz iz programa:
c = 2.000000
Uzrok problema : 5/2 = 2.000000
Popravljeno : 5.0/2.0 = 2.500000
Moze i : 5/2.0 = 2.500000 i 5.0/2 = 2.500000
Za promenljive mora kastovanje : 2.500000

Zadatak 1 Šta će biti ispisano nakon izvršavanja sledećeg programa?


#include <stdio.h>
main()
{
int x=506, y=3, z=21, t=2;
printf("x=%d y=%d\n",x,y);
printf("z - t=%d\n", z-t);
printf("z / t =%d\n",z / t);
printf("-x=%d\n",- x);
printf("x %% y=%d\n", x%y);
}

1.7 Operatori i izrazi dodeljivanja vrednosti


i = i + 2;
ekvivalento je sa
i+=2;

Moze i za:
+ - * / % << >> ^ |
izraz1 op = izraz2
je ekvivalnetno sa
izraz1 = (izraz1) op (izraz2)

x*= y+1 je ekvivalento sa x = x * (y+1)

Takvo pisanje je krace i efikasnije.

11
12 Milena Vujošević–Janičić

1.8 Inkrementacija i dekrementacija


Operatori ++ i --
x=++n; se razlikuje od x=n++;

y=(x++)*(++z);

Primer 1.8.1 Ilustracija prefiksnog i postfiksnog operatora ++


#include <stdio.h>
main()
{
int x, y;
int a = 0, b = 0;

printf("Na pocetku : \na = %d\nb = %d\n", a, b);

/* Ukoliko se vrednost izraza ne koristi, prefiksni i


postfiksni operator se ne razlikuju */
a++;
++b;
printf("Posle : a++; ++b; \na = %d\nb = %d\n", a, b);

/* Prefiksni operator uvecava promenljivu, i rezultat


je uvecana vrednost */
x = ++a;

/* Postfiksni operator uvecava promenljivu, i rezultat je


stara (neuvecana) vrednost */
y = b++;

printf("Posle : x = ++a; \na = %d\nx = %d\n", a, x);


printf("Posle : y = b++; \nb = %d\ny = %d\n", b, y);
}

Izlaz iz programa:
Na pocetku:
a = 0
b = 0
Posle : a++; ++b;
a = 1
b = 1
Posle : x = ++a;

12
1.9 Relacioni i logički operatori 13

a = 2
x = 2
Posle : y = b++;
b = 2
y = 1

1.9 Relacioni i logički operatori


Relacioni operatori:
> >= < <= isti prioritet
== != nizi prioritet

(3<5)
(a<=10)
a < 5 != 1 <=> (a < 5)!=1
Logicki operatori:
! unarna negacija (najvisi prioritet)
&& logicko i (visi prioritet od ili)
|| logicko ili izracunavaju se sleva na desno!

5 && 4 vrednost je tacno


10 || 0 vrednost je tacno
0 && 5 vrednost je 0
!1 vrednost je 0
!9 vrednost je 0
!0 vrednost je 1
!(2>3) je 1
a>b && b>c || b>d je isto sto i ((a>b) && (b>c)) || (b>d)
koja je vrednost ako je a=10, b=5, c=1, d=15?
Primer 1.9.1 Ilustracija logičkih i relacijskih operatora.
#include <stdio.h>

main()
{
int a = 3>5, /* manje */
b = 5>3, /* vece */
c = 3==5, /* jednako */
d = 3!=5; /* razlicito */

printf("3>5 - %d\n5>3 - %d\n3==5 - %d\n3!=5 - %d\n", a, b, c, d);

13
14 Milena Vujošević–Janičić

/*Lenjo izracunavanje: kako 3 nije vece od 5 to se vrednost


drugog poredjenja nece racunati jer je netacno u konjunkciji
sa proizvoljnim izrazom sigurno netacno. */
printf("Konjunkcija : 3>5 && 5>3 - %d\n", a && b);

/*Lenjo izravunavanje: tacno u disjunkciji sa proizvoljnim


izrazom daje tacno tako da se vrednost izraza 3>5 nece
izracunavati*/
printf("Disjunkcija : 5>3 || 3>5 - %d\n", b || a);
printf("Negacija : !(3>5) - %d\n", !a);

Izlaz iz programa:
3>5 - 0
5>3 - 1
3==5 - 0
3!=5 - 1
Konjunkcija : 3>5 && 5>3 - 0
Disjunkcija : 3>5 || 5>3 - 1
Negacija : !(3>5) - 1

1.10 Kontrola toka — if, while, do - while, for


1.10.1 if
if (izraz)
iskaz1
else
iskaz2
Primer 1.10.1 Program ilustruje if i ispisuje ukoliko je uneti ceo
broj negativan
#include <stdio.h>

main()
{
int b;
printf("Unesi ceo broj:");
scanf("%d", &b);
if (b < 0)
printf("Broj je negativan\n");

14
1.10 Kontrola toka — if, while, do - while, for 15

}
Else se odnosi na prvi neuparen if, voditi o tome računa, ako
želimo drugačije moramo da navedemo vitičaste zagrade.
if (izraz)
if (izraz1) iskaz 1
else iskaz
ovo else se odnosi na drugo if a ne na prvo if!
if (izraz)
{
if (izraz1) iskaz 1
}
else iskaz
tek sada se else odnosi na prvo if!!!

1.10.2 Else-if
if (izraz1)
iskaz1
else if (izraz2)
iskaz2
else if (izraz3)
iskaz3
else if (izraz4)
iskaz4
else iskaz

npr if (a<5)
printf("A je manje od 5\n");
else if (a=5)
printf("A je jednako 5\n");
else if (a>10)
printf("A je vece od 10\n");
else if (a=10)
printf("A je jednako 10\n");
else printf("A je vece od pet i manje od 10\n");
Primer 1.10.2 Program ilustruje if-else konstrukciju i ispituje znak
broja.
#include <stdio.h>

15
16 Milena Vujošević–Janičić

main()
{
int b;
printf("Unesi ceo broj : ");
scanf("%d", &b);
if (b < 0)
printf("Broj je negativan\n");
else if (b == 0)
printf("Broj je nula\n");
else
printf("Broj je pozitivan\n");
}

Ulaz:
Unesi ceo broj:-5
Izlaz:
Broj je negativan

Ulaz:
Unesi ceo broj:5
Izlaz:
Broj je pozitivan

Primer 1.10.3 Pogresan program sa dodelom = umesto poredjenja


==.
#include <stdio.h>

main()
{
int b;
printf("Unesi ceo broj : ");
scanf("%d", &b);

/* Obratiti paznju na = umesto == Analizirati rad programa*/


if (b = 0)
printf("Broj je nula\n");
else if (b < 0)
printf("Broj je negativan\n");
else
printf("Broj je pozitivan\n");
}

16
1.10 Kontrola toka — if, while, do - while, for 17

Ulaz:
Unesi ceo broj:-5
Izlaz:
Broj je pozitivan

1.10.3 while
while(uslov) { ... }
Uslov u zagradi se testira i ako je ispunjen telo petlje se izvrsava.
Zatim se uslov ponovo testira i ako je ispunjen ponovo se izvrsava
telo petlje. I tako sve dok uslov ne bude ispunjen. Tada se izlazi iz
petlje i nastavlja sa prvom sledecom naredbom u programu.
Ukoliko iza while sledi samo jedna naredba nema potrebe za
zagradama.
while (i<j)
i=2*i;

1.10.4 do-while
Ovo je slično paskalskom repeat-until izrazu.
do iskaz while (izraz)

Primer 1.10.4 Program ilustruje petlju do-while.


#include <stdio.h>

main()
{
int x;

x = 1;
do
{
printf("x = %d\n",x);
x++; /* x++ je isto kao i x=x+1 */
} while (x<=10);
}

1.10.5 for
Primer 1.10.5 Program ilustruje petlju - for.

17
18 Milena Vujošević–Janičić

#include <stdio.h>

main()
{
int x;

/* Inicijalizacija; uslov; inkrementacija*/


for (x = 1; x < 5; x++)
printf("x = %d\n",x);

}
Izlaz:
1
2
3
4

1.11 Switch
switch (iskaz) {
case konstantan_izraz1: iskazi1
case konstantan_izraz2: iskazi2
...
default: iskazi
}

Primer 1.11.1 Voditi računa o upotrebi break-a.


#include <stdio.h> /*
Upotreba switch-a
*/

main() {
char x;
scanf("%c",&x);

switch (x)
{
case ’a’:
case ’e’:
case ’i’:
case ’o’:
case ’u’: printf(" x je samoglasnik");

18
1.12 Uslovni izraz 19

break;
case ’r’: printf(" x je r");
break;
default: printf(" x je suglasnik");
}
}
Primer 1.11.2 Ilustracija switch konstrukcije.
#include<stdio.h>
main()
{
int n;
printf("Unesi paran broj manji od 10\n");
scanf("%d",&n);
switch(n) {
case 0:
printf("Uneli ste nulu\n");
break;
case 2:
printf("Uneli ste dvojku\n");
break;
case 4:
printf("Uneli ste cetvorku\n");
break;
case 6:
printf("Uneli ste sesticu\n");
break;
case 8:
printf("Uneli ste osmicu\n");
break;
defalut:
printf("Uneli ste nesto sto nije paran broj\n");
}
}
Ulaz:
Unesi paran broj manji od 10
2
Izlaz:
Uneli ste dvojku

1.12 Uslovni izraz


Slično kao if.

19
20 Milena Vujošević–Janičić

izraz1 ? izraz2 : izraz3

z = (a<b)? a : b; /*z=min(a,b)*/
max = (a>b)? a : b;

1.13 Simboličke konstante


Primer 1.13.1 Konverzija centimetara u inče - while petlja.
#include <stdio.h>

/* Definicija simbolickih konstanti preko #define direktiva */


/* U fazi pretprocesiranja se vrsi doslovna zamena konstanti
njihovim vrednostima */

#define POCETAK 0
#define KRAJ 20
#define KORAK 10

main()
{
int a;
a = POCETAK;
while (a <= KRAJ)
{
printf("%d cm = %f in\n", a, a/2.54);
a += KORAK; /* isto sto i a = a + KORAK; */
}
}

Izlaz:
0 cm = 0.000000 in
10 cm = 3.937008 in
20 cm = 7.874016 in

Primer 1.13.2 Konverzija centimetara u inče - for petlja.


#include <stdio.h>
#define POCETAK 0
#define KRAJ 20
#define KORAK 10

main()

20
1.14 Enumeracija 21

{
int a;
for (a = POCETAK; a <= KRAJ; a += KORAK)
printf("%d cm = %f in\n", a, a/2.54);
}

Izlaz:
0 cm = 0.000000 in
10 cm = 3.937008 in
20 cm = 7.874016 in

Zadatak 2 Šta će biti ispisano nakon izvršavanja sledećeg programa?


#include <stdio.h>
#define EURO 85.90
main()
{
printf("4 eura ima vrednost %f dinara\n", 4*EURO);
printf("1 euro ima vrednost %.0f dinara\n",EURO);
}

1.14 Enumeracija
Izvesna alternativa za define
enum boolean {NO, YES};
enum meseci {JAN = 1, FEB, MAR, APR, MAJ, JUN,
JUL, AVG, SEP, OKT, NOV, DEC}
enum boje {CRVENA, ZELENA=5, PLAVA,
LJUBICASTA=10, ZUTA, CRNA}

koriscenje:

int x=0;
boje b;

x=CRVENA+3; /*x ce biti jednako tri*/

b=ZELENA;
x=b+CRNA; /* 5 + 12=17*/

b=0; /*Greska, ovako ne moze!!!*/

21
22 Milena Vujošević–Janičić

1.15 Funkcije
Primer 1.15.1 sum - najjednostavnija funkcija koja sabira dva broja
/* Definicija funkcije */
int sum(int a, int b)
{
int c;
c = a + b;
return c;
/* Ovo je krace moglo da bude napisano
kao return a+b; */
}

main()
{

int c;
/* Poziv funkcije */
c = sum(3,5);
printf("%d\n", c);

/* Ovo smo krace mogli da napisemo kao


printf("%d\n", sum(3,5)); */
}

Primer 1.15.2 Deklaracija funkcije moze da stoji nezavisno od defini-


cije funkcije. Deklaracija je neophodna u situacijama kada se defini-
cija funkcije navodi nakon upotrebe date funkcije u kodu.
/* Deklaracija funkcije*/
int zbir(int, int);

main()
{
/* Poziv funkcije */
printf("%d\n", zbir(3,5));
}

/* Definicija funkcije */
int zbir(int a, int b)
{
return a+b;
}

22
1.15 Funkcije 23

Primer 1.15.3 power - funkcija koja stepenuje realan broj na celo-


brojni izlozilac
#include <stdio.h>

/* stepenuje x^k tako sto k puta pomnozi x */


float power(float x, int k)
{
int i;
float rezultat = 1;
for (i = 0; i<k; i++)
rezultat*=x;

return rezultat;
}

Primer 1.15.4 Verzija koja radi i za negativne izlozioce


float power(float x, int k)
{
int i;
float s = 1;
int negativan = (k<0);
float rezultat;

if (negativan)
k = -k;

for (i = 0; i<k; i++)


s*=x;

rezultat = negativan ? 1.0/s : s;


return rezultat;
}

main()
{
/* Poziv funkcije */
float s = power(2.0,8);
printf("%f\n", s);
}

Primer 1.15.5 Ilustracija lenjog izračunavanja logičkih operatora.


Prilikom izracunavanja izraza - A && B, ukoliko je A netačno,

23
24 Milena Vujošević–Janičić

izraz B se ne izračunava. Prilikom izračunavanja izraza - A k B,


ukoliko je A tačno, izraz B se ne izračunava.

#include <stdio.h>

/* Globalna promenljiva, vidljiva i iz funkcije main() i


iz funkcije izracunaj*/
int b = 0;

/* Funkcija ispisuje da je pozvana i uvecava promenjivu b.


Funkcija uvek vraca vrednost 1 (tacno)
*/
int izracunaj()
{
printf("Pozvano izracunaj()\n");
b++;
return 1;
}

main()
{
/* Funkcija izracunaj() ce biti pozvana
samo za parne vrednosti a */
int a;
for (a = 0; a < 10; a++)
if (a%2 == 0 && izracunaj())
printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
else
printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);

printf("----------------------------\n");

/* Funkcija izracunaj() ce se pozivati samo


za neparne vrednosti a */
b = 0;
for (a = 0; a < 10; a++)
if (a%2 == 0 || izracunaj())
printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
else
printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);
}

24
1.16 Nizovi 25

1.16 Nizovi
Deklaracija niza:
int niz[5]; /* niz od 5 elemenata tipa int*/
Pristupanje elementima niza:
niz[0] = 4;
niz[1] = 2 * niz[0]; /*niz[1] = 8*/
niz[2] = niz[0] * niz[1]; /*niz[2] = 32*/
niz[3] = 5;
niz[4] = 7;
Unos vrednosti elemenata niza sa tastature:
for(i=0; i<5; i++)
scanf("%d", &a[i]);
Stampanje elemenata niza
for(i=0; i<5; i++)
printf("%d ", a[i]);
Brojanje elemenata niza je od nule!
Pristupanje elementu niza, indeks može da bude proizvoljan izraz
celobrojne vrednosti: niz[i*2]=5.
Primer 1.16.1 Program ilustruje korišćenje nizova. Ispisuje 10
unetih brojeva unazad.
#include <stdio.h>

main()
{
int a[10];
int i;
for (i = 0; i<10; i++)
{
printf("a[%d]=",i);
scanf("%d",&a[i]);
}

printf("Unazad : \n");

for (i = 9; i>=0; i--)


printf("a[%d]=%d\n",i,a[i]);
}

25
26 Milena Vujošević–Janičić

Primer 1.16.2 Program pronalazi maksimum brojeva sa ulaza -


verzija sa nizom.
#include <stdio.h>
#define BR_ELEM 5
main()
{
int a[BR_ELEM];
int i;
int max;

/* Ucitavamo niz brojeva */


for (i = 0; i < BR_ELEM; i++)
scanf("%d",&a[i]);

/* Pronalazimo maksimum */
max = a[0];
for (i = 1; i < BR_ELEM; i++)
if (a[i]>max)
max = a[i];

/* Ispisujemo maksimum */
printf("Max = %d\n",max);
}

Primer 1.16.3 Program pronalazi maksimum brojeva sa ulaza -


verzija bez niza.
#include <stdio.h>
#define BR_ELEM 5

main()
{
int a, max, i;
scanf("%d",&a);
max = a;
for (i = 1; i < BR_ELEM; i++)
{
scanf("%d",&a);
if (a>max)
max = a;
}

printf("Max : %d\n", max);

26
1.17 Konstante 27

1.17 Konstante
Koji su tipovi konstanti?
Celobrojna konstanta 1234 je tipa int.
Da bi konstanta bila long navodi se iza nje slovo L ili l, npr 123456789L.
Ako želimo da nam je konstanta unsigned onda na kraju pišemo U
ili u.
Može i 1234567ul.

Konstante realnih brojeva sadrže decimalnu tačku(123.4) ili


eksponent(1e-2) ili i jedno i drugo. Njihov tip je double osim ako
nemaj sufiks f ili F kada je u pitanju float. L ili l označavaju long
double.
Oktalna konstanta počinje sa 0, a heksadecimalna sa 0x. Npr
broj 31 ili 037 - oktalno ili 0x1f - heksadecimalno. I one mogu da
imaju U i L na kraju.
Znakovna konstanta je celobrojna vrednost napisana izme u 

jednostrukih navodnika. Vrednost date konstante je numerička vred-


nost datog znaka u računarskom setu znakova. Npr možemo da
pišemo ’0’ umesto 48.
!!!Razlikovati znakovne konstante i niske koje se navode izme u 

dvostrukih navodnika!
Posebni znaci su znak za kraj reda, tab i slično.
Znakovna konstanta ’\0’ predstavlja znak čija je vrednost nula,
treba ga razlikovati od ’0’ koja je znak čija je vrednost 48.
Konstantna niska: ”Ja sam niska”
ili
”” /*prazna niska*/
Navodnici nisu deo niske već se koriste da bi je ograničili. Ako ih
želimo unutar niske, oni se navode sa \".
Konstantna niska je polje znakova. Da bi se znalo gde je kraj
niske, fizičko memorisanje liste zahteva da postoji jedan znak više
koji označava kraj, to je ’\0’. Da bi se odredila dužina niske mora
se proći kroz celu nisku.
!!!Važno:

Koja je razlika izme u ”x” i ’x’ ?




Primer 1.17.1 Primer funkcije koja izračunava dužinu niske znakova.


#include <stdio.h>

27
28 Milena Vujošević–Janičić

int strlen(char s[])


{
int i=0;

while (s[i] != ’\0’)


++i;
return i;
}

int main()
{
printf("Duzina ove niske
je: %d \n",strlen("Duzina ove niske je:"));
return 0;
}

1.18 Konverzija
1.18.1 Automatska konverzija
Ako je jedan od operanada razližličit vrši se konverzija, uvek u smeru
manjeg ka većem tipu

Naredba dodele:
int i=5;
float f=2.3;
f=i; /* f ce imati vrednost 5.0*/

obrnuto:

int i=5;
float f=2.3;
i=f; /* i ce imati vrednost 2*/

1.18.2 Eksplicitna konverzija


(tip)<izraz>

float x;
x=2.3+4.2; /* x ce imati vrednost 6.5 */
x=(int)2.3+(int)4.2; /* x ce imati vrednost 6 */

28
1.18 Konverzija 29

x=(int)2.3*4.5; /* x ce imati vrednost 9.0 jer zbog prioriteta


operatora konverzije prvo ce biti izvrsena
konverzija broja 2.3 u 2 pa tek onda izvrseno
mnozenje. */
x=(int)(2.3*4.5) /* x ce imati vrednost 10.0 */
Primer 1.18.1 Kako izbeći celobrojno deljenje
int a,b;
float c;
a = 5;
b = 2;
c = a/b; /* Celobrojno deljenje, c=2*/
c = (1.0*a)/b; /* Implicitna konverzija: 1.0*a je realan
broj pa priliko deljenja sa b dobija se
realan rezultat c=2.5*/
c = (0.0+a)/b; /* Implicitna konverzija: (0.0+a) je realan
broj pa priliko deljenja sa b dobija se
realan rezultat c=2.5*/
c = (float)a/(float)b; /* Eksplicitna konverzija*/

1.18.3 Funkcije koje vrše konverziju


Primer 1.18.2
#include <stdio.h>
main()
{
int vrednost;
vrednost=’A’;
printf("Veliko slovo\n karakter=%3c\nvrednost=%3d\n",vrednost,vrednost);
vrednost=’a’;
printf("Malo\n karakter=%3c\nvrednost=%3d\n",vrednost,vrednost);
}

Izlaz (u slucaju ASCII):


Veliko slovo
karakter= A
vrednost= 65
Malo
karakter= a
vrednost= 97
Primer 1.18.3 Funkcija koja konvertuje velika slova u mala slova.
#include<stdio.h>

29
30 Milena Vujošević–Janičić

/* Konvertuje karakter iz velikog u malo slovo */


char lower(char c)
{
if (c >= ’A’ && c <= ’Z’)
return c - ’A’ + ’a’ ;
else
return c;
}

main()
{
char c;
printf("Unesi neko veliko slovo:\n");
scanf("%c", &c);
printf("Odgovarajuce malo slovo je %c\n", lower(c));
}

Primer 1.18.4 Konvertovanje niske cifara u ceo broj.


#include<stdio.h>

/* atoi: konvertuje s u ceo broj */


int atoi(char s[])
{
int i, n;
n = 0;
for (i = 0; (s[i] >= ’0’) && (s[i] <= ’9’); ++i)
n = 10 * n + (s[i] - ’0’);
return n;
}

main()
{
int n;
n = atoi("234");
printf("\nN je : %d\n",n);
}

1.19 Operator sizeof()


Primer 1.19.1 Demonstracija sizeof operatora. Sizeof operator
izračunava veličinu tipa odnosno promenjive.

30
1.20 Znakovni ulaz i izlaz 31

#include<stdio.h>
main()
{
int i;
float f;
int n[10];

printf("sizeof(int)=%d\n", sizeof(int));
printf("sizeof(long)=%d\n", sizeof(long));
printf("sizeof(short)=%d\n", sizeof(short));
printf("sizeof(signed)=%d\n", sizeof(signed));
printf("sizeof(unsigned)=%d\n", sizeof(unsigned));
printf("sizeof(char)=%d\n", sizeof(char));
printf("sizeof(float)=%d\n", sizeof(float));
printf("sizeof(double)=%d\n", sizeof(double));

printf("sizeof(i)=%d\n", sizeof(i));
printf("sizeof(f)=%d\n", sizeof(f));
printf("sizeof(n)=%d\n", sizeof(n));
printf("Broj elemenata niza n : %d\n", sizeof(n)/sizeof(int));

Izlaz iz programa(u konkretnom slucaju):


sizeof(int)=4
sizeof(long)=4
sizeof(short)=2
sizeof(signed)=4
sizeof(unsigned)=4
sizeof(char)=1
sizeof(float)=4
sizeof(double)=8
sizeof(i)=4
sizeof(f)=4
sizeof(n)=40
Broj elemenata niza n : 10

1.20 Znakovni ulaz i izlaz


Funkcija za čitanje jednog znaka sa ulaza
c = getchar()
promenljiva c sadrži jedan znak sa ulaza.

31
32 Milena Vujošević–Janičić

Funkcija za štampanje jednog znaka na izlaz


putchar(c)
štampa sadržaj promenljive c obično na ekranu.

Konstanta EOF je celobrojna vrednost definisana u biblioteci <stdio.h>.


Ovu vrednost vrati funkcija getchar() kada nema više ulaza. Naz-
vana je EOF kao End Of File, kraj datoteke. Ova vrednost mora da
se razlikuje od svake vrednosti koja može da bude karakter. Zato
za c za koje je c=getchar() treba da koristimo tip dovoljno veliki
da moze da prihvati sve sto moze da vrati getchar(), dakle i EOF.
Zbog toga se za c koristi tip int.
Primer 1.20.1 Program cita jedan karakter i ispisuje ga - demon-
stracija putchar i getchar.
#include <stdio.h>

main()
{
int c; /* Karakter - obratiti paznju na int */
c = getchar(); /* cita karakter sa standardnog ulaza */
putchar(c); /* pise karakter c na standardni izlaz */

putchar(’\n’); /* prelazak u novi red */


putchar(’a’); /* ispisuje malo a */
putchar(97); /* ekvivalentno prethodnom */
}
Ulaz:
s
Izlaz iz programa:
s
s
aa
Primer 1.20.2 Program prepisuje standardni ulaz na standardni
izlaz. Ilustracija redirekcije standardnog ulaza i izlaza, pokrenuti
program sa :
./a.out <primer.c
./a.out >tekst.txt
./a.out <primer.c >kopija.c
#include <stdio.h>

32
1.20 Znakovni ulaz i izlaz 33

main()
{
/*Koristi se int a ne char zato sto zelimo
da razlikujemo kraj ulaza od vazecih znakova*/
int c;

/*Ucitava se prvi znak sa ulaza*/


c = getchar();

/*EOF predstavlja celobrojnu vrednost kraja datoteke.


To je konstanta definisana u <stdio.h>*/
while (c != EOF) {
putchar(c);
c = getchar();
}
}
Bilo koje dodeljivanje vrednosti je izraz koji ima vrednost a to je
vrednost leve strane posle dodeljivanja.
Primer 1.20.3 Program koji kopira ulaz na izlaz, skraćeni kod.
#include <stdio.h>

main()
{
int c;

/* Obratiti paznju na raspored zagrada */


while ((c = getchar()) != EOF)
putchar(c);
}
Primer 1.20.4 Brojanje znakova na ulazu.
#include <stdio.h>

main()
{
long nc;

nc = 0;
while (getchar() != EOF)
++nc;
/* %ld odnosi se na tip long. */

33
34 Milena Vujošević–Janičić

printf("%ld\n", nc);
}

Primer 1.20.5 Brojanje znakova na ulazu korišćenjem for petlje.


#include <stdio.h>

main()
{
double nc;

/*For petlja mora da ima telo pa makar


ono bilo przno*/
for (nc = 0; getchar() != EOF; ++nc)
;
printf("%.0f\n", nc);
}

Primer 1.20.6 Program broji linije i znakove na ulazu.


#include <stdio.h>
main()
{
int znak; /*prihvata znak sa ulaza */
long linije=0 ; /*brojac linija */
long br_znak=0; /*brojac znakova na ulazu */

while ( (znak=getchar() ) != EOF)


{
br_znak++;
if (znak==’\n’) linije ++;
}

printf("Prelazaka u novi red: %ld, karaktera: %ld \n",linije,br_znak);


}

Primer 1.20.7 Program broji blankove, horizontalne tabulatore i


linije na ulazu.
#include <stdio.h>
main()
{
int znak; /*prihvata znak sa ulaza */
int Blanks=0; /*brojac blankova */
int Tabs=0; /*brojac horizontalnih tabulatora */

34
1.20 Znakovni ulaz i izlaz 35

int NewLines=0; /*brojac linija */

/*UOCITI: blok naredbi while ciklusa NIJE OGRADJEN


viticastim zagradama jer postoji samo jedna if naredba! */
while( (znak=getchar())!=EOF )
if( znak==’ ’ ) ++Blanks; /* brojimo blanko simbole */
else if( znak==’\t’ ) ++Tabs; /* brojimo tab-ove */
else if( znak==’\n’ ) ++NewLines; /* brojimo redove */

/*izdavanje rezultata na standardni izlaz*/


printf("Blankova: %d. Tabulatora: %d. Prelazaka u novi red: %d\n",
Blanks, Tabs, NewLines);

Primer 1.20.8 Program prepisuje ulaz na izlaz pri čemu više blanko
znakova zamenjuje jednim.
#include <stdio.h>

main()
{
int znak; /*tekuci znak sa ulaza*/
int preth; /*znak koji prethodi tekucem */
preth=’a’; /* inicijalizujemo vrednost prethodnog
da bi prvi prolazak kroz petlju bio ispravan*/
while ( (znak=getchar() ) !=EOF)
{
if (znak !=’ ’ || preth != ’ ’) putchar(znak);
preth=znak;
}
}

Primer 1.20.9 Program vrši prebrojavanje cifara unetih na ulazu.


#include <stdio.h>

main()
{
int c;
int br_cifara = 0;
while ((c = getchar()) != EOF)
if (’0’<=c && c<=’9’)
br_cifara++;

35
36 Milena Vujošević–Janičić

printf("Broj cifara je : %d\n", br_cifara);


}
Primer 1.20.10 Program vrši brojanje pojavljivanja karaktera 0, 1
i 2 (ilustruje switch).
#include <stdio.h>

main()
{
int c;
int br_0=0, br_1=0, br_2=0;

while ((c = getchar()) != EOF)


{
switch(c)
{
/* Obratiti paznju da nije
case 0: */
case ’0’:
br_0++;
break; /* Isprobati veziju bez break */
case ’1’:
br_1++;
break;
case ’2’:
br_2++;
break;
default:
}
}
printf("Br 0 : %d\nBr 1 : %d\nBr 2 : %d\n",br_0, br_1, br_2);
}

1.21 Nizovi
Primer 1.21.1 Program ilustruje inicijalizaciju nizova.
#include <stdio.h>

main()
{
/* Niz inicijalizujemo tako sto mu navodimo vrednosti

36
1.21 Nizovi 37

u viticasnim zagradama. Dimenzija niza se odredjuje


na osnovu broja inicijalizatora */
int a[] = {1, 2, 3, 4, 5, 6};

/* Isto vazi i za niske karaktera */


char s[] = {’a’, ’b’, ’c’};

/* Ekvivalentno prethodnom bi bilo


char s[] = {97, 98, 99};
*/

/* Broj elemenata niza */


int a_br_elem = sizeof(a)/sizeof(int);
int s_br_elem = sizeof(s)/sizeof(char);

/* Ispisujemo nizove */

int i;
for (i = 0; i < a_br_elem; i++)
printf("a[%d]=%d\n",i, a[i]);

for (i = 0; i < s_br_elem; i++)


printf("s[%d]=%c\n",i, s[i]);

}
Primer 1.21.2 Program uvodi niske karaktera terminisane nulom.
#include <stdio.h>

main()
{
/* Poslednji bajt niske karaktera se postavlja na ’\0’ tj. 0 */
char s[] = {’a’, ’b’, ’c’, ’\0’ };

/* Kraci nacin da se postigne prethodno */


char t[] = "abc";

/* Ispis niske s karakter po karakter*/


int i;
for (i = 0; s[i] != ’\0’; i++)
putchar(s[i]);
putchar(’\n’);

37
38 Milena Vujošević–Janičić

/* Ispis niske s koristeci funkciju printf */


printf("%s\n", s);

/* Ispis niske t karakter po karakter*/


for (i = 0; t[i] != ’\0’; i++)
putchar(t[i]);
putchar(’\n’);

/* Ispis niske t koristeci funkciju printf */


printf("%s\n", t);
}
Primer 1.21.3 Brojanje pojavljivanja svake od cifara. Koriscenje
niza brojača.
#include <stdio.h>

/* zbog funkcije isdigit */


#include <ctype.h>

main()
{
/* Niz brojaca za svaku od cifara */
int br_cifara[10];
int i, c;

/* Resetovanje brojaca */
for (i = 0; i < 10; i++)
br_cifara[i] = 0;

/* Citamo sa ulaza i povecavamo odgovarajuce brojace */


while ((c = getchar()) != EOF)
if (isdigit(c))
br_cifara[c-’0’]++;

/* Ispis rezultata */
for (i = 0; i < 10; i++)
printf("Cifra %d se pojavila %d put%s\n",
i, br_cifara[i], br_cifara[i] == 1 ? "" : "a");
}
Primer 1.21.4 Brojanje reči
#include <stdio.h>

38
1.22 Dvostruka for petlja 39

#define IN 1 /* inside a word */


#define OUT 0 /* outside a
word */

/* count lines, words, and characters in input */

main()
{
int c, nl, nw, nc, state;

state = OUT;

/*Postavljaju se sve tri promenljive na nulu*/


/*Isto kao da smo napisali
nl = (nw = (nc = 0));*/

nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == ’\n’)
++nl;
/*Operator || znaci OR*/
if (c == ’ ’ || c == ’\n’ || c == ’\t’)
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}

1.22 Dvostruka for petlja


Primer 1.22.1 Dvostruka for petlja
#include<stdio.h>
int main()
{
int i,j;

for(i=1; i<=10; i++)

39
40 Milena Vujošević–Janičić

{
for(j=1; j<=10; j++)
printf("%d * %d = %d\t", i, j, i*j);
printf("\n");
}
}

Primer 1.22.2 Trostruka for petlja


#include<stdio.h>
int main()
{
int i,j;

for(i=1; i<=10; i++)


for(j=1; j<=10; j++)
{
for(k=1; k<=10; k++)
printf("%d * %d * %d = %d\t", i, j, k, i*j*k);
printf("\n");
}
}
Koliko puta se izvrsi naredba štampanja
printf("%d * %d * %d = %d\t", i, j, k, i*j*k);

1.23 Formiranje HTML dokumenta


Primer 1.23.1 Prilikm pokretanja programa koristiti redirekciju:
a.out >primer.html
kako bi se rezultat rada programa upisao u datoteku primer.html.
/*Ovaj program formira html dokument*/
#include <stdio.h>
main()
{
printf("<html><head><title>Ova stranica
je napravljena u c-u</title></head>");
printf("<body><h3 align=center>
Rezultat </h3></body></html>");
}

Primer 1.23.2 Napisati program koji generiše html dokument sa


engleskim alfabetom.

40
1.23 Formiranje HTML dokumenta 41

#include <stdio.h>
main()
{
int i;
printf("<HTML><head><title>Engleski alfabet</title><head>\n");
printf("<body><ul>");
for(i=0;i<=25;i++)
printf("<li> %c %c \n",’A’+i,’a’+i);
printf("</ul></body></HTML>\n"); }
Primer 1.23.3 Napisati program koji generise html dokument koji
prikazuje tablicu mnozenja za brojeve od 1 do 10.
#include<stdio.h>
main()
{
int i,j;
printf("<html><head><title>Mnozenje</title></head>");
printf("<body><h3 align=center> Rezultat </h3>");
printf("<table border=1>\n");

/* Prva vrsta sadrzi brojeve od 1 do 10*/


printf("<tr>");
printf("<th></th>");
for(i=1; i<=10; i++)
printf("<th> %d </th>\n", i);
printf("</tr>");

for(i=1; i<=10; i++)


{
printf("<tr>");

/* Na pocetku svake vrste stampamo broj


odgovarajuce vrste*/
printf("<th>%d</th>", i);

for(j=1; j<=10; j++)


printf("<td>%d\t</td>\n", i*j);

printf("</tr>");
}
printf("</table>");
printf("</body></html>");
}

41
42 Milena Vujošević–Janičić

1.24 Funkcije — prenos parametara po vred-


nosti
Primer 1.24.1 Funkcija koja proverava da li je broj prost i program
koji ispisuje sve proste brojeve manje od 100.
#include<stdio.h>
#include<math.h>

int prost(int p)
{
int i, koren, ind;
koren=sqrt(p);
ind=(p%2) || (p==2);
i=3;
while (ind && i<=koren)
{
ind=p%i;
i+=2;
}
return ind;
}

main()
{
int k;
for(k=2;k<=100;k++)
if (prost(k)) printf("%d ",k);
}
Primer 1.24.2
#include <stdio.h> /* Ilustruje vidljivost imena*/

int i=10;

void main() {
{
int i=3;
{
int i=1;
printf("%d\n", i);
}
printf("%d\n",i);
}

42
1.24 Funkcije — prenos parametara po vrednosti 43

printf("%d\n",i);
}

Primer 1.24.3 Demonstracija prenosa parametara po vrednosti -


preneti parametri se ne mogu menjati
#include <stdio.h>
void f(int x)
{
x++;
}

main()
{
int x=3;
f(x);
printf("%d\n", x);
}

Primer 1.24.4 Demonstrira prenos nizova u funkciju - preneti niz


se moze menjati.
#include <stdio.h>
#include <ctype.h>

/* Funkcija ucitava rec sa standardnog ulaza i smesta je u niz karaktera s.


Ovo uspeva zbog toga sto se po vrednosti prenosi adresa pocetka niza,
a ne ceo niz */
void get_word(char s[])
{
int c, i = 0;
while (!isspace(c=getchar()))
s[i++] = c;
s[i] = ’\0’;
}

main()
{
/* Obavezno je alocirati memoriju za niz karaktera */
char s[100];

get_word(s);
printf("%s\n", s);
}

43
44 Milena Vujošević–Janičić

Primer 1.24.5 Funkcija za ispis niza brojeva - demonstrira prenos


nizova brojeva u funkciju.
#include <stdio.h>

/* Nizovi se prenose tako sto se prenese adresa njihovog pocetka.


Uglaste zagrade ostaju prazne!

Nizove je neophodno prenositi zajedno sa dimenzijom niza


(osim za niske karaktera, jer tamo vazi konvencija da
se kraj niza obelezava znakom ’\0’)
*/
void print_array(int a[], int n)
{
int i;
for (i = 0; i < n; i++)
printf("%d ",a[i]);
putchar(’\n’);

/* Obratite paznju na ovo : */


printf("sizeof(a) - u okviru fje : %d\n", sizeof(a));
}

main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

printf("sizeof(a) - u okviru main : %d\n", sizeof(a));


print_array(a, sizeof(a)/sizeof(int));
}

Primer 1.24.6 Funkcija za ispis niske karaktera - demonstrira prenos


niske karaktera u funkciju.
#include <stdio.h>

/* Uz nisku karaktera nije potrebno prenositi dimenziju


ukoliko se postuje dogovor
da se svaka niska zavrsava karakterom ’\0’.*/
void print_string(char s[])
{
int i;
for (i = 0; s[i]!=’\0’; i++)
putchar(s[i]);

44
1.25 Break i continue 45

main()
{
print_string("Zdravo\n");
}

1.25 Break i continue


Primer 1.25.1 Funkcija uklanja beline, tabulatore ili znak za kraj
reda sa kraja stringa.
int trim(char s[])
{
int n;
for (n = strlen(s)-1; n >= 0; n--)
if (s[n] != ’ ’ && s[n] != ’\t’ && s[n] != ’\n’)
break;
s[n+1] = ’\0’;
return n;
}
Continue se re e koristi, on prouzrokuje da se pre e na sledeću
 

iteraciju u petlji.
Primer 1.25.2
for(i=0; i<n; i++)
{
if (a[i]==0) continue;
... /* obradi pozitivne elemente nekako*/
}

1.26 Rad sa niskama karaktera


Primer 1.26.1 string reverse - obrće nisku karaktera.
#include <stdio.h>

/* Ova funkcija racuna duzinu date niske karaktera.


Umesto nje, moguce je koristiti standardnu funkciju strlen
za cije je koriscenje potrebno ukljuciti zaglavlje
<string.h>
*/

45
46 Milena Vujošević–Janičić

int string_length(char s[])


{
int i;
for (i = 0; s[i]!=’\0’; i++)
;

return i;
}

/* Funkcija obrce nisku karaktera */


void string_reverse(char s[])
{
int i, j;
for (i = 0, j = string_length(s)-1; i<j; i++, j--)
{
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}

/* Napomena : razlikovati prethodnu petlju od dve ugnjezdjene petlje:


for ( i = 0; ....)
for ( j = duzina(s)-1; ...
*/

main()
{
char s[] = "Zdravo svima";
string_reverse(s);
printf("%s\n", s);
}
/*
Izlaz:
amivs ovardZ
*/
Primer 1.26.2 strlen, strcpy, strcat, strcmp, strchr, strstr
- manipulacija niskama karaktera. Vezbe radi, implementirane su
funkcije biblioteke string.h

#include <stdio.h>

46
1.26 Rad sa niskama karaktera 47

/* Izracunava duzinu stringa */


int string_length(char s[])
{
int i;
/* Uslov s[i] je ekvivalentan uslovu
s[i]!=’\0’ ili uslovu s[i]! = 0*/
for (i = 0; s[i]; i++)
;
return i;
}

/* Kopira string src u string dest.


Pretpostavlja da u dest ima dovoljno prostora. */
void string_copy(char dest[], char src[])
{
/* Kopira karakter po karakter, sve dok nije iskopiran karakter ’\0’ */
int i;
for (i = 0; (dest[i]=src[i]) != ’\0’; i++)
;

/* Uslov != ’\0’ se, naravno, moze izostaviti :

for (i = 0; dest[i]=src[i]; i++)


;
*/

/* Nadovezuje string t na kraj stringa s.


Pretpostavlja da u s ima dovoljno prostora. */
void string_concatenate(char s[], char t[])
{
int i, j;
/* Pronalazimo kraj stringa s */
for (i = 0; s[i]; i++)
;

/* Vrsi se kopiranje, slicno funkciji string_copy */


for (j = 0; s[i] = t[j]; j++, i++)
;
}

47
48 Milena Vujošević–Janičić

/* Vrsi leksikografsko poredjenje dva stringa.


Vraca :
0 - ukoliko su stringovi jednaki
<0 - ukoliko je s leksikografski ispred t
>0 - ukoliko je s leksikografski iza t
*/
int string_compare(char s[], char t[])
{
/* Petlja tece sve dok ne naidjemo na prvi razliciti karakter */
int i;
for (i = 0; s[i]==t[i]; i++)
if (s[i] == ’\0’) /* Naisli smo na kraj oba stringa,
a nismo nasli razliku */
return 0;

/* s[i] i t[i] su prvi karakteri u kojima se niske razlikuju.


Na osnovu njihovog odnosa, odredjuje se odnos stringova */
return s[i] - t[i];
}

/* Pronalazi prvu poziciju karaktera c u stringu s, odnosno -1


ukoliko s ne sadrzi c */
int string_char(char s[], char c)
{
int i;
for (i = 0; s[i]; i++)
if (s[i] == c)
return i;
/* nikako
else
return -1;
*/
/* Nije nadjeno */
return -1;
}

/* Pronalazi poslednju poziciju karaktera c u stringu s, odnosno -1


ukoliko s ne sadrzi c */
int string_last_char(char s[], char c)
{
/* Pronalazimo kraj stringa s */
int i;

48
1.26 Rad sa niskama karaktera 49

for (i = 0; s[i]; i++)


;

/* Krecemo od kraja i trazimo c unazad */


for (i--; i>=0; i--)
if (s[i] == c)
return i;

/* Nije nadjeno */
return -1;

/*
Koristeci string_length :

for (i = string_length(s) - 1; i>0; i--)


if (s[i] == c)
return i;

return -1;
*/
}

/* Proverava da li string str sadrzi string sub.


Vraca poziciju na kojoj sub pocinje, odnosno -1 ukoliko ga nema
*/
int string_string(char str[], char sub[])
{
int i, j;
/* Proveravamo da li sub pocinje na svakoj poziciji i */
for (i = 0; str[i]; i++)
/* Poredimo sub sa str pocevsi od poziciji i
sve dok ne naidjemo na razliku */
for (j = 0; str[i+j] == sub[j]; j++)
/* Nismo naisli na razliku a ispitali smo
sve karaktere niske sub */
if (sub[j+1]==’\0’)
return i;
/* Nije nadjeno */
return -1;
}

main()
{

49
50 Milena Vujošević–Janičić

char s[100];
char t[] = "Zdravo";
char u[] = " svima";

string_copy(s, t);
printf("%s\n", s);

string_concatenate(s, u);
printf("%s\n", s);

printf("%d\n",string_char("racunari", ’n’));
printf("%d\n",string_last_char("racunari", ’a’));

printf("%d\n",string_string("racunari", "rac"));
printf("%d\n",string_string("racunari", "ari"));
printf("%d\n",string_string("racunari", "cun"));
printf("%d\n",string_string("racunari", "cna"));
}

/*
Izlaz:
Zdravo
Zdravo svima
4
5
0
5
2
-1*/

1.27 Makroi
#define ime tekst_zamene

Zamene se vrše samo na simbolima, a ne obavljaju se u niskama


nutar navodnika.
Moguće je definisati makroe sa argumentima tako da tekst zamene
bude različit za različita pojavljivanja makroa.

Primer 1.27.1 Demonstracija pretprocesorske direktive #define


#include<stdio.h>

50
1.27 Makroi 51

/* Racuna sumu dva broja */


#define sum(a,b) ((a)+(b))

/* Racuna kvadrat broja - pogresna verzija */


#define square_w(a) a*a

/* Racuna kvadrat broja */


#define square(a) ((a)*(a))

/* Racuna minimum tri broja */


#define min(a, b, c) (a)<(b)? ((a)<(c)? (a) : (c)) : ((b)<(c)? (b) : (c))

main()
{
printf("sum(3,5) = %d\n", sum(3,5));
printf("square_w(5) = %d\n", square_w(5));
printf("square_w(3+2) = %d\n", square_w(3+2));
printf("square(3+2) = %d\n", square(3+2));
printf("min(1,2,3) = %d\n", min(1,2,3));
printf("min(1,3,2) = %d\n", min(1,3,2));
printf("min(2,1,3) = %d\n", min(2,1,3));
printf("min(2,3,1) = %d\n", min(2,3,1));
printf("min(3,1,2) = %d\n", min(3,1,2));
printf("min(3,2,1) = %d\n", min(3,2,1));
}

Izlaz iz programa:
sum(3,5) = 8
square_w(5) = 25
square_w(3+2) = 11
square(3+2) = 25
min(1,2,3) = 1
min(1,3,2) = 1
min(2,1,3) = 1
min(2,3,1) = 1
min(3,1,2) = 1
min(3,2,1) = 1

Primer 1.27.2
#define max(A, B) ((A)>(B) ? (A) : (B))
na osnovu ovoga će linija
x=max(p+q, r+s)

51
52 Milena Vujošević–Janičić

biti zamenjena linijom


x=((p+q) > (r+s) ? (p+q) : (r+s));
Treba voditi računa o sporednim efektima. Sledeća linija koda
pruzrokovaće uvećanje vrednosti i ili j za dva.
max(i++, j++)
Tako e treba voditi računa o zagradama. Sledeći makro prouzrokovaće


neočekivane rezultate za upotrebu square(a+1)


#define square(x) x*x
Primer 1.27.3 Ilustacija beskonačne petlje:
#define forever for(;;);
Primer 1.27.4
#include <stdio.h>
#define max1(x,y) (x>y?x:y)
#define max2(x,y) ((x)>(y)?(x):(y))
#define swapint(x,y) { int z; z=x; x=y; y=z; }
#define swap(t,x,y) { \
t z; \
z=x; \
x=y; \
y=z; }

main()
{

int x=2,y=3;

printf( "max1(x,y) = %d\n", max1(x,y) );


/* max1(x,y) = 3 */

/* Zamena makroom se ne vrsi


unutar niski pod navodnicima*/
printf( "max1(x=5,y) = %d\n", max1(x,y) );
/* max1(x=5,y) = 3 */

printf( "max1(x++,y++) = %d\n", max1(x++,y++) );


/* max1(x++,y++) = 4 */

printf( "x = %d, y = %d\n", x, y );

52
1.28 Bitski operatori 53

/* x = 3, y = 5 */

swapint(x,y);

printf( "x = %d, y = %d\n", x, y );


/* x = 5, y = 3 */

swap(int,x,y);
printf( "x = %d, y = %d\n", x, y );
/* x = 3, y = 5 */
}

Izlaz:
max1(x,y) = 3
max1(x=5,y) = 3
max1(x++,y++) = 4
x = 3, y = 5
x = 5, y = 3
x = 3, y = 5

1.28 Bitski operatori


!!!Ne mešati sa logičkim operatorima!!!

& bitsko AND


| bitsko OR
^ bitsko ekskluzivno OR
<< levo pomeranje
>> desno pomeranje
~ jedinicni komplement

Primer 1.28.1 Demonstracija bitskih operatora


#include <stdio.h>

main()
{ printf("%o %o\n",255,15);
printf( "255 & 15 = %d\n", 255 & 15 );
printf( "255 | 15 = %d\n", 255 | 15 );
printf( "255 ^ 15 = %d\n", 255 ^ 15 );
printf( "2 << 2 = %d\n", 2 << 2 );
printf( "16 >> 2 = %d\n", 16 >> 2 );
}

53
54 Milena Vujošević–Janičić

Izlaz iz programa je:


377 17
255 & 15 = 15
255 | 15 = 255
255 ^ 15 = 240
2 << 2 = 8
16 >> 2 = 4
Primer 1.28.2 print bits - stampa bitove u zapisu datog celog broja
x.
#include <stdio.h>

/* Funkcija stampa bitove datog celog broja x.


Vrednost bita na poziciji i je 0 ako i
samo ako se pri konjunkciji broja x sa maskom
000..010....000 - sve 0 osim 1 na poziciji i,
dobija 0.
Funkcija krece od pozicije najvece tezine
kreirajuci masku pomeranjem jedinice u levo
za duzina(x) - 1 mesto, i zatim pomerajuci
ovu masku za jedno mesto u levo u svakoj
sledecoj iteraciji sve dok maska ne postane 0.
*/

void print_bits(int x)
{
/* Broj bitova tipa unsigned */
int wl = sizeof(int)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

main()
{
print_bits(127);
print_bits(128);
print_bits(0x00FF00FF);
print_bits(0xFFFFFFFF);

54
1.28 Bitski operatori 55

Izlaz iz programa:
00000000000000000000000001111111
00000000000000000000000010000000
00000000111111110000000011111111
11111111111111111111111111111111

Primer 1.28.3 Program proverava da li se na k-tom mestu nalazi


1.
#include <stdio.h>

/* Pozicije brojimo kao u sledecem primeru:


poz: ... 10 9 8 7 6 5 4 3 2 1 0
bit: ... 0 0 0 1 1 1 0 0 1 1 0 */

main()
{
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da proverite:\n");
scanf("%d%d",&n,&k);
if ((n & (1 << k))!=0)
printf("Bit je 1\n");
else
printf("Bit je 0\n");
}

Primer 1.28.4 Program postavlja na k-to mesto 1


#include <stdio.h>

void print_bits(int x)
{
/* Broj bitova tipa unsigned */
int wl = sizeof(int)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

55
56 Milena Vujošević–Janičić

main(){
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da promenite:\n")
scanf("%d%d",&n,&k);
printf("Binarno, une\v seni broj je\n");
print_bits(n);
printf("Novi broj je %d\n",(n |(1<<k)));
printf("Binarno, novi broj je\n");
print_bits((n |(1<<k)));
}

Izrazom a>>b vrši se pomeranje sadržaja operanda a predstavl-


jenog u binarnom obliku za b mesta u desno. Popunjavanje upražnjenih
mesta na levoj strani zavisi od tipa podataka i vrste računara. Ako
se pomeranje primenjuje nad operandom tipa unsigned popunja-
vanje je nulama. Ako se radi o označenom operandu popunjavanje
je jedinicama kada je u krajnjem levom bitu jedinica, a nulama kada
je u krajnjem levom bitu nula.

Primer 1.28.5 sum of bits - izračunava sumu bitova datog neoznačenog


broja.
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

int sum_of_bits(unsigned x)
{
int br;
for (br = 0; x; x>>=1)
if (x&1)
br++;

return br;

56
1.28 Bitski operatori 57

main()
{
printf("Binarni zapis broja 127 je\n");
print_bits(127);
printf("Suma bitova broja 127 je %d\n",sum_of_bits(127));
printf("Binarni zapis broja 128 je\n");
print_bits(128);
printf("Suma bitova broja 128 je %d\n",sum_of_bits(128));
printf("Binarni zapis broja 0x00FF00FF je\n");
print_bits(0x00FF00FF);
printf("Suma bitova broja 0x00FF00FF je %d\n",sum_of_bits(0x00FF00FF));
printf("Binarni zapis broja 0xFFFFFFFF je\n");
print_bits(0xFFFFFFFF);
printf("Suma bitova broja 0xFFFFFFFF je %d\n",sum_of_bits(0xFFFFFFFF));
}

Izlaz iz programa:
Binarni zapis broja 127 je
00000000000000000000000001111111
Suma bitova broja 127 je 7
Binarni zapis broja 128 je
00000000000000000000000010000000
Suma bitova broja 128 je 1
Binarni zapis broja 0x00FF00FF je
00000000111111110000000011111111
Suma bitova broja 0x00FF00FF je 16
Binarni zapis broja 0xFFFFFFFF je
11111111111111111111111111111111
Suma bitova broja 0xFFFFFFFF je 32
Primer 1.28.6 get bits, set bits, invert bits - izdvajanje, postavl-
janje i invertovanje pojedinacnih bitova
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)

57
58 Milena Vujošević–Janičić

putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

/* Funkcija vraca n bitova broja x koji pocinju na poziciji p */


unsigned get_bits(unsigned x, int p, int n)
{
/* Gradimo masku koja ima poslednjih n jedinica
0000000...00011111
tako sto sve jedinice ~0 pomerimo u levo za n mesta
1111111...1100000
a zatim komplementiramo
*/
unsigned last_n_1 = ~(~0 << n);

/* x pomerimo u desno za odgovarajuci broj mesta, a zatim


konjunkcijom sa konstruisanom maskom obrisemo pocetne cifre */

return (x >> p+1-n) & last_n_1;


}

/* Funkcija vraca modifikovano x tako sto mu je izmenjeno n bitova


pocevsi od pozicije p i na ta mesta je upisano poslednjih n bitova
broja y */
unsigned set_bits(unsigned x, int p, int n, unsigned y)
{
/* Maska 000000...000111111 - poslednjih n jedinica */
unsigned last_n_1 = ~(~0 << n);

/* Maska 1111100..000111111 - n nula pocevsi od pozicije p */


unsigned middle_n_0 = ~(last_n_1 << p+1-n);

/* Brisemo n bitova pocevsi od pozicije p */


x = x & middle_n_0;

/* Izdvajamo poslednjih n bitova broja y i pomeramo ih


na poziciju p */
y = (y & last_n_1) << p+1-n;

/* Upisujemo bitove broja y u broj x i vracamo rezultat */


return x | y;
}

58
1.28 Bitski operatori 59

/* Invertuje n bitova broja x pocevsi od pozicije p */


unsigned invert_bits(unsigned x, int p, int n)
{
/* Maska 000000111...1100000 - n jedinica pocevsi od pozicije p */
unsigned middle_n_1 = ~(~0 << n) << p+1-n;

/* Invertujemo koristeci ekskluzivnu disjunkciju */


return x ^ middle_n_1;
}

main()
{
unsigned x = 0x0AA0AFA0;
print_bits(x);

print_bits(get_bits(x, 15, 8));


print_bits(set_bits(x, 15, 8, 0xFF));
print_bits(invert_bits(x, 15, 8));
}

Izlaz iz programa:
00001010101000001010111110100000
00000000000000000000000010101111
00001010101000001111111110100000
00001010101000000101000010100000
Primer 1.28.7 right rotate bits, mirror bits - rotiranje i simetrija
bitova.
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

59
60 Milena Vujošević–Janičić

/* Funkcija vrsi rotaciju neoznacenog broja x za n pozicija u desno */


unsigned right_rotate(unsigned x, int n)
{
int i;
int wl = sizeof(unsigned)*8;

/* Postupak se ponavlja n puta */


for (i = 0; i < n; i++)
{
/* Poslednji bit broja x */
unsigned last_bit = x & 1;

/* x pomeramo za jedno mesto u desno */


x >>= 1;

/* Zapamceni poslednji bit stavljamo na pocetak broja x*/

x |= last_bit<<wl-1;
}

return x;
}

/* Funkcija obrce binarni zapis neoznacenog broja x tako sto bitove


cita unatrag */
unsigned mirror(unsigned x)
{
int i;
int wl = sizeof(unsigned)*8;

/* Rezultat inicijalizujemo na poslednji bit broja x */


unsigned y = x & 1;

/* Postupak se ponavlja wl-1 puta */


for (i = 1; i<wl; i++)
{
/* x se pomera u desno za jedno mesto */
x >>= 1;
/* rezultat se pomera u levo za jedno mesto */
y <<= 1;

/* Poslednji bit broja x upisujemo na poslednje


mesto rezultata */

60
1.29 Linearna i binarna pretraga 61

y |= x & 1;
}
return y;
}

main()
{
unsigned x = 0xFAF0FAF0;
print_bits(x);
print_bits(mirror(x));
print_bits(right_rotate(x, 2));
}

Izlaz iz programa:
11111010111100001111101011110000
00001111010111110000111101011111
00111110101111000011111010111100

1.29 Linearna i binarna pretraga


Primer 1.29.1 Linearna pretraga
#include <stdio.h>

/* Funkcija proverava da li se dati element x nalazi


u datom nizu celih brojeva.
Funkcija vraca poziciju u nizu na
kojoj je x pronadjen
odnosno -1 ukoliko elementa nema.
*/
int linearna_pretraga(int niz[], int br_elem, int x)
{
int i;
for (i = 0; i<br_elem; i++)
if (niz[i] == x)
return i;
/* nikako else */

return -1;
}

main()
{

61
62 Milena Vujošević–Janičić

/* Inicijalizacija niza moguca je


i na ovaj nacin*/
int a[] = {4, 3, 2, 6, 7, 9, 11};

/* Da bi smo odredili koliko clanova


ima niz mozemo koristiti operator
sizeof*/
int br_elem = sizeof(a)/sizeof(int);
int x;
int i;
printf("Unesite broj koji trazimo : ");
scanf("%d",&x);

i = linearna_pretraga(a, br_elem, x);


if (i == -1)
printf("Element %d nije nadjen\n",x);
else
printf("Element %d je nadjen na
poziciji %d\n",x, i);
}
Primer 1.29.2 Binarna pretraga niza
/* Binarna pretraga niza celih brojeva - iterativna verzija*/
#include <stdio.h>

/* Funkcija proverava da li se element x javlja unutar niza


celih brojeva a.
Funkcija vraca poziciju na kojoj je element nadjen odnosno
-1 ako ga nema.

!!!!! VAZNO !!!!!


Pretpostavka je da je niz a uredjen po velicini
*/

int binarna_pretraga(int a[], int n, int x)


{
/* Pretrazujemo interval [l, d] */
int l = 0;
int d = n-1;

/* Sve dok interval [l, d] nije prazan */


while (l <= d)
{

62
1.30 Razni zadaci 63

/* Srednja pozicija intervala [l, d] */


int s = (l+d)/2;

/* Ispitujemo odnos x i a[srednjeg elementa] */


if (x == a[s])
/* Element je pronadjen */
return s;
else if (x < a[s])
{
/* Pretrazujemo interval [l, s-1] */
d = s-1;
}
else
{
/* Pretrazujemo interval [s+1, d] */
l = s+1;
}
}

/* Element je nadjen */
return -1;
}

main()
{
int a[] = {3, 5, 7, 9, 11, 13, 15};
int x;
int i;

printf("Unesi element kojega trazimo : ");


scanf("%d",&x);
i = binarna_pretraga(a, sizeof(a)/sizeof(int), x);

if (i==-1)
printf("Elementa %d nema\n", x);
else
printf("Pronadjen na poziciji %d\n", i);
}

1.30 Razni zadaci


Primer 1.30.1 Obrtanje stringa i pretvaranje broja u string

63
64 Milena Vujošević–Janičić

#include <stdio.h>
#include <string.h>

/* reverse: obrce string, npr string "1234" postaje "4321" */


void reverse(char s[])
{
int c, i, j;

for (i = 0, j = strlen(s)-1; i < j; i++, j--)


{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}

/* itoa: konvertuje broj n u niz karaktera s */


void itoa(int n, char s[])
{
int i, sign;

if ((sign = n) < 0) /* sacuvaj znak */


n = -n; /* napravi da je n pozitivno */
i = 0;
do {
/* generisanje cifara u obrnutom smeru */
s[i++] = n % 10 + ’0’; /* izracunaj sledecu cifru */
} while ((n /= 10) > 0); /* izbaci cifru iz zapisa */
if (sign < 0)
s[i++] = ’-’;
s[i] = ’\0’;
reverse(s);
}

main()
{
int n=-44;
char nst[100];
itoa(n,nst);
printf("%s\n",nst);
}

Primer 1.30.2 btoi - konverzija iz datog brojnog sistema u dekadni.

64
1.30 Razni zadaci 65

#include <stdio.h>
#include <ctype.h>

/* Pomocna funkcija koja izracunava vrednost


koju predstavlja karakter u datoj osnovi
Funkcija vraca -1 ukoliko cifra nije validna.

Npr.
cifra ’B’ u osnovi 16 ima vrednost 11
cifra ’8’ nije validna u osnovi 6
*/

int digit_value(char c, int base)


{
/* Proveravamo obicne cifre */
if (isdigit(c) && c < ’0’+base)
return c-’0’;

/* Proveravamo slovne cifre za mala slova */


if (’a’<=c && c < ’a’+base-10)
return c-’a’+10;

/* Proveravamo slovne cifre za velika slova */


if (’A’<=c && c < ’A’+base-10)
return c-’A’+10;

return -1;
}

/* Funkcija izracunava vrednost celog broja koji je zapisan u datom


nizu karaktera u datoj osnovi. Za izracunavanje se koristi
Hornerova shema.
*/
int btoi(char s[], int base)
{
int sum = 0;

/* Obradjuju se karakteri sve dok su to validne cifre */


int i, vr;
for (i = 0; (vr = digit_value(s[i], base)) != -1; i++)
sum = base*sum + vr;

return sum;

65
66 Milena Vujošević–Janičić

main()
{
char bin[] = "11110000";
char hex[] = "FF";

printf("Dekadna vrednost binarnog broja %s je %d\n", bin, btoi(bin, 2));


printf("Dekadna vrednost heksadekadnog
broja %s je %d\n", hex, btoi(hex, 16));
}
Primer 1.30.3 Učitava linije sa ulaza i pamti najdužu liniju.
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */

int getline(char line[], int maxline);


void copy(char to[], char from[]);

/* print the longest input line */


main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */

max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
}

/* getline: read a line into s, return length */


int getline(char s[],int lim)
{
int c, i;

for (i=0; i < lim-1

66
1.30 Razni zadaci 67

&& (c=getchar())!=EOF && c!=’\n’;++i)


s[i] = c;
if (c == ’\n’) {
s[i] = c;
++i;
}
s[i] = ’\0’;
return i;
}

/* copy: copy ’from’ into ’to’;


assume to is big enough */
void copy(char to[], char from[])
{
int i;

i = 0;
while ((to[i] = from[i]) != ’\0’)
++i;
}

Primer 1.30.4 Konvertovanje stringa u broj u pokretnom zarezu.


#include <ctype.h>
#include <stdio.h>
#define MAXLINE 100

/* getline: get line into s, return length */


int getline(char s[], int lim)
{
int c, i;

i = 0;
while (--lim > 0 && (c=getchar()) != EOF && c != ’\n’)
s[i++] = c;
if (c == ’\n’)
s[i++] = c;
s[i] = ’\0’;
return i;
}

/* atof: convert string s to double */


double atof(char s[])

67
68 Milena Vujošević–Janičić

{
double val, power;
int i, sign;

/* skip white space */


for (i = 0; isspace(s[i]); i++)
;
/* Postavlja se znak broja*/
sign = (s[i] == ’-’) ? -1 : 1;

/* Preskace se jedno mesto ukoliko je bio upisan znak u broj*/


if (s[i] == ’+’ || s[i] == ’-’)
i++;

/* Racuna se vrednost broja dok se ne naidje na tacku */


for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - ’0’);

if (s[i] == ’.’)
i++;

/* Racuna se vrednost broja iza tacke*/


for (power = 1.0; isdigit(s[i]); i++)
{
val = 10.0 * val + (s[i] - ’0’);
power *= 10;
}
return sign * val / power;
}

/* Program sabira brojeve u pokretnom zarezu koji se unose sa ulaza*/


main()
{
double sum;
char line[MAXLINE];

sum = 0;
while (getline(line, MAXLINE) > 0)
printf("\t%g\n", sum += atof(line));
}

Primer 1.30.5 Funkcija koja uklanja znak c kad god se pojavi u


stringu s.

68
1.30 Razni zadaci 69

#include <stdio.h>

void squeeze(char s[], char c)


{
int i,j;
for(i=j=0; s[i]!=’\0’;i++)
if(s[i]!=c) s[j++]=s[i];
s[j]=’\0’;
}

main()
{
char niz[20];
char c;

printf("Unesi karakter\n\n");
scanf("%c", &c);

scanf("%s", niz);
squeeze(niz, c);
printf("%s\n", niz);
}

69
Osnovi programiranja
Programski jezik C
— Zadaci sa vežbi, drugi semestar —

Milena Vujošević - Janičić 2005/2006


2

2
Sadržaj

1 Programski jezik C 7
1.1 Sortiranje . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Rekurzija . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3 Životni vek i oblast važenja promenjivih, statičke promenljive 21
1.4 Pokazivači . . . . . . . . . . . . . . . . . . . . . . . . 24
1.5 Pokazivači i argumenti funkcija . . . . . . . . . . . . 26
1.6 Pokazivači i nizovi (polja) . . . . . . . . . . . . . . . 28
1.7 Alokacija memorije . . . . . . . . . . . . . . . . . . . 35
1.8 Niz pokazivača . . . . . . . . . . . . . . . . . . . . . 37
1.9 Pokazivači na funkcije . . . . . . . . . . . . . . . . . 39
1.10 Matrice . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.11 Strukture . . . . . . . . . . . . . . . . . . . . . . . . 47
1.11.1 Operator typedef . . . . . . . . . . . . . . . . 50
1.12 qsort . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
1.13 Sortiranje — generička funkcija . . . . . . . . . . . . 59
1.14 qSort funkcija iz standardne biblioteke . . . . . . . . 66
1.15 Generičko sortiranje reči . . . . . . . . . . . . . . . . 68
1.16 Argumenti komandne linije . . . . . . . . . . . . . . . 71
1.17 Datoteke . . . . . . . . . . . . . . . . . . . . . . . . . 72
1.18 Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
1.18.1 Red . . . . . . . . . . . . . . . . . . . . . . . 78
1.18.2 Kružna lista . . . . . . . . . . . . . . . . . . . 86
1.18.3 Stek . . . . . . . . . . . . . . . . . . . . . . . 87
1.18.4 Dvostruko povezane liste . . . . . . . . . . . . 92
1.19 Drvo . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
1.20 Grafovi . . . . . . . . . . . . . . . . . . . . . . . . . . 112
1.21 Razno . . . . . . . . . . . . . . . . . . . . . . . . . . 117

3
4 SADRŽAJ

4
Predgovor

Ovo je prateći materijal za vežbe koje držim iz predmenta Osnovi


programiranja. On ne može zameniti poha anje vežbi niti korišćenje
druge preporučene literature.
Veliki deo materijala čine zadaci i rešenja mr Filipa Marića (raspoloživi
na www.matf.bg.ac.yu/~filip/pp/0405/index.pl). Tako e korišćen
je i materijal sa sajta koleginice Jelene Grmuše www.matf.bg.ac.yu/~jelenagr
i kolege Miroslava Marića www.matf.bg.ac.yu/~maricm. Tekstovi
i objašnjenja su uglavnom zasnovani na knjizi Programski jezik C,
autora Kerninghan & Ritchie
Zahvaljujem svojim studentima na aktivnom učešću u nastavi
čime su mi pomogli u uobličavanju ovog materijala.
Svi komentari i sugestije vezane za ovaj materijal biće veoma
dobrodošli.

Milena Vujošević-Janičić
www.matf.bg.ac.yu/~milena

5
6 SADRŽAJ

6
Glava 1

Programski jezik C

1.1 Sortiranje
Primer 1.1.1 U prvom prolazu se razmenjuju vrednosti a[0] sa onim
članovima ostatka niza koji su veći od njega. Na taj način će se posle
prvog prolaza kroz niz a[0] postaviti na najveći element niza.

#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Niz od maksimalno MAXDUZ elemenata*/
int a[MAXDUZ];

/* Dimenzija niza, pomocna i brojacke promenljive */


int n,pom,i,j;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);

7
8 Milena Vujošević–Janičić

scanf("%d",&a[i]);
}

/*Sortiranje*/
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
pom=a[i];
a[i]=a[j];
a[j]=pom;
}

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

putchar(’\n’);

return 0;

}
Primer 1.1.2 sort2
Modifikacija prethodnog rešenja radi dobijanja na efikasnosti. Ne
vrše se zamene svaki put već samo jednom, kada se prona e odgo-


varajući element u nizu sa kojim treba izvršiti zamenu tako da u nizu


bude postavljen trenutno najveći element na odgovarajuće mesto.
#include<stdio.h>
#define MAXDUZ 100

int main()
{

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

/* Dimenzija niza, indeks najveceg elementa


u i-tom prolazu,pomocna i brojacke promenljive */
int n,ind,pom,i,j;

printf("Unesite dimenziju niza\n");

8
1.1 Sortiranje 9

scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje - bez stalnih zamena vec se


pronalazi indeks trenutno najveceg clana niza*/
for(i=0; i<n-1; i++)
{
for(ind=i,j=i+1; j<n; j++)
if(a[ind]<a[j])
ind=j;

/* Vrsi se zamena onda kada na i-tom mestu


nije najveci element. Tada se na i-to mesto
postavlja najveci element koji se nalazio na
mestu ind. */
if(i != ind)
{
pom=a[ind];
a[ind]=a[i];
a[i]=pom;
}
}
/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

return 0;

9
10 Milena Vujošević–Janičić

Primer 1.1.3 bbsort1


Algoritam sortiranja buble sort poredi dva susedna elementa niza i
ako su pogrešno raspore eni zamenjuje im mesta. Posle pore enja
 

svih susednih parova najmanji od njih će isplivati na kraj niza. Zbog
toga se ovaj metod naziva metod mehurića. Da bi se najmanji broj
nesortiranog dela niza doveo na svoje mesto treba ponoviti postupak.

#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Dimenzija niza, pomocna promenljiva
i brojacke promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje */
for(i=n-1; i>0; i--)
for(j=0; j<i; j++)
if(a[j]<a[j+1])
{
pom=a[j];
a[j]=a[j+1];
a[j+1]=pom;

10
1.1 Sortiranje 11

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

/* Stampa prazan red */


putchar(’\n’);

/*Regularan zavrsetak rada programa */


return 0;

}
Primer 1.1.4 bbsort2
Unapredjujemo prethodni algoritam kako bismo obezbedli da se ne
vrše provere onda kada je niz već sortiran nego da se u tom slučaju
prekine rad.
#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Dimenzija niza, pomocna promenljiva
i brojacke promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

/* Promenljiva koja govori da li je izvrsena


zamena u i-tom prolazu kroz niz pa ako nije
sortiranje je zavrseno jer su svaka dva
susedna elementa niza u odgovarajucem poretku */
int zam;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");

11
12 Milena Vujošević–Janičić

exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje */
for(zam=1,i=n-1; zam && i>0; i--)
for(zam=0,j=0; j<i; j++)
if(a[j]<a[j+1])
{
/* Zamena odgovarajucih clanova niza */
pom=a[j];
a[j]=a[j+1];
a[j+1]=pom;

/* Posto je u i-tom prolazu


izvrsena bar ova zamena zam
se postavlja na 1 sto
nastavlja sortiranje */
zam=1;
}

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

return 0;

}
Primer 1.1.5 isort
Insert sort, u svakom trenutku je početak niza sortiran a sortiranje
se vrši tako što se jedan po jedan element niza sa kraja ubacuje na
odgovarajuće mesto.
#include<stdio.h>
#define MAXDUZ 100

12
1.1 Sortiranje 13

int main()
{
/* Dimenzija niza, pomocna
i brojacke promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n!\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje*/
for(i=1; i<n; i++)
for(j=i; (j>0) && (a[j]>a[j-1]); j--)
{
pom=a[j];
a[j]=a[j-1];
a[j-1]=pom;
}

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

putchar(’\n’);
return 0;
}

13
14 Milena Vujošević–Janičić

Primer 1.1.6 Binarno pretrazivanje

#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Dimenzija niza,pomocna i brojacke
promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

/* Elemet koji se trazi i pozicija


na kojoj se nalazi- ukoliko je u nizu*/
int x,pozicija;

/* Pomocne promenljive za pretragu */


int donji, gornji, srednji;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje*/
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]>a[j])
{
pom=a[i];
a[i]=a[j];
a[j]=pom;
}
/* Unos elementa binarne pretrage */
printf("Unesite element koji se trazi\n");
scanf("%d",&x);

14
1.1 Sortiranje 15

donji = 0;
gornji = n-1;
pozicija = -1;

while(donji<=gornji)
{
srednji = (donji + gornji)/2;
if(a[srednji] == x)
{
pozicija = srednji;
break;
}
else
if(a[srednji] < x)
donji = srednji + 1;
else
gornji = srednji -1;
}

/* Ispis rezultata */
if(pozicija == -1)
printf("Trazeni broj se ne nalazi u nizu!\n");
else
printf("Broj %d se nalazi na %d poziciji
sortiranog niza! \n",x,pozicija+1);

putchar(’\n’);

return 0;
}
Primer 1.1.7 Sabiranje dva velika broja, njihovo pore enje, unos i


ispis, množenje velikog broja cifrom.

#include<stdio.h>
#define MAXDUZ 1000

int unos_broja(int cifre[], int maxduz)


{
int brcifara=0;
char c;

15
16 Milena Vujošević–Janičić

c=getchar();
while ( brcifara < maxduz && c >= ’0’ && c <= ’9’)
{
cifre[brcifara++]=c-’0’;
c=getchar();
}

return brcifara;
}

void obrni(int cifre[],int brcifara)


{
int i,pom;

for (i=0; i<brcifara/2; i++)


{
pom=cifre[i];
cifre[i]=cifre[brcifara-i-1];
cifre[brcifara-i-1]=pom;
}
}

void ispisi(int cifre[],int brcifara)


{ int i;
putchar(’\n’);
for (i=brcifara-1; i>=0; i--)
printf("%d",cifre[i]);
/* ili
putchar(cifre[i]+’0’);
*/
putchar(’\n’);
}

int jednaki(int cifre1[],int cifre2[],


int brcifara1, int brcifara2)
{
int i;
if (brcifara1 != brcifara2) return 0;

for (i=0; i<brcifara1; i++)


if (cifre1[i] != cifre2[i]) return 0;
return 1;

16
1.1 Sortiranje 17

int veci(int cifre1[], int brcifara1,


int cifre2[], int brcifara2)
{
int i;
if (brcifara1>brcifara2) return 1;
if (brcifara1<brcifara2) return 0;

for (i=brcifara1-1; i>=0; i--)


{
if (cifre1[i]<cifre2[i]) return 0;
if (cifre1[i]>cifre2[i]) return 1;
}

return 0;
}

int saberi(int cifre1[], int brcifara1,


int cifre2[], int brcifara2,
int cifre[])
{
int brcifara=0;
int i,pom,pamtim=0;

for(i=0; i<brcifara1 || i<brcifara2; i++)


{
pom =((i < brcifara1)? cifre1[i] : 0 )
+((i < brcifara2)? cifre2[i] : 0)
+ pamtim;

cifre[i] = pom%10;
pamtim = pom/10;
}
if (pamtim)
{
cifre[i]=pamtim;
brcifara=i+1;
}
else brcifara=i;

17
18 Milena Vujošević–Janičić

return brcifara;
}

int pomnozic(int c,int cifre[],


int brcifara, int pcifre[])
{
int pbrcifara=0;
int i,pamtim=0;
for (i=0; i<brcifara; i++)
{
pcifre[i]=(cifre[i]*c+pamtim)%10;
pamtim=(cifre[i]*c+pamtim)/10;
}
pbrcifara=brcifara;
if (pamtim)
{
pcifre[pbrcifara]=pamtim;
pbrcifara++;
}

return pbrcifara;
}

int main()
{
int d1,d2,d;
int broj1[MAXDUZ], broj2[MAXDUZ], zbir[MAXDUZ];
d1=unos_broja(broj1,MAXDUZ);
d2=unos_broja(broj2,MAXDUZ);

obrni(broj1,d1);
obrni(broj2,d2);
d=saberi(broj1,d1,broj2,d2,zbir);
ispisi(zbir,d);
return 0;
}

1.2 Rekurzija
C funkcije se mogu rekurzivno koristiti, što znači da funkcija može
pozvati samu sebe direktno ili indirektno.

18
1.2 Rekurzija 19

Primer 1.2.1 Štampanje celog broja.


#include<stdio.h>
void printb(long int n)
{
if(n<0)
{
putchar(’-’);
n=-n;
}
if(n/10)
printb(n/10);
putchar(n % 10 + ’0’);
}

int main()
{
long int b=-1234;
printb(b);
putchar(’\n’);
return 0;
}
Kad funkcija rekurzivno pozove sebe, svakim pozivom pojavljuje
se novi skup svih automatskih promenljivih, koji je nezavisan od
prethodonog skupa. Prva funkcija printb kao argument dobija broj
-12345, ona prenosi 1234 u drugu printb funkciju, koja dalje prenosi
123 u treću, i tako redom do poslednje koja prima 1 kao argument.
Ta funkcija štampa 1 i završava sa radom tako da se vraća na
prethodni nivo, na kome se štampa dva i tako redom.
Primer 1.2.2 Računanje sume prvih n prirodnih brojeva.
#include<stdio.h>
int suma(int n)
{
if(n!=0)
return( n + suma(n-1) );
else return n;
}

main()
{
int S,n;
printf("Unesite n\n");

19
20 Milena Vujošević–Janičić

scanf("%d",&n);
S=suma(n);
printf("S=%d",S);
putchar(’\n’);
}

Primer 1.2.3 Računanje faktorijela prirodnog broja.


#include<stdio.h>
unsigned long fakt(int n)
{
if(n!=0)
return( n*fakt(n-1) );
else return 1;
}

main()
{
int n;
unsigned long f;
printf("Unesite n\n");
scanf("%d",&n);
f=fakt(n);
printf("f=%d",f);
putchar(’\n’);
}

Primer 1.2.4 Fibonačijevi brojevi.


#include<stdio.h>
int fibr(int n)
{
if((n==1)||(n==2))
return 1;
else return(fibr(n-1)+fibr(n-2));
}

int main()
{
int Fn,n;
printf("Unesite n\n");
scanf("%d",&n);
Fn=fibr(n);
printf("F[%d]=%d",n,Fn);

20
1.3 Životni vek i oblast važenja promenjivih, statičke promenljive 21

putchar(’\n’);
return 0;
}

Primer 1.2.5 Iterativna i rekurzivna varijanta računanja sume niza.


int suma_niza_iterativno(int a[], int n)
{
int suma = 0;
int i;
for (i = 0; i<n; i++)
suma+=a[i];
return suma;
}

int suma_niza(int a[], int n)


{
if (n == 1)
return a[0];
else
return suma_niza(a, n-1)+a[n-1];
}

Primer 1.2.6 Stepenovanje prirodnog broja


int stepenuj (int n, int k)
{
if (k == 0)
return 1;
else
return n*stepenuj(n, k-1);
}

1.3 Životni vek i oblast važenja promenjivih, statičke


promenljive
Primer 1.3.1 Demonstracija životnog veka i oblasti važenja promen-
jivih (scope).

#include <stdio.h>

/* Globalna promenjiva */
int a = 0;

21
22 Milena Vujošević–Janičić

/* Uvecava se globalna promenjiva a */


void increase()
{
a++;
printf("increase::a = %d\n", a);
}

/* Umanjuje se lokalna promenjiva a.


Globalna promenjiva zadrzava svoju vrednost. */
void decrease()
{
/* Ovo a je nezavisna promenjiva u odnosu na globalno a */
int a = 0;
a--;
printf("decrease::a = %d\n", a);

void nonstatic_var()
{
/* Nestaticke promenjive ne cuvaju vrednosti kroz pozive funkcije */
int s=0;
s++;
printf("nonstatic::s=%d\n",s);
}

void static_var()
{
/* Staticke promenjive cuvaju vrednosti kroz pozive funkcije.
Inicijalizacija se odvija samo u okviru prvog poziva. */
static int s=0;
s++;
printf("static::s=%d\n",s);
}

main()
{
/* Promenjive lokalne za funkciju main */
int i;
int x = 3;

printf("main::x = %d\n", x);

22
1.3 Životni vek i oblast važenja promenjivih, statičke promenljive 23

for (i = 0; i<3; i++)


{
/* Promenjiva u okviru bloka je nezavisna od spoljne promenjive.
Ovde se koristi promenjiva x lokalna za blok petlje koja ima
vrednost 5, dok originalno x i dalje ima vrednost 3*/
int x = 5;
printf("for::x = %d\n", x);
}

/* U ovom bloku x ima vrednost 3 */


printf("main::x = %d\n", x);

increase();
decrease();

/* Globalna promenjiva a */
printf("main::a = %d\n", a);

/* Demonstracija nestatickih promenjivih */


for (i = 0; i<3; i++)
nonstatic_var();

/* Demonstracija statickih promenjivih */


for (i = 0; i<3; i++)
static_var();
}

Izlaz iz programa:
main::x = 3
for::x = 5
for::x = 5
for::x = 5
main::x = 3
increase::a = 1
decrease::a = -1
main::a = 1
nonstatic::s=1
nonstatic::s=1
nonstatic::s=1
static::s=1
static::s=2
static::s=3

23
24 Milena Vujošević–Janičić

Primer 1.3.2 Ilustracija statičkih promenljivih.


#include <stdio.h>

void f()
{
static int a;
a++;
printf("%d\n",a);
}

main()
{
int i;
for (i=0; i<=10; i++)
f();
}

/* Izlaz iz programa 1 2 3 4 5 6 7 8 9 10 11*/

1.4 Pokazivači
Pokazivač je promenljiva koja sadrži adresu promenljive.

int x=1, y=1, z[10];


int *ip; /* ip je pokazivac na int,
odnosno *ip je tipa int*/

ip = &x; /* ip sada pokazuje na x */


y=*ip; /* y je sada 1 */
*ip = 0; /* x je sada 0 */

*ip+=10; /* x je sada 10*/


++*ip; /* x je sada 11*/
(*ip)++; /* x je sada 12,
zagrada neophodna zbog prioriteta
operatora*/

ip = &z[0]; /* ip sada pokazuje na z[0]*/

Primer 1.4.1 Ilustracija rada sa pokazivačkim promenljivim.


#include <stdio.h>
main()

24
1.4 Pokazivači 25

{
int x = 3;

/* Adresu promenjive x zapamticemo u novoj promeljivoj.


Nova promenljiva je tipa pokazivaca na int (int*) */
int* px;

printf("Adresa promenljive x je : %p\n", &x);


printf("Vrednost promenljive x je : %d\n", x);

px = &x;
printf("Vrednost promenljive px je (tj. px) : %p\n", px);
printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);

/* Menjamo vrednost promenljive na koju ukazuje px */


*px = 6;
printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);

/* Posto px sadrzi adresu promenljive x, ona ukazuje na x tako da je


posredno promenjena i vrednost promenljive x */
printf("Vrednost promenljive x je : %d\n", x);

Izlaz (u konkretnom slucaju):


Adresa promenljive x je : 0012FF88
Vrednost promenljive x je : 3
Vrednost promenljive px je (tj. px) : 0012FF88
Vrednost promenljive na koju ukazuje px (tj. *px) je : 3
Vrednost promenljive na koju ukazuje px (tj. *px) je : 6
Vrednost promenljive x je : 6
Pored pokazivača na osnovne tipove, postoji i pokazivač na prazan
tip (void).
void *pp;
Njemu može da se dodeli da pokazuje na int, ili na char ili na
proizvoljan tip ali je to neophodno eksplicitno naglasiti svaki put
kada želimo da koristimo ono na šta on pokazuje.
Primer 1.4.2 Upotreba pokazivača na prazan tip.
#include<stdio.h>

25
26 Milena Vujošević–Janičić

main()
{
void *pp;
int x=2;
char c=’a’;

pp = &x;
*(int *)pp = 17; /* x postaje 17*/
printf("\n adresa od x je %p", &x);
printf("\n%d i %p",*(int*)pp,(int * )pp);

pp = &c;
printf("\n adresa od c je %p", &c);
printf("\n%c i %p",*(char*)pp,(char * )pp);

/*
adresa od x je 0012FF78
17 i 0012FF78
adresa od c je 0012FF74
a i 0012FF74
*/
Posebna konstanta koja se koristi da se označi da pokazivač ne
pokazuje na neko mesto u memoriji je NULL.

1.5 Pokazivači i argumenti funkcija


C prosle uje argumente u funkcije pomoću vrednosti. To znači da
sledeća funkcija neće uraditi ono što želimo:
void swap (int x, int y) /* POGRESNO!!!!!!!!*/
{
int temp;
temp = x;
x=y;
y=temp;
}
Zbog prenosa parametara preko vrednosti swap ne može da utiče
na argumente a i b u funkciji koja je pozvala swap. Ova swap
funkcija samo zamenjuje kopije od a i b.
Da bi se dobio željeni efekat, potrebno je da se proslede pokazivači:

26
1.5 Pokazivači i argumenti funkcija 27

/* Zameni *px i *py */


void swap (int *px, int *py)
{
int temp;
temp =*px;
*px = *py;
*py = temp;
}

a poziv funkcije swap izlgeda sada ovako


swap(&a, &b);

Primer 1.5.1 Demonstracija više povratnih vrednosti funkcije ko-


risteći prenos preko pokazivača.

/* Funkcija istovremeno vraca dve vrednosti - kolicnik i ostatak


dva data broja. Ovo se postize tako sto se funkciji predaju
vrednosti dva broja (x i y) koji se dele
i adrese dve promenljive na koje ce se smestiti rezultati */

void div_and_mod(int x, int y, int* pdiv, int* pmod)


{
printf("Kolicnik postavljam na adresu : %p\n", pdiv);
printf("Ostatak postavljam na adresu : %p\n", pmod);
*pdiv = x / y;
*pmod = x % y;
}

main()
{
int div, mod;
printf("Adresa promenljive div je %p\n", &div);
printf("Adresa promenljive mod je %p\n", &mod);

/* Pozivamo funkciju tako sto joj saljemo


vrednosti dva broja (5 i 2)
i adrese promenljvih div i mod na koje
ce se postaviti rezultati */
div_and_mod(5, 2, &div, &mod);

printf("Vrednost promenljive div je %d\n", div);


printf("Vrednost promenljive mod je %d\n", mod);

27
28 Milena Vujošević–Janičić

Izlaz u konkretnom slucaju:


Adresa promenljive div je 0012FF88
Adresa promenljive mod je 0012FF84
Kolicnik postavljam na adresu : 0012FF88
Ostatak postavljam na adresu : 0012FF84
Vrednost promenljive div je 2
Vrednost promenljive mod je 1

1.6 Pokazivači i nizovi (polja)


U C-u postoji čvrsta veza izme u pokazivača i nizova. Bilo koja
operacija koja se može ostvariti dopisivanjem indeksa niza može se
uraditi i sa pokazivačima.
Deklaracija
int a[10];
definiše niz a veličine 10 koji predstavlja blok od 10 uzastopnih
objekata nazvanih a[0], a[1], ..., a[9]. Notacija a[i] odgo-
vara i-tom elementu niza.
Ako je pa pokazivač na ceo broj
int *pa;
tada iskaz pa = &a[0];
podešava da pa pokaže na nulti element niza a, odnosno pa sadrži
adresu od a[0].
Ako pa pokazuje na odre eni element polja, onda po definiciji
pa+1 pokazuje na sledeći element, pa+i pokazuje na i-ti element
posle pa. Stoga, ako pa pokazuje na a[0] tada
*(pa+1)
se odnosi na sadržaj od a[1].
pa+i je adresa od a[i], a
*(pa+i)
je sadržaj od a[i]. Dozvoljeno je upotrebljavati i sintaksu kao
kod nizova:
*(pa+i) <==> pa[i]
Ovo sve važi bez obzira na tip ili veličinu elemenata u polju a.
Iskaz pa=&a[0] se može napisati kao pa=a jer je ime niza
sinonim za lokaciju početnog elementa.

Primer 1.6.1 Veza izme u pokazivača i nizova.




#include <stdio.h>

28
1.6 Pokazivači i nizovi (polja) 29

void print_array(int* pa, int n);

main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int num_of_elements = sizeof(a)/sizeof(int);
int* pa;

/* Niz je isto sto i adresa prvog elementa */


printf("Niz a : %p\n", a);
printf("Adresa prvog elementa niza a (&a[0]) : %p\n", &a[0]);
/* Niz a : 0012FF5C
Adresa prvog elementa niza a (&a[0]) : 0012FF5C */

/* Moguce je dodeliti niz pokazivacu odgovarajuceg tipa */


pa = a;

printf("Pokazivac pa ukazuje na adresu : %p\n", pa);


/* Pokazivac pa ukazuje na adresu : 0012FF5C */

/* Nizu nije moguce dodeliti pokazivacku promenljivu


(nizove mozemo smatrati KONSTANTNIM pokazivacima na prvi element) */
/* a = pa; */

/* Pokazivace je dalje moguce indeksirati kao nizove */


printf("pa[0] = %d\n", pa[0]);
printf("pa[5] = %d\n", pa[5]);
/* pa[0] = 1
pa[5] = 6 */

/* Medjutim, sizeof(pa) je samo velicina pokazivaca, a ne niza */


printf("sizeof(a) = %d\n", sizeof(a));
printf("sizeof(pa) = %d\n", sizeof(pa));
/* sizeof(a) = 40
sizeof(pa) = 4 */

/* Pozivamo funkciju za stampanje niza i saljemo joj niz */


print_array(a, num_of_elements);
/* 1 2 3 4 5 6 7 8 9 10 */

/* Pozivamo funkciju za stampanje niza


i saljemo joj pokazivac na pocetak niza */
print_array(pa, num_of_elements);

29
30 Milena Vujošević–Janičić

/* 1 2 3 4 5 6 7 8 9 10 */
}

/* Prosledjivanje niza u funkciju


void print_array(int pa[], int n);
je ekvivalentno prosledjivanju pokazivaca u funkciju
void print_array(int* pa, int n);
Izmedju ovih konstrukcija nema nikakve razlike!
*/
void print_array(int* pa, int n)
{
int i;
for (i = 0; i<n; i++)
printf("%d ", pa[i]);
putchar(’\n’);
}

Prilikom deklaracije treba praviti razliku izme u niza znakova i


pokazivača:

char poruka[]="danas je lep dan!";


char *pporuka = "danas je lep dan!";

poruka je niz znakova koji sadrži dati tekst. Pojedine znake moguće
je promeniti ali se poruka uvek odnosi na isto mesto u memoriji.
pporuka je pokazivač, koji je inicijalizovan da pokazuje na kon-
stantnu nisku, on može biti preusmeren da pokazuje na nešto drugo,
ali rezultat neće biti definisan ako pokušate da modifikujete sadržaj
niske (jer je to konstantna niska).
Ako deklarišemo

char *pporuka1 = "danas je lep dan!";


char *pporuka2 = "danas je lep dan!";
char *pporuka3 = "danas pada kisa";

tada će pokazivači pporuka1 i pporuka2 pokazivati na isto mesto u


memoriji, a pporuka3 na neko drugo mesto u memoriji.
Ako uporedimo (pporuka1==pporuka3) uporediće se vrednosti
pokazivača. Ako uporedimo (pporuka1 < pporuka2) uporediće se
vrednosti pokazivača. Ako dodelimo pporuka1=pporuka3 tada će
pporuka1 dobiti vrednost pokazivača pporuka3 i pokazivaće na isto
mesto u memoriji. Neće se izvršiti kopiranje sadržaja memorije!!!

Primer 1.6.2 Vežba pokazivačke aritmetike.

30
1.6 Pokazivači i nizovi (polja) 31

#include <stdio.h>

/* Funkcija pronalazi x u nizu niz date dimenzije,


bez koriscenja indeksiranja. Funkcija vraca pokazivac na
poziciju pronadjenog elementa. */

int* nadjiint(int* niz, int n, int x)


{
while (--n >= 0 && *niz!=x)
niz++;

return (n>=0)? niz: NULL;


}

main()
{
int a[]={1,2,3,4,5,6,7,8};
int* poz=nadjiint(a,sizeof(a)/sizeof(int),4);

if (poz!=NULL)
printf("Element pronadjen na poziciji %d\n",poz-a);
}
Primer 1.6.3
int strlen(char *s)
{
int n;
for(n=0; *s != ’\0’; s++) n++;
return n;
}

Primer 1.6.4
/* Funkcija kopira string t u string s */
void copy(char* s, char* t)
{
while (*s++=*t++)
;
}

/* Ovo je bio skraceni zapis za sledeci kod


while(*t != ’\0’)
{
*s=*t;

31
32 Milena Vujošević–Janičić

s++;
t++;
}
*s = ’\0’;

*/
Primer 1.6.5
/* Vrsi leksikografsko poredjenje dva stringa.
Vraca :
0 - ukoliko su stringovi jednaki
<0 - ukoliko je s leksikografski ispred t
>0 - ukoliko je s leksikografski iza t
*/
int string_compare1(char *s, char *t)
{
/* Petlja tece sve dok ne naidjemo
na prvi razliciti karakter */
for (; *s == *t; s++, t++)
if (*s == ’\0’) /* Naisli smo na kraj
oba stringa, a nismo nasli razliku */
return 0;

/* *s i *t su prvi karakteri u kojima


se niske razlikuju.
Na osnovu njihovog odnosa,
odredjuje se odnos stringova */

return *s - *t;
}

/* Mozemo koristiti i sintaksu kao kod nizova */


int string_compare2(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];
}
Primer 1.6.6 Pronalazi prvu poziciju karaktera c u stringu s, i
vraća pokazivač na nju, odnosno NULL ukoliko s ne sadrži c.

32
1.6 Pokazivači i nizovi (polja) 33

char* string_char(char *s, char c)


{
int i;
for (; *s; s++)
if (*s == c)
return s;

/* Nije nadjeno */
return NULL;
}

Primer 1.6.7 Pronalazi poslednju poziciju karaktera c u stringu s,


i vraća pokazivač na nju, odnosno NULL ukoliko s ne sadrži c.
char* string_last_char(char *s, char c)
{
char *t = s;
/* Pronalazimo kraj stringa s */
while (*t++)
;

/* Krecemo od kraja i trazimo c unazad */


for (t--; t >= s; t--)
if (*t == c)
return t;

/* Nije nadjeno */
return NULL;
}

Primer 1.6.8
#include <stdio.h>

/* proverava da li se niska t nalazi unutar niske s*/


int sadrzi_string(char s[], char t[])
{
int i;
for (i = 0; s[i]; i++)
{
int j;
for (j=0, k=0; s[i+j]==t[j]; j++)
if (t[j+1]==’\0’)
return i;
}

33
34 Milena Vujošević–Janičić

return -1;
}

/* Verzija funkcije strstr implementirane bez


koriscenja indeksiranja */
/* proverava da li se niska t nalazi unutar niske s*/
char* sadrzi_string_pok(char* s, char* t)
{
while(*s)
{
char *i, *j;
for (i = s, j = t; *i == *j; i++,j++)
if (*(j+1)==’\0’)
return s;
s++;
}
return NULL;
}

/* Cita liniju sa stadnardnog ulaza i


vraca njenu duzinu */
int getline(char* line, int max)
{
char *s=line;
int c;
while ( max-->0 && (c=getchar())!=’\n’ && c!=EOF)
*s++ = c;

if (c==’\n’)
*s++ = c;

*s = ’\0’;
return s - line;
}

main()
{
char rec[]="zdravo";
char linija[100];
while (getline(linija, 100))
if (sadrzi_string_pok(linija, rec))
printf("%s",linija);

34
1.7 Alokacija memorije 35

1.7 Alokacija memorije


void* malloc(size_t n) vraća pokazivač na n bajtova neinicijal-
izovane memorije ili NULL ukoliko zahtev ne može da se ispuni.
Za njeno korišćenje neophodno je uključiti zaglavlje stdlib.h.
Osloba anje memorije - funkcija free.
Ne sme se koristiti nešto što je već oslobo eno, ne sme se dva
puta osloba ati ista memorija.
Primer 1.7.1
#include <stdio.h>
#include <stdlib.h>

main()
{
int n;
int i;
int *a;

printf("Unesi broj clanova niza : ");


scanf("%d", &n);

/* Kao da ste mogli da uradite


int a[n];
*/
a = (int*)malloc(n*sizeof(int));

/* Kad god se vrsi alokacija memorije mora se proveriti da li je ona


uspesno izvrsena!!! */
if (a == NULL)
{
printf("Nema slobodne memorije\n");
exit(1);
}

/* Od ovog trenutka a koristim kao obican niz */


for (i = 0; i<n; i++)
scanf("%d",&a[i]);

/* Stampamo niz u obrnutom redosledu */

35
36 Milena Vujošević–Janičić

for(i = n-1; i>=0; i--)


printf("%d",a[i]);

/* Oslobadjamo memoriju*/
free(a);
}

Primer 1.7.2 Demonstracija funkcije calloc - funkcija inicijal-


izuje sadrzaj memorije na 0.

#include <stdio.h>
#include <stdlib.h>

main()
{
int *m, *c, i, n;

printf("Unesi broj clanova niza : ");


scanf("%d", &n);

/* Niz m NE MORA garantovano da ima sve nule */


m = malloc(n*sizeof(int));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

/* Niz c MORA garantovano da ima sve nule */


c = calloc(n, sizeof(int));
if (c == NULL) {
printf("Greska prilikom alokacije memorije!\n");
free(m);
exit(1);
}
for (i = 0; i<n; i++)
printf("m[%d] = %d\n", i, m[i]);

for (i = 0; i<n; i++)


printf("c[%d] = %d\n", i, c[i]);

free(m);
free(c);
}

36
1.8 Niz pokazivača 37

1.8 Niz pokazivača


Primer 1.8.1
#include <stdio.h>
#include <stdlib.h>
main()
{
/* Niz od tri elemenata tipa int*/
int nizi[3];

/* Niz od tri elemenata tipa int*, dakle


niz od tri pokazivaca na int*/
int* nizip[3];

/* Alociramo memoriju za prvi element niza*/


nizip[0] = (int*) malloc(sizeof(int));
if (nizip[0] == NULL)
{
printf("Nema slobodne memorije\n");
exit(1);
}
/* Upisujemo u prvi element niza broj 5*/
*nizip[0] = 5;
printf("%d", *nizip[0]);

/* Alociramo memoriju za drugi element niza.


Drugi element niza pokazuje na niz od dva
elementa*/
nizip[1] = (int*) malloc(2*sizeof(int));
if (nizip[1] == NULL) {
printf("Nema slobodne memorije\n");
free(nizip[0]);
exit(1);
}

/* Pristupamo prvom elementu na koji pokazuje


pokazivac nizip[1]*/
*(nizip[1]) = 1;

/* Pristupamo sledecem elementu u nizu na koji pokazuje


nizip[1].
*/
*(nizip[1] + 1) = 2;

37
38 Milena Vujošević–Janičić

printf("%d", nizip[1][1]);

/* Alociramo memoriju za treci element niza nizip. */


nizip[2] = (int*) malloc(sizeof(int));
if (nizip[2] == NULL) {
printf("Nema slobodne memorije\n");
free(nizip[0]);
free(nizip[1]);
exit(1);
}

*(nizip[2]) = 2;

printf("%d", *(nizip[2]));

free(nizip[0]);
free(nizip[1]);
free(nizip[2]);
}

Primer 1.8.2
#include <stdio.h>
#include <stdlib.h>
main()
{
/* Niz karaktera*/
char nizc[5];

/* Niz karaktera od cetiri elementa


(’A’, ’n’, ’a’, ’\0’)*/
char nizcc[]="Ana";
printf("%s", nizcc);

/* Niz od tri pokazivaca. Prvi pokazuje na


nisku karaktera Kruska, drugi na nisku karaktera
Sljiva a treci na Ananas. */
char* nizcp[]={"Kruska", "Sljiva", "Ananas"};

printf("%s", nizcp[0]);
printf("%s", nizcp[1]);
printf("%s", nizcp[2]);
}

38
1.9 Pokazivači na funkcije 39

1.9 Pokazivači na funkcije


Primer 1.9.1 Program demonstrira upotrebu pokazivača na funkcije.

#include <stdio.h>

int kvadrat(int n)
{
return n*n;
}

int kub(int n)
{
return n*n*n;
}

int parni_broj(int n)
{
return 2*n;
}

/* Funkcija izracunava sumu od 1 do n f(i),


gde je f data funkcija */
int sumiraj(int (*f) (int), int n)
{
int i, suma=0;
for (i=1; i<=n; i++)
suma += (*f)(i);

return suma;
}

main()
{
printf("Suma kvadrata brojeva od jedan do 3 je %d\n", sumiraj(kvadrat,3));
printf("Suma kubova brojeva od jedan do 3 je %d\n", sumiraj(kub,3));
printf("Suma prvih pet parnih brojeva je %d\n", sumiraj(parni_broj,5));
}
/*Izlaz:
Suma kvadrata brojeva od jedan do 3 je 14
Suma kubova brojeva od jedan do 3 je 36
Suma prvih pet parnih brojeva je 30
*/

39
40 Milena Vujošević–Janičić

1.10 Matrice
Primer 1.10.1 Statička alokacija prostora za matricu.
#include <stdio.h>

main()
{
int a[3][3] = {{0, 1, 2}, {10, 11, 12}, {20, 21, 22}};
int i, j;

/* Alternativni unos elemenata matrice


for(i=0; i<3; i++)
for(j=0; j<3; j++)
{
printf("a[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
*/

a[1][1] = a[0][0] + a[2][2];


/* a[1][1] = 0 + 22 = 22 */

printf("%d\n", a[1][1]); /* 22 */

/* Stampanje elemenata matrice*/


for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
printf("%d\t", a[i][j]);
printf("\n");
}
}
Nama je potrebno da imamo veću fleksibilnost, tj da se dimenzije
matrice mogu uneti kao parametri našeg programa. Zbog toga je
neophodno koristiti dinamicku alokaciju memorije.
Primer 1.10.2 Implementacija matrice preko niza.
#include <stdlib.h>
#include <stdio.h>

/* Makro pristupa clanu na poziciji i, j matrice koja ima


m vrsta i n kolona */

40
1.10 Matrice 41

#define a(i,j) a[(i)*n+(j)]

main()
{
/* Dimenzije matrice */
int m, n;

/* Matrica */
int *a;

int i,j;

/* Suma elemenata matrice */


int s=0;

/* Unos i alokacija */
printf("Unesi broj vrsta matrice : ");
scanf("%d",&m);

printf("Unesi broj kolona matrice : ");


scanf("%d",&n);

a=malloc(m*n*sizeof(int));
if (a == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<m; i++)


for (j=0; j<n; j++)
{
printf("Unesi element na poziciji (%d,%d) : ",i,j);
scanf("%d",&a(i,j));
}

/* Racunamo sumu elemenata matrice */


for (i=0; i<m; i++)
for (j=0; j<n; j++)
s+=a(i,j);

/* Ispis unete matrice */


printf("Uneli ste matricu : \n");
for (i=0; i<m; i++)

41
42 Milena Vujošević–Janičić

{ for (j=0; j<n; j++)


printf("%d ",a(i,j));
printf("\n");
}

printf("Suma elemenata matrice je %d\n", s);

/* Oslobadjamo memoriju */
free(a);
}
Primer 1.10.3 Program ilustruje rad sa kvadratnim matricama i
relacijama. Elementi i je u relaciji sa elementom j ako je m[i][j] =
1, a nisu u relaciji ako je m[i][j] = 0.
#include <stdlib.h>
#include <stdio.h>

/* Dinamicka matrica je odredjena adresom


pocetka niza pokazivaca i dimenzijama tj.
int** a;
int m,n;
*/

/* Alokacija kvadratne matrice nxn */


int** alociraj(int n)
{
int** m;
int i;
m=malloc(n*sizeof(int*));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<n; i++)


{
m[i]=malloc(n*sizeof(int));
if (m[i] == NULL)
{
int k;
printf("Greska prilikom alokacije memorije!\n");
for(k=0;k<i;k++)
free(m[k]);

42
1.10 Matrice 43

free(m);
exit(1);
}
}

return m;
}

/* Dealokacija matrice dimenzije nxn */


void obrisi(int** m, int n)
{
int i;
for (i=0; i<n; i++)
free(m[i]);
free(m);
}

/* Ispis matrice /
void ispisi_matricu(int** m, int n)
{
int i, j;
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf("%d ",m[i][j]);
printf("\n");
}
}

/* Provera da li je relacija predstavljena matricom refleksivna */


int refleksivna(int** m, int n)
{
int i;
for (i=0; i<n; i++)
if (m[i][i]==0)
return 0;

return 1;
}

/* Provera da li je relacija predstavljena matricom simetricna */


int simetricna(int** m, int n)
{

43
44 Milena Vujošević–Janičić

int i,j;
for (i=0; i<n; i++)
for (j=i+1; j<n; j++)
if (m[i][j]!=m[j][i])
return 0;
return 1;
}

/* Provera da li je relacija predstavljena matricom tranzitivna*/


int tranzitivna(int** m, int n)
{
int i,j,k;

for (i=0; i<n; i++)


for (j=0; j<n; j++)
for (k=0; k<n; k++)
if ((m[i][j]==1)
&& (m[j][k]==1)
&& (m[i][k]!=1))
return 0;
return 1;
}

/* Pronalazi najmanju simetricnu relaciju koja sadrzi relaciju a */


void simetricno_zatvorenje(int** a, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{
if (a[i][j]==1 && a[j][i]==0)
a[j][i]=1;
if (a[i][j]==0 && a[j][i]==1)
a[i][j]=1;
}
}

main()
{
int **m;
int n;
int i,j;

44
1.10 Matrice 45

printf("Unesi dimenziju matrice : ");


scanf("%d",&n);
m=alociraj(n);

for (i=0; i<n; i++)


for (j=0; j<n; j++)
scanf("%d",&m[i][j]);

printf("Uneli ste matricu : \n");

ispisi_matricu(m,n);

if (refleksivna(m,n))
printf("Relacija je refleksivna\n");
if (simetricna(m,n))
printf("Relacija je simetricna\n");
if (tranzitivna(m,n))
printf("Relacija je tranzitivna\n");

simetricno_zatvorenje(m,n);

ispisi_matricu(m,n);

obrisi(m,n);
}
Primer 1.10.4 Izračunati vrednost determinante matrice preko Laplasovog
razvoja.
#include <stdio.h>
#include <stdlib.h>

/* Funkcija alocira matricu dimenzije nxn */


int** allocate(int n)
{
int **m;
int i;
m=(int**)malloc(n*sizeof(int*));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<n; i++)

45
46 Milena Vujošević–Janičić

{
m[i]=malloc(n*sizeof(int));
if (m[i] == NULL)
{
int k;
for(k=0;k<i;k++)
free(m[k]);
printf("Greska prilikom alokacije memorije!\n");
free(m);
exit(1);
}
}

return m;
}

/* Funkcija vrsi dealociranje date matrice dimenzije n */


void deallocate(int** m, int n)
{
int i;
for (i=0; i<n; i++)
free(m[i]);
free(m);
}

/* Funkcija ucitava datu alociranu matricu sa standardnog ulaza */


void ucitaj_matricu(int** matrica, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
scanf("%d",&matrica[i][j]);
}

/* Rekurzivna funkcija koja vrsi Laplasov razvoj */


int determinanta(int** matrica, int n)
{
int i;
int** podmatrica;
int det=0,znak;

/* Izlaz iz rekurzije je matrica 1x1 */


if (n==1) return matrica[0][0];

46
1.11 Strukture 47

/* Podmatrica ce da sadrzi minore polazne matrice */


podmatrica=allocate(n-1);
znak=1;
for (i=0; i<n; i++)
{
int vrsta,kolona;
for (kolona=0; kolona<i; kolona++)
for(vrsta=1; vrsta<n; vrsta++)
podmatrica[vrsta-1][kolona] = matrica[vrsta][kolona];
for (kolona=i+1; kolona<n; kolona++)
for(vrsta=1; vrsta<n; vrsta++)
podmatrica[vrsta-1][kolona-1] = matrica[vrsta][kolona];

det+= znak*matrica[0][i]*determinanta(podmatrica,n-1);
znak*=-1;
}
deallocate(podmatrica,n-1);
return det;
}

main()
{
int **matrica;
int n;

scanf("%d", &n);
matrica = allocate(n);
ucitaj_matricu(matrica, n);
printf("Determinanta je : %d\n",determinanta(matrica,n));
deallocate(matrica, n);
}

1.11 Strukture
Informacije kojima se opisuje realni svet retko se predstavljaju u
elementarnoj formi u vidu celih, realnih, znakovnih konstanti itd.
Mnogo češće imamo posla sa složenim objektima koji se sastoje od
elemenata raznih tipova. Na primer jednu osobu karakterišu ime,
prezime, datum i mesto ro enja.
Struktura predstavlja skup podataka kojim se opisuju neka bitna
svojstva objekta. Komponente koje obrazuju strukturu nazivaju se

47
48 Milena Vujošević–Janičić

elementi strukture.
Sintaksa strukture:

struct ime_strukture
{
tip ime_elementa1;
tip ime_elementa2;
...
};

Primer 1.11.1 Primer jednostavne strukture.

struct licnost
{
char ime[31];
char adresa[41];
unsigned starost;
};

struct licnost osoba1, osoba2;

Deklaraciju osobe1 i osobe2 mogli smo da zapišemo i na sledeći


način

struct licnost
{
char ime[31];
char adresa[41];
unsigned starost;
} osoba1, osoba2;

Ukoliko nemamo potrebu da se ličnost koristi dalje u programu


mogu se napraviti dve osobe bez davanja imena strukturi:

struct
{
char ime[31];
char adresa[41];
unsigned starost;
} osoba1, osoba2;

Kada imamo promenljivu strukturnog tipa tada elementima date


strukture pristupamo uz pomoc operatora ’.’.

48
1.11 Strukture 49

Primer 1.11.2
osoba1.starost=20;
osoba2.starost=21;
...
if (osoba1.starost == osoba2.starost)
printf(" Osobe su iste starosti");

Dozvoljeno je praviti nizove struktura. Npr. niz od 20 elemenata


koji sadrži ličnosti:
struct licnost nizLicnosti[20];
Tada da bi pročitali starost neke ličnosti u nizu pišemo:
nizLicnosti[5].starost
Može se definisati pokazivač na strukturu.
struct licnost *posoba;
Tada se pristupanje elementima strukture može vršiti upotrebom
operatora ’.’ na standardni način:
(*posoba).ime
(*posoba).adresa
(*posoba).starost
ili korišćenjem specijalnog operatora 0 − >0 na sledeći način:
posoba->ime
posoba->adresa
posoba->starost

Primer 1.11.3 Elementi strukture mogu da budu i druge strukture.


struct datum
{
unsigned dan;
unsigned mesec;
unsigned godina;
};

struct licnost
{
char ime[30];
struct datum datumrodjenja;
};

49
50 Milena Vujošević–Janičić

Sada se danu, mesecu i godini datuma rodjenja pristupa na sledeći


način:
osoba.datumrodjenja.dan = 10;
osoba.datumrodjenja.mesec = 5;
osoba.datumrodjenja.godina = 1986;

1.11.1 Operator typedef


Operator typedef omogućava nam da definišemo naša imena za neki
od osnovih ili izvedenih tipova. Na primer, možemo da uradimo
sledeće:
typedef double RealanBroj;
Nakon ovoga možemo u tekstu deklarista promenljivu x kao Realan-
Broj, ona će zapravo biti tipa double.
RealanBroj x; /* Umesto: double x;*/
Ili, ako želimo da skratimo pisanje za neoznačene duge brojeve tj
za unsigned long int to možemo da uradimo na sledeći način
typedef unsigned long int VelikiBroj;
Sada u kodu možemo da koristimo VelikiBroj kao tip.
Operator typedef je naročito pogodan da bi se izbeglo ponavljal-
nje reči struct pri deklarisanju strukturnih promenljivih.
typedef struct _licnost licnost;
Sada deklaracija može da bude:
licnost osoba1, osoba2;
/* umesto: struct _licnost osoba1, osoba2; */
Kao skraćen zapis za
struct _tacka {
float x;
float y;
}

typedef struct _tacka tacka;


može se koristiti:
typedef struct _tacka
{
float x;
float y;
} tacka;

50
1.11 Strukture 51

Primer 1.11.4 Struktura artikal.


typedef struct _artikal
{
long bar_kod;
char ime[MAX_IME];
float pdv;
} artikal;

Primer 1.11.5 Program ilustruje osnovne geometrijske algoritme


kao i rad sa strukturama.
#include <math.h>
#include <stdio.h>

typedef struct _tacka


{
float x;
float y;
} tacka;

typedef struct _vektor


{
float x, y;
} vektor;

/* Koordinatni pocetak */
tacka kp={0.0,0.0};

/* Niz tacaka */
tacka niz[100];

/* Pokazivac na strukturu tacke */


tacka *pt;

void IspisiTacku(tacka A)
{
printf("(%f,%f)\n",A.x,A.y);
}

void IspisiVektor(vektor v)
{
printf("(%f,%f)\n",v.x,v.y);
}

51
52 Milena Vujošević–Janičić

float duzina(vektor v)
{
return sqrt(v.x*v.x+v.y*v.y);
}

vektor NapraviVektor(tacka *pA, tacka *pB)


{
vektor ab;
ab.x=pB->x - pA->x;
ab.y=pB->y - pA->y;
return ab;
}

float rastojanje(tacka A, tacka B)


{
float dx=B.x - A.x;
float dy=B.y - A.y;
return sqrt(dx*dx+dy*dy);
}

/* Heronov obrazac */
float PovrsinaTrougla(tacka A, tacka B, tacka C)
{
float a=rastojanje(B,C);
float b=rastojanje(A,C);
float c=rastojanje(A,B);

float s=(a+b+c)/2.0;
return sqrt(s*(s-a)*(s-b)*(s-c));
}

float PovrsinaKonveksnogPoligona(tacka poligon[], int br_temena)


{
int i;
float povrsina=0.0;
for (i=1; i<br_temena-1; i++)
povrsina+=PovrsinaTrougla(poligon[0], poligon[i], poligon[i+1]);

return povrsina;
}

float Obim(tacka poligon[], int br_temena)

52
1.11 Strukture 53

{
int i;
float o=0;

for (i=0; i<br_temena-1; i++)


o+=rastojanje(poligon[i], poligon[i+1]);

o+=rastojanje(poligon[0], poligon[br_temena-1]);
return o;
}

main()
{
tacka poligon[]={{0.0,0.0},
{0.0,1.0},
{1.0,1.0},
{1.0,0.0}};
printf("Obim poligona je %f\n",Obim(poligon,4));
printf("Povrsina poligona je %f\n",
PovrsinaKonveksnogPoligona(poligon,4));
}
Primer 1.11.6 Program koji učitava niz studenata i sortira ih po
njihovim ocenama.
#include <stdio.h>
#include <ctype.h>

#define MAX_IME 20

typedef struct _student


{
char ime[MAX_IME];
char prezime[MAX_IME];
int ocena;
} student;

/* Funkcija ucitava rec i vraca njenu duzinu ili


-1 ukoliko smo dosli do znaka EOF*/
int getword(char word[],int max)
{
int c, i=0;

while (isspace(c=getchar()))

53
54 Milena Vujošević–Janičić

while(!isspace(c) && c!=EOF && i<max-1)


{
word[i++]=c;
c = getchar();
}

word[i]=’\0’;

if (c==EOF) return -1;


else return i;

/* Funkcija ucitava niz studenata, vraca duzinu niza koji ucita */


int UcitajPodatke(student studenti[], int max)
{
int i=0;
while(i<max && getword(studenti[i].ime, MAX_IME)>0)
{
if (getword(studenti[i].prezime, MAX_IME) < 0)
break;
scanf("%d",&studenti[i].ocena);
i++;
}
return i;
}

void IspisiPodatke(student studenti[], int br_studenata)


{
int i;
printf("IME PREZIME OCENA\n");
printf("--------------------------------------\n");
for (i=0; i<br_studenata; i++)
printf("%-20s %-20s %5d\n",studenti[i].
ime, studenti[i].prezime, studenti[i].ocena);
}

/* Sortiranje studenata po ocenama */


void SelectionSort(student studenti[], int br_studenata)
{
int i,j;

54
1.11 Strukture 55

for (i=0; i<br_studenata-1; i++)


for (j=i; j<br_studenata; j++)
if (studenti[i].ocena<studenti[j].ocena)
{ student tmp=studenti[i];
studenti[i]=studenti[j];
studenti[j]=tmp;
}
}

main()
{
student studenti[100];
int br_studenata = UcitajPodatke(studenti,100);

SelectionSort(studenti, br_studenata);

IspisiPodatke(studenti, br_studenata);

}
Primer 1.11.7 Dinamički niz.
/* Program za svaku rec unetu sa standardnog
ulaza ispisuje broj pojavljivanja.
Verzija sa dinamickim nizom i realokacijom.
*/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Rec je opisana imenom i brojem pojavljivanja */


typedef struct _rec
{ char ime[80];
int br_pojavljivanja;
} rec;

/* Dinamicki niz reci je opisan pokazivacem na


pocetak, tekucim brojem upisanih elemenata i
tekucim brojem alociranih elemenata */
rec* niz_reci;
int duzina=0;
int alocirano=0;

55
56 Milena Vujošević–Janičić

/* Realokacija se vrsi sa datim korakom */


#define KORAK 10

/* Funkcija ucitava rec i vraca njenu duzinu ili


-1 ukoliko smo dosli do znaka EOF*/
int getword(char word[],int max)
{
int c, i=0;

while (isspace(c=getchar()))
;

while(!isspace(c) && c!=EOF && i<max-1)


{
word[i++]=c;
c = getchar();
}

word[i]=’\0’;

if (c==EOF) return -1;


else return i;
}

main()
{
char procitana_rec[80];
int i;

while (getword(procitana_rec,80)!=-1)
{
/* Proveravamo da li rec vec postoji u nizu */
for (i=0; i<duzina; i++)
/* Ako bismo uporedili procitana_rec == niz_reci[i].ime
bili bi uporedjeni pokazivaci a ne odgovarajuci sadrzaji!!!
Zato koristimo strcmp. */
if (strcmp(procitana_rec, niz_reci[i].ime)==0)
{
niz_reci[i].br_pojavljivanja++;
break;
}

56
1.11 Strukture 57

/* Ukoliko rec ne postoji u nizu */


if (i==duzina)
{
rec nova_rec;
/* Ako bismo dodelili nova_rec.ime = procitana_rec
izvrsila bi se dodela pokazivaca a ne kopiranje niske
procitana_rec u nova_rec.ime. Zato koristimo strcpy!!! */
strcpy(nova_rec.ime,procitana_rec);
nova_rec.br_pojavljivanja=1;

/* Ukoliko je niz "kompletno popunjen" vrsimo realokaciju */


if (duzina==alocirano)
{
alocirano+=KORAK;

/* Sledeca linija zamenjuje blok koji sledi i moze se


koristiti alternativno. Blok je ostavljen samo da bi
demonstrirao korisnu tehniku */
/* niz_reci=realloc(niz_reci, (alocirano)*sizeof(rec)); */
{
/* alociramo novi niz, veci nego sto je bio prethodni */
rec* novi_niz=(rec *)malloc(alocirano*sizeof(rec));

if (novi_niz == NULL)
{
free(niz_reci);
printf("Greska prilikom alokacije memorije");
exit(1);
}

/* Kopiramo elemente starog niza u novi */


for (i=0; i<duzina; i++)
novi_niz[i]=niz_reci[i];

/* Uklanjamo stari niz */


free(niz_reci);

/* Stari niz postaje novi */


niz_reci=novi_niz;
}
}
/* Upisujemo rec u niz */
niz_reci[duzina]=nova_rec;

57
58 Milena Vujošević–Janičić

duzina++;
}
}

/* Ispisujemo elemente niza */


for(i=0; i<duzina; i++)
printf("%s - %d\n",niz_reci[i].ime, niz_reci[i].br_pojavljivanja);

free(niz_reci);
}

1.12 qsort
Primer 1.12.1 Implementacija funkcije qsort.
#include <stdio.h>
#include <string.h>

void printarray(int v[], int left, int right)


{
int i;
for (i=left; i<=right; i++)
printf("%d ",v[i]);
putchar(’\n’);
}

void swap(int v[], int i, int j)


{
int tmp=v[i];
v[i]=v[j];
v[j]=tmp;
}

/* qsort: sortira v[left]...v[right] u rastucem poretku */


void qsort(int v[], int left, int right)
{
int i, last;

/* ne radi nista ako niz sadrzi */


/* manje od dva elementa */
if (left >= right)
return;
/* prebaci element particioniranja */

58
1.13 Sortiranje — generička funkcija 59

/* u v[left] */
swap(v, left, (left + right)/2);
last = left;

/* partition */
for (i = left + 1; i <= right; i++)
if (v[i] < v[left])
swap(v, ++last, i);

/* restore partition elem */


swap(v, left, last);

/* Sortiraj preostala dva dela niza */


qsort(v, left, last-1);
qsort(v, last+1, right);
}

main()
{
int array[]={8, 3, 2, 6, 5, 7, 4, 9, 1};
int n=sizeof(array)/sizeof(int);

printarray(array, 0, n-1);
qsort(array, 0, n-1);
printarray(array, 0, n-1);

1.13 Sortiranje — generička funkcija


Sortiranje niza celih brojeva (jedan od algoritama)
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
int pom=a[i];
a[i]=a[j];
a[j]=pom;
}
Sortiranje iz programa mozemo da izdvojimo u funkciju:
void sort_int(int a[], int n)

59
60 Milena Vujošević–Janičić

{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
int pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Sortiranje niza realnih brojeva:

void sort_float(float a[], int n)


{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
float pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Razlike:
• prvi argument funkcije;
• pomoćna promenljiva;
• pore enje.
Sortiranje studenata po oceni ukoliko je data struktura student:

typedef struct _student {


char ime[MAX_IME];
char prezime[MAX_IME];
int ocena;
} student;

void sort_po_oceni(student a[], int n)


{
int i, j;

60
1.13 Sortiranje — generička funkcija 61

for(i=0; i<n-1; i++)


for(j=i+1; j<n; j++)
if(a[i].ocena < a[j].ocena)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Sortiranje studenta po prezimenu:


void sort_po_prezimenu(student a[], int n)
{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(strcmp(a[i].prezime, a[j].prezime)<0)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}
Sortiranje studenta po imenu:
void sort_po_imenu(student a[], int n)
{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(strcmp(a[i].ime, a[j].ime)<0)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}
Kako da napravimo jednu funkciju koja sortira studente bez obzira
na kriterijum?
Prvo moramo da izdvojimo funkciju pore enja:
int poredi_po_oceni(student st1, student st2)

61
62 Milena Vujošević–Janičić

{
return st1.ocena - st2.ocena;
}

int poredi_po_prezimenu(student st1, student st2)


{
return strcmp(st1.prezime, s2.prezime);
}

int poredi_po_imenu(student st1, student st2)


{
return strcmp(st1.ime, st2.ime);
}
Funkcija pore enja vraća 0 ukoliko su elementi jednaki, broj manji
od nule ukoliko je prvi manji od drugog i broj veći od nule ukolikoje
prvi veći od drugog.

void sort_po_imenu(student a[], int n)


{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
/*if(poredi_po_prezimenu(a[i], a[j])<0)*/
/*if(poredi_po_oceni(a[i], a[j])<0)*/
if(poredi_po_imenu(a[i], a[j])<0)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Sada možemo da dodamo još jedan argument funkciji sortiranja


i tako da dobijemo jednu funkciju umesto tri:
void sort_studente(student a[], int n, int (*f)(student, student))
{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if((*f)(a[i], a[j])<0)
{
student pom=a[i];

62
1.13 Sortiranje — generička funkcija 63

a[i]=a[j];
a[j]=pom;
}
}
Šta dalje? Kako da dobijemo jednu funkciju sortiranja bez obzira
na tip elemenata niza?
Teba da rešimo sledeće stvari:
• razmena mesta elemenata ne sme da zavisi od tipa elemenata
koji se razmenjuju.
• potpis funkcije pore enja ne sme da zavisi od tipa elemenata
koji se porede kako bi on bio jedinstven.
• prvi argument funkcije ne sme da zavisi od tipa elemenata niza.
Da bi smo razmenili dva elementa potrebna nam je pomoćna
promenljiva u kojoj privremeno čuvamo neku vrednost. Ako ne
znamo tip elementa onda ne možemo da napravimo pomoćnu promenljivu.
Ali zato mozemo da koristeći funkciju malloc odvojimo neko mesto
u memoriji za smestanje elementa koji nam u datoj situaciji treba.
Koliko je to mesto? Nekada 4 bajta, npr za int, a nekada dosta veće,
npr za studenta. Kako funkcija sortiranja zna koliko mesta treba da
odvoji? Znace tako sto ćemo joj tu veličinu proslediti kao argument.
Sada, dakle umesto pomoćne promenljive, imamo blok u memoriji,
a umesto naredbe dodele koristićemo funkciju memcpy koja kopira
deo memorije sa jednog mesta na drugo mesto.
Dakle, razmenu ćemo da radimo na sledeći način:
void* tmp = malloc(size);
if (tmp==NULL) {printf("Greska prilikom alokacije memorije!\n");exit(1);}
memcpy(tmp, adresa_itog, size);
memcpy(adresa_itog, adresa_jtog, size);
memcpy(adresa_jtog, tmp, size);
free(tmp);
Potpis funkcije pore enja ne sme da zavisi od tipa elemenata koji
se porede. To se može postići koristeći pokazivač na tip void.
Na primer, pore enje dva cela broja:
int poredi_br(void* a, void* b)
{
int br_a = *(int*)a;
int br_b = *(int*)b;

return br_a-br_b;
}

63
64 Milena Vujošević–Janičić

Na primer, pore enje dva realna broja:


int poredi_br(void* a, void* b)
{
float br_a = *(float*)a;
float br_b = *(float*)b;

if (br_a > br_b) return 1;


else if (br_a < br_b) return -1;
else return 0;
}
Na primer, pore enje dva studenta po oceni
int poredi_br(void* a, void* b)
{
student student1 = *(studnet*)a;
student student2 = *(studnet*)b;

return student1.ocena-student2.ocena;
}

Sada funkcija pore enja ima uvek potpis


int poredi(void* a, void* b)
i može se kao parametar proslediti našoj funkciji sortiranja.
Primer 1.13.1 /* Genericka funkcija sortiranja -
nezavisna od tipa elemenata niza
koji se sortira */
#include <stdlib.h>

void sort(void* a, int n, int size, int (*poredi)(void*, void*))


{
int i, j;
for (i = 0; i<n-1; i++)
for (j = i+1; j<n; j++)
{
void* adresa_itog = (char*)a+i*size;
void* adresa_jtog = (char*)a+j*size;

if (poredi(adresa_itog, adresa_jtog)<0)
{
void* tmp = malloc(size);

64
1.13 Sortiranje — generička funkcija 65

if (tmp==NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}
memcpy(tmp, adresa_itog, size);
memcpy(adresa_itog, adresa_jtog, size);
memcpy(adresa_jtog, tmp, size);
free(tmp);
}

}
}

int poredi_br(void* a, void* b) {


int br_a = *(int*)a;
int br_b = *(int*)b;

return br_a-br_b;
}

int poredi_float(void* a, void* b) {


float br_a = *(float*)a;
float br_b = *(float*)b;

if (br_a > br_b) return 1;


else if (br_a < br_b) return -1;
else return 0;
}

main() {
int a[] = {8, 2, 1, 9, 3, 7, 6, 4, 5};
float b[] = {0.3, 2, 5, 5.8, 8}
int n = sizeof(a)/sizeof(int);
int nf = sizeof(b)/sizeof(float);
int i;

sort(a, n, sizeof(int), poredi_br);

for (i = 0; i < n; i++)


printf("%d ", a[i]);
putchar(’\n’);

65
66 Milena Vujošević–Janičić

sort(b, nf, sizeof(float), poredi_float);

for (i = 0; i < n; i++)


printf("%f ", b[i]);
putchar(’\n’);
}

1.14 qSort funkcija iz standardne biblioteke


Primer 1.14.1 qSort-Upotreba.
/* Ilustracija upotrebe funkcije qsort iz stdlib.h
Sortira se niz celih brojeva.
*/

#include <stdlib.h>
#include <stdio.h>

/* const znaci da ono na sta pokazuje a (odnosno b)


nece biti menjano u funkciji */
int poredi(const void* a, const void* b)
{
/* Skracen zapis za
int br_a = *(int*)a;
int br_b = *(int*)b;

return br_a-br_b;
*/
return *((int*)a)-*((int*)b);
}

int poredi_float(const void* a, const void* b)


{
float br_a = *(float*)a;
float br_b = *(float*)b;

if (br_a > br_b) return 1;


else if (br_a < br_b) return -1;
else return 0;
}

main()

66
1.14 qSort funkcija iz standardne biblioteke 67

{
int i;
int niz[]={3,8,7,1,2,3,5,6,9};
float nizf[]={3.0,8.7,7.8,1.9,2.1,3.3,6.6,9.9};

int n=sizeof(niz)/sizeof(int);
qsort((void*)niz, n, sizeof(int), poredi);
for(i=0; i<n; i++)
printf("%d",niz[i]);

n=sizeof(nizf)/sizeof(float);
qsort((void*)nizf, n, sizeof(float), poredi_float);
for(i=0; i<n; i++)
printf("%f",nizf[i]);

}
Primer 1.14.2 Binarno pretraživanje - korišćenje ugra ene bsearch


funkcije.

/* Funkcija ilustruje koriscenje ugradjene funkcije bsearch */


#include <stdlib.h>

int poredi(const void* a, const void *b)


{
return *(int*)a-*(int*)b;
}

main()
{
int x=-1;
int niz[]={1,2,3,4,5,6,7,8,9,10,11,12};

int* elem=(int*)bsearch((void*)&x,
(void*)niz,
sizeof(niz)/sizeof(int),
sizeof(int),
poredi);

if (elem==NULL)
printf("Element nije pronadjen\n");
else
printf("Element postoji na poziciji %d\n",elem-niz);

67
68 Milena Vujošević–Janičić

1.15 Generičko sortiranje reči


Primer 1.15.1 Sortiranje reči. Ako se sortira niz stringova, onda
svaki element je sam po sebi pokazivač tipa char *, te funkcija
pore enja tada prima podatke tipa char ** koji se konvertuju u svoj


tip i derefenciraju radi dobijanja podataka tipa char *.

/* Ilustracija upotrebe funkcije qsort iz stdlib.h


Sortira se niz reci i to ili leksikografski
ili po duzini
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int poredi(const void* a, const void* b)


{
char *s1 = *(char **)a;
char *s2 = *(char **) b;
return strcmp(s1, s2);

/* Prethodno je ekvivalentno sa:


return strcmp(*(char**)a,*(char**)b); */
}

int poredi_po_duzini(const void* a, const void* b)


{
char *s1 = *(char **) a;
char *s2 = *(char **) b;
return strlen(s1) - strlen(s2);
/* Prethodno je ekvivalentno sa:
return strlen(*(char**)b)-strlen(*(char**)a); */
}

main()
{
int i;
char* nizreci[]={"Jabuka","Kruska","Sljiva","Dinja","Lubenica"};

68
1.15 Generičko sortiranje reči 69

qsort((void*)nizreci, 5, sizeof(char*), poredi_po_duzini);

for (i=0; i<5; i++)


printf("%s\n",nizreci[i]);

qsort((void*)nizreci, 5, sizeof(char*), poredi);

for (i=0; i<5; i++)


printf("%s\n",nizreci[i]);
}
Primer 1.15.2 Sa ulaza se unose reči. Program broji pojavljivanja
svake od ključnih reči programskog jezika C. Na kraju se reči ispisuju
opadajuće po broju pojavljivanja.
#include <stdio.h>
#include <stdlib.h>

/* Svaka kljucna rec se odlikuje imenom i brojem pojavljivanja */


typedef struct _keyword
{
char* word;
int num;
} keyword;

/* Kreiramo niz struktura sortiranih leksikografski


po imenu kljucne reci, kako bismo ubrzali pronalazak reci */
keyword keywords[]={ {"break",0},
{"continue",0},
{"float",0},
{"for",0},
{"if",0},
{"return",0},
{"struct",0},
{"while",0}
};

/* Funkcija cita sledecu rec sa standardnog ulaza */


int getword(char word[], int lim)
{
int c, i=0;
while(!isalpha(c=getchar()) && c!=EOF)
;
if (c==EOF)

69
70 Milena Vujošević–Janičić

return -1;
do
{
word[i++]=c;
} while(--lim>0 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

/* Funkcija leksikografskog poredjenja za bsearch */


int cmp(const void* a, const void* b) {
/* Funkcija strcmp prima kao argumente dva
pokazivaca na karaktere. Prvi je rec koju
trazimo u nizu, a drugi je element niza
sa kojim se vrsi poredjenje. Pokazivac
b konvertujemo u pokazivac na strukturu
keyword a zatim posmatramo rec koja se tu
cuva */
return strcmp((char*)a, (*(keyword*)b).word); }

/* Funkcija numerickog poredjenja za qsort */


int numcmp(const void* a, const void* b)
{
return ((*(keyword*)b).num-(*(keyword*)a).num);
}

main()
{
char word[80];
int i;

/* Broj kljucnih reci */


int num_of_keywords=sizeof(keywords)/sizeof(keyword);

/* Citamo reci */
while (getword(word,80)!=-1)
{
/* Trazimo rec u spisku kljucnih reci binarnom pretragom */
keyword* k=(keyword*)bsearch((void*)word,
(void*)keywords,
num_of_keywords,
sizeof(keyword),

70
1.16 Argumenti komandne linije 71

cmp);
/* Ukoliko je pronadjena uvecavamo broj pojavljivanja */
if (k!=NULL)
(*k).num++;
}

/* Sortiramo niz na osnovu broja pojavljivanja */


qsort((void*)keywords, num_of_keywords, sizeof(keyword), numcmp);

/* Vrsimo ispis */
for (i=0; i<num_of_keywords; i++)
printf("%s %d\n", keywords[i].word, keywords[i].num);
}

1.16 Argumenti komandne linije


Primer 1.16.1
/* Argumenti komandne linije programa */

/* Program pozivati sa npr.:


a.out
a.out prvi
a.out prvi drugi treci
a.out -a -bc ime.txt
*/

#include <stdio.h>

/* Imena ovih promenljivih mogu biti proizvoljna.


Npr:
main (int br_argumenata, char* argumenti[]);
ipak, uobicajeno je da se koriste sledeca imena:
*/

main(int argc, char* argv[])


{
int i;
printf("argc = %d\n", argc);

/* Nulti argument uvek je ime programa (a.out)*/


for (i = 0; i<argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);

71
72 Milena Vujošević–Janičić

1.17 Datoteke
Primer 1.17.1 Program demonstrira otvaranje datoteka ("r" - read
i "w" - write mod) i osnovne tehnike rada sa datotekama.
/* U datoteku se upisuje prvih 10 prirodnih
brojeva, a zatim se iz iste datoteke
citaju brojevi dok se ne stigne do kraja i
ispisuju se na standardni izlaz */

#include <stdio.h>
#include <stdlib.h>

main()
{
int i;

/* Otvaramo datoteku sa imenom podaci.txt za pisanje */


FILE* f = fopen("podaci.txt", "w");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */
if (f == NULL)
{
printf("Greska prilikom otvaranja datoteke podaci.txt za pisanje\n");
exit(1);
}

/* Upisujemo u datoteku prvih 10 prirodnih brojeva


(svaki u posebnom redu) */
for (i = 0; i<10; i++)
fprintf(f, "%d\n", i);

/* Zatvaramo datoteku */
fclose(f);

/* Otvaramo datoteku sa imenom podaci.txt za citanje */


f = fopen("podaci.txt", "r");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */

72
1.17 Datoteke 73

if (f == NULL) {
printf("Greska prilikom otvaranja datoteke podaci.txt za citanje\n");
exit(1);
}

/* Citamo brojeve iz datoteke dok ne stignemo do kraja i ispisujemo ih


na standardni izlaz */
while(1) {
int br;
/* Pokusavamo da procitamo broj */
fscanf(f, "%d", &br);

/* Ukoliko smo dosli do kraja datoteke, prekidamo */


if (feof(f))
break;

/* Ispisujemo procitani broj */


printf("Procitano : %d\n", br);
}

/* Funkciju feof ne treba pozivati pre pokusaja citanja.


Sledeci kod moze dovesti do greske:
while (!feof(f))
fscanf(f,"%d",&br);
*/

/* Zatvaramo datoteku */
fclose(f);
}

Pokazivači stdin, stdout i stderr su definisani u okviru stdio.h.


FILE* stdin;
FILE* stdout;
FILE* stderr;

Primer 1.17.2 Program demonstrira ”a” - append mod datoteka -


nadovezivanje.
#include <stdio.h>

main()
{
FILE* datoteka;

73
74 Milena Vujošević–Janičić

/* Otvaramo datoteku za nadovezivanje


i proveravamo da li je doslo do greske */
if ( (datoteka=fopen("dat.txt","a"))==NULL)
{
fprintf(stderr,"Greska prilikom otvaranja dat.txt\n");
return 1;
}

/* Upisujemo sadrzaj u datoteku */


fprintf(datoteka,"Zdravo svima\n");

/* Zatvaramo datoteku */
fclose(datoteka);
}
Primer 1.17.3 Program ilustruje rad sa datotekama. Program kopira
datoteku čije se ime zadaje kao prvi argument komandne linije u da-
toteku čije se ime zadaje kao drugi argument komandne linije. Uz
svaku liniju se zapisuje i njen redni broj.
#include <stdio.h>

#define MAX_LINE 256

/* Funkcija fgets definisana je u stdio.h

char* fgets(char *s, int n, FILE* stream)

fgets ucitava najvise sledecih n-1 znakova


u polje niza karaktera s, zaustavljajuci se
ako naidje na novu liniju koju takodje
upisuje u polje. Na kraju upisuje ’\0’.
Funkcija vraca s ili NULL ako dodje do kraja
datoteke ili se pojavi greska

Funkcija getline moze jednostavno da se


realizuje preko funkcije fgets.

int getline(char s[], int lim)


{
char* c = fgets(s, lim, stdin);
return c==NULL ? 0 : strlen(s);
}

74
1.17 Datoteke 75

*/

main(int argc, char* argv[])


{

char line[MAX_LINE];
FILE *in, *out;
int line_num;

if (argc != 3) {
fprintf(stderr,"Upotreba : %s ulazna_datoteka izlazna_datoteka\n",argv[0]);
return 1;
}

if ((in = fopen(argv[1],"r")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke %s\n", argv[1]);
return 1;
}

if ((out = fopen(argv[2],"w")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke %s\n",argv[2]);
return 1;
}

/* Prepisivanje karakter po karakter je moguce ostvariti preko:


int c;
while ((c=fgetc(in)) != EOF)
putc(c,out);
*/

line_num = 1;

/* Citamo liniju po liniju sa ulaza*/


while (fgets(line, MAX_LINE, in) != NULL)
{
/* Ispisujemo broj linije i sadrzaj linije na izlaz */
fprintf(out, "%d :\t", line_num++);
fputs(line, out);
}

/* Zatvaramo datoteke */

75
76 Milena Vujošević–Janičić

fclose(in);
fclose(out);
}
Primer 1.17.4 Prodavnica - ilustruje čitanje niza struktura iz tek-
tsualne datoteke.
/* Datoteka, cije se ime zadaje kao argument komandne linije
ili ako se ne zada onda se ime unosi sa standardnog
ulaza, sadrzi podatke o proizvodima koji se prodaju
u okviru odredjene prodavnice. Svaki
proizvod se odlikuje sledecim podacima:
bar-kod - petocifreni pozitivan broj
ime - niska karaktera
cena - realan broj zaokruzen na dve decimale
pdv - stopa poreza - realan broj zaokruzen na dve decimale
Pretpostavljamo da su podaci u datoteci
korektno zadati.

Pretpostavljamo da se u prodavnici ne
prodaje vise od 1000 razlicitih artikala
Na standardni izlaz ispisati podatke o
svim proizvodima koji se prodaju u prodavnici.
Zadatak je moguce resiti i bez koriscenja nizova
(i takvo resenje je bolje). */

#include <stdio.h>

/* Maksimalna duzina imena proizvoda */


#define MAX_IME 30

/* Maksimalni broj artikala */


#define MAX_ARTIKALA 1000

/* Struktura za cuvanje podataka o jednom artiklu */


typedef struct _artikal {
int bar_kod;
char ime[MAX_IME];
float cena;
float pdv;
} artikal;

/* Niz struktura u kome se cuvaju podaci o artiklima */

76
1.17 Datoteke 77

artikal artikli[MAX_ARTIKALA];

/* Broj trenutno ucitanih artikala */


int br_artikala = 0;

/* Ucitava podatke o jednom artiklu iz date datoteke.


Vraca da li su podaci uspesno procitani */
int ucitaj_artikal(FILE* f, artikal* a)
{
/* Citamo bar kod, ime, cenu, pdv */
fscanf(f, "%d%s%f%f", &(a->bar_kod), a->ime, &(a->cena), &(a->pdv));

/* Ukoliko smo dosli do kraja datoteke prilikom pokusaja ucitavanja


prijavljujemo neuspeh */
if (feof(f))
return 0;

/* Prijavljujemo uspeh */
return 1;
}

/* Izracunava ukupnu cenu datog artikla */


float cena(artikal a)
{
return a.cena*(1+a.pdv);
}

/* Ispisuje podatke o svim artiklima */


void ispisi_artikle()
{
int i;
for (i = 0; i<br_artikala; i++)
printf("%-5d %-10s %.2f %.2f = %.2f\n",
artikli[i].bar_kod, artikli[i].ime,
artikli[i].cena, artikli[i].pdv,
cena(artikli[i]));
}

main(int argc, char* argv[])


{
FILE* f;

/* Ukoliko nije navedeno ime kao argument komandne linije, trazimo

77
78 Milena Vujošević–Janičić

od korisnika da ga unese */
if (argc<2) {
/* Ucitavamo ime datoteke */
char ime_datoteke[256];
printf("U kojoj datoteci se nalaze podaci o proizvodima: ");
scanf("%s", ime_datoteke);

/* Otvaramo datoteku i proveravamo da li smo uspeli */


if ( (f = fopen(ime_datoteke, "r")) == NULL)
{
printf("Greska prilikom otvaranja datoteke %s\n", ime_datoteke);
return 1;
}
}
/* Ime datoteke je prvi argument komandne linije */
else {
/* Otvaramo datoteku i proveravamo da li smo uspeli */
if ( (f = fopen(argv[1], "r")) == NULL)
{
printf("Greska : datoteka %s ne moze biti otvorena\n", argv[1]);
return 1;
}

/* Ucitavamo artikle */
while (ucitaj_artikal(f, &artikli[br_artikala]))
br_artikala++;

/* Ispisujemo podatke o svim artiklima */


ispisi_artikle();

/* Zatvara se datoteka*/
fclose(f);
}

1.18 Liste
1.18.1 Red

Primer 1.18.1 Program formira listu brojeva i demonstrira osnovne


elemente rada sa listom.

78
1.18 Liste 79

početak reda (brisanje — get)


kraj reda (dodavanje — add)

A B ... X NULL

novi element

početak reda
novi kraj reda

A B ... X Y NULL

početak reda nakon brisanja kraj reda

B ... X Y NULL

Slika 1.1: Red

#include <stdio.h>
#include <stdlib.h>

typedef struct elem {


int broj;
struct elem *sled;
} Elem;

/* Citanje brojeva i formiranje liste. Funkcija vraca pokazivac


na pocetak liste. */
Elem *citaj (void)
{
Elem *lista = NULL, *poslednji = NULL, *novi;
int broj;

printf("\n\nUnesite elemente liste - 0 za kraj\n");


scanf ("%d", &broj);

79
80 Milena Vujošević–Janičić

while (broj) {
/*Alocira se prostor za novi clan liste*/
novi =(Elem*)malloc (sizeof (Elem));
if (novi == NULL)
{
fprintf(stderr, "Greska prilikom alokacije memorije\n");
exit(1);
}

/* Postavljanje vrednosti */
novi->broj = broj;
novi->sled = NULL;

/* Ukoliko lista nije prazna novi element se postavlja iza


poslednjeg elemnta liste - na koji pokazuje poslednji */
if (poslednji != NULL)
poslednji->sled = novi;
/* Inace se postavlja da bude pocetak liste */
else
lista = novi;

/*Poslednji se postavlja da pokazuje na poslednji element liste */


/*Ekvivalentno je sa
poslednji = poslednji ->sledeci */
poslednji = novi;
/* Ucitavanje novog elementa liste 0 za kraj */
scanf ("%d", &broj);
}
/* Funkcija vraca pokazivac na pocetak liste */
return lista;
}

/* Ispisivanje liste*/
void pisi (Elem *lista)
{
while (lista != NULL)
{
printf ("%d ", lista->broj),
lista = lista->sled;
}
putchar (’\n’);
}

80
1.18 Liste 81

/* Oslobadjanje memorije koju lista zauzima*/


void brisi (Elem* lista)
{
Elem *stari;
while (lista != NULL)
{
stari = lista;
lista = lista->sled;
free (stari);
}
}

/* Izbacivanje (brisanje) zadatog broja iz liste. Kako se


ovime pocetak liste moze izmeniti, vrednost pocetka liste
je povratna vrednost funkcije */
Elem* izbaci(Elem *lista, int k)
{
Elem *preth = NULL, *tekuci = lista, *zaizbacivanje;

while (tekuci != NULL)


/* Ukoliko tekuci pokazuje na clana
liste kojeg treba izbaciti */
if (tekuci->broj == k)
{
zaizbacivanje = tekuci;
tekuci = tekuci->sled;

if (preth != NULL )
preth->sled = tekuci;
/* Ovaj slucaj odnosi se na izbacivanje
elementa sa pocetka liste */
else lista = tekuci;

free (zaizbacivanje);
}
else
{
preth = tekuci;
tekuci = tekuci->sled;
}
return lista;
}

81
82 Milena Vujošević–Janičić

main ()
{
Elem *lista;
int k;

lista = citaj ();


printf ("Ucitani lista = ");
pisi (lista);

printf("Koji element liste zelite da izbacite?\n");


scanf ("%d", &k);
printf ("Izostavlja se = %d\n", k);
printf ("Novi lista = ");
pisi (lista = izbaci (lista, k));
printf ("\n");

printf("Lista mi vise nije potrebna, oslobadjam memoriju!\n");


brisi (lista);
}
Primer 1.18.2 Rad sa listama - celine izdvojene u funkcije.
#include <stdio.h>
#include <stdlib.h>

typedef struct cvor {


int br;
struct cvor* sl;
} CVOR;

/* Pomocna funkcija koja kreira cvor liste sa datim sadrzajem.


Funkcija kreira cvor i postavlja mu sadrzaj na dati broj.
Funkcija vraca pokazivac na kreirani cvor. */
CVOR* napravi_cvor(int br) {
CVOR* novi = (CVOR*)malloc(sizeof(CVOR));
if (novi == NULL)
{
fprintf(stderr, "Greska prilikom alokacije memorije\n");
exit(1);
}
novi->br = br;
novi->sl = NULL;
return novi;
}

82
1.18 Liste 83

/* --------------------------------------------- */
/* Ispisivanje liste: iterativna verzija */
void ispisi_listu_i(CVOR* l) {
CVOR* t;
for (t = l; t != NULL; t=t->sl)
printf("%d ", t->br);
}

/* Ispisivanje liste: rekurzivna verzija */


void ispisi_listu_r(CVOR* l) {
if (l != NULL)
{
printf("%d ", l->br);
ispisi_listu_r(l->sl);
}
}

/* Ispisivanje liste unazad: rekurzivna verzija */


void ispisi_listu_unazad(CVOR* l) {
if (l != NULL)
{
ispisi_listu_unazad(l->sl);
printf("%d ", l->br);
}
}

/* --------------------------------------------- */
/* Oslobadjanje liste : iterativna verzija */
void oslobodi_listu_i(CVOR* l) {
while (l!=NULL)
{
CVOR* tmp = l->sl;
free(l);
l = tmp;
}
}

/* Oslobadjanje liste : rekurzivna verzija */


void oslobodi_listu_r(CVOR* l) {
if (l != NULL)
{
oslobodi_listu_r(l->sl);

83
84 Milena Vujošević–Janičić

/* Prvo se oslobadja poslednji element liste */


free(l);
}
}

/* --------------------------------------------- */
/* Ubacuje dati broj na pocetak date liste.
Funkcija pozivaocu eksplicitno vraca pocetak
rezultujuce liste.*/
CVOR* ubaci_na_pocetak(CVOR* l, int br) {
CVOR* novi = napravi_cvor(br);
novi->sl = l;
return novi;
}

/* Funkcija vraca pocetak rezultujuce liste, a ubacuje


cvor na kraj bez pamcenja pokazivaca na kraj */
CVOR* ubaci_na_kraj(CVOR* l, int br) {
CVOR* novi = napravi_cvor(br);

if (l == NULL)
return novi;
else
{
CVOR* t;
/* Prodjemo do kraja liste */
for (t = l; t->sl!=NULL; t=t->sl)
;
t->sl = novi;

/* Pocetak se nije promenio */


return l;
}
}

/* Rekurzivna varijanta prethodne funkcije.


I ova funkcija vraca pokazivac na pocetak
rezultujuce liste */
CVOR* ubaci_na_kraj_rekurzivno(CVOR* l, int br) {
if (l == NULL)
{
CVOR* novi = napravi_cvor(br);
return novi;

84
1.18 Liste 85

l->sl = ubaci_na_kraj_rekurzivno(l->sl, br);


return l;
}

/* --------------------------------------------- */
/* Kljucna ideja u realizaciji ove funkcije je
pronalazenje poslednjeg elementa liste ciji
je kljuc manji od datog elementa br.
*/
CVOR* ubaci_sortirano(CVOR* pl, int br) {
CVOR* novi = napravi_cvor(br);

/* U sledeca dva slucaja ne postoji cvor


ciji je kljuc manji od datog broja (br)
- Prvi je slucaj prazne liste
- Drugi je slucaj kada je br manji od prvog elementa

U oba slucaja ubacujemo na pocetak liste.


*/
if (pl == NULL || br < pl->br)
{
novi->sl = pl;
pl = novi;
}
else
{
/* Krecemo od pocetka i idemo dalje sve dok t nije poslednji
manji element liste ili eventualno bas poslednji */
CVOR* t;
for(t = pl; t->sl!=NULL && t->sl->br < br; t=t->sl)
;
novi->sl = t->sl;
t->sl = novi;
}

return pl;
}

main() {
CVOR* l = NULL;
CVOR* s = NULL;

85
86 Milena Vujošević–Janičić

int i;
for (i = 0; i<5; i++)
l = ubaci_na_kraj(l, i);
for (; i<10; i++)
l = ubaci_na_kraj_rekurzivno(l, i);

for (i = 0; i < 10 ; i++)


l = ubaci_na_pocetak(l, i);

ispisi_listu_i(l);
putchar(’\n’);

ispisi_listu_r(l);
putchar(’\n’);

ispisi_listu_unazad(l);
putchar(’\n’);

oslobodi_listu_i(l);

s = ubaci_sortirano(s, 5);
s = ubaci_sortirano(s, 8);
s = ubaci_sortirano(s, 7);
s = ubaci_sortirano(s, 6);
s = ubaci_sortirano(s, 4);

ispisi_listu_r(s);
putchar(’\n’);

oslobodi_listu_r(s);
}

1.18.2 Kružna lista


Primer 1.18.3 (februar 2006.) Grupa od n plesača (na čijim kos-
timima su u smeru kazaljke na satu redom brojevi od 1 do n) izvodi
svoju plesnu tačku tako što formiraju krug iz kog najpre izlazi k-ti
plesač (odbrojava se počev od plesača označenog brojem 1 u smeru
kretanja kazaljke na satu). Preostali plesači obrazuju manji krug
iz kog opet izlazi k-ti plesač (odbrojava se pocev od sledećeg suseda
prethodno izbačenog, opet u smeru kazaljke na satu). Izlasci iz kruga
se nastavljaju sve dok svi plesači ne budu isključeni. Celi brojevi n,

86
1.18 Liste 87

početak ciklične liste

A B C ... Z

Slika 1.2: Kružna lista

k (k < n) se učitavaju sa standardnog ulaza. Napisati program


koji će na standardni izlaz ispisati redne brojeve plesača u redosledu
napuštanja kruga.
PRIMER: za n = 5, k = 3 redosled izlaska je 3 1 5 2 4.

1.18.3 Stek
Primer 1.18.4 Program proverava da li su zagrade ( i ) dobro up-
arene.

#include <stdio.h>
#include <stdlib.h>

main()
{
int c;
int br_otv = 0;
while((c=getchar()) != EOF)
{
switch(c)
{
case ’(’:
br_otv++;
break;
case ’)’:
br_otv--;
if (br_otv<0)
{
printf("Visak zatvorenih zagrada\n");
exit(1);
}

87
88 Milena Vujošević–Janičić

}
}

if (br_otv == 0)
printf("Zagrade su u redu\n");
else
printf("Visak otvorenih zagrada\n");
}
Primer 1.18.5 Program proverava da li su zagrade (, [, {, }, ] i )
dobro uparene - statička implementacija steka.
#include <stdio.h>
#include <stdlib.h>
#define MAX_ZAGRADA 100

int odgovarajuce(char z1, char z2) {


return (z1 == ’(’ && z2 == ’)’) ||
(z1 == ’{’ && z2 == ’}’) ||
(z1 == ’[’ && z2 == ’]’);
}

main()
{
int c;
char otv_zagrade[MAX_ZAGRADA];
int br_otv = 0;

while((c=getchar()) != EOF)
{
switch(c)
{
case ’(’:
case ’{’:
case ’[’:
{
otv_zagrade[br_otv] = c;
br_otv++;
break;
}
case ’]’:
case ’}’:
case ’)’:
if (br_otv>0 && odgovarajuce(otv_zagrade[br_otv-1], c))

88
1.18 Liste 89

{
br_otv--;
}
else
{
printf("Visak zatvorenih zagrada: %c u liniji %d\n", c, br_linija);
exit(1);
}
}
}

if (br_otv == 0)
printf("Zagrade su u redu\n");
else
printf("Visak otvorenih zagrada\n");
}

vrh steka (i dodavanje i brisanje — push i pop)

X Y ... A NULL

novi element

novi vrh steka

Y X V ... A NULL

vrh steka nakon brisanja

X V ... A NULL

Slika 1.3: Stek

Primer 1.18.6 Program ilustruje proveru validnosti HTML datoteke

89
90 Milena Vujošević–Janičić

- proverava se da li su etikete dobro uparene pri cemu se stek imple-


mentira preko liste.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* Maksimalna duzina etikete */


#define MAX_TAG 100

#define OTVORENA 1
#define ZATVORENA 2
#define GRESKA 0

/* Funkcija ucitava sledecu etiketu i smesta njen naziv u niz s


duzine max. Vraca OTVORENA za otvorenu etiketu, ZATVORENA za
zatvorenu etiketu, odnosno GRESKA inace */
int gettag(char s[], int max) {
int c, i;
int zatvorenost=OTVORENA;

/* Preskacemo sve do znaka ’<’ */


while ((c=getchar())!=EOF && c!=’<’)
;
/* Nismo naisli na etiketu */
if (c==EOF)
return GRESKA;

/* Proveravamo da li je etiketa zatvorena */


if ((c=getchar())==’/’)
zatvorenost=ZATVORENA;
else
/* Funkcija ungetc vraca karakter c na standardni ulaz */
ungetc(c,stdin);

/* Citamo etiketu dok nailaze slova i smestamo ih u nisku */


for (i=0; isalpha(c=getchar()) && i<max-1; s[i++] = c)
;
/* Vracamo poslednji karakter na ulaz jer je to bio neki karakter
koji nije slovo*/
ungetc(c,stdin);

s[i]=’\0’;

90
1.18 Liste 91

/* Preskacemo atribute do znaka > */


while ((c=getchar())!=EOF && c!=’>’)
;

/* Greska ukoliko nismo naisli na ’>’ */


return c==’>’ ? zatvorenost : GRESKA;
}

/* Stek ce biti implementiran koriscenjem liste */


typedef struct
cvor {
char tag[MAX_TAG];
struct cvor* sledeci;
} CVOR;

CVOR* stek = NULL;

main()
{
char tag[MAX_TAG];
int zatvorenost;
while ((zatvorenost = gettag(tag, MAX_TAG))>0)
{
if (zatvorenost==OTVORENA)
{
/* Svaku otvorenu etiketu stavljamo na stek */

CVOR* tmp = (CVOR*)malloc(sizeof(CVOR));


if (tmp == NULL)
{
printf("Greska prilikom alokacije memorije!\n");
return 1;
}
strcpy(tmp->tag, tag);
tmp->sledeci = stek;
stek = tmp;

printf("Postavio <%s> na stek\n", stek->tag);


}

else
{

91
92 Milena Vujošević–Janičić

/* Za zatvorene etikete proveravamo da li je stek prazan


odnosno da li se na vrhu steka nalazi odgovarajuca
otvorena etiketa */
if (stek != NULL && strcmp(stek->tag, tag) == 0)
{
/* Uklanjamo etiketu sa steka */
CVOR* tmp = stek->sledeci;
free(stek);
stek = tmp;
}
else
{
/* Prijavljujemo gresku */
printf("Neodgovarajuci tag : </%s>!\n",tag);
exit(1);
}
}
}

if (stek == NULL) printf("Datoteka je ispravna\n ");


else
{
printf("Visak otvorenih etiketa!\n");
/* Oslobadjamo memoriju koja je ostala
zarobljena na steku. */
while(stek!=NULL)
{
CVOR* tmp = stek->sledeci;
free(stek);
stek = tmp;
}
}
}

1.18.4 Dvostruko povezane liste


Primer 1.18.7 Napisati funkciju koja omogućava umetanje čvora u
dvostruko povezanu kružnu listu kao i izbacivanje čora iz dvostruko
povezane kružne liste. Omogućiti i štampanje podataka koje čuva
lista.

/* Program implementira deciju razbrajalicu eci-peci-pec i sluzi


da ilustruje rad sa dvostruko povezanim kruznim listama */

92
1.18 Liste 93

početak dvostruko povezane liste kraj liste

...
NULL A B C ... Z NULL

Slika 1.4: Dvostruko povezana lista

#include <stdlib.h>
#include <stdio.h>

/* Dvostruko povezana lista */


typedef struct _cvor {
int broj;
struct _cvor* prethodni, *sledeci;
} cvor;

/* Umetanje u dvostruko povezanu listu */


cvor* ubaci(int br, cvor* lista) {
cvor* novi=(cvor*)malloc(sizeof(cvor));
if (novi==NULL)
{ printf("Greska prilikom alokacije memorije \n");
exit(1);
}
novi->broj=br;

if (lista==NULL)
{ novi->sledeci=novi;
novi->prethodni=novi;
return novi;
}
else
{ novi->prethodni=lista;
novi->sledeci=lista->sledeci;
lista->sledeci->prethodni=novi;
lista->sledeci=novi;
return novi;

93
94 Milena Vujošević–Janičić

}
}

/* Ispis liste */
void ispisi(cvor* lista)
{
if (lista!=NULL)
{ cvor* tekuci=lista;
do
{ printf("%d\n",tekuci->broj);
tekuci=tekuci->sledeci;
} while (tekuci!=lista);
}
}

/* Izbacivanje datog cvora iz liste, funkcija


vraca pokazivac na novonastalu listu */
cvor* izbaci(cvor* lista) {
if (lista!=NULL)
{ cvor* sledeci=lista->sledeci;
if (lista==lista->sledeci)
{ printf("Pobednik %d\n",lista->broj);
free(lista);
return NULL;
}

printf("Ispada %d\n",lista->broj);

lista->sledeci->prethodni=lista->prethodni;
lista->prethodni->sledeci=lista->sledeci;
free(lista);
return sledeci;
}
else return NULL;
}

main() {
/* Umecemo petoro dece u listu */
cvor* lista = NULL;
lista=ubaci(1,lista);
lista=ubaci(2,lista);
lista=ubaci(3,lista);
lista=ubaci(4,lista);

94
1.18 Liste 95

lista=ubaci(5,lista);
lista=lista->sledeci;

/*Proverimo da smo dobro formirali listu*/


ispisi(lista);

int smer = 0;
/* Dok ima dece u listi */
while(lista!=NULL)
{ int i;

/* brojimo 13 slogova u krug i u svakom brojanju


menjamo smer obilaska*/
for (i=1; i<=13; i++)
lista = 1-smer ? lista->sledeci : lista->prethodni;

lista=izbaci(lista);
smer = smer ? 0 : 1;
}
}
Primer 1.18.8 Program ispisuje broj pojavljivanja za svaku od reči
koja se pojavila u tekstu unetom sa standardnog ulaza. Verzija sa
(sortiranom) listom.
#include <stdlib.h>
#include <stdio.h>

/* Definicija cvora liste */


typedef struct _cvor
{
char ime[80];
int br_pojavljivanja;
struct _cvor* sledeci;
} cvor;

/* Funkcija ispisuje listu rekurzivno, pocevsi od poslednjeg


elementa */
void ispisi_listu(cvor* pocetak)
{
if (pocetak!=NULL)
{
ispisi_listu(pocetak->sledeci);
printf("%s %d\n",pocetak->ime,pocetak->br_pojavljivanja);

95
96 Milena Vujošević–Janičić

}
}

/* Funkcija koja brise listu */


void obrisi_listu(cvor* pocetak)
{
if (pocetak!=NULL)
{
obrisi_listu(pocetak->sledeci);
free(pocetak);
}
}

/* Funkcija ubacuje rekurzivno datu rec u listu koja je


leksikografski sortirana, na odgovarajuce mesto i vraca
pokazivac na novi pocetak liste */
cvor* ubaci_sortirano(cvor* pocetak, char* rec)
{
int cmp;
/* Ukoliko je lista prazna ubacujemo na pocetak liste*/
if (pocetak==NULL)
{ pocetak=(cvor*)malloc(sizeof(cvor));
if (pocetak == NULL)
{
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}
strcpy(pocetak->ime,rec);
pocetak->br_pojavljivanja=1;
return pocetak;
}
/* Ukoliko lista nije prazna poredimo rec sa elementom u glavi */
cmp=strcmp(pocetak->ime,rec);
/* Ukoliko je rec pronadjena samo uvecavamo njen broj
pojavljivanja */
if (cmp==0)
{ pocetak->br_pojavljivanja++;
return pocetak;
}
/* Ukoliko je rec koju ubacujemo veca od tekuce reci, ubacujemo je
rekurzivno u rep */
else if (cmp>0)
{ pocetak->sledeci=ubaci_sortirano(pocetak->sledeci,rec);

96
1.18 Liste 97

return pocetak;
}
/* Ukoliko je rec koju ubacujemo manja od tekuce reci, gradimo novi
cvor i ubacujemo ga ispred pocetka */
else
{ cvor* novi=malloc(sizeof(cvor));
if (novi == NULL)
{
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}
strcpy(novi->ime,rec);
novi->br_pojavljivanja=1;
novi->sledeci=pocetak;
return novi;
}
}

/* Pomocna funkcija koja cita rec sa standardnog ulaza i vraca


njenu duzinu, odnosno -1 ukoliko se naidje na EOF */
int getword(char word[], int lim) {
int c, i=0;
while (!isalpha(c=getchar()) && c!=EOF)
;

if (c==EOF)
return -1;
do
{ word[i++]=c;
}while (i<lim-1 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

/* Funkcija koja rekurzivno pronalazi datu rec u datoj listi.


Funkcija vraca pokazivac na cvor u kome je nadjena rec, ili
NULL ukoliko rec nije nadjena */
cvor* nadji_rec(cvor* lista, char rec[])
{
if (lista==NULL)
return NULL;

97
98 Milena Vujošević–Janičić

if (strcmp(lista->ime,rec)==0)
return lista;

return nadji_rec(lista->sledeci,rec);
}

main()
{
cvor* lista=NULL;
char procitana_rec[80];
while(getword(procitana_rec,80)!=-1)
{ cvor* pronadjen=nadji_rec(lista,procitana_rec);
if (pronadjen!=NULL)
pronadjen->br_pojavljivanja++;
else
lista=ubaci_sortirano(lista,procitana_rec);
}
ispisi_listu(lista);
obrisi_listu(lista);
}

1.19 Drvo
Primer 1.19.1 Binarno pretrazivacko drvo - drvo sadrži cele bro-
jeve.

/* Program demonstrira rad sa binarnim pretrazivackim drvetima.


Drveta sadrze cele brojeve i sortirana su po velicini.
Za svaki cvor, levo podstabla sadrzi manje elemente, dok desno
podstablo sadrzi vece.
*/

#include <stdlib.h>
#include <stdio.h>

typedef struct _cvor


{
int broj;
struct _cvor *l, *d;
} cvor;

98
1.19 Drvo 99

NULL NULL

NULL NULL NULL

NULL NULL

Slika 1.5: Stablo

cvor* napravi_cvor(int b) {
cvor* novi = (cvor*)malloc(sizeof(cvor));
if (novi == NULL)
{
fprintf(stderr, "Greska prilikom
alokacije memorije");
exit(1);
}
novi->broj = b;
novi->l = NULL;
novi->d = NULL;
return novi;
}

/* Funkcija umece broj br u drvo ciji je koren dat preko

99
100 Milena Vujošević–Janičić

17, 12, 21, 15, 5, 14


17

12 21

NULL NULL

5 15

NULL NULL NULL

inf ix : 5, 12, 14, 15, 17, 21


14 pref ix : 17, 12, 5, 15, 14, 21

postf ix : 5, 14, 15, 12, 21, 17


NULL NULL

Slika 1.6: Ure eno stablo




pokazivaca drvo. Funkcija vraca pokazivac na koren


novog drveta */
cvor* ubaci_u_drvo(cvor* drvo, int b)
{
if (drvo == NULL)
return napravi_cvor(b);

if (b < drvo->broj)
drvo->l = ubaci_u_drvo(drvo->l, b);
else
drvo->d = ubaci_u_drvo(drvo->d, b);

return drvo;
}

100
1.19 Drvo 101

/* Funkcija proverava da li dati broj postoji u drvetu */


int pronadji(cvor* drvo, int b)
{
if (drvo == NULL)
return 0;

if (drvo->broj == b)
return 1;

if (b < drvo->broj)
return pronadji(drvo->l, b);
else
return pronadji(drvo->d, b);
}

/* Funkcija ispisuje sve cvorove drveta u infiksnom redosledu */


void ispisi_drvo(cvor* drvo) {
if (drvo != NULL)
{
ispisi_drvo(drvo->l);
printf("%d ", drvo->broj);
ispisi_drvo(drvo->d);
}
}

void obrisi_drvo(cvor* drvo) {


if (drvo != NULL)
{
obrisi_drvo(drvo->l);
obrisi_drvo(drvo->d);
free(drvo);
}
}

/* Funkcija sumira sve vrednosti binarnog stabla */


int suma_cvorova(cvor* drvo)
{
if (drvo == NULL)
return 0;
return suma_cvorova(drvo->l) +
drvo->broj +
suma_cvorova(drvo->d);

101
102 Milena Vujošević–Janičić

int broj_cvorova(cvor* drvo)


{
if (drvo == NULL)
return 0;
return broj_cvorova(drvo->l) +
1 +
broj_cvorova(drvo->d);
}

int broj_listova(cvor* drvo)


{
if (drvo == NULL)
return 0;
if (drvo->l == NULL && drvo->d == NULL)
return 1;
return broj_listova(drvo->l) +
broj_listova(drvo->d);
}

int suma_listova(cvor* drvo)


{
if (drvo == NULL)
return 0;

if (drvo->l == NULL && drvo->d == NULL)


return drvo->broj;

return suma_listova(drvo->l) +
suma_listova(drvo->d);
}

void ispisi_listove(cvor* drvo)


{
if (drvo == NULL)
return;

ispisi_listove(drvo->l);

if (drvo->l == NULL && drvo->d == NULL)


printf("%d ", drvo->broj);

102
1.19 Drvo 103

ispisi_listove(drvo->d);
}

/* Funkcija pronalazi maksimalnu vrednost u drvetu


Koristi se cinjenica da je ova vrednost
smestena u najdesnjem listu */
int max_vrednost(cvor* drvo)
{
if (drvo==NULL)
return 0;

if (drvo->d==NULL)
return drvo->broj;

return max_vrednost(drvo->d);
}

/* Iterativna funkcija za pronalazenje maksimalne vrednosti. */


int max_vrednost_nerekurzivno(cvor* drvo)
{
if (drvo==NULL)
return 0;
else
{
cvor* tekuci;
for (tekuci=drvo; tekuci->d!=NULL; tekuci=tekuci->d)
;
return tekuci->broj;
}
}

/* Funkcija racuna "dubinu" binarnog stabla */


#define max(a,b) (((a)>(b))?(a):(b))

int dubina(cvor* drvo)


{
if (drvo==NULL)
return 0;
else
{ int dl=dubina(drvo->l);
int dd=dubina(drvo->d);
return 1+max(dl,dd);

103
104 Milena Vujošević–Janičić

}
}

main()
{
cvor* drvo = NULL;
drvo = ubaci_u_drvo(drvo, 1);
drvo = ubaci_u_drvo(drvo, 8);
drvo = ubaci_u_drvo(drvo, 5);
drvo = ubaci_u_drvo(drvo, 3);
drvo = ubaci_u_drvo(drvo, 7);
drvo = ubaci_u_drvo(drvo, 6);
drvo = ubaci_u_drvo(drvo, 9);

if (pronadji(drvo, 3))
printf("Pronadjeno 3\n");
if (pronadji(drvo, 2))
printf("Pronadjeno 2\n");
if (pronadji(drvo, 7))
printf("Pronadjeno 7\n");

ispisi_drvo(drvo);

putchar(’\n’);
printf("Suma cvorova : %d\n", suma_cvorova(drvo));
printf("Broj cvorova : %d\n", broj_cvorova(drvo));
printf("Broj listova : %d\n", broj_listova(drvo));
printf("Suma listova : %d\n", suma_listova(drvo));
printf("Dubina drveta : %d\n", dubina(drvo));
printf("Maximalna vrednost : %d\n", max_vrednost(drvo));

ispisi_listove(drvo);

obrisi_drvo(drvo);
}

/*
Pronadjeno 3
Pronadjeno 7
1 3 5 6 7 8 9
Suma cvorova : 39
Broj cvorova : 7
Broj listova : 3

104
1.19 Drvo 105

Suma listova : 18
Dubina drveta : 5
Maximalna vrednost : 9
3 6 9
*/
Primer 1.19.2 Program sa ulaza čita tekst i ispisuje broj pojavlji-
vanja svake od reči koje su se javljale u tekstu. Radi poboljsanja
efikasnosti, prilikom brojanja reci koristi se struktura podataka pogodna
za leksikografsku pretragu - u ovom slucaju binarno pretrazivacko
drvo.
#include <stdlib.h>
#include <stdio.h>

/* Cvor drveta sadrzi ime reci i


broj njenih pojavljivanja */
typedef struct _cvor {
char ime[80];
int br_pojavljivanja;
struct _cvor* levo, *desno;
} cvor;

/* Funkcija ispisuje drvo u inorder redosledu */


void ispisi_drvo(cvor* drvo)
{
if (drvo!=NULL)
{
ispisi_drvo(drvo->levo);
printf("%s %d\n",drvo->ime,drvo->br_pojavljivanja);
ispisi_drvo(drvo->desno);
}
}

/* Funkcija uklanja binarno drvo iz memorije */


void obrisi_drvo(cvor* drvo)
{
if (drvo!=NULL)
{
obrisi_drvo(drvo->levo);
obrisi_drvo(drvo->desno);
free(drvo);
}
}

105
106 Milena Vujošević–Janičić

/* Funkcija ubacuje datu rec u dato drvo


i vraca pokazivac na koren drveta */
cvor* ubaci(cvor* drvo, char rec[]) {
/* Ukoliko je drvo prazno gradimo novi cvor */
if (drvo==NULL)
{
cvor* novi_cvor=(cvor*)malloc(sizeof(cvor));
if (novi_cvor==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
strcpy(novi_cvor->ime, rec);
novi_cvor->br_pojavljivanja=1;
return novi_cvor;
}

/* Uporedjujemo rec koju smo ucitali sa recju koja


se nalazi u cvoru drveta*/
int cmp = strcmp(rec, drvo->ime);

/* Ukoliko rec vec postoji u drvetu


uvecavamo njen broj pojavljivanja */
if (cmp==0)
{ drvo->br_pojavljivanja++;
return drvo;
}

/* Ukoliko je rec koju ubacujemo leksikografski


ispred reci koja je u korenu drveta, rec
ubacujemo u levo podstablo */
if (cmp<0)
{ drvo->levo=ubaci(drvo->levo, rec);
return drvo;
}

/* Ukoliko je rec koju ubacujemo


leksikografski iza reci koja je u
korenu drveta, rec ubacujemo u desno
podstablo */
if (cmp>0)
{ drvo->desno=ubaci(drvo->desno, rec);

106
1.19 Drvo 107

return drvo;
}
}

/* Pomocna funkcija koja cita rec sa


standardnog ulaza i vraca njenu
duzinu, odnosno -1 ukoliko se naidje na EOF.
Ukoliko umesto funkcije getword koristimo
funkciju gettag program ce ispisivati
broj pojavljivanja svakog od tagova sa ulaza */
int getword(char word[], int lim) {
int c, i=0;
while (!isalpha(c=getchar()) && c!=EOF)
;

if (c==EOF)
return -1;
do
{
word[i++]=c;
} while (i<lim-1 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

main() {
/* Drvo je na pocetku prazno */
cvor* drvo=NULL;
char procitana_rec[80];

/* Citamo rec po rec dok ne


naidjemo na kraj datoteke i
ubacujemo ih u drvo */
while(getword(procitana_rec,80)!=-1)
drvo=ubaci(drvo,procitana_rec);

/* Ispisujemo drvo */
ispisi_drvo(drvo);

/* Uklanjamo ga iz memorije */
obrisi_drvo(drvo);
}

107
108 Milena Vujošević–Janičić

Primer 1.19.3 Program iz datoteke čita tekst i ispisuje n najfrekvent-


nijih reči koje su se javljale u tekstu.
Radi poboljšanja efikasnosti, prilikom brojanja reči koristi se struk-
tura podataka pogodna za leksikografsku pretragu - u ovom slučaju
binarno pretraživačko drvo.
Na kraju rada, čvorovi drveta se ”presortiraju” na osnovu broja
pojavljivanja. Zbog ovoga je potrebno čuvati niz pokazivača na ra-
zličite čvorove drveta.
Da bismo ispisali 10 najfrekventnijih etiketa, potrebno je zameniti
funkciju getword funkcijom gettag.

#include <stdlib.h>
#include <stdio.h>

/* Cvor drveta sadrzi ime reci i


broj njenih pojavljivanja */
typedef struct _cvor {
char ime[80];
int br_pojavljivanja;
struct _cvor* levo, *desno;
} cvor;

/* Gradimo niz pokazivaca na cvorove drveta koji ce


nam sluziti da po prihvatanju svih reci izvrsimo
sortiranje po broju pojavljivanja */

#define MAX_BROJ_RAZLICITIH_RECI 1000

cvor* razlicite_reci[MAX_BROJ_RAZLICITIH_RECI];

/* Tekuci broj cvorova drveta */


int broj_razlicitih_reci=0;

/* Funkcija uklanja binarno drvo iz memorije */


void obrisi_drvo(cvor* drvo)
{
if (drvo!=NULL)
{ obrisi_drvo(drvo->levo);
obrisi_drvo(drvo->desno);
free(drvo);
}
}

108
1.19 Drvo 109

/* Funkcija ubacuje datu rec u dato drvo i vraca pokazivac na


koren drveta */
cvor* ubaci(cvor* drvo, char rec[])
{
/* Ukoliko je drvo prazno gradimo novi cvor */
if (drvo==NULL)
{
cvor* novi_cvor=(cvor*)malloc(sizeof(cvor));
if (novi_cvor==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
strcpy(novi_cvor->ime, rec);
novi_cvor->br_pojavljivanja=1;

/* pokazivac na novo napravljeni cvor smestamo u niz


pokazivaca na sve cvorove drveta */
razlicite_reci[broj_razlicitih_reci++] = novi_cvor;

return novi_cvor;
}
int cmp = strcmp(rec, drvo->ime);

/* Ukoliko rec vec postoji u drvetu


uvecavamo njen broj pojavljivanja */
if (cmp==0)
{ drvo->br_pojavljivanja++;
return drvo;
}

/* Ukoliko je rec koju ubacujemo leksikografski ispred


reci koja je u korenu drveta, rec ubacujemo
u levo podstablo */
if (cmp<0)
{ drvo->levo=ubaci(drvo->levo, rec);
return drvo;
}

/* Ukoliko je rec koju ubacujemo


leksikografski iza reci koja je u
korenu drveta, rec ubacujemo
u desno podstablo */

109
110 Milena Vujošević–Janičić

if (cmp>0)
{ drvo->desno=ubaci(drvo->desno, rec);
return drvo;
}
}

/* Pomocna funkcija koja cita rec iz date datoteke i vraca


njenu duzinu, odnosno -1 ukoliko se naidje na EOF */
int getword(char word[], int lim, FILE* ulaz)
{
int c, i=0;
/* Umesto funkcije getchar koristimo fgetc
za rad sa datotekama */
while (!isalpha(c=fgetc(ulaz)) && c!=EOF)
;
if (c==EOF)
return -1;
do
{ word[i++]=c;
}while (i<lim-1 && isalpha(c=fgetc(ulaz)));

word[i]=’\0’;
return i;
}

/* Funkcija poredjenja za funkciju qsort. */


int poredi_br_pojavljivanja(const void* a, const void* b)
{
return
/* Konverzija pokazivaca b iz pokazivaca
na tip void u pokazivac na cvor jer
nam je svaki element niza koji sortiramo
tipa pokazivaca na cvor */
(*(cvor**)b)->br_pojavljivanja
-
(*(cvor**)a)->br_pojavljivanja;
}

main(int argc, char* argv[])


{
int i;

110
1.19 Drvo 111

/* Drvo je na pocetku prazno */


cvor* drvo=NULL;
char procitana_rec[80];
FILE* ulaz;

if (argc!=2)
{ fprintf(stderr,"Greska :
Ocekivano ime datoteke\n");
exit(1);
}

if ((ulaz=fopen(argv[1],"r"))==NULL)
{
fprintf(stderr,"Greska : nisam uspeo da otvorim datoteku %s\n");
exit(1);
}

/* Citamo rec po rec dok ne naidjemo na kraj datoteke i


ubacujemo ih u drvo */
while(getword(procitana_rec,80,ulaz)!=-1)
drvo=ubaci(drvo,procitana_rec);

/* Sortiramo niz pokazivaca na cvorove


drveta po broju pojavljivanja */
qsort(razlicite_reci,
broj_razlicitih_reci,
sizeof(cvor*),
poredi_br_pojavljivanja);

/* Ispisujemo prvih 10 (ukoliko ih ima)


reci i njihov broj pojavljivanja */
for (i=0; i<10 && i<broj_razlicitih_reci; i++)
printf("%s - %d\n",razlicite_reci[i]->ime,
razlicite_reci[i]->br_pojavljivanja);

/* Uklanjamo drvo iz memorije */


obrisi_drvo(drvo);

fclose(ulaz);
}

111
112 Milena Vujošević–Janičić

1.20 Grafovi
Graf1 G=(V,E) sastoji se od skupa V čvorova i skupa E grana. Grane
predstavljaju relacije izme u čvorova i odgovara paru čvorova. Graf
može biti usmeren (orijentisan), ako su mu grane ure eni parovi i
neusmeren (neorjentisan) ako su grane neure eni parovi.
Uobičajena su dva načina predstavljanja grafova. To su matrica
povezanosti grafa i lista povezanosti.
Matrica povezanosti je kvadratna matrica dimenzije n, pri čemu
je n broj čvorova u grafu, takva da je element na preseku i-te vrste
i j-te kolone jednak jedinici ukoliko postoji grana u grafu od i-tog
do j-tog čvora, inače je nula.
Umesto da se i sve nepostojeće grane eksplicitno predstavljaju u
matrici povezanosti, mogu se formirati povezane liste od jedinica iz
i-te vrste za i=1,2,...,n. To je lista povezanosti. Svakom čvoru se
pridružuje povezana lista, koja sadrži sve grane susedne tom čvoru.
Graf je predstavljen vektorom lista. Svaki elemenat vektora sadrži
ime (indeks) čvora i pokazivač na njegovu listu čvorova.
Prvi problem na koji se nailazi pri konstrukciji bilo kog algo-
ritma za obradu grafa je kako pregledati ulaz. Postoje dva osnovna
algoritma za obilazak grafa: pretraga u dubinu (DFS, skraćenica od
depth-first-search) i pretraga u širinu (BFS, skraćenica od breadth-
first-search).
Kod DFS algoritma, obilazak započinje iz proizvoljnog zadatog
čvora r koji se naziva koren pretrage u dubinu. Koren se označava
kao posećen. Zatim se bira proizvoljan neoznačen čvor r1, susedan
sa r, pa se iz čvora r1 rekurzivno startuje pretraga u dubinu. Iz
nekog nivoa rekurzije izlazi se kad se nai e na čvor v kome su svi
susedi već označeni.
Primer 1.20.1 Primer reprezentovanja grafa preko matrice povezanosti.
U programu se unosi neorijentisan graf i DFS algoritmom se utvr uju 

čvrovi koji su dostižni iz čvora 0.


#include <stdlib.h>
#include <stdio.h>

int** alociraj_matricu(int n)
{ int **matrica;
int i;
matrica=malloc(n*sizeof(int*));
if (matrica==NULL)
1 Tekst i primeri preuzeti od Jelene Tomašević, url: www.matf.bg.ac.yu/˜jtomasevic, zas-

novano na materijalu Algoritmi, Miodrag Živković i http://www.matf.bg.ac.yu/˜filip

112
1.20 Grafovi 113

{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}

for (i=0; i<n; i++)


{
/* Funkcija calloc popunjava rezervisan
prostor u memoriji nulama. */
matrica[i]=calloc(n,sizeof(int));
if (matrica[i]==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
}
return matrica;
}

void oslobodi_matricu(int** matrica, int n)


{ int i;
for (i=0; i<n; i++)
free(matrica[i]);
free(matrica);
}

int* alociraj_niz(int n)
{ int* niz;
niz=calloc(n,sizeof(int));
if (niz==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
return niz;
}

void oslobodi_niz(int* niz)


{ free(niz);
}

void unesi_graf(int** graf, int n)


{ int i,j;

113
114 Milena Vujošević–Janičić

for (i=0; i<n; i++)


for (j=i; j<n; j++)
{ printf("Da li su element %d i %d povezani : ",i,j);
do
{ scanf("%d",&graf[i][j]);
/* Radimo sa neusmerenim grafom */
graf[j][i]=graf[i][j];
} /* Obezbedjujemo ispravan unos */
while (graf[i][j]!=0 && graf[i][j]!=1);
}
}

void ispisi_graf(int** graf, int n)


{ int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
printf("%d",graf[i][j]);
printf("\n");
}
}

/* Broj cvorova grafa (dimenzija matrice) */


int n;
/* Matrica povezanosti */
int **graf;

/* Pomocni vektor koji govori o tome koji su cvorovi posecivani


tokom DFS obilaska */
int *posecen;

/* Rekurzivna implementacija DFS algoritma */


void poseti(int i)
{ int j;
posecen[i]=1;
printf("Posecujem cvor %d\n",i);
for (j=0; j<n; j++)
if (graf[i][j] && !posecen[j])
poseti(j);
}

114
1.20 Grafovi 115

main()
{
int i, j;
printf("Unesi broj cvorova : ");
scanf("%d",&n);

graf=alociraj_matricu(n);
unesi_graf(graf,n);
ispisi_graf(graf,n);

posecen=alociraj_niz(n);
poseti(0);

oslobodi_niz(posecen);
oslobodi_matricu(graf,n);
}
Primer 1.20.2 Primer predstavljanja grafa preko niza listi suseda
svakog od čvorova grafa U programu se unosi graf i DFS algoritmom
se utvrdjuje koji su čvorovi dostižni iz cvora 0.
#include <stdlib.h>
#include <stdio.h>

/* Cvor liste suseda */


typedef struct _cvor_liste
{ int broj; /* Indeks suseda */
struct _cvor_liste* sledeci;
} cvor_liste;

/* Ubacivanje na pocetak liste */


cvor_liste* ubaci_u_listu(cvor_liste* lista, int broj)
{ cvor_liste* novi=malloc(sizeof(cvor_liste));
if (novi==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
novi->broj=broj;
novi->sledeci=lista;
return novi;
}

115
116 Milena Vujošević–Janičić

/* Rekurzivno brisanje liste */


void obrisi_listu(cvor_liste* lista)
{ if (lista)
{ obrisi_listu(lista->sledeci);
free(lista);
}
}

/* Ispis liste */
void ispisi_listu(cvor_liste* lista)
{ if (lista)
{ printf("%d ",lista->broj);
ispisi_listu(lista->sledeci);
}
}

/* Graf predstavlja niz pokazivaca na pocetke listi suseda */


#define MAX_BROJ_CVOROVA 100
cvor_liste* graf[MAX_BROJ_CVOROVA];
int broj_cvorova;

/* Rekurzivna implementacija DFS algoritma */


int posecen[MAX_BROJ_CVOROVA];
void poseti(int i)
{ cvor_liste* sused;
printf("Posecujem cvor %d\n",i);
posecen[i]=1;
for( sused=graf[i]; sused!=NULL; sused=sused->sledeci)
if (!posecen[sused->broj])
poseti(sused->broj);
}

main()
{
int i;
printf("Unesi broj cvorova grafa : ");
scanf("%d",&broj_cvorova);
for (i=0; i<broj_cvorova; i++)
{ int br_suseda,j;

graf[i]=NULL;

116
1.21 Razno 117

printf("Koliko cvor %d ima suseda : ",i);


scanf("%d",&br_suseda);
for (j=0; j<br_suseda; j++)
{ int sused;
do
{
printf("Unesi broj %d.-tog suseda cvora %d : ",j,i);
scanf("%d",&sused);
} while (sused<1 && sused>broj_cvorova);
graf[i]=ubaci_u_listu(graf[i],sused-1);
}
}

for (i=0; i<broj_cvorova; i++)


{ printf("%d - ",i);
ispisi_listu(graf[i]);
printf("\n");
}

poseti(0);
}

1.21 Razno
k
Primer 1.21.1 Stepenovanje prirodnog broja efikasno: nk = (n 2 )2
k−1
ako je k parno ili nk = n(n 2 )2 ako je k neparno.
int stepen(int n, int k)
{
int p, s;
if (k==1) s=n;
else
{
p=stepen(n,k/2);
if(k%2==0) s=p*p;
else s=p*p*n;
}
return s;
}
Primer 1.21.2 MINESWEEPER - primer jednostavne igrice.
#include <stdlib.h>

117
118 Milena Vujošević–Janičić

#include <stdio.h>
#include <time.h>

/* Dimenzija table */
int n;

/* Tabla koja sadrzi 0 i 1 u zavisnosti


od toga da li na polju postoji bomba */
int** bombe;

#define PRAZNO (-1)


#define ZATVORENO 0
#define ZASTAVICA 9

/* Tabla koja opisuje tekuce stanje igre.


Moze da sadrzi sledece vrednosti :
ZATVORENO - opisuje polje
koje jos nije bilo otvarano
PRAZNO - polje na kome ne
postoji ni jedna bomba
BROJ od 1-8 - polje koje je
otvoreno i na kome pise
koliko bombi postoji u okolini
ZASTAVICA - polje koje je korisnik
oznacio zastavicom
*/
int** stanje;

/* Ukupan broj bombi */


int broj_bombi;

/* Ukupan broj postavljenih zastavica */


int broj_zastavica = 0;

/* Pomocne funkcije za rad sa matricama */


int** alociraj(int n)
{
int i;
int** m=(int**)malloc(n*sizeof(int*));
for (i=0; i<n; i++)
m[i]=(int *)calloc(n,sizeof(int));
return m;
}

118
1.21 Razno 119

void obrisi(int** m, int n)


{ int i;
for (i=0; i<n; i++)
free(m[i]);

free(m);
}

/* Funkcija postavlja bombe */ void postavi_bombe()


{ broj_bombi=(n*n)/6;
int kolona;
int vrsta;
int i;

/* Inicijalizujemo generator slucajnih brojeva */


srand(time(NULL));

for (i=0; i<broj_bombi; i++)


{ /* Racunamo slucajni polozaj bombe */
kolona=rand()%n;
vrsta=rand()%n;

/* Ukoliko bomba vec postoji tu,


opet idemo u istu iteraciju */
if (bombe[vrsta][kolona]==1)
{ i--;
continue;
}

/* Postavljamo bombu */
bombe[vrsta][kolona]=1;
}
}

/* Funkcija ispisuje tablu sa bombama */


void ispisi_bombe()
{
int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
printf("%d",bombe[i][j]);

119
120 Milena Vujošević–Janičić

printf("\n");
}
}

/* Funkcija ispisuje tekuce stanje */


void ispisi_stanje()
{ int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
{ if (stanje[i][j]==ZATVORENO)
printf(".");
else if (stanje[i][j]==PRAZNO)
printf(" ");
else if (stanje[i][j]==ZASTAVICA)
printf("*");
else
printf("%d",stanje[i][j]);
}
printf("\n");
}
}

/* Funkcija postavlja zastavicu na


dato polje ili je uklanja
ukoliko vec postoji */
void postavi_zastavicu(int i, int j)
{
if (stanje[i][j]==ZATVORENO)
{ stanje[i][j]=ZASTAVICA;
broj_zastavica++;
}
else if (stanje[i][j]==ZASTAVICA)
{ stanje[i][j]=ZATVORENO;
broj_zastavica--;
}
}

/* Funkcija izracunava koliko bombi


postoji u okolini date bombe */
int broj_bombi_u_okolini(int v, int k)
{ int i, j;
int br=0;
/* Prolazimo kroz sva okolna polja */

120
1.21 Razno 121

for (i=-1; i<=1; i++)


for(j=-1; j<=1; j++)
{ /* preskacemo centralno polje */
if (i==0 && j==0)
continue;
/* preskacemo polja "van table" */
if (v+i<0 || k+j<0 || v+i>=n || k+j>=n)
continue;
if (bombe[v+i][k+j]==1)
br++;
}

return br;

/* Centralna funkcija koja vrsi otvaranje


polja i pritom se otvaranje "siri"
i na polja koja su oko datog */

void otvori_polje(int v, int k) {


/* Ukoliko smo "nagazili" bombu
zavrsavamo program */
if (bombe[v][k]==1)
{ printf("BOOOOOOOOOOOOOOOOM!!!!\n");
ispisi_bombe();
exit(1);
}
else
{
/* Brojimo bombe u okolini */
int br=broj_bombi_u_okolini(v,k);

/* Azuriramo stanje ovog polja */


stanje[v][k]=(br==0)?PRAZNO:br;

/* Ukoliko u okolini nema bombi,


rekurzivno otvaramo
sva polja u okolini koja su zatvorena */
if (br==0)
{
/* Petlje indeksiraju sva okolna polja */
int i,j;

121
122 Milena Vujošević–Janičić

for (i=-1; i<=1; i++)


for (j=-1; j<=1; j++)
{
/* Preskacemo centralno polje */
/* if (i==0 && j==0)
continue; */
/* Preskacemo polja van table */
if (v+i<0 || v+i>=n || k+j<0 || k+j>=n)
continue;
/* Ukoliko je okolno polje
zatvoreno, otvaramo ga */
if (stanje[v+i][k+j]==ZATVORENO)
otvori_polje(v+i, k+j);
}
}
}
}

/* Funkcija utrdjuje da li je partija gotova


Partija je gotova u trenutku kada su sve
bombe pokrivene zastavicama i
kada nijedno drugo polje nije
pokriveno zastavicom
*/

int gotova_partija()
{ int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{ /* Ukoliko postoji nepokrivena bomba,
partija nije zavrsena */
if (bombe[i][j]==1 && stanje[i][j]!=ZASTAVICA)
return 0;
}

/* Partija je zavrsena samo ukoliko je


broj zastavica jednak broj bombi */
return broj_zastavica==broj_bombi;

main() {

122
1.21 Razno 123

/* Unosimo dimenziju table */


printf("Unesite dimenziju table : ");
scanf("%d",&n);

/* Alociramo table */
bombe=alociraj(n);
stanje=alociraj(n);

/* Postavljamo bombe */
postavi_bombe();

/* Sve dok partija nije gotova */


while(!gotova_partija())
{ int v,k;
char akcija;

/* Ispisujemo tekuce stanje */


ispisi_stanje();

/* Sve dok korisnik ne unese o ili z


trazimo od njega da upise
odgovarajucu akciju */
do
{
getchar();
printf("Unesi akciju (o - otvaranje polja,
z - postavljanje zastavice) : ");
scanf("%c",&akcija);
} while (akcija!=’o’ && akcija!=’z’);

/* Trazimo od korisnika da unese koordinate


polja sve dok ih ne unese ispravno
Korisnicke koordinate krecu od 1,
a interne od 0 */
do
{
printf("Unesi koordinate polja : ");
scanf("%d",&v);
scanf("%d",&k);
} while(v<1 || v>n || k<1 || k>n);

/* Reagujemo na akciju */

123
124 Milena Vujošević–Janičić

switch(akcija)
{ case ’o’:
otvori_polje(v-1,k-1);
break;
case ’z’:
postavi_zastavicu(v-1,k-1);
}
}

/* Konstatujemo pobedu */
ispisi_stanje();
printf ("Cestitam! Pobedili ste\n");
obrisi(stanje,n);
obrisi(bombe,n);
}

124
Osnovi programiranja
Programski jezik C
— Zadaci sa vežbi —

Milena Vujošević - Janičić 2005/2006


2

2
Sadržaj

1 HTML 7

2 Konverzije 9
2.1 Pozicioni brojni sistemi . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Prevo enje iz dekadnog sistema u binarni . . . . . . . . . . . . . 10
2.3 Prevo enje iz dekadnog sistema u oktalni . . . . . . . . . . . . . 10
2.4 Prevo enje iz dekadnog sistema u heksadekadni . . . . . . . . . . 10
2.5 Prevo enje iz dekadnog sistema u sistem sa osnovom n . . . . . . 11
2.6 Prevo enje iz binarnog sistema u heksadekadni . . . . . . . . . . 11
2.7 Prevo enje iz binarnog sistema u oktalni . . . . . . . . . . . . . . 12

3 Algoritmi 13
3.1 Rešavanje problema uz pomoć računara . . . . . . . . . . . . . . 13
3.2 Formiranje algoritma . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3 Algebarski algoritmi . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3.1 NZD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3.2 Koren prirodnog broja . . . . . . . . . . . . . . . . . . . . 19

4 Programski jezik C 21
4.1 Zdravo svete! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.2 Imena promenljivih . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3 Deklaracije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.4 Tipovi i veličina podataka . . . . . . . . . . . . . . . . . . . . . . 22
4.5 Funkcije printf i scanf . . . . . . . . . . . . . . . . . . . . . . . . 23
4.6 Aritmetički operatori . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.7 Operatori i izrazi dodeljivanja vrednosti . . . . . . . . . . . . . . 26
4.8 Inkrementacija i dekrementacija . . . . . . . . . . . . . . . . . . . 27
4.9 Relacioni i logički operatori . . . . . . . . . . . . . . . . . . . . . 28
4.10 Kontrola toka — if, while, do - while, for . . . . . . . . . . . . . . 30
4.10.1 if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.10.2 Else-if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.10.3 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.10.4 do-while . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.10.5 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.11 Switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.12 Uslovni izraz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.13 Simboličke konstante . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.14 Enumeracija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

3
4 SADRŽAJ

4.15 Funkcije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.16 Nizovi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.17 Konstante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4.18 Konverzija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.18.1 Automatska konverzija . . . . . . . . . . . . . . . . . . . . 41
4.18.2 Eksplicitna konverzija . . . . . . . . . . . . . . . . . . . . 41
4.18.3 Funkcije koje vrše konverziju . . . . . . . . . . . . . . . . 42
4.19 Operator sizeof() . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.20 Znakovni ulaz i izlaz . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.21 Nizovi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
4.22 Dvostruka for petlja . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.23 Formiranje HTML dokumenta . . . . . . . . . . . . . . . . . . . . 51
4.24 Funkcije — prenos parametara po vrednosti . . . . . . . . . . . . 53
4.25 Break i continue . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
4.26 Rad sa niskama karaktera . . . . . . . . . . . . . . . . . . . . . . 56
4.27 Makroi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4.28 Bitski operatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.29 Linearna i binarna pretraga . . . . . . . . . . . . . . . . . . . . . 69
4.30 Razni zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.31 Sortiranje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.32 Rekurzija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
4.33 Životni vek i oblast važenja promenjivih, statičke promenljive . . 89
4.34 Pokazivači . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.35 Pokazivači i argumenti funkcija . . . . . . . . . . . . . . . . . . . 93
4.36 Pokazivači i nizovi (polja) . . . . . . . . . . . . . . . . . . . . . . 94
4.37 Alokacija memorije . . . . . . . . . . . . . . . . . . . . . . . . . . 100
4.38 Niz pokazivača . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
4.39 Pokazivači na funkcije . . . . . . . . . . . . . . . . . . . . . . . . 104
4.40 Matrice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
4.41 Strukture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
4.41.1 Operator typedef . . . . . . . . . . . . . . . . . . . . . . . 113
4.42 qsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
4.43 Sortiranje — generička funkcija . . . . . . . . . . . . . . . . . . . 121
4.44 qSort funkcija iz standardne biblioteke . . . . . . . . . . . . . . . 127
4.45 Generičko sortiranje reči . . . . . . . . . . . . . . . . . . . . . . . 129
4.46 Argumenti komandne linije . . . . . . . . . . . . . . . . . . . . . 131
4.47 Datoteke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
4.48 Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
4.48.1 Red . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
4.48.2 Kružna lista . . . . . . . . . . . . . . . . . . . . . . . . . . 145
4.48.3 Stek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
4.48.4 Dvostruko povezane liste . . . . . . . . . . . . . . . . . . 150
4.49 Drvo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
4.50 Grafovi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
4.51 Razni zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

4
Predgovor

Ovo je prateći materijal za vežbe koje držim iz predmenta Osnovi programi-


ranja. On ne može zameniti poha anje vežbi niti korišćenje druge preporučene
literature.
Veliki deo materijala čine zadaci i rešenja mr Filipa Marića (raspoloživi na
www.matf.bg.ac.yu/~filip/pp/0405/index.pl). Tako e korišćen je i mater-
ijal sa sajta koleginice Jelene Grmuše www.matf.bg.ac.yu/~jelenagr i kolege
Miroslava Marića www.matf.bg.ac.yu/~maricm. Tekstovi i objašnjenja su uglavnom
zasnovani na knjizi Programski jezik C, autora Kerninghan & Ritchie
Zahvaljujem svojim studentima na aktivnom učešću u nastavi čime su mi
pomogli u uobličavanju ovog materijala.
Svi komentari i sugestije vezane za ovaj materijal biće veoma dobrodošli.

Milena Vujošević-Janičić
www.matf.bg.ac.yu/~milena

5
6 SADRŽAJ

6
Glava 1

HTML

http://www.matf.bg.ac.yu/nastavno/dvitas/nastava/op/html/op-html.html

7
8 Milena Vujošević–Janičić

8
Glava 2

Konverzije

2.1 Pozicioni brojni sistemi


Brojevni sistemi1

naziv vrednost osnove cifre


dekadni 10 0,1,2,3,4,5,6,7,8,9
binarni 2 0,1
oktalni 8 0,1,2,3,4,5,6,7
heksadekadni 16 0,1,2,3,4,5,6,7,8,9,
A, B, C, D, E, F

Zapis u osnovi (bazi) b


(cn cn−1 ...c1 c0 )b
gde su
cn , cn−1 , ...c1 , c0
cifre u sistemu sa osnovom b ima vrednost

c0 ∗ b0 + c1 ∗ b1 + ... + cn−1 ∗ bn−1 + cn ∗ bn

Primer 2.1.1 1. (1101)2 = 1 ∗ 20 + 0 ∗ 21 + 1 ∗ 22 + 1 ∗ 23 = (13)10

2. (1101)16 = 1 ∗ 160 + 0 ∗ 161 + 1 ∗ 162 + 1 ∗ 163 = 1 + 256 + 4096 = (4353)10

3. (1101)7 = 1 ∗ 70 + 0 ∗ 71 + 1 ∗ 72 + 1 ∗ 73 = (399)10

4. (F 9A)16 = A ∗ 160 + 9 ∗ 161 + F ∗ 162 == = 10 ∗ 160 + 9 ∗ 161 + 15 ∗ 162 =


10 + 144 + 3840 = (3994)10

Zadatak 1
(110111100)2 = (?)10
(77)8 = (?)10
(F F F F )16 = (?)10
1 Deo teksta i primera preuzet sa sajta www.matf.bg.ac.yu/˜jelenagr

9
10 Milena Vujošević–Janičić

2.2 Prevo enje iz dekadnog sistema u binarni




Primer 2.2.1
(26)10 = (?)2
kolicnik ostatak
26 / 2 = 13 0
13 / 2 = 6 1
6/2=30
3/2=11
1 / 2 = 0 1 kraj postupka konverzije
(26)10 = (11010)2
Zadatak 2
(54)10 = (?)2
(126)10 = (?)2
(332)10 = (?)2

2.3 Prevo enje iz dekadnog sistema u oktalni




Primer 2.3.1
(181)10 = (?)8
kolicnik ostatak
181 / 8 = 22 5
22 / 8 = 2 6
2 / 8 = 0 2 kraj postupka konverzije
(181)10 = (265)8
Zadatak 3
(67)10 = (?)8
(336)10 = (?)8
(442)10 = (?)8

2.4 Prevo enje iz dekadnog sistema u heksadekadni




Primer 2.4.1
(181)10 = (?)16
kolicnik ostatak
181 / 16 = 11 5
11 / 16 = 0 11 (heksadekadna cifra B) kraj postupka konverzije
(181)10 = (B5)16
Zadatak 4
(48)10 = (?)16
(1336)10 = (?)16
(332)10 = (?)16

10
2.5 Prevo enje iz dekadnog sistema u sistem sa osnovom n
 11

2.5 Prevo enje iz dekadnog sistema u sistem sa




osnovom n
Primer 2.5.1
(181)10 = (?)n
kolicnik ostatak
181 / n = k1 o1
k 1 / n = k 2 o2
...
kl / n = 0 ol+1 kraj postupka konverzije

(181)10 = (ol+1 ol ...o1 )n

Zadatak 5
(48)10 = (?)16
(1336)10 = (?)16
(332)10 = (?)16

2.6 Prevo enje iz binarnog sistema u heksadekadni




Prevo enje iz binarnog sistema u heksadekadni može se uraditi bez me ukonverzije


u osnovu 10. Za kodiranje heksadecimalnih cifara dovoljne su binarne reči dužine
cetiri.

heksadekadna cifra kod


0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
A 1010
B 1011
C 1100
D 1101
E 1110
F 1111

primer:
4 0100 (0 ∗ 20 + 0 ∗ 21 + 1 ∗ 22 + 0 ∗ 23 )
F 1111 (1 ∗ 20 + 1 ∗ 21 + 1 ∗ 22 + 1 ∗ 23 )

Odavde je jasno kako zadovoljiti zahtev da se konverzija odvija direktno bez


posrednih konverzija. Binarne cifre se grupišu podgrupe od po 4 cifre, pocev

11
12 Milena Vujošević–Janičić

od bitova najmanje težine. Ako ukupan broj bitova nije deljiv sa cetiri, onda se
dopisuje potreban broj vodecih nula (one su bez uticaja na promenu vrednosti
originalnog zapisa).

Primer 2.6.1
(1111011100001101010000)2 =
= (001111011100001101010000)2 =
= (3DC350)16

Zadatak 6
(1111110111001100011010100100)2 = (?)16

2.7 Prevo enje iz binarnog sistema u oktalni




Prevo enje iz binarnog sistema u oktalni može se uraditi bez me ukonverzije u


osnovu 10. Za kodiranje oktalnih cifara dovoljne su binarne reci dužine tri.

oktalna cifra kod


0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111

4 100 (0 ∗ 20 + 0 ∗ 21 + 1 ∗ 22 )

Odavde je jasno kako zadovoljiti zahtev da se konverzija odvija direktno bez


posrednih konverzija. Binarne cifre se grupišu podgrupe od po 3 cifre, pocev
od bitova najmanje težine. Ako ukupan broj bitova nije deljiv sa tri, onda se
dopisuje potreban broj vodecih nula.

Primer 2.7.1
(11111010001010)2 =
= (011111010001010)2 =
= (37212)8

Zadatak 7
(1111110111010100100)2 = (?)8

12
Glava 3

Algoritmi

3.1 Rešavanje problema uz pomoć računara


Rešavanje problema uz pomoć računara može se podeliti na sledeće korake:
1. Razumevanje problema
2. Izgradnja modela
3. Formiranje algoritma
4. Provera ispravnosti algoritma
5. Realizacija (implementacija) algoritma — pisanje programa
6. Testiranje programa
7. Sastavljanje dokumentacije.

3.2 Formiranje algoritma


Formirati algoritam znači dati skup preciznih uputstava kako doći do rešenja
zadatog problema.
Algoritmi se mogu opisivati: prirodnim jezikom, pseudo-jezikom, blok-shemom
(dijagramom toka).
• OPIS ALGORITAMA PRIRODNIM JEZIKOM
Opisati prirodnim jezikom detaljno, precizno i nedvosmisleno korake pri
resavanju problema, vodeći računa o redosledu operacija koji se izvršavaju.
• OPIS ALGORITAMA PSEUDO JEZIKOM
Pseudo jezik je neformalna kombinacija prirodnog jezika i nekog program-
skoj jezika. Pri upotrebi pseudo jezika mora se voditi računa da se jezičke
konstrukcije koriste uvek na isti način i da budu praćene objašnjenjima
(ako je potebno).
• OPISIVANJE ALGORITAMA BLOK SEMOM
Za ovaj oblik opisa koriste se grafički simboli ciji je opis propisan ISO stan-
dardom. Tekst koji opisuje obradu se zapisuje unutar grafičkih simbola.

13
14 Milena Vujošević–Janičić

Tok rada algoritma se opisuju linijama koje povezuju grafičke simbole koji
reprezenuju obradu.

3.3 Algebarski algoritmi


Primer 3.3.1 Algoritam zdravo svete

Algoritam Ispis
ulaz: nema podataka na ulazu
izlaz: poruka Zdravo, svete!!!
{
output " Zdravo, svete!!!"
}

Primer 3.3.2 Algoritam za sabiranje dva broja.

Algoritam Sabiranje
ulaz: x,y
izlaz: zbir brojeva x,y
/* algoritam je formiran tako da funkcionise
za bilo koji realan broj sa ulaza. Zbog toga se
u algoritmu koristi promenljiva - ime koje
oznacava promenljivu vrednost.*/
{
input x,y;
zbir = x + y;
output zbir;
}

Primer 3.3.3 Algoritam za maksimum dva broja.

Algoritam Maksimum
ulaz: x, y;
izlaz: veci od brojeva x i y
{
input x,y;
if (x>y) max=x
else max=y;
output max;
}

Primer 3.3.4 Algoritam za izracunavanje sume brojeva koja se unosi pre unosa
nule.

Algoritam Zbir
ulaz: brojevi sve dok se ne unese nula
izlaz: zbir brojeva
{
zbir=0; /*Inicijalizujemo zbir na nulu*/
input x; /*Unosimo prvi u nizu brojeva*/
while x!=0 /*Proveravani da li je broj

14
3.3 Algebarski algoritmi 15

x razlicit od nule i ako jeste


onda ga dodajemo na zbir*/
{
zbir=zbir+x;
input x; /*unosimo novi ulazni broj*/
}
output zbir; /*Na izlaz saljemo izracunati zbir*/
}

Zadatak 8 Algoritam za maksimum brojeva koji se unose, zavrsetak unosa je


nula.

Algoritam Maksimum
ulaz: brojevi sve dok se ne unese nula
izlaz: maksimum unetih brojeva
{
input x;
max = x;
while (x!=0) /*Proveravani da li je broj
x razlicit od nule*/
{
input x; /*unosimo novi ulazni broj*/
if (x>max) max=x; /*proveravamo da li je uneti
broj veci od tekuceg
maksimuma i ako jeste
onda tekucem maksimumu
dodeljujemo njegovu
vrednost*/
}
output max; /*Na izlaz saljemo izracunati
maximum*/
}

Zadatak 9 Algoritam za n!.

Algoritam n!
ulaz: prirodan broj n;
izlaz: faktorijel prirodnog broja n;
{
input n;
f=1;
while (n>1)
{
f=f*n;
n=n-1;
}
output f;
}

Zadatak 10 Algoritam za razmenu dva broja.

15
16 Milena Vujošević–Janičić

Algoritam razmena
ulaz: dva broja
izlaz: razmena dva broja
{
input x,y;
pom=x;
x=y;
y=pom;
output x,y;
}

Zadatak 11 Celobrojni kolicnik i ostatak pri deljenju

x = qy + r, 0 ≤ r < y, 0 ≤ q

.
Algoritam kolicnik
ulaz: prirodni brojevi x i y;
izlaz: kolicnik i ostatak pri deljenju
{
input x,y;
kolicnik=0;
ostatak=x;
while (ostatak>=y)
{
ostatak=ostatak-y;
kolicnik=kolicnik+1;
}
output kolicnik, ostatak;
}

Zadatak 12 Algoritam koji resava kvadratnu jednacinu.

a ∗ x2 + b ∗ x + c

Algoritam kvadratna jednacina


ulaz: koeficijenti a, b,c
izlaz: resenje kvadratne jednacine
{
input a,b,c;
if (a=0)
if (b=0)
if (c=0)
output "C";
else output "prazan skup";
else x=-c/b
output x;
else d=b*b - 4ac
if (d>0)
{
x1=(-b+sqrt(d))/2a;

16
3.3 Algebarski algoritmi 17

x2=(-b-sqrt(d))/2a;
output x1, x2;
}
else if (d=0)
{
x=-b/2a;
output x;
}
else
{
Re=-b/2a;
Im=sqrt(-d)/2a;
output Re+i*Im, Re-i*Im;
}
}

Zadatak 13 Fibonacijevi brojevi.


Algoritam fibonaci
ulaz n;
izlaz n-ti fibonacijev broj;
{
input n;
x0=0;
x1=1;
if n=0 rezultat=x0;
else {
while (n>1)
{
novi=x0+x1;
x0=x1;
x1=novi;
n=n-1;
}
rezultat=x1;
output rezultat;
}
}

3.3.1 NZD
Zadatak 14 Naći najveći zajednički delitelj za dva broja.
Algoritam NZD1
ulaz prirodni brojevi a, b;
izlaz nzd(a,b);
{
input a,b;
nzd = 1;
br=2;
while (br<=a && br<=b)

17
18 Milena Vujošević–Janičić

{
if (a%br)==0 && (b%br)==0 nzd=br;
br=br+1;
}
output nzd;
}

Zadatak 15 Naći najveći zajednički delitelj za dva broja.


Algoritam NZD2
ulaz prirodni brojevi a, b;
izlaz nzd(a,b);
{
input a,b;
nzd = 1;
if (a<b) nzd=a;
else nzd=b;
indikator=1;
while (indikator)
{
if (a%nzd)==0 && (b%nzd)==0 indikator=0;
else nzd=nzd-1;
}
output nzd;
}

Zadatak 16 Euklidov algoritam 1.


Algoritam NZD3
ulaz prirodni brojevi a, b;
izlaz nzd(a,b);
{
input a,b;
while (a!=b)
{
if (a>b) a=a-b;
else b=b-a;
}
output a;
}

Zadatak 17 Euklidov Algoritam 2.


Algoritam NZD4
ulaz prirodni brojevi a, b;
izlaz nzd(a,b);
{
input a,b;
if (a<b) {
pom=a;
a=b;
b=pom;

18
3.3 Algebarski algoritmi 19

}
while (b!=0)
{
pom = b;
b = a % b;
a = pom;
}
output a;
}

3.3.2 Koren prirodnog broja


Zadatak 18 Naći ceo deo korena prirodnog broja.

Algoritam Koren1
ulaz prirodan broj n;
izlaz ceo deo korena prirodnog broja;
{
input n;
koren=1;
while (koren*koren<=n)
koren=koren+1;
koren=koren-1;
output koren;
}

Zadatak 19 Naći ceo deo korena prirodnog broja.

Algoritam Koren2
ulaz prirodan broj n;
izlaz ceo deo korena prirodnog broja;
{
input n;
suma=0;
broj=0;
while (suma<=n)
{
suma=suma+broj+broj+1;
broj=broj+1;
}
broj=broj-1;
output broj;
}

19
20 Milena Vujošević–Janičić

20
Glava 4

Programski jezik C

4.1 Zdravo svete!


Primer 4.1.1 Program štampa poruku ”hello, world”.
#include <stdio.h>

main()
/*iskazi f-je main su zatvoreni u zagrade */
{
/*poziv f-je printf da odstampa poruku*/
printf("hello, world\n");
}
Primer 4.1.2 Program štampa poruku ”hello, world”
#include <stdio.h>

main()
{
printf("hello, ");
printf("world");
printf("\n");
}
Specijalni znaci:
\n novi red
\t tabulator
\\ kosa crta
\" navodnici
\a zvuk
\’ jednstruki navodnik

4.2 Imena promenljivih


Postoje ograničenja: u imenu se mogu pojaviti slova i cifre, potcrta ” ” se sma-
tra slovom.

21
22 Milena Vujošević–Janičić

Velika i mala slova se razlikuju.


int x, X; /*To su dve razlicite promenljive!!!*/
Ključne reči kao što su if, else, for, while, se ne mogu koristiti za imena promenljivih.

4.3 Deklaracije
Da bi se promenljiva mogla upotrebljavati ona se mora na početku programa
deklarisati. Prilikom deklaracije može se izvršiti i početna inicijalizacija.

int broj; /*Deklaracija celog broja*/


int vrednost=5; /*Deklaracija i inicijalizacija celog broja*/

Kvalifikator const može biti dodeljen deklaraciji bilo koje promenljive da bi


označio da se ona neće menjati

const double e=2.71828182845905

4.4 Tipovi i veličina podataka


Osnovni tipovi podataka:

int ceo broj


char znak, jedan bajt
float realan broj
double realan broj dvostruke tacnosti

char jedan bajt, sadrzi jedan znak


int celobrojna vrednost,2 ili 4 bajta
float realan broj, jednostruka tacnost
double dvostruka tacnost

Postoje kvalifikatori koje pridružujemo osnovnim tipovima short(16) i long(32):

short int kratak_broj;


long int dugacak_broj;
short kratak;
long dugacak;

Važi

broj bajtova(short) <= broj bajtova(int) <= broj bajtova(long)

Postoje kvalifikatori signed i unsigned koji se odnose na označene i neoznačene


cele brojeve. Npr.
signed char: -128 do 127
dok je
unsigned char: od 0 do 255.
Float, double i long double.

Primer 4.4.1 Uvo enje promenljivih u program.




22
4.5 Funkcije printf i scanf 23

#include <stdio.h>

main()
{
/*deklaracija vise promenljivih
istog tipa */
int rez,pom1,pom2;
pom1=20;
pom2=15;
rez=pom1-pom2;

/*ispisivanje rezultata*/
printf("Rezultat je %d-%d=%d\n",pom1,pom2,rez);
}
Izlaz iz programa:
Rezultat je 20-15=5

Iskaz dodele:
pom1=20;
pom2=15;
Individualni iskazi se zavrsavaju sa ;

4.5 Funkcije printf i scanf


printf("%d\t%d\n", broj1, broj2);
uvek je prvi argument izmedju " "
%d ceo broj
\t tab izmedju
\n novi red
Svaka % konstrukcija je u paru sa argumentom koji sledi.

Primer 4.5.1
#include <stdio.h>
main()
{
printf("Slova:\n%3c\n%5c\n", ’z’ , ’Z’);
}
Izlaz iz programa:
Slova:
z
Z
%c je za stampanje karaktera
%3c je za stampanje karaktera na tri pozicije
Isto tako smo mogli i %3d za stampanje broja na tri pozicije ili %6d za stampanje
broja na 6 pozicija.

Pravila:
%d stampaj kao ceo broj

23
24 Milena Vujošević–Janičić

%6d stampaj kao ceo broj sirok najvise 6 znakova


%f stampaj kao realan broj
%6f stampaj kao realan broj sirok najvise 6 znakova
%.2f stampaj kao realan broj sa dve decimale
%6.2f stampaj kao realan broj sirok najvise 6 znakova a od toga 2 iza decimalne
tacke
%c karakter
%s string
%x heksadecimalni broj
%% je procenat

Primer 4.5.2 Prikazuje unos celog broja koristeci scanf("%d", &x)

#include <stdio.h>

main()
{
int x;
printf("Unesi ceo broj : ");

/* Obratiti paznju na znak &


(operator uzimanja adrese)
pre imena promenljive u funkciji
scanf */
scanf("%d",&x);

/* U funkciji printf nije


potrebno stavljati & */
printf("Uneli ste broj %d\n", x);
}

Primer 4.5.3 Program sabira dva uneta cela broja

#include <stdio.h>

main()
{
int a, b, c;
printf("Unesi prvi broj : ");
scanf("%d", &a);
printf("Unesi drugi broj : ");
scanf("%d", &b);
c = a + b;
printf("%d + %d = %d\n", a, b, c);
}
Ulaz:
Unesi prvi broj : 2 <enter>
Unesi drugi broj : 3 <enter>
Izlaz:
2 + 3 = 5

24
4.6 Aritmetički operatori 25

4.6 Aritmetički operatori


+ - * /
% (samo za celobrojne vrednosti)
unarno + i -

Asocijativnost sleva na desno, prioritet kao u matematici.

Primer 4.6.1 Program ilustruje neke od aritmetičkih operacija.

#include <stdio.h>
main()
{
int a, b;
printf("Unesi prvi broj : ");
scanf("%d",&a);

printf("Unesi drugi broj : ");


scanf("%d",&b);

/* Kada se saberu dva cela broja, rezultat je ceo broj*/


printf("Zbir a+b je : %d\n",a+b);
/* Kada se oduzmu dva cela broja, rezultat je ceo broj*/
printf("Razlika a-b je : %d\n",a-b);
/* Kada se pomnoze dva cela broja, rezultat je ceo broj*/
printf("Proizvod a*b je : %d\n",a*b);
/* Kada se podele dva cela broja, rezultat je ceo broj!!!*/
printf("Celobrojni kolicnik a/b je : %d\n", a/b);
/* Rezultat je ceo broj, bez obzira sto ga ispisujemo kao realan*/
printf("Pogresan pokusaj racunanja realnog kolicnika a/b je : %f\n", a/b);
/* Eksplicitna konverzija, a i b pretvaramo u relane brojeve kako
bi deljenje bilo realno*/
printf("Realni kolicnik a/b je : %f\n", (float)a/(float)b);
/* Ostatak pri deljenju se moze izvrsiti samo nad celim brojevima*/
printf("Ostatak pri deljenju a/b je : %d\n", a%b);
}

Ulaz:
Unesi prvi broj : 2 <enter>
Unesi drugi broj : 3 <enter>
Izlaz:
Zbir a+b je : 5
Razlika a-b je : -1
Proizvod a*b je : 6
Celobrojni kolicnik a/b je : 0
Progresan pokusaj racunanja realnog kolicnika a/b je : 0.000000
Realni kolicnik a/b je : 0.666667
Ostatak pri deljenju a/b je : 2

Primer 4.6.2 Program ilustruje celobrojno i realno deljenje.

25
26 Milena Vujošević–Janičić

#include <stdio.h>

main()
{
int a = 5;
int b = 2;
int d = 5/2; /* Celobrojno deljenje - rezultat je 2 */
float c = a/b; /* Iako je c float, vrsi se celobrojno
deljenje jer su i a i b celi */

/* Neocekivani rezultat 2.000000 */


printf("c = %f\n",c);
printf("Uzrok problema : 5/2 = %f\n", 5/2);
printf("Popravljeno : 5.0/2.0 = %f\n", 5.0/2.0);
printf("Moze i : 5/2.0 = %f i 5.0/2 = %f \n", 5/2.0, 5.0/2);
printf("Za promenljive mora kastovanje : %f\n", (float)a/(float)b);

Izlaz iz programa:
c = 2.000000
Uzrok problema : 5/2 = 2.000000
Popravljeno : 5.0/2.0 = 2.500000
Moze i : 5/2.0 = 2.500000 i 5.0/2 = 2.500000
Za promenljive mora kastovanje : 2.500000

Zadatak 20 Šta će biti ispisano nakon izvršavanja sledećeg programa?


#include <stdio.h>
main()
{
int x=506, y=3, z=21, t=2;
printf("x=%d y=%d\n",x,y);
printf("z - t=%d\n", z-t);
printf("z / t =%d\n",z / t);
printf("-x=%d\n",- x);
printf("x %% y=%d\n", x%y);
}

4.7 Operatori i izrazi dodeljivanja vrednosti


i = i + 2;
ekvivalento je sa
i+=2;

Moze i za:
+ - * / % << >> ^ |
izraz1 op = izraz2
je ekvivalnetno sa
izraz1 = (izraz1) op (izraz2)

26
4.8 Inkrementacija i dekrementacija 27

x*= y+1 je ekvivalento sa x = x * (y+1)

Takvo pisanje je krace i efikasnije.

4.8 Inkrementacija i dekrementacija


Operatori ++ i --

x=++n; se razlikuje od x=n++;

y=(x++)*(++z);

Primer 4.8.1 Ilustracija prefiksnog i postfiksnog operatora ++

#include <stdio.h>
main()
{
int x, y;
int a = 0, b = 0;

printf("Na pocetku : \na = %d\nb = %d\n", a, b);

/* Ukoliko se vrednost izraza ne koristi, prefiksni i


postfiksni operator se ne razlikuju */
a++;
++b;
printf("Posle : a++; ++b; \na = %d\nb = %d\n", a, b);

/* Prefiksni operator uvecava promenljivu, i rezultat


je uvecana vrednost */
x = ++a;

/* Postfiksni operator uvecava promenljivu, i rezultat je


stara (neuvecana) vrednost */
y = b++;

printf("Posle : x = ++a; \na = %d\nx = %d\n", a, x);


printf("Posle : y = b++; \nb = %d\ny = %d\n", b, y);
}

Izlaz iz programa:
Na pocetku:
a = 0
b = 0
Posle : a++; ++b;
a = 1
b = 1
Posle : x = ++a;
a = 2

27
28 Milena Vujošević–Janičić

x = 2
Posle : y = b++;
b = 2
y = 1

4.9 Relacioni i logički operatori


Relacioni operatori:
> >= < <= isti prioritet
== != nizi prioritet

(3<5)
(a<=10)
a < 5 != 1 <=> (a < 5)!=1
Logicki operatori:
! unarna negacija (najvisi prioritet)
&& logicko i (visi prioritet od ili)
|| logicko ili izracunavaju se sleva na desno!

5 && 4 vrednost je tacno


10 || 0 vrednost je tacno
0 && 5 vrednost je 0
!1 vrednost je 0
!9 vrednost je 0
!0 vrednost je 1
!(2>3) je 1
a>b && b>c || b>d je isto sto i ((a>b) && (b>c)) || (b>d)
koja je vrednost ako je a=10, b=5, c=1, d=15?

Primer 4.9.1 Ilustracija logičkih i relacijskih operatora.


#include <stdio.h>

main()
{
int a = 3>5, /* manje */
b = 5>3, /* vece */
c = 3==5, /* jednako */
d = 3!=5; /* razlicito */

printf("3>5 - %d\n5>3 - %d\n3==5 - %d\n3!=5 - %d\n", a, b, c, d);

/*Lenjo izracunavanje: kako 3 nije vece od 5 to se vrednost


drugog poredjenja nece racunati jer je netacno u konjunkciji
sa proizvoljnim izrazom sigurno netacno. */
printf("Konjunkcija : 3>5 && 5>3 - %d\n", a && b);

/*Lenjo izravunavanje: tacno u disjunkciji sa proizvoljnim

28
4.9 Relacioni i logički operatori 29

izrazom daje tacno tako da se vrednost izraza 3>5 nece


izracunavati*/
printf("Disjunkcija : 5>3 || 3>5 - %d\n", b || a);
printf("Negacija : !(3>5) - %d\n", !a);

Izlaz iz programa:
3>5 - 0
5>3 - 1
3==5 - 0
3!=5 - 1
Konjunkcija : 3>5 && 5>3 - 0
Disjunkcija : 3>5 || 5>3 - 1
Negacija : !(3>5) - 1
Primer 4.9.2 Ilustracija lenjog izračunavanja logičkih operatora.
Prilikom izracunavanja izraza - A && B, ukoliko je A netačno, izraz B se
ne izračunava. Prilikom izračunavanja izraza - A k B, ukoliko je A tačno, izraz
B se ne izračunava.
#include <stdio.h>

/* Globalna promenljiva, vidljiva i iz funkcije main() i


iz funkcije izracunaj*/
int b = 0;

/* Funkcija ispisuje da je pozvana i uvecava promenjivu b.


Funkcija uvek vraca vrednost 1 (tacno)
*/
int izracunaj()
{
printf("Pozvano izracunaj()\n");
b++;
return 1;
}

main()
{
/* Funkcija izracunaj() ce biti pozvana
samo za parne vrednosti a */
int a;
for (a = 0; a < 10; a++)
if (a%2 == 0 && izracunaj())
printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
else
printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);

printf("----------------------------\n");

/* Funkcija izracunaj() ce se pozivati samo

29
30 Milena Vujošević–Janičić

za neparne vrednosti a */
b = 0;
for (a = 0; a < 10; a++)
if (a%2 == 0 || izracunaj())
printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
else
printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);
}

4.10 Kontrola toka — if, while, do - while, for


4.10.1 if
if (izraz)
iskaz1
else
iskaz2

Primer 4.10.1 Program ilustruje if i ispisuje ukoliko je uneti ceo broj negativan
#include <stdio.h>

main()
{
int b;
printf("Unesi ceo broj:");
scanf("%d", &b);
if (b < 0)
printf("Broj je negativan\n");
}

Else se odnosi na prvi neuparen if, voditi o tome računa, ako želimo drugačije
moramo da navedemo vitičaste zagrade.
if (izraz)
if (izraz1) iskaz 1
else iskaz
ovo else se odnosi na drugo if a ne na prvo if!
if (izraz)
{
if (izraz1) iskaz 1
}
else iskaz
tek sada se else odnosi na prvo if!!!

4.10.2 Else-if
if (izraz1)
iskaz1

30
4.10 Kontrola toka — if, while, do - while, for 31

else if (izraz2)
iskaz2
else if (izraz3)
iskaz3
else if (izraz4)
iskaz4
else iskaz

npr if (a<5)
printf("A je manje od 5\n");
else if (a=5)
printf("A je jednako 5\n");
else if (a>10)
printf("A je vece od 10\n");
else if (a=10)
printf("A je jednako 10\n");
else printf("A je vece od pet i manje od 10\n");

Primer 4.10.2 Program ilustruje if-else konstrukciju i ispituje znak broja.

#include <stdio.h>

main()
{
int b;
printf("Unesi ceo broj : ");
scanf("%d", &b);
if (b < 0)
printf("Broj je negativan\n");
else if (b == 0)
printf("Broj je nula\n");
else
printf("Broj je pozitivan\n");
}

Ulaz:
Unesi ceo broj:-5
Izlaz:
Broj je negativan

Ulaz:
Unesi ceo broj:5
Izlaz:
Broj je pozitivan

Primer 4.10.3 Pogresan program sa dodelom = umesto poredjenja ==.

#include <stdio.h>

main()

31
32 Milena Vujošević–Janičić

{
int b;
printf("Unesi ceo broj : ");
scanf("%d", &b);

/* Obratiti paznju na = umesto == Analizirati rad programa*/


if (b = 0)
printf("Broj je nula\n");
else if (b < 0)
printf("Broj je negativan\n");
else
printf("Broj je pozitivan\n");
}

Ulaz:
Unesi ceo broj:-5
Izlaz:
Broj je pozitivan

4.10.3 while
while(uslov) { ... }
Uslov u zagradi se testira i ako je ispunjen telo petlje se izvrsava. Zatim se uslov
ponovo testira i ako je ispunjen ponovo se izvrsava telo petlje. I tako sve dok
uslov ne bude ispunjen. Tada se izlazi iz petlje i nastavlja sa prvom sledecom
naredbom u programu.
Ukoliko iza while sledi samo jedna naredba nema potrebe za zagradama.

while (i<j)
i=2*i;

4.10.4 do-while
Ovo je slično paskalskom repeat-until izrazu.

do iskaz while (izraz)

Primer 4.10.4 Program ilustruje petlju do-while.

#include <stdio.h>

main()
{
int x;

x = 1;
do
{
printf("x = %d\n",x);
x++; /* x++ je isto kao i x=x+1 */

32
4.11 Switch 33

} while (x<=10);
}

4.10.5 for
Primer 4.10.5 Program ilustruje petlju - for.

#include <stdio.h>

main()
{
int x;

/* Inicijalizacija; uslov; inkrementacija*/


for (x = 1; x < 5; x++)
printf("x = %d\n",x);

}
Izlaz:
1
2
3
4

4.11 Switch
switch (iskaz) {
case konstantan_izraz1: iskazi1
case konstantan_izraz2: iskazi2
...
default: iskazi
}

Primer 4.11.1 Voditi računa o upotrebi break-a.

#include <stdio.h> /*
Upotreba switch-a
*/

main() {
char x;
scanf("%c",&x);

switch (x)
{
case ’a’:
case ’e’:
case ’i’:
case ’o’:
case ’u’: printf(" x je samoglasnik");

33
34 Milena Vujošević–Janičić

break;
case ’r’: printf(" x je r");
break;
default: printf(" x je suglasnik");
}
}

Primer 4.11.2 Ilustracija switch konstrukcije.

#include<stdio.h>
main()
{
int n;
printf("Unesi paran broj manji od 10\n");
scanf("%d",&n);
switch(n) {
case 0:
printf("Uneli ste nulu\n");
break;
case 2:
printf("Uneli ste dvojku\n");
break;
case 4:
printf("Uneli ste cetvorku\n");
break;
case 6:
printf("Uneli ste sesticu\n");
break;
case 8:
printf("Uneli ste osmicu\n");
break;
defalut:
printf("Uneli ste nesto sto nije paran broj\n");
}
}
Ulaz:
Unesi paran broj manji od 10
2
Izlaz:
Uneli ste dvojku

4.12 Uslovni izraz


Slično kao if.

izraz1 ? izraz2 : izraz3

z = (a<b)? a : b; /*z=min(a,b)*/
max = (a>b)? a : b;

34
4.13 Simboličke konstante 35

4.13 Simboličke konstante


Primer 4.13.1 Konverzija centimetara u inče - while petlja.

#include <stdio.h>

/* Definicija simbolickih konstanti preko #define direktiva */


/* U fazi pretprocesiranja se vrsi doslovna zamena konstanti
njihovim vrednostima */

#define POCETAK 0
#define KRAJ 20
#define KORAK 10

main()
{
int a;
a = POCETAK;
while (a <= KRAJ)
{
printf("%d cm = %f in\n", a, a/2.54);
a += KORAK; /* isto sto i a = a + KORAK; */
}
}

Izlaz:
0 cm = 0.000000 in
10 cm = 3.937008 in
20 cm = 7.874016 in

Primer 4.13.2 Konverzija centimetara u inče - for petlja.

#include <stdio.h>
#define POCETAK 0
#define KRAJ 20
#define KORAK 10

main()
{
int a;
for (a = POCETAK; a <= KRAJ; a += KORAK)
printf("%d cm = %f in\n", a, a/2.54);
}

Izlaz:
0 cm = 0.000000 in
10 cm = 3.937008 in
20 cm = 7.874016 in

Zadatak 21 Šta će biti ispisano nakon izvršavanja sledećeg programa?

35
36 Milena Vujošević–Janičić

#include <stdio.h>
#define EURO 85.90
main()
{
printf("4 eura ima vrednost %f dinara\n", 4*EURO);
printf("1 euro ima vrednost %.0f dinara\n",EURO);
}

4.14 Enumeracija
Izvesna alternativa za define

enum boolean {NO, YES};


enum meseci {JAN = 1, FEB, MAR, APR, MAJ, JUN,
JUL, AVG, SEP, OKT, NOV, DEC}
enum boje {CRVENA, ZELENA=5, PLAVA,
LJUBICASTA=10, ZUTA, CRNA}

koriscenje:

int x=0;
boje b;

x=CRVENA+3; /*x ce biti jednako tri*/

b=ZELENA;
x=b+CRNA; /* 5 + 12=17*/

b=0; /*Greska, ovako ne moze!!!*/

4.15 Funkcije
Primer 4.15.1 sum - najjednostavnija funkcija koja sabira dva broja

/* Definicija funkcije */
int sum(int a, int b)
{
int c;
c = a + b;
return c;
/* Ovo je krace moglo da bude napisano
kao return a+b; */
}

main()
{

int c;

36
4.15 Funkcije 37

/* Poziv funkcije */
c = sum(3,5);
printf("%d\n", c);

/* Ovo smo krace mogli da napisemo kao


printf("%d\n", sum(3,5)); */
}

Primer 4.15.2 Deklaracija funkcije moze da stoji nezavisno od definicije funkcije.


Deklaracija je neophodna u situacijama kada se definicija funkcije navodi nakon
upotrebe date funkcije u kodu.
/* Deklaracija funkcije*/
int zbir(int, int);

main()
{
/* Poziv funkcije */
printf("%d\n", zbir(3,5));
}

/* Definicija funkcije */
int zbir(int a, int b)
{
return a+b;
}

Primer 4.15.3 power - funkcija koja stepenuje realan broj na celobrojni izlozi-
lac
#include <stdio.h>

/* stepenuje x^k tako sto k puta pomnozi x */


float power(float x, int k)
{
int i;
float rezultat = 1;
for (i = 0; i<k; i++)
rezultat*=x;

return rezultat;
}

Primer 4.15.4 Verzija koja radi i za negativne izlozioce


float power(float x, int k)
{
int i;
float s = 1;
int negativan = (k<0);
float rezultat;

37
38 Milena Vujošević–Janičić

if (negativan)
k = -k;

for (i = 0; i<k; i++)


s*=x;

rezultat = negativan ? 1.0/s : s;


return rezultat;
}

main()
{
/* Poziv funkcije */
float s = power(2.0,8);
printf("%f\n", s);
}

4.16 Nizovi
Deklaracija niza:
int niz[5]; /* niz od 5 elemenata tipa int*/
Pristupanje elementima niza:
niz[0] = 4;
niz[1] = 2 * niz[0]; /*niz[1] = 8*/
niz[2] = niz[0] * niz[1]; /*niz[2] = 32*/
niz[3] = 5;
niz[4] = 7;
Unos vrednosti elemenata niza sa tastature:
for(i=0; i<5; i++)
scanf("%d", &a[i]);
Stampanje elemenata niza
for(i=0; i<5; i++)
printf("%d ", a[i]);
Brojanje elemenata niza je od nule!
Pristupanje elementu niza, indeks može da bude proizvoljan izraz celobrojne
vrednosti: niz[i*2]=5.

Primer 4.16.1 Program ilustruje korišćenje nizova. Ispisuje 10 unetih brojeva


unazad.
#include <stdio.h>

main()
{
int a[10];

38
4.16 Nizovi 39

int i;
for (i = 0; i<10; i++)
{
printf("a[%d]=",i);
scanf("%d",&a[i]);
}

printf("Unazad : \n");

for (i = 9; i>=0; i--)


printf("a[%d]=%d\n",i,a[i]);
}

Primer 4.16.2 Program pronalazi maksimum brojeva sa ulaza - verzija sa ni-


zom.
#include <stdio.h>
#define BR_ELEM 5
main()
{
int a[BR_ELEM];
int i;
int max;

/* Ucitavamo niz brojeva */


for (i = 0; i < BR_ELEM; i++)
scanf("%d",&a[i]);

/* Pronalazimo maksimum */
max = a[0];
for (i = 1; i < BR_ELEM; i++)
if (a[i]>max)
max = a[i];

/* Ispisujemo maksimum */
printf("Max = %d\n",max);
}

Primer 4.16.3 Program pronalazi maksimum brojeva sa ulaza - verzija bez


niza.

#include <stdio.h>
#define BR_ELEM 5

main()
{
int a, max, i;
scanf("%d",&a);
max = a;
for (i = 1; i < BR_ELEM; i++)
{

39
40 Milena Vujošević–Janičić

scanf("%d",&a);
if (a>max)
max = a;
}

printf("Max : %d\n", max);


}

4.17 Konstante
Koji su tipovi konstanti?
Celobrojna konstanta 1234 je tipa int.
Da bi konstanta bila long navodi se iza nje slovo L ili l, npr 123456789L.
Ako želimo da nam je konstanta unsigned onda na kraju pišemo U ili u.
Može i 1234567ul.

Konstante realnih brojeva sadrže decimalnu tačku(123.4) ili eksponent(1e-


2) ili i jedno i drugo. Njihov tip je double osim ako nemaj sufiks f ili F kada je
u pitanju float. L ili l označavaju long double.
Oktalna konstanta počinje sa 0, a heksadecimalna sa 0x. Npr broj 31 ili
037 - oktalno ili 0x1f - heksadecimalno. I one mogu da imaju U i L na kraju.
Znakovna konstanta je celobrojna vrednost napisana izme u jednostrukih
navodnika. Vrednost date konstante je numerička vrednost datog znaka u
računarskom setu znakova. Npr možemo da pišemo ’0’ umesto 48.
!!!Razlikovati znakovne konstante i niske koje se navode izme u dvostrukih
navodnika!
Posebni znaci su znak za kraj reda, tab i slično.
Znakovna konstanta ’\0’ predstavlja znak čija je vrednost nula, treba ga
razlikovati od ’0’ koja je znak čija je vrednost 48.
Konstantna niska: ”Ja sam niska”
ili
”” /*prazna niska*/
Navodnici nisu deo niske već se koriste da bi je ograničili. Ako ih želimo unutar
niske, oni se navode sa \".
Konstantna niska je polje znakova. Da bi se znalo gde je kraj niske, fizičko
memorisanje liste zahteva da postoji jedan znak više koji označava kraj, to je
’\0’. Da bi se odredila dužina niske mora se proći kroz celu nisku.
!!!Važno:

Koja je razlika izme u ”x” i ’x’ ?

Primer 4.17.1 Primer funkcije koja izračunava dužinu niske znakova.


#include <stdio.h>

int strlen(char s[])


{
int i=0;

while (s[i] != ’\0’)

40
4.18 Konverzija 41

++i;
return i;
}

int main()
{
printf("Duzina ove niske
je: %d \n",strlen("Duzina ove niske je:"));
return 0;
}

4.18 Konverzija
4.18.1 Automatska konverzija
Ako je jedan od operanada razližličit vrši se konverzija, uvek u smeru manjeg
ka većem tipu

Naredba dodele:
int i=5;
float f=2.3;
f=i; /* f ce imati vrednost 5.0*/

obrnuto:

int i=5;
float f=2.3;
i=f; /* i ce imati vrednost 2*/

4.18.2 Eksplicitna konverzija


(tip)<izraz>

float x;
x=2.3+4.2; /* x ce imati vrednost 6.5 */
x=(int)2.3+(int)4.2; /* x ce imati vrednost 6 */
x=(int)2.3*4.5; /* x ce imati vrednost 9.0 jer zbog prioriteta
operatora konverzije prvo ce biti izvrsena
konverzija broja 2.3 u 2 pa tek onda izvrseno
mnozenje. */
x=(int)(2.3*4.5) /* x ce imati vrednost 10.0 */

Primer 4.18.1 Kako izbeći celobrojno deljenje


int a,b;
float c;
a = 5;
b = 2;
c = a/b; /* Celobrojno deljenje, c=2*/
c = (1.0*a)/b; /* Implicitna konverzija: 1.0*a je realan

41
42 Milena Vujošević–Janičić

broj pa priliko deljenja sa b dobija se


realan rezultat c=2.5*/
c = (0.0+a)/b; /* Implicitna konverzija: (0.0+a) je realan
broj pa priliko deljenja sa b dobija se
realan rezultat c=2.5*/
c = (float)a/(float)b; /* Eksplicitna konverzija*/

4.18.3 Funkcije koje vrše konverziju


Primer 4.18.2
#include <stdio.h>
main()
{
int vrednost;
vrednost=’A’;
printf("Veliko slovo\n karakter=%3c\nvrednost=%3d\n",vrednost,vrednost);
vrednost=’a’;
printf("Malo\n karakter=%3c\nvrednost=%3d\n",vrednost,vrednost);
}

Izlaz (u slucaju ASCII):


Veliko slovo
karakter= A
vrednost= 65
Malo
karakter= a
vrednost= 97

Primer 4.18.3 Funkcija koja konvertuje velika slova u mala slova.

#include<stdio.h>

/* Konvertuje karakter iz velikog u malo slovo */


char lower(char c)
{
if (c >= ’A’ && c <= ’Z’)
return c - ’A’ + ’a’ ;
else
return c;
}

main()
{
char c;
printf("Unesi neko veliko slovo:\n");
scanf("%c", &c);
printf("Odgovarajuce malo slovo je %c\n", lower(c));
}

Primer 4.18.4 Konvertovanje niske cifara u ceo broj.

42
4.19 Operator sizeof() 43

#include<stdio.h>

/* atoi: konvertuje s u ceo broj */


int atoi(char s[])
{
int i, n;
n = 0;
for (i = 0; (s[i] >= ’0’) && (s[i] <= ’9’); ++i)
n = 10 * n + (s[i] - ’0’);
return n;
}

main()
{
int n;
n = atoi("234");
printf("\nN je : %d\n",n);
}

4.19 Operator sizeof()


Primer 4.19.1 Demonstracija sizeof operatora. Sizeof operator izračunava
veličinu tipa odnosno promenjive.
#include<stdio.h>
main()
{
int i;
float f;
int n[10];

printf("sizeof(int)=%d\n", sizeof(int));
printf("sizeof(long)=%d\n", sizeof(long));
printf("sizeof(short)=%d\n", sizeof(short));
printf("sizeof(signed)=%d\n", sizeof(signed));
printf("sizeof(unsigned)=%d\n", sizeof(unsigned));
printf("sizeof(char)=%d\n", sizeof(char));
printf("sizeof(float)=%d\n", sizeof(float));
printf("sizeof(double)=%d\n", sizeof(double));

printf("sizeof(i)=%d\n", sizeof(i));
printf("sizeof(f)=%d\n", sizeof(f));
printf("sizeof(n)=%d\n", sizeof(n));
printf("Broj elemenata niza n : %d\n", sizeof(n)/sizeof(int));

Izlaz iz programa(u konkretnom slucaju):


sizeof(int)=4
sizeof(long)=4

43
44 Milena Vujošević–Janičić

sizeof(short)=2
sizeof(signed)=4
sizeof(unsigned)=4
sizeof(char)=1
sizeof(float)=4
sizeof(double)=8
sizeof(i)=4
sizeof(f)=4
sizeof(n)=40
Broj elemenata niza n : 10

4.20 Znakovni ulaz i izlaz


Funkcija za čitanje jednog znaka sa ulaza
c = getchar()
promenljiva c sadrži jedan znak sa ulaza.

Funkcija za štampanje jednog znaka na izlaz


putchar(c)
štampa sadržaj promenljive c obično na ekranu.

Konstanta EOF je celobrojna vrednost definisana u biblioteci <stdio.h>.


Ovu vrednost vrati funkcija getchar() kada nema više ulaza. Nazvana je EOF
kao End Of File, kraj datoteke. Ova vrednost mora da se razlikuje od svake
vrednosti koja može da bude karakter. Zato za c za koje je c=getchar() treba
da koristimo tip dovoljno veliki da moze da prihvati sve sto moze da vrati
getchar(), dakle i EOF. Zbog toga se za c koristi tip int.

Primer 4.20.1 Program cita jedan karakter i ispisuje ga - demonstracija putchar


i getchar.

#include <stdio.h>

main()
{
int c; /* Karakter - obratiti paznju na int */
c = getchar(); /* cita karakter sa standardnog ulaza */
putchar(c); /* pise karakter c na standardni izlaz */

putchar(’\n’); /* prelazak u novi red */


putchar(’a’); /* ispisuje malo a */
putchar(97); /* ekvivalentno prethodnom */
}
Ulaz:
s
Izlaz iz programa:
s
s
aa

44
4.20 Znakovni ulaz i izlaz 45

Primer 4.20.2 Program prepisuje standardni ulaz na standardni izlaz. Ilus-


tracija redirekcije standardnog ulaza i izlaza, pokrenuti program sa :
./a.out <primer.c
./a.out >tekst.txt
./a.out <primer.c >kopija.c

#include <stdio.h>

main()
{
/*Koristi se int a ne char zato sto zelimo
da razlikujemo kraj ulaza od vazecih znakova*/
int c;

/*Ucitava se prvi znak sa ulaza*/


c = getchar();

/*EOF predstavlja celobrojnu vrednost kraja datoteke.


To je konstanta definisana u <stdio.h>*/
while (c != EOF) {
putchar(c);
c = getchar();
}
}

Bilo koje dodeljivanje vrednosti je izraz koji ima vrednost a to je vrednost


leve strane posle dodeljivanja.

Primer 4.20.3 Program koji kopira ulaz na izlaz, skraćeni kod.


#include <stdio.h>

main()
{
int c;

/* Obratiti paznju na raspored zagrada */


while ((c = getchar()) != EOF)
putchar(c);
}

Primer 4.20.4 Brojanje znakova na ulazu.


#include <stdio.h>

main()
{
long nc;

nc = 0;
while (getchar() != EOF)

45
46 Milena Vujošević–Janičić

++nc;
/* %ld odnosi se na tip long. */
printf("%ld\n", nc);
}

Primer 4.20.5 Brojanje znakova na ulazu korišćenjem for petlje.


#include <stdio.h>

main()
{
double nc;

/*For petlja mora da ima telo pa makar


ono bilo przno*/
for (nc = 0; getchar() != EOF; ++nc)
;
printf("%.0f\n", nc);
}

Primer 4.20.6 Program broji linije i znakove na ulazu.


#include <stdio.h>
main()
{
int znak; /*prihvata znak sa ulaza */
long linije=0 ; /*brojac linija */
long br_znak=0; /*brojac znakova na ulazu */

while ( (znak=getchar() ) != EOF)


{
br_znak++;
if (znak==’\n’) linije ++;
}

printf("Prelazaka u novi red: %ld, karaktera: %ld \n",linije,br_znak);


}

Primer 4.20.7 Program broji blankove, horizontalne tabulatore i linije na ulazu.


#include <stdio.h>
main()
{
int znak; /*prihvata znak sa ulaza */
int Blanks=0; /*brojac blankova */
int Tabs=0; /*brojac horizontalnih tabulatora */
int NewLines=0; /*brojac linija */

/*UOCITI: blok naredbi while ciklusa NIJE OGRADJEN


viticastim zagradama jer postoji samo jedna if naredba! */
while( (znak=getchar())!=EOF )
if( znak==’ ’ ) ++Blanks; /* brojimo blanko simbole */

46
4.20 Znakovni ulaz i izlaz 47

else if( znak==’\t’ ) ++Tabs; /* brojimo tab-ove */


else if( znak==’\n’ ) ++NewLines; /* brojimo redove */

/*izdavanje rezultata na standardni izlaz*/


printf("Blankova: %d. Tabulatora: %d. Prelazaka u novi red: %d\n",
Blanks, Tabs, NewLines);

Primer 4.20.8 Program prepisuje ulaz na izlaz pri čemu više blanko znakova
zamenjuje jednim.
#include <stdio.h>

main()
{
int znak; /*tekuci znak sa ulaza*/
int preth; /*znak koji prethodi tekucem */
preth=’a’; /* inicijalizujemo vrednost prethodnog
da bi prvi prolazak kroz petlju bio ispravan*/
while ( (znak=getchar() ) !=EOF)
{
if (znak !=’ ’ || preth != ’ ’) putchar(znak);
preth=znak;
}
}

Primer 4.20.9 Program vrši prebrojavanje cifara unetih na ulazu.


#include <stdio.h>

main()
{
int c;
int br_cifara = 0;
while ((c = getchar()) != EOF)
if (’0’<=c && c<=’9’)
br_cifara++;

printf("Broj cifara je : %d\n", br_cifara);


}

Primer 4.20.10 Program vrši brojanje pojavljivanja karaktera 0, 1 i 2 (ilus-


truje switch).
#include <stdio.h>

main()
{
int c;
int br_0=0, br_1=0, br_2=0;

47
48 Milena Vujošević–Janičić

while ((c = getchar()) != EOF)


{
switch(c)
{
/* Obratiti paznju da nije
case 0: */
case ’0’:
br_0++;
break; /* Isprobati veziju bez break */
case ’1’:
br_1++;
break;
case ’2’:
br_2++;
break;
default:
}
}
printf("Br 0 : %d\nBr 1 : %d\nBr 2 : %d\n",br_0, br_1, br_2);
}

4.21 Nizovi
Primer 4.21.1 Program ilustruje inicijalizaciju nizova.
#include <stdio.h>

main()
{
/* Niz inicijalizujemo tako sto mu navodimo vrednosti
u viticasnim zagradama. Dimenzija niza se odredjuje
na osnovu broja inicijalizatora */
int a[] = {1, 2, 3, 4, 5, 6};

/* Isto vazi i za niske karaktera */


char s[] = {’a’, ’b’, ’c’};

/* Ekvivalentno prethodnom bi bilo


char s[] = {97, 98, 99};
*/

/* Broj elemenata niza */


int a_br_elem = sizeof(a)/sizeof(int);
int s_br_elem = sizeof(s)/sizeof(char);

/* Ispisujemo nizove */

int i;
for (i = 0; i < a_br_elem; i++)
printf("a[%d]=%d\n",i, a[i]);

48
4.21 Nizovi 49

for (i = 0; i < s_br_elem; i++)


printf("s[%d]=%c\n",i, s[i]);

Primer 4.21.2 Program uvodi niske karaktera terminisane nulom.

#include <stdio.h>

main()
{
/* Poslednji bajt niske karaktera se postavlja na ’\0’ tj. 0 */
char s[] = {’a’, ’b’, ’c’, ’\0’ };

/* Kraci nacin da se postigne prethodno */


char t[] = "abc";

/* Ispis niske s karakter po karakter*/


int i;
for (i = 0; s[i] != ’\0’; i++)
putchar(s[i]);
putchar(’\n’);

/* Ispis niske s koristeci funkciju printf */


printf("%s\n", s);

/* Ispis niske t karakter po karakter*/


for (i = 0; t[i] != ’\0’; i++)
putchar(t[i]);
putchar(’\n’);

/* Ispis niske t koristeci funkciju printf */


printf("%s\n", t);
}

Primer 4.21.3 Brojanje pojavljivanja svake od cifara. Koriscenje niza brojača.

#include <stdio.h>

/* zbog funkcije isdigit */


#include <ctype.h>

main()
{
/* Niz brojaca za svaku od cifara */
int br_cifara[10];
int i, c;

/* Resetovanje brojaca */

49
50 Milena Vujošević–Janičić

for (i = 0; i < 10; i++)


br_cifara[i] = 0;

/* Citamo sa ulaza i povecavamo odgovarajuce brojace */


while ((c = getchar()) != EOF)
if (isdigit(c))
br_cifara[c-’0’]++;

/* Ispis rezultata */
for (i = 0; i < 10; i++)
printf("Cifra %d se pojavila %d put%s\n",
i, br_cifara[i], br_cifara[i] == 1 ? "" : "a");
}

Primer 4.21.4 Brojanje reči

#include <stdio.h>

#define IN 1 /* inside a word */


#define OUT 0 /* outside a
word */

/* count lines, words, and characters in input */

main()
{
int c, nl, nw, nc, state;

state = OUT;

/*Postavljaju se sve tri promenljive na nulu*/


/*Isto kao da smo napisali
nl = (nw = (nc = 0));*/

nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == ’\n’)
++nl;
/*Operator || znaci OR*/
if (c == ’ ’ || c == ’\n’ || c == ’\t’)
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}

50
4.22 Dvostruka for petlja 51

4.22 Dvostruka for petlja


Primer 4.22.1 Dvostruka for petlja

#include<stdio.h>
int main()
{
int i,j;

for(i=1; i<=10; i++)


{
for(j=1; j<=10; j++)
printf("%d * %d = %d\t", i, j, i*j);
printf("\n");
}
}

Primer 4.22.2 Trostruka for petlja

#include<stdio.h>
int main()
{
int i,j;

for(i=1; i<=10; i++)


for(j=1; j<=10; j++)
{
for(k=1; k<=10; k++)
printf("%d * %d * %d = %d\t", i, j, k, i*j*k);
printf("\n");
}
}

Koliko puta se izvrsi naredba štampanja


printf("%d * %d * %d = %d\t", i, j, k, i*j*k);

4.23 Formiranje HTML dokumenta


Primer 4.23.1 Prilikm pokretanja programa koristiti redirekciju:
a.out >primer.html
kako bi se rezultat rada programa upisao u datoteku primer.html.

/*Ovaj program formira html dokument*/


#include <stdio.h>
main()
{
printf("<html><head><title>Ova stranica
je napravljena u c-u</title></head>");
printf("<body><h3 align=center>
Rezultat </h3></body></html>");
}

51
52 Milena Vujošević–Janičić

Primer 4.23.2 Napisati program koji generiše html dokument sa engleskim al-
fabetom.

#include <stdio.h>
main()
{
int i;
printf("<HTML><head><title>Engleski alfabet</title><head>\n");
printf("<body><ul>");
for(i=0;i<=25;i++)
printf("<li> %c %c \n",’A’+i,’a’+i);
printf("</ul></body></HTML>\n"); }

Primer 4.23.3 Napisati program koji generise html dokument koji prikazuje
tablicu mnozenja za brojeve od 1 do 10.

#include<stdio.h>
main()
{
int i,j;
printf("<html><head><title>Mnozenje</title></head>");
printf("<body><h3 align=center> Rezultat </h3>");
printf("<table border=1>\n");

/* Prva vrsta sadrzi brojeve od 1 do 10*/


printf("<tr>");
printf("<th></th>");
for(i=1; i<=10; i++)
printf("<th> %d </th>\n", i);
printf("</tr>");

for(i=1; i<=10; i++)


{
printf("<tr>");

/* Na pocetku svake vrste stampamo broj


odgovarajuce vrste*/
printf("<th>%d</th>", i);

for(j=1; j<=10; j++)


printf("<td>%d\t</td>\n", i*j);

printf("</tr>");
}
printf("</table>");
printf("</body></html>");
}

52
4.24 Funkcije — prenos parametara po vrednosti 53

4.24 Funkcije — prenos parametara po vred-


nosti
Primer 4.24.1 Funkcija koja proverava da li je broj prost i program koji ispisuje
sve proste brojeve manje od 100.
#include<stdio.h>
#include<math.h>

int prost(int p)
{
int i, koren, ind;
koren=sqrt(p);
ind=(p%2) || (p==2);
i=3;
while (ind && i<=koren)
{
ind=p%i;
i+=2;
}
return ind;
}

main()
{
int k;
for(k=2;k<=100;k++)
if (prost(k)) printf("%d ",k);
}

Primer 4.24.2
#include <stdio.h> /* Ilustruje vidljivost imena*/

int i=10;

void main() {
{
int i=3;
{
int i=1;
printf("%d\n", i);
}
printf("%d\n",i);
}
printf("%d\n",i);
}

Primer 4.24.3 Demonstracija prenosa parametara po vrednosti - preneti parametri


se ne mogu menjati
#include <stdio.h>

53
54 Milena Vujošević–Janičić

void f(int x)
{
x++;
}

main()
{
int x=3;
f(x);
printf("%d\n", x);
}

Primer 4.24.4 Demonstrira prenos nizova u funkciju - preneti niz se moze


menjati.
#include <stdio.h>
#include <ctype.h>

/* Funkcija ucitava rec sa standardnog ulaza i smesta je u niz karaktera s.


Ovo uspeva zbog toga sto se po vrednosti prenosi adresa pocetka niza,
a ne ceo niz */
void get_word(char s[])
{
int c, i = 0;
while (!isspace(c=getchar()))
s[i++] = c;
s[i] = ’\0’;
}

main()
{
/* Obavezno je alocirati memoriju za niz karaktera */
char s[100];

get_word(s);
printf("%s\n", s);
}

Primer 4.24.5 Funkcija za ispis niza brojeva - demonstrira prenos nizova bro-
jeva u funkciju.

#include <stdio.h>

/* Nizovi se prenose tako sto se prenese adresa njihovog pocetka.


Uglaste zagrade ostaju prazne!

Nizove je neophodno prenositi zajedno sa dimenzijom niza


(osim za niske karaktera, jer tamo vazi konvencija da
se kraj niza obelezava znakom ’\0’)
*/
void print_array(int a[], int n)

54
4.25 Break i continue 55

{
int i;
for (i = 0; i < n; i++)
printf("%d ",a[i]);
putchar(’\n’);

/* Obratite paznju na ovo : */


printf("sizeof(a) - u okviru fje : %d\n", sizeof(a));
}

main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

printf("sizeof(a) - u okviru main : %d\n", sizeof(a));


print_array(a, sizeof(a)/sizeof(int));
}

Primer 4.24.6 Funkcija za ispis niske karaktera - demonstrira prenos niske


karaktera u funkciju.

#include <stdio.h>

/* Uz nisku karaktera nije potrebno prenositi dimenziju


ukoliko se postuje dogovor
da se svaka niska zavrsava karakterom ’\0’.*/
void print_string(char s[])
{
int i;
for (i = 0; s[i]!=’\0’; i++)
putchar(s[i]);
}

main()
{
print_string("Zdravo\n");
}

4.25 Break i continue


Primer 4.25.1 Funkcija uklanja beline, tabulatore ili znak za kraj reda sa kraja
stringa.

int trim(char s[])


{
int n;
for (n = strlen(s)-1; n >= 0; n--)
if (s[n] != ’ ’ && s[n] != ’\t’ && s[n] != ’\n’)
break;

55
56 Milena Vujošević–Janičić

s[n+1] = ’\0’;
return n;
}

Continue se re e koristi, on prouzrokuje da se pre e na sledeću iteraciju u


petlji.

Primer 4.25.2
for(i=0; i<n; i++)
{
if (a[i]==0) continue;
... /* obradi pozitivne elemente nekako*/
}

4.26 Rad sa niskama karaktera


Primer 4.26.1 string reverse - obrće nisku karaktera.

#include <stdio.h>

/* Ova funkcija racuna duzinu date niske karaktera.


Umesto nje, moguce je koristiti standardnu funkciju strlen
za cije je koriscenje potrebno ukljuciti zaglavlje
<string.h>
*/
int string_length(char s[])
{
int i;
for (i = 0; s[i]!=’\0’; i++)
;

return i;
}

/* Funkcija obrce nisku karaktera */


void string_reverse(char s[])
{
int i, j;
for (i = 0, j = string_length(s)-1; i<j; i++, j--)
{
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}

/* Napomena : razlikovati prethodnu petlju od dve ugnjezdjene petlje:


for ( i = 0; ....)
for ( j = duzina(s)-1; ...
*/

56
4.26 Rad sa niskama karaktera 57

main()
{
char s[] = "Zdravo svima";
string_reverse(s);
printf("%s\n", s);
}
/*
Izlaz:
amivs ovardZ
*/

Primer 4.26.2 strlen, strcpy, strcat, strcmp, strchr, strstr - manip-


ulacija niskama karaktera. Vezbe radi, implementirane su funkcije biblioteke
string.h

#include <stdio.h>

/* Izracunava duzinu stringa */


int string_length(char s[])
{
int i;
/* Uslov s[i] je ekvivalentan uslovu
s[i]!=’\0’ ili uslovu s[i]! = 0*/
for (i = 0; s[i]; i++)
;
return i;
}

/* Kopira string src u string dest.


Pretpostavlja da u dest ima dovoljno prostora. */
void string_copy(char dest[], char src[])
{
/* Kopira karakter po karakter, sve dok nije iskopiran karakter ’\0’ */
int i;
for (i = 0; (dest[i]=src[i]) != ’\0’; i++)
;

/* Uslov != ’\0’ se, naravno, moze izostaviti :

for (i = 0; dest[i]=src[i]; i++)


;
*/

/* Nadovezuje string t na kraj stringa s.

57
58 Milena Vujošević–Janičić

Pretpostavlja da u s ima dovoljno prostora. */


void string_concatenate(char s[], char t[])
{
int i, j;
/* Pronalazimo kraj stringa s */
for (i = 0; s[i]; i++)
;

/* Vrsi se kopiranje, slicno funkciji string_copy */


for (j = 0; s[i] = t[j]; j++, i++)
;
}

/* Vrsi leksikografsko poredjenje dva stringa.


Vraca :
0 - ukoliko su stringovi jednaki
<0 - ukoliko je s leksikografski ispred t
>0 - ukoliko je s leksikografski iza t
*/
int string_compare(char s[], char t[])
{
/* Petlja tece sve dok ne naidjemo na prvi razliciti karakter */
int i;
for (i = 0; s[i]==t[i]; i++)
if (s[i] == ’\0’) /* Naisli smo na kraj oba stringa,
a nismo nasli razliku */
return 0;

/* s[i] i t[i] su prvi karakteri u kojima se niske razlikuju.


Na osnovu njihovog odnosa, odredjuje se odnos stringova */
return s[i] - t[i];
}

/* Pronalazi prvu poziciju karaktera c u stringu s, odnosno -1


ukoliko s ne sadrzi c */
int string_char(char s[], char c)
{
int i;
for (i = 0; s[i]; i++)
if (s[i] == c)
return i;
/* nikako
else
return -1;
*/
/* Nije nadjeno */
return -1;
}

/* Pronalazi poslednju poziciju karaktera c u stringu s, odnosno -1

58
4.26 Rad sa niskama karaktera 59

ukoliko s ne sadrzi c */
int string_last_char(char s[], char c)
{
/* Pronalazimo kraj stringa s */
int i;
for (i = 0; s[i]; i++)
;

/* Krecemo od kraja i trazimo c unazad */


for (i--; i>=0; i--)
if (s[i] == c)
return i;

/* Nije nadjeno */
return -1;

/*
Koristeci string_length :

for (i = string_length(s) - 1; i>0; i--)


if (s[i] == c)
return i;

return -1;
*/
}

/* Proverava da li string str sadrzi string sub.


Vraca poziciju na kojoj sub pocinje, odnosno -1 ukoliko ga nema
*/
int string_string(char str[], char sub[])
{
int i, j;
/* Proveravamo da li sub pocinje na svakoj poziciji i */
for (i = 0; str[i]; i++)
/* Poredimo sub sa str pocevsi od poziciji i
sve dok ne naidjemo na razliku */
for (j = 0; str[i+j] == sub[j]; j++)
/* Nismo naisli na razliku a ispitali smo
sve karaktere niske sub */
if (sub[j+1]==’\0’)
return i;
/* Nije nadjeno */
return -1;
}

main()
{
char s[100];
char t[] = "Zdravo";

59
60 Milena Vujošević–Janičić

char u[] = " svima";

string_copy(s, t);
printf("%s\n", s);

string_concatenate(s, u);
printf("%s\n", s);

printf("%d\n",string_char("racunari", ’n’));
printf("%d\n",string_last_char("racunari", ’a’));

printf("%d\n",string_string("racunari", "rac"));
printf("%d\n",string_string("racunari", "ari"));
printf("%d\n",string_string("racunari", "cun"));
printf("%d\n",string_string("racunari", "cna"));
}

/*
Izlaz:
Zdravo
Zdravo svima
4
5
0
5
2
-1*/

4.27 Makroi
#define ime tekst_zamene

Zamene se vrše samo na simbolima, a ne obavljaju se u niskama nutar navodnika.


Moguće je definisati makroe sa argumentima tako da tekst zamene bude
različit za različita pojavljivanja makroa.

Primer 4.27.1 Demonstracija pretprocesorske direktive #define

#include<stdio.h>

/* Racuna sumu dva broja */


#define sum(a,b) ((a)+(b))

/* Racuna kvadrat broja - pogresna verzija */


#define square_w(a) a*a

/* Racuna kvadrat broja */


#define square(a) ((a)*(a))

/* Racuna minimum tri broja */

60
4.27 Makroi 61

#define min(a, b, c) (a)<(b)? ((a)<(c)? (a) : (c)) : ((b)<(c)? (b) : (c))

main()
{
printf("sum(3,5) = %d\n", sum(3,5));
printf("square_w(5) = %d\n", square_w(5));
printf("square_w(3+2) = %d\n", square_w(3+2));
printf("square(3+2) = %d\n", square(3+2));
printf("min(1,2,3) = %d\n", min(1,2,3));
printf("min(1,3,2) = %d\n", min(1,3,2));
printf("min(2,1,3) = %d\n", min(2,1,3));
printf("min(2,3,1) = %d\n", min(2,3,1));
printf("min(3,1,2) = %d\n", min(3,1,2));
printf("min(3,2,1) = %d\n", min(3,2,1));
}

Izlaz iz programa:
sum(3,5) = 8
square_w(5) = 25
square_w(3+2) = 11
square(3+2) = 25
min(1,2,3) = 1
min(1,3,2) = 1
min(2,1,3) = 1
min(2,3,1) = 1
min(3,1,2) = 1
min(3,2,1) = 1

Primer 4.27.2
#define max(A, B) ((A)>(B) ? (A) : (B))

na osnovu ovoga će linija

x=max(p+q, r+s)

biti zamenjena linijom

x=((p+q) > (r+s) ? (p+q) : (r+s));

Treba voditi računa o sporednim efektima. Sledeća linija koda pruzrokovaće


uvećanje vrednosti i ili j za dva.

max(i++, j++)

Tako e treba voditi računa o zagradama. Sledeći makro prouzrokovaće


neočekivane rezultate za upotrebu square(a+1)

#define square(x) x*x

Primer 4.27.3 Ilustacija beskonačne petlje:

#define forever for(;;);

61
62 Milena Vujošević–Janičić

Primer 4.27.4
#include <stdio.h>
#define max1(x,y) (x>y?x:y)
#define max2(x,y) ((x)>(y)?(x):(y))
#define swapint(x,y) { int z; z=x; x=y; y=z; }
#define swap(t,x,y) { \
t z; \
z=x; \
x=y; \
y=z; }

main()
{

int x=2,y=3;

printf( "max1(x,y) = %d\n", max1(x,y) );


/* max1(x,y) = 3 */

/* Zamena makroom se ne vrsi


unutar niski pod navodnicima*/
printf( "max1(x=5,y) = %d\n", max1(x,y) );
/* max1(x=5,y) = 3 */

printf( "max1(x++,y++) = %d\n", max1(x++,y++) );


/* max1(x++,y++) = 4 */

printf( "x = %d, y = %d\n", x, y );


/* x = 3, y = 5 */

swapint(x,y);

printf( "x = %d, y = %d\n", x, y );


/* x = 5, y = 3 */

swap(int,x,y);
printf( "x = %d, y = %d\n", x, y );
/* x = 3, y = 5 */
}

Izlaz:
max1(x,y) = 3
max1(x=5,y) = 3
max1(x++,y++) = 4
x = 3, y = 5
x = 5, y = 3
x = 3, y = 5

62
4.28 Bitski operatori 63

4.28 Bitski operatori


!!!Ne mešati sa logičkim operatorima!!!

& bitsko AND


| bitsko OR
^ bitsko ekskluzivno OR
<< levo pomeranje
>> desno pomeranje
~ jedinicni komplement

Primer 4.28.1 Demonstracija bitskih operatora

#include <stdio.h>

main()
{ printf("%o %o\n",255,15);
printf( "255 & 15 = %d\n", 255 & 15 );
printf( "255 | 15 = %d\n", 255 | 15 );
printf( "255 ^ 15 = %d\n", 255 ^ 15 );
printf( "2 << 2 = %d\n", 2 << 2 );
printf( "16 >> 2 = %d\n", 16 >> 2 );
}

Izlaz iz programa je:


377 17
255 & 15 = 15
255 | 15 = 255
255 ^ 15 = 240
2 << 2 = 8
16 >> 2 = 4

Primer 4.28.2 print bits - stampa bitove u zapisu datog celog broja x.

#include <stdio.h>

/* Funkcija stampa bitove datog celog broja x.


Vrednost bita na poziciji i je 0 ako i
samo ako se pri konjunkciji broja x sa maskom
000..010....000 - sve 0 osim 1 na poziciji i,
dobija 0.
Funkcija krece od pozicije najvece tezine
kreirajuci masku pomeranjem jedinice u levo
za duzina(x) - 1 mesto, i zatim pomerajuci
ovu masku za jedno mesto u levo u svakoj
sledecoj iteraciji sve dok maska ne postane 0.
*/

void print_bits(int x)
{
/* Broj bitova tipa unsigned */

63
64 Milena Vujošević–Janičić

int wl = sizeof(int)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

main()
{
print_bits(127);
print_bits(128);
print_bits(0x00FF00FF);
print_bits(0xFFFFFFFF);
}

Izlaz iz programa:
00000000000000000000000001111111
00000000000000000000000010000000
00000000111111110000000011111111
11111111111111111111111111111111

Primer 4.28.3 Program proverava da li se na k-tom mestu nalazi 1.

#include <stdio.h>

/* Pozicije brojimo kao u sledecem primeru:


poz: ... 10 9 8 7 6 5 4 3 2 1 0
bit: ... 0 0 0 1 1 1 0 0 1 1 0 */

main()
{
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da proverite:\n");
scanf("%d%d",&n,&k);
if ((n & (1 << k))!=0)
printf("Bit je 1\n");
else
printf("Bit je 0\n");
}

Primer 4.28.4 Program postavlja na k-to mesto 1


#include <stdio.h>

void print_bits(int x)
{
/* Broj bitova tipa unsigned */
int wl = sizeof(int)*8;

64
4.28 Bitski operatori 65

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

main(){
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da promenite:\n");
scanf("%d%d",&n,&k);
printf("Binarno, une\v seni broj je\n");
print_bits(n);
printf("Novi broj je %d\n",(n |(1<<k)));
printf("Binarno, novi broj je\n");
print_bits((n |(1<<k)));
}

Izrazom a>>b vrši se pomeranje sadržaja operanda a predstavljenog u bi-


narnom obliku za b mesta u desno. Popunjavanje upražnjenih mesta na levoj
strani zavisi od tipa podataka i vrste računara. Ako se pomeranje primen-
juje nad operandom tipa unsigned popunjavanje je nulama. Ako se radi o
označenom operandu popunjavanje je jedinicama kada je u krajnjem levom bitu
jedinica, a nulama kada je u krajnjem levom bitu nula.

Primer 4.28.5 sum of bits - izračunava sumu bitova datog neoznačenog broja.
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

int sum_of_bits(unsigned x)
{
int br;
for (br = 0; x; x>>=1)
if (x&1)
br++;

return br;
}

65
66 Milena Vujošević–Janičić

main()
{
printf("Binarni zapis broja 127 je\n");
print_bits(127);
printf("Suma bitova broja 127 je %d\n",sum_of_bits(127));
printf("Binarni zapis broja 128 je\n");
print_bits(128);
printf("Suma bitova broja 128 je %d\n",sum_of_bits(128));
printf("Binarni zapis broja 0x00FF00FF je\n");
print_bits(0x00FF00FF);
printf("Suma bitova broja 0x00FF00FF je %d\n",sum_of_bits(0x00FF00FF));
printf("Binarni zapis broja 0xFFFFFFFF je\n");
print_bits(0xFFFFFFFF);
printf("Suma bitova broja 0xFFFFFFFF je %d\n",sum_of_bits(0xFFFFFFFF));
}

Izlaz iz programa:
Binarni zapis broja 127 je
00000000000000000000000001111111
Suma bitova broja 127 je 7
Binarni zapis broja 128 je
00000000000000000000000010000000
Suma bitova broja 128 je 1
Binarni zapis broja 0x00FF00FF je
00000000111111110000000011111111
Suma bitova broja 0x00FF00FF je 16
Binarni zapis broja 0xFFFFFFFF je
11111111111111111111111111111111
Suma bitova broja 0xFFFFFFFF je 32
Primer 4.28.6 get bits, set bits, invert bits - izdvajanje, postavljanje i inver-
tovanje pojedinacnih bitova
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

/* Funkcija vraca n bitova broja x koji pocinju na poziciji p */


unsigned get_bits(unsigned x, int p, int n)
{
/* Gradimo masku koja ima poslednjih n jedinica

66
4.28 Bitski operatori 67

0000000...00011111
tako sto sve jedinice ~0 pomerimo u levo za n mesta
1111111...1100000
a zatim komplementiramo
*/
unsigned last_n_1 = ~(~0 << n);

/* x pomerimo u desno za odgovarajuci broj mesta, a zatim


konjunkcijom sa konstruisanom maskom obrisemo pocetne cifre */

return (x >> p+1-n) & last_n_1;


}

/* Funkcija vraca modifikovano x tako sto mu je izmenjeno n bitova


pocevsi od pozicije p i na ta mesta je upisano poslednjih n bitova
broja y */
unsigned set_bits(unsigned x, int p, int n, unsigned y)
{
/* Maska 000000...000111111 - poslednjih n jedinica */
unsigned last_n_1 = ~(~0 << n);

/* Maska 1111100..000111111 - n nula pocevsi od pozicije p */


unsigned middle_n_0 = ~(last_n_1 << p+1-n);

/* Brisemo n bitova pocevsi od pozicije p */


x = x & middle_n_0;

/* Izdvajamo poslednjih n bitova broja y i pomeramo ih


na poziciju p */
y = (y & last_n_1) << p+1-n;

/* Upisujemo bitove broja y u broj x i vracamo rezultat */


return x | y;
}

/* Invertuje n bitova broja x pocevsi od pozicije p */


unsigned invert_bits(unsigned x, int p, int n)
{
/* Maska 000000111...1100000 - n jedinica pocevsi od pozicije p */
unsigned middle_n_1 = ~(~0 << n) << p+1-n;

/* Invertujemo koristeci ekskluzivnu disjunkciju */


return x ^ middle_n_1;
}

main()
{
unsigned x = 0x0AA0AFA0;
print_bits(x);

67
68 Milena Vujošević–Janičić

print_bits(get_bits(x, 15, 8));


print_bits(set_bits(x, 15, 8, 0xFF));
print_bits(invert_bits(x, 15, 8));
}

Izlaz iz programa:
00001010101000001010111110100000
00000000000000000000000010101111
00001010101000001111111110100000
00001010101000000101000010100000
Primer 4.28.7 right rotate bits, mirror bits - rotiranje i simetrija bitova.
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

/* Funkcija vrsi rotaciju neoznacenog broja x za n pozicija u desno */


unsigned right_rotate(unsigned x, int n)
{
int i;
int wl = sizeof(unsigned)*8;

/* Postupak se ponavlja n puta */


for (i = 0; i < n; i++)
{
/* Poslednji bit broja x */
unsigned last_bit = x & 1;

/* x pomeramo za jedno mesto u desno */


x >>= 1;

/* Zapamceni poslednji bit stavljamo na pocetak broja x*/

x |= last_bit<<wl-1;
}

return x;
}

/* Funkcija obrce binarni zapis neoznacenog broja x tako sto bitove

68
4.29 Linearna i binarna pretraga 69

cita unatrag */
unsigned mirror(unsigned x)
{
int i;
int wl = sizeof(unsigned)*8;

/* Rezultat inicijalizujemo na poslednji bit broja x */


unsigned y = x & 1;

/* Postupak se ponavlja wl-1 puta */


for (i = 1; i<wl; i++)
{
/* x se pomera u desno za jedno mesto */
x >>= 1;
/* rezultat se pomera u levo za jedno mesto */
y <<= 1;

/* Poslednji bit broja x upisujemo na poslednje


mesto rezultata */
y |= x & 1;
}
return y;
}

main()
{
unsigned x = 0xFAF0FAF0;
print_bits(x);
print_bits(mirror(x));
print_bits(right_rotate(x, 2));
}

Izlaz iz programa:
11111010111100001111101011110000
00001111010111110000111101011111
00111110101111000011111010111100

4.29 Linearna i binarna pretraga


Primer 4.29.1 Linearna pretraga
#include <stdio.h>

/* Funkcija proverava da li se dati element x nalazi


u datom nizu celih brojeva.
Funkcija vraca poziciju u nizu na
kojoj je x pronadjen
odnosno -1 ukoliko elementa nema.
*/
int linearna_pretraga(int niz[], int br_elem, int x)

69
70 Milena Vujošević–Janičić

{
int i;
for (i = 0; i<br_elem; i++)
if (niz[i] == x)
return i;
/* nikako else */

return -1;
}

main()
{
/* Inicijalizacija niza moguca je
i na ovaj nacin*/
int a[] = {4, 3, 2, 6, 7, 9, 11};

/* Da bi smo odredili koliko clanova


ima niz mozemo koristiti operator
sizeof*/
int br_elem = sizeof(a)/sizeof(int);
int x;
int i;
printf("Unesite broj koji trazimo : ");
scanf("%d",&x);

i = linearna_pretraga(a, br_elem, x);


if (i == -1)
printf("Element %d nije nadjen\n",x);
else
printf("Element %d je nadjen na
poziciji %d\n",x, i);
}
Primer 4.29.2 Binarna pretraga niza
/* Binarna pretraga niza celih brojeva - iterativna verzija*/
#include <stdio.h>

/* Funkcija proverava da li se element x javlja unutar niza


celih brojeva a.
Funkcija vraca poziciju na kojoj je element nadjen odnosno
-1 ako ga nema.

!!!!! VAZNO !!!!!


Pretpostavka je da je niz a uredjen po velicini
*/

int binarna_pretraga(int a[], int n, int x)


{
/* Pretrazujemo interval [l, d] */
int l = 0;

70
4.30 Razni zadaci 71

int d = n-1;

/* Sve dok interval [l, d] nije prazan */


while (l <= d)
{
/* Srednja pozicija intervala [l, d] */
int s = (l+d)/2;

/* Ispitujemo odnos x i a[srednjeg elementa] */


if (x == a[s])
/* Element je pronadjen */
return s;
else if (x < a[s])
{
/* Pretrazujemo interval [l, s-1] */
d = s-1;
}
else
{
/* Pretrazujemo interval [s+1, d] */
l = s+1;
}
}

/* Element je nadjen */
return -1;
}

main()
{
int a[] = {3, 5, 7, 9, 11, 13, 15};
int x;
int i;

printf("Unesi element kojega trazimo : ");


scanf("%d",&x);
i = binarna_pretraga(a, sizeof(a)/sizeof(int), x);

if (i==-1)
printf("Elementa %d nema\n", x);
else
printf("Pronadjen na poziciji %d\n", i);
}

4.30 Razni zadaci


Primer 4.30.1 Obrtanje stringa i pretvaranje broja u string
#include <stdio.h>
#include <string.h>

71
72 Milena Vujošević–Janičić

/* reverse: obrce string, npr string "1234" postaje "4321" */


void reverse(char s[])
{
int c, i, j;

for (i = 0, j = strlen(s)-1; i < j; i++, j--)


{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}

/* itoa: konvertuje broj n u niz karaktera s */


void itoa(int n, char s[])
{
int i, sign;

if ((sign = n) < 0) /* sacuvaj znak */


n = -n; /* napravi da je n pozitivno */
i = 0;
do {
/* generisanje cifara u obrnutom smeru */
s[i++] = n % 10 + ’0’; /* izracunaj sledecu cifru */
} while ((n /= 10) > 0); /* izbaci cifru iz zapisa */
if (sign < 0)
s[i++] = ’-’;
s[i] = ’\0’;
reverse(s);
}

main()
{
int n=-44;
char nst[100];
itoa(n,nst);
printf("%s\n",nst);
}
Primer 4.30.2 btoi - konverzija iz datog brojnog sistema u dekadni.
#include <stdio.h>
#include <ctype.h>

/* Pomocna funkcija koja izracunava vrednost


koju predstavlja karakter u datoj osnovi
Funkcija vraca -1 ukoliko cifra nije validna.

Npr.
cifra ’B’ u osnovi 16 ima vrednost 11

72
4.30 Razni zadaci 73

cifra ’8’ nije validna u osnovi 6


*/

int digit_value(char c, int base)


{
/* Proveravamo obicne cifre */
if (isdigit(c) && c < ’0’+base)
return c-’0’;

/* Proveravamo slovne cifre za mala slova */


if (’a’<=c && c < ’a’+base-10)
return c-’a’+10;

/* Proveravamo slovne cifre za velika slova */


if (’A’<=c && c < ’A’+base-10)
return c-’A’+10;

return -1;
}

/* Funkcija izracunava vrednost celog broja koji je zapisan u datom


nizu karaktera u datoj osnovi. Za izracunavanje se koristi
Hornerova shema.
*/
int btoi(char s[], int base)
{
int sum = 0;

/* Obradjuju se karakteri sve dok su to validne cifre */


int i, vr;
for (i = 0; (vr = digit_value(s[i], base)) != -1; i++)
sum = base*sum + vr;

return sum;
}

main()
{
char bin[] = "11110000";
char hex[] = "FF";

printf("Dekadna vrednost binarnog broja %s je %d\n", bin, btoi(bin, 2));


printf("Dekadna vrednost heksadekadnog
broja %s je %d\n", hex, btoi(hex, 16));
}
Primer 4.30.3 Učitava linije sa ulaza i pamti najdužu liniju.
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */

73
74 Milena Vujošević–Janičić

int getline(char line[], int maxline);


void copy(char to[], char from[]);

/* print the longest input line */


main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */

max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
}

/* getline: read a line into s, return length */


int getline(char s[],int lim)
{
int c, i;

for (i=0; i < lim-1


&& (c=getchar())!=EOF && c!=’\n’;++i)
s[i] = c;
if (c == ’\n’) {
s[i] = c;
++i;
}
s[i] = ’\0’;
return i;
}

/* copy: copy ’from’ into ’to’;


assume to is big enough */
void copy(char to[], char from[])
{
int i;

i = 0;
while ((to[i] = from[i]) != ’\0’)
++i;
}

Primer 4.30.4 Konvertovanje stringa u broj u pokretnom zarezu.

74
4.30 Razni zadaci 75

#include <ctype.h>
#include <stdio.h>
#define MAXLINE 100

/* getline: get line into s, return length */


int getline(char s[], int lim)
{
int c, i;

i = 0;
while (--lim > 0 && (c=getchar()) != EOF && c != ’\n’)
s[i++] = c;
if (c == ’\n’)
s[i++] = c;
s[i] = ’\0’;
return i;
}

/* atof: convert string s to double */


double atof(char s[])
{
double val, power;
int i, sign;

/* skip white space */


for (i = 0; isspace(s[i]); i++)
;
/* Postavlja se znak broja*/
sign = (s[i] == ’-’) ? -1 : 1;

/* Preskace se jedno mesto ukoliko je bio upisan znak u broj*/


if (s[i] == ’+’ || s[i] == ’-’)
i++;

/* Racuna se vrednost broja dok se ne naidje na tacku */


for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - ’0’);

if (s[i] == ’.’)
i++;

/* Racuna se vrednost broja iza tacke*/


for (power = 1.0; isdigit(s[i]); i++)
{
val = 10.0 * val + (s[i] - ’0’);
power *= 10;
}
return sign * val / power;
}

75
76 Milena Vujošević–Janičić

/* Program sabira brojeve u pokretnom zarezu koji se unose sa ulaza*/


main()
{
double sum;
char line[MAXLINE];

sum = 0;
while (getline(line, MAXLINE) > 0)
printf("\t%g\n", sum += atof(line));
}

Primer 4.30.5 Funkcija koja uklanja znak c kad god se pojavi u stringu s.

#include <stdio.h>

void squeeze(char s[], char c)


{
int i,j;
for(i=j=0; s[i]!=’\0’;i++)
if(s[i]!=c) s[j++]=s[i];
s[j]=’\0’;
}

main()
{
char niz[20];
char c;

printf("Unesi karakter\n\n");
scanf("%c", &c);

scanf("%s", niz);
squeeze(niz, c);
printf("%s\n", niz);
}

4.31 Sortiranje
Primer 4.31.1 U prvom prolazu se razmenjuju vrednosti a[0] sa onim članovima
ostatka niza koji su veći od njega. Na taj način će se posle prvog prolaza kroz
niz a[0] postaviti na najveći element niza.

#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Niz od maksimalno MAXDUZ elemenata*/
int a[MAXDUZ];

76
4.31 Sortiranje 77

/* Dimenzija niza, pomocna i brojacke promenljive */


int n,pom,i,j;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje*/
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
pom=a[i];
a[i]=a[j];
a[j]=pom;
}

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

putchar(’\n’);

return 0;

}
Primer 4.31.2 sort2
Modifikacija prethodnog rešenja radi dobijanja na efikasnosti. Ne vrše se zamene
svaki put već samo jednom, kada se prona e odgovarajući element u nizu sa


kojim treba izvršiti zamenu tako da u nizu bude postavljen trenutno najveći
element na odgovarajuće mesto.
#include<stdio.h>
#define MAXDUZ 100

int main()
{

77
78 Milena Vujošević–Janičić

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

/* Dimenzija niza, indeks najveceg elementa


u i-tom prolazu,pomocna i brojacke promenljive */
int n,ind,pom,i,j;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje - bez stalnih zamena vec se


pronalazi indeks trenutno najveceg clana niza*/
for(i=0; i<n-1; i++)
{
for(ind=i,j=i+1; j<n; j++)
if(a[ind]<a[j])
ind=j;

/* Vrsi se zamena onda kada na i-tom mestu


nije najveci element. Tada se na i-to mesto
postavlja najveci element koji se nalazio na
mestu ind. */
if(i != ind)
{
pom=a[ind];
a[ind]=a[i];
a[i]=pom;
}
}
/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

return 0;

78
4.31 Sortiranje 79

}
Primer 4.31.3 bbsort1
Algoritam sortiranja buble sort poredi dva susedna elementa niza i ako su pogrešno
raspore eni zamenjuje im mesta. Posle pore enja svih susednih parova najmanji
 

od njih će isplivati na kraj niza. Zbog toga se ovaj metod naziva metod mehurića.
Da bi se najmanji broj nesortiranog dela niza doveo na svoje mesto treba ponoviti
postupak.
#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Dimenzija niza, pomocna promenljiva
i brojacke promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje */
for(i=n-1; i>0; i--)
for(j=0; j<i; j++)
if(a[j]<a[j+1])
{
pom=a[j];
a[j]=a[j+1];
a[j+1]=pom;
}

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

79
80 Milena Vujošević–Janičić

/* Stampa prazan red */


putchar(’\n’);

/*Regularan zavrsetak rada programa */


return 0;

}
Primer 4.31.4 bbsort2
Unapredjujemo prethodni algoritam kako bismo obezbedli da se ne vrše provere
onda kada je niz već sortiran nego da se u tom slučaju prekine rad.
#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Dimenzija niza, pomocna promenljiva
i brojacke promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

/* Promenljiva koja govori da li je izvrsena


zamena u i-tom prolazu kroz niz pa ako nije
sortiranje je zavrseno jer su svaka dva
susedna elementa niza u odgovarajucem poretku */
int zam;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

/*Sortiranje */
for(zam=1,i=n-1; zam && i>0; i--)
for(zam=0,j=0; j<i; j++)
if(a[j]<a[j+1])

80
4.31 Sortiranje 81

{
/* Zamena odgovarajucih clanova niza */
pom=a[j];
a[j]=a[j+1];
a[j+1]=pom;

/* Posto je u i-tom prolazu


izvrsena bar ova zamena zam
se postavlja na 1 sto
nastavlja sortiranje */
zam=1;
}

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

return 0;

}
Primer 4.31.5 isort
Insert sort, u svakom trenutku je početak niza sortiran a sortiranje se vrši tako
što se jedan po jedan element niza sa kraja ubacuje na odgovarajuće mesto.
#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Dimenzija niza, pomocna
i brojacke promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n!\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);

81
82 Milena Vujošević–Janičić

scanf("%d",&a[i]);
}

/*Sortiranje*/
for(i=1; i<n; i++)
for(j=i; (j>0) && (a[j]>a[j-1]); j--)
{
pom=a[j];
a[j]=a[j-1];
a[j-1]=pom;
}

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

putchar(’\n’);
return 0;
}
Primer 4.31.6 Binarno pretrazivanje
#include<stdio.h>
#define MAXDUZ 100

int main()
{
/* Dimenzija niza,pomocna i brojacke
promenljive */
int n,pom,i,j;

/* Niz od maksimalno MAXDUZ elemenata*/


int a[MAXDUZ];

/* Elemet koji se trazi i pozicija


na kojoj se nalazi- ukoliko je u nizu*/
int x,pozicija;

/* Pomocne promenljive za pretragu */


int donji, gornji, srednji;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

82
4.31 Sortiranje 83

/*Sortiranje*/
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]>a[j])
{
pom=a[i];
a[i]=a[j];
a[j]=pom;
}
/* Unos elementa binarne pretrage */
printf("Unesite element koji se trazi\n");
scanf("%d",&x);

donji = 0;
gornji = n-1;
pozicija = -1;

while(donji<=gornji)
{
srednji = (donji + gornji)/2;
if(a[srednji] == x)
{
pozicija = srednji;
break;
}
else
if(a[srednji] < x)
donji = srednji + 1;
else
gornji = srednji -1;
}

/* Ispis rezultata */
if(pozicija == -1)
printf("Trazeni broj se ne nalazi u nizu!\n");
else
printf("Broj %d se nalazi na %d poziciji
sortiranog niza! \n",x,pozicija+1);

putchar(’\n’);

return 0;
}
Primer 4.31.7 Sabiranje dva velika broja, njihovo pore enje, unos i ispis, množenje


velikog broja cifrom.

#include<stdio.h>

83
84 Milena Vujošević–Janičić

#define MAXDUZ 1000

int unos_broja(int cifre[], int maxduz)


{
int brcifara=0;
char c;

c=getchar();
while ( brcifara < maxduz && c >= ’0’ && c <= ’9’)
{
cifre[brcifara++]=c-’0’;
c=getchar();
}

return brcifara;
}

void obrni(int cifre[],int brcifara)


{
int i,pom;

for (i=0; i<brcifara/2; i++)


{
pom=cifre[i];
cifre[i]=cifre[brcifara-i-1];
cifre[brcifara-i-1]=pom;
}
}

void ispisi(int cifre[],int brcifara)


{ int i;
putchar(’\n’);
for (i=brcifara-1; i>=0; i--)
printf("%d",cifre[i]);
/* ili
putchar(cifre[i]+’0’);
*/
putchar(’\n’);
}

int jednaki(int cifre1[],int cifre2[],


int brcifara1, int brcifara2)
{
int i;
if (brcifara1 != brcifara2) return 0;

for (i=0; i<brcifara1; i++)


if (cifre1[i] != cifre2[i]) return 0;
return 1;
}

84
4.31 Sortiranje 85

int veci(int cifre1[], int brcifara1,


int cifre2[], int brcifara2)
{
int i;
if (brcifara1>brcifara2) return 1;
if (brcifara1<brcifara2) return 0;

for (i=brcifara1-1; i>=0; i--)


{
if (cifre1[i]<cifre2[i]) return 0;
if (cifre1[i]>cifre2[i]) return 1;
}

return 0;
}

int saberi(int cifre1[], int brcifara1,


int cifre2[], int brcifara2,
int cifre[])
{
int brcifara=0;
int i,pom,pamtim=0;

for(i=0; i<brcifara1 || i<brcifara2; i++)


{
pom =((i < brcifara1)? cifre1[i] : 0 )
+((i < brcifara2)? cifre2[i] : 0)
+ pamtim;

cifre[i] = pom%10;
pamtim = pom/10;
}
if (pamtim)
{
cifre[i]=pamtim;
brcifara=i+1;
}
else brcifara=i;

return brcifara;
}

int pomnozic(int c,int cifre[],


int brcifara, int pcifre[])
{
int pbrcifara=0;
int i,pamtim=0;

85
86 Milena Vujošević–Janičić

for (i=0; i<brcifara; i++)


{
pcifre[i]=(cifre[i]*c+pamtim)%10;
pamtim=(cifre[i]*c+pamtim)/10;
}
pbrcifara=brcifara;
if (pamtim)
{
pcifre[pbrcifara]=pamtim;
pbrcifara++;
}

return pbrcifara;
}

int main()
{
int d1,d2,d;
int broj1[MAXDUZ], broj2[MAXDUZ], zbir[MAXDUZ];
d1=unos_broja(broj1,MAXDUZ);
d2=unos_broja(broj2,MAXDUZ);

obrni(broj1,d1);
obrni(broj2,d2);
d=saberi(broj1,d1,broj2,d2,zbir);
ispisi(zbir,d);
return 0;
}

4.32 Rekurzija
C funkcije se mogu rekurzivno koristiti, što znači da funkcija može pozvati samu
sebe direktno ili indirektno.

Primer 4.32.1 Štampanje celog broja.


#include<stdio.h>
void printb(long int n)
{
if(n<0)
{
putchar(’-’);
n=-n;
}
if(n/10)
printb(n/10);
putchar(n % 10 + ’0’);
}

86
4.32 Rekurzija 87

int main()
{
long int b=-1234;
printb(b);
putchar(’\n’);
return 0;
}

Kad funkcija rekurzivno pozove sebe, svakim pozivom pojavljuje se novi skup
svih automatskih promenljivih, koji je nezavisan od prethodonog skupa. Prva
funkcija printb kao argument dobija broj -12345, ona prenosi 1234 u drugu printb
funkciju, koja dalje prenosi 123 u treću, i tako redom do poslednje koja prima
1 kao argument. Ta funkcija štampa 1 i završava sa radom tako da se vraća na
prethodni nivo, na kome se štampa dva i tako redom.

Primer 4.32.2 Računanje sume prvih n prirodnih brojeva.

#include<stdio.h>
int suma(int n)
{
if(n!=0)
return( n + suma(n-1) );
else return n;
}

main()
{
int S,n;
printf("Unesite n\n");
scanf("%d",&n);
S=suma(n);
printf("S=%d",S);
putchar(’\n’);
}

Primer 4.32.3 Računanje faktorijela prirodnog broja.

#include<stdio.h>
unsigned long fakt(int n)
{
if(n!=0)
return( n*fakt(n-1) );
else return 1;
}

main()
{
int n;
unsigned long f;
printf("Unesite n\n");
scanf("%d",&n);

87
88 Milena Vujošević–Janičić

f=fakt(n);
printf("f=%d",f);
putchar(’\n’);
}

Primer 4.32.4 Fibonačijevi brojevi.


#include<stdio.h>
int fibr(int n)
{
if((n==1)||(n==2))
return 1;
else return(fibr(n-1)+fibr(n-2));
}

int main()
{
int Fn,n;
printf("Unesite n\n");
scanf("%d",&n);
Fn=fibr(n);
printf("F[%d]=%d",n,Fn);
putchar(’\n’);
return 0;
}

Primer 4.32.5 Iterativna i rekurzivna varijanta računanja sume niza.


int suma_niza_iterativno(int a[], int n)
{
int suma = 0;
int i;
for (i = 0; i<n; i++)
suma+=a[i];
return suma;
}

int suma_niza(int a[], int n)


{
if (n == 1)
return a[0];
else
return suma_niza(a, n-1)+a[n-1];
}

Primer 4.32.6 Stepenovanje prirodnog broja


int stepenuj (int n, int k)
{
if (k == 0)
return 1;
else

88
4.33 Životni vek i oblast važenja promenjivih, statičke promenljive89

return n*stepenuj(n, k-1);


}

4.33 Životni vek i oblast važenja promenjivih,


statičke promenljive
Primer 4.33.1 Demonstracija životnog veka i oblasti važenja promenjivih (scope).

#include <stdio.h>

/* Globalna promenjiva */
int a = 0;

/* Uvecava se globalna promenjiva a */


void increase()
{
a++;
printf("increase::a = %d\n", a);
}

/* Umanjuje se lokalna promenjiva a.


Globalna promenjiva zadrzava svoju vrednost. */
void decrease()
{
/* Ovo a je nezavisna promenjiva u odnosu na globalno a */
int a = 0;
a--;
printf("decrease::a = %d\n", a);

void nonstatic_var()
{
/* Nestaticke promenjive ne cuvaju vrednosti kroz pozive funkcije */
int s=0;
s++;
printf("nonstatic::s=%d\n",s);
}

void static_var()
{
/* Staticke promenjive cuvaju vrednosti kroz pozive funkcije.
Inicijalizacija se odvija samo u okviru prvog poziva. */
static int s=0;
s++;
printf("static::s=%d\n",s);
}

main()

89
90 Milena Vujošević–Janičić

{
/* Promenjive lokalne za funkciju main */
int i;
int x = 3;

printf("main::x = %d\n", x);

for (i = 0; i<3; i++)


{
/* Promenjiva u okviru bloka je nezavisna od spoljne promenjive.
Ovde se koristi promenjiva x lokalna za blok petlje koja ima
vrednost 5, dok originalno x i dalje ima vrednost 3*/
int x = 5;
printf("for::x = %d\n", x);
}

/* U ovom bloku x ima vrednost 3 */


printf("main::x = %d\n", x);

increase();
decrease();

/* Globalna promenjiva a */
printf("main::a = %d\n", a);

/* Demonstracija nestatickih promenjivih */


for (i = 0; i<3; i++)
nonstatic_var();

/* Demonstracija statickih promenjivih */


for (i = 0; i<3; i++)
static_var();
}

Izlaz iz programa:
main::x = 3
for::x = 5
for::x = 5
for::x = 5
main::x = 3
increase::a = 1
decrease::a = -1
main::a = 1
nonstatic::s=1
nonstatic::s=1
nonstatic::s=1
static::s=1
static::s=2
static::s=3

90
4.34 Pokazivači 91

Primer 4.33.2 Ilustracija statičkih promenljivih.

#include <stdio.h>

void f()
{
static int a;
a++;
printf("%d\n",a);
}

main()
{
int i;
for (i=0; i<=10; i++)
f();
}

/* Izlaz iz programa 1 2 3 4 5 6 7 8 9 10 11*/

4.34 Pokazivači
Pokazivač je promenljiva koja sadrži adresu promenljive.

int x=1, y=1, z[10];


int *ip; /* ip je pokazivac na int,
odnosno *ip je tipa int*/

ip = &x; /* ip sada pokazuje na x */


y=*ip; /* y je sada 1 */
*ip = 0; /* x je sada 0 */

*ip+=10; /* x je sada 10*/


++*ip; /* x je sada 11*/
(*ip)++; /* x je sada 12,
zagrada neophodna zbog prioriteta
operatora*/

ip = &z[0]; /* ip sada pokazuje na z[0]*/

Primer 4.34.1 Ilustracija rada sa pokazivačkim promenljivim.

#include <stdio.h>
main()
{
int x = 3;

/* Adresu promenjive x zapamticemo u novoj promeljivoj.


Nova promenljiva je tipa pokazivaca na int (int*) */
int* px;

91
92 Milena Vujošević–Janičić

printf("Adresa promenljive x je : %p\n", &x);


printf("Vrednost promenljive x je : %d\n", x);

px = &x;
printf("Vrednost promenljive px je (tj. px) : %p\n", px);
printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);

/* Menjamo vrednost promenljive na koju ukazuje px */


*px = 6;
printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);

/* Posto px sadrzi adresu promenljive x, ona ukazuje na x tako da je


posredno promenjena i vrednost promenljive x */
printf("Vrednost promenljive x je : %d\n", x);

Izlaz (u konkretnom slucaju):


Adresa promenljive x je : 0012FF88
Vrednost promenljive x je : 3
Vrednost promenljive px je (tj. px) : 0012FF88
Vrednost promenljive na koju ukazuje px (tj. *px) je : 3
Vrednost promenljive na koju ukazuje px (tj. *px) je : 6
Vrednost promenljive x je : 6

Pored pokazivača na osnovne tipove, postoji i pokazivač na prazan tip (void).

void *pp;

Njemu može da se dodeli da pokazuje na int, ili na char ili na proizvoljan tip ali
je to neophodno eksplicitno naglasiti svaki put kada želimo da koristimo ono na
šta on pokazuje.

Primer 4.34.2 Upotreba pokazivača na prazan tip.

#include<stdio.h>

main()
{
void *pp;
int x=2;
char c=’a’;

pp = &x;
*(int *)pp = 17; /* x postaje 17*/
printf("\n adresa od x je %p", &x);
printf("\n%d i %p",*(int*)pp,(int * )pp);

pp = &c;
printf("\n adresa od c je %p", &c);

92
4.35 Pokazivači i argumenti funkcija 93

printf("\n%c i %p",*(char*)pp,(char * )pp);

/*
adresa od x je 0012FF78
17 i 0012FF78
adresa od c je 0012FF74
a i 0012FF74
*/

Posebna konstanta koja se koristi da se označi da pokazivač ne pokazuje na


neko mesto u memoriji je NULL.

4.35 Pokazivači i argumenti funkcija


C prosle uje argumente u funkcije pomoću vrednosti. To znači da sledeća
funkcija neće uraditi ono što želimo:

void swap (int x, int y) /* POGRESNO!!!!!!!!*/


{
int temp;
temp = x;
x=y;
y=temp;
}

Zbog prenosa parametara preko vrednosti swap ne može da utiče na argu-


mente a i b u funkciji koja je pozvala swap. Ova swap funkcija samo zamenjuje
kopije od a i b.
Da bi se dobio željeni efekat, potrebno je da se proslede pokazivači:

/* Zameni *px i *py */


void swap (int *px, int *py)
{
int temp;
temp =*px;
*px = *py;
*py = temp;
}

a poziv funkcije swap izlgeda sada ovako

swap(&a, &b);

Primer 4.35.1 Demonstracija više povratnih vrednosti funkcije koristeći prenos


preko pokazivača.

/* Funkcija istovremeno vraca dve vrednosti - kolicnik i ostatak


dva data broja. Ovo se postize tako sto se funkciji predaju
vrednosti dva broja (x i y) koji se dele

93
94 Milena Vujošević–Janičić

i adrese dve promenljive na koje ce se smestiti rezultati */

void div_and_mod(int x, int y, int* pdiv, int* pmod)


{
printf("Kolicnik postavljam na adresu : %p\n", pdiv);
printf("Ostatak postavljam na adresu : %p\n", pmod);
*pdiv = x / y;
*pmod = x % y;
}

main()
{
int div, mod;
printf("Adresa promenljive div je %p\n", &div);
printf("Adresa promenljive mod je %p\n", &mod);

/* Pozivamo funkciju tako sto joj saljemo


vrednosti dva broja (5 i 2)
i adrese promenljvih div i mod na koje
ce se postaviti rezultati */
div_and_mod(5, 2, &div, &mod);

printf("Vrednost promenljive div je %d\n", div);


printf("Vrednost promenljive mod je %d\n", mod);

Izlaz u konkretnom slucaju:


Adresa promenljive div je 0012FF88
Adresa promenljive mod je 0012FF84
Kolicnik postavljam na adresu : 0012FF88
Ostatak postavljam na adresu : 0012FF84
Vrednost promenljive div je 2
Vrednost promenljive mod je 1

4.36 Pokazivači i nizovi (polja)


U C-u postoji čvrsta veza izme u pokazivača i nizova. Bilo koja operacija koja
se može ostvariti dopisivanjem indeksa niza može se uraditi i sa pokazivačima.
Deklaracija
int a[10];
definiše niz a veličine 10 koji predstavlja blok od 10 uzastopnih objekata
nazvanih a[0], a[1], ..., a[9]. Notacija a[i] odgovara i-tom elementu
niza.
Ako je pa pokazivač na ceo broj
int *pa;
tada iskaz pa = &a[0];
podešava da pa pokaže na nulti element niza a, odnosno pa sadrži adresu od
a[0].

94
4.36 Pokazivači i nizovi (polja) 95

Ako pa pokazuje na odre eni element polja, onda po definiciji pa+1 pokazuje
na sledeći element, pa+i pokazuje na i-ti element posle pa. Stoga, ako pa
pokazuje na a[0] tada
*(pa+1)
se odnosi na sadržaj od a[1].
pa+i je adresa od a[i], a
*(pa+i)
je sadržaj od a[i]. Dozvoljeno je upotrebljavati i sintaksu kao kod nizova:
*(pa+i) <==> pa[i]
Ovo sve važi bez obzira na tip ili veličinu elemenata u polju a.
Iskaz pa=&a[0] se može napisati kao pa=a jer je ime niza sinonim za
lokaciju početnog elementa.

Primer 4.36.1 Veza izme u pokazivača i nizova.




#include <stdio.h>

void print_array(int* pa, int n);

main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int num_of_elements = sizeof(a)/sizeof(int);
int* pa;

/* Niz je isto sto i adresa prvog elementa */


printf("Niz a : %p\n", a);
printf("Adresa prvog elementa niza a (&a[0]) : %p\n", &a[0]);
/* Niz a : 0012FF5C
Adresa prvog elementa niza a (&a[0]) : 0012FF5C */

/* Moguce je dodeliti niz pokazivacu odgovarajuceg tipa */


pa = a;

printf("Pokazivac pa ukazuje na adresu : %p\n", pa);


/* Pokazivac pa ukazuje na adresu : 0012FF5C */

/* Nizu nije moguce dodeliti pokazivacku promenljivu


(nizove mozemo smatrati KONSTANTNIM pokazivacima na prvi element) */
/* a = pa; */

/* Pokazivace je dalje moguce indeksirati kao nizove */


printf("pa[0] = %d\n", pa[0]);
printf("pa[5] = %d\n", pa[5]);
/* pa[0] = 1
pa[5] = 6 */

/* Medjutim, sizeof(pa) je samo velicina pokazivaca, a ne niza */


printf("sizeof(a) = %d\n", sizeof(a));
printf("sizeof(pa) = %d\n", sizeof(pa));

95
96 Milena Vujošević–Janičić

/* sizeof(a) = 40
sizeof(pa) = 4 */

/* Pozivamo funkciju za stampanje niza i saljemo joj niz */


print_array(a, num_of_elements);
/* 1 2 3 4 5 6 7 8 9 10 */

/* Pozivamo funkciju za stampanje niza


i saljemo joj pokazivac na pocetak niza */
print_array(pa, num_of_elements);
/* 1 2 3 4 5 6 7 8 9 10 */
}

/* Prosledjivanje niza u funkciju


void print_array(int pa[], int n);
je ekvivalentno prosledjivanju pokazivaca u funkciju
void print_array(int* pa, int n);
Izmedju ovih konstrukcija nema nikakve razlike!
*/
void print_array(int* pa, int n)
{
int i;
for (i = 0; i<n; i++)
printf("%d ", pa[i]);
putchar(’\n’);
}

Prilikom deklaracije treba praviti razliku izme u niza znakova i pokazivača:


char poruka[]="danas je lep dan!";
char *pporuka = "danas je lep dan!";
poruka je niz znakova koji sadrži dati tekst. Pojedine znake moguće je promeniti
ali se poruka uvek odnosi na isto mesto u memoriji.
pporuka je pokazivač, koji je inicijalizovan da pokazuje na konstantnu nisku, on
može biti preusmeren da pokazuje na nešto drugo, ali rezultat neće biti definisan
ako pokušate da modifikujete sadržaj niske (jer je to konstantna niska).
Ako deklarišemo
char *pporuka1 = "danas je lep dan!";
char *pporuka2 = "danas je lep dan!";
char *pporuka3 = "danas pada kisa";
tada će pokazivači pporuka1 i pporuka2 pokazivati na isto mesto u memoriji, a
pporuka3 na neko drugo mesto u memoriji.
Ako uporedimo (pporuka1==pporuka3) uporediće se vrednosti pokazivača.
Ako uporedimo (pporuka1 < pporuka2) uporediće se vrednosti pokazivača. Ako
dodelimo pporuka1=pporuka3 tada će pporuka1 dobiti vrednost pokazivača
pporuka3 i pokazivaće na isto mesto u memoriji. Neće se izvršiti kopiranje
sadržaja memorije!!!

Primer 4.36.2 Vežba pokazivačke aritmetike.

96
4.36 Pokazivači i nizovi (polja) 97

#include <stdio.h>

/* Funkcija pronalazi x u nizu niz date dimenzije,


bez koriscenja indeksiranja. Funkcija vraca pokazivac na
poziciju pronadjenog elementa. */

int* nadjiint(int* niz, int n, int x)


{
while (--n >= 0 && *niz!=x)
niz++;

return (n>=0)? niz: NULL;


}

main()
{
int a[]={1,2,3,4,5,6,7,8};
int* poz=nadjiint(a,sizeof(a)/sizeof(int),4);

if (poz!=NULL)
printf("Element pronadjen na poziciji %d\n",poz-a);
}
Primer 4.36.3
int strlen(char *s)
{
int n;
for(n=0; *s != ’\0’; s++) n++;
return n;
}

Primer 4.36.4
/* Funkcija kopira string t u string s */
void copy(char* s, char* t)
{
while (*s++=*t++)
;
}

/* Ovo je bio skraceni zapis za sledeci kod


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

*/

97
98 Milena Vujošević–Janičić

Primer 4.36.5
/* Vrsi leksikografsko poredjenje dva stringa.
Vraca :
0 - ukoliko su stringovi jednaki
<0 - ukoliko je s leksikografski ispred t
>0 - ukoliko je s leksikografski iza t
*/
int string_compare1(char *s, char *t)
{
/* Petlja tece sve dok ne naidjemo
na prvi razliciti karakter */
for (; *s == *t; s++, t++)
if (*s == ’\0’) /* Naisli smo na kraj
oba stringa, a nismo nasli razliku */
return 0;

/* *s i *t su prvi karakteri u kojima


se niske razlikuju.
Na osnovu njihovog odnosa,
odredjuje se odnos stringova */

return *s - *t;
}

/* Mozemo koristiti i sintaksu kao kod nizova */


int string_compare2(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];
}

Primer 4.36.6 Pronalazi prvu poziciju karaktera c u stringu s, i vraća pokazivač


na nju, odnosno NULL ukoliko s ne sadrži c.

char* string_char(char *s, char c)


{
int i;
for (; *s; s++)
if (*s == c)
return s;

/* Nije nadjeno */
return NULL;
}

Primer 4.36.7 Pronalazi poslednju poziciju karaktera c u stringu s, i vraća


pokazivač na nju, odnosno NULL ukoliko s ne sadrži c.

98
4.36 Pokazivači i nizovi (polja) 99

char* string_last_char(char *s, char c)


{
char *t = s;
/* Pronalazimo kraj stringa s */
while (*t++)
;

/* Krecemo od kraja i trazimo c unazad */


for (t--; t >= s; t--)
if (*t == c)
return t;

/* Nije nadjeno */
return NULL;
}

Primer 4.36.8
#include <stdio.h>

/* proverava da li se niska t nalazi unutar niske s*/


int sadrzi_string(char s[], char t[])
{
int i;
for (i = 0; s[i]; i++)
{
int j;
for (j=0, k=0; s[i+j]==t[j]; j++)
if (t[j+1]==’\0’)
return i;
}
return -1;
}

/* Verzija funkcije strstr implementirane bez


koriscenja indeksiranja */
/* proverava da li se niska t nalazi unutar niske s*/
char* sadrzi_string_pok(char* s, char* t)
{
while(*s)
{
char *i, *j;
for (i = s, j = t; *i == *j; i++,j++)
if (*(j+1)==’\0’)
return s;
s++;
}
return NULL;
}

/* Cita liniju sa stadnardnog ulaza i

99
100 Milena Vujošević–Janičić

vraca njenu duzinu */


int getline(char* line, int max)
{
char *s=line;
int c;
while ( max-->0 && (c=getchar())!=’\n’ && c!=EOF)
*s++ = c;

if (c==’\n’)
*s++ = c;

*s = ’\0’;
return s - line;
}

main()
{
char rec[]="zdravo";
char linija[100];
while (getline(linija, 100))
if (sadrzi_string_pok(linija, rec))
printf("%s",linija);
}

4.37 Alokacija memorije


void* malloc(size_t n) vraća pokazivač na n bajtova neinicijalizovane mem-
orije ili NULL ukoliko zahtev ne može da se ispuni.
Za njeno korišćenje neophodno je uključiti zaglavlje stdlib.h. Osloba anje
memorije - funkcija free.
Ne sme se koristiti nešto što je već oslobo eno, ne sme se dva puta osloba ati
ista memorija.

Primer 4.37.1
#include <stdio.h>
#include <stdlib.h>

main()
{
int n;
int i;
int *a;

printf("Unesi broj clanova niza : ");


scanf("%d", &n);

/* Kao da ste mogli da uradite

100
4.37 Alokacija memorije 101

int a[n];
*/
a = (int*)malloc(n*sizeof(int));

/* Kad god se vrsi alokacija memorije mora se proveriti da li je ona


uspesno izvrsena!!! */
if (a == NULL)
{
printf("Nema slobodne memorije\n");
exit(1);
}

/* Od ovog trenutka a koristim kao obican niz */


for (i = 0; i<n; i++)
scanf("%d",&a[i]);

/* Stampamo niz u obrnutom redosledu */


for(i = n-1; i>=0; i--)
printf("%d",a[i]);

/* Oslobadjamo memoriju*/
free(a);
}
Primer 4.37.2 Demonstracija funkcije calloc - funkcija inicijalizuje sadrzaj
memorije na 0.
#include <stdio.h>
#include <stdlib.h>

main()
{
int *m, *c, i, n;

printf("Unesi broj clanova niza : ");


scanf("%d", &n);

/* Niz m NE MORA garantovano da ima sve nule */


m = malloc(n*sizeof(int));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

/* Niz c MORA garantovano da ima sve nule */


c = calloc(n, sizeof(int));
if (c == NULL) {
printf("Greska prilikom alokacije memorije!\n");
free(m);
exit(1);
}

101
102 Milena Vujošević–Janičić

for (i = 0; i<n; i++)


printf("m[%d] = %d\n", i, m[i]);

for (i = 0; i<n; i++)


printf("c[%d] = %d\n", i, c[i]);

free(m);
free(c);
}

4.38 Niz pokazivača


Primer 4.38.1
#include <stdio.h>
#include <stdlib.h>
main()
{
/* Niz od tri elemenata tipa int*/
int nizi[3];

/* Niz od tri elemenata tipa int*, dakle


niz od tri pokazivaca na int*/
int* nizip[3];

/* Alociramo memoriju za prvi element niza*/


nizip[0] = (int*) malloc(sizeof(int));
if (nizip[0] == NULL)
{
printf("Nema slobodne memorije\n");
exit(1);
}
/* Upisujemo u prvi element niza broj 5*/
*nizip[0] = 5;
printf("%d", *nizip[0]);

/* Alociramo memoriju za drugi element niza.


Drugi element niza pokazuje na niz od dva
elementa*/
nizip[1] = (int*) malloc(2*sizeof(int));
if (nizip[1] == NULL) {
printf("Nema slobodne memorije\n");
free(nizip[0]);
exit(1);
}

/* Pristupamo prvom elementu na koji pokazuje


pokazivac nizip[1]*/
*(nizip[1]) = 1;

102
4.38 Niz pokazivača 103

/* Pristupamo sledecem elementu u nizu na koji pokazuje


nizip[1].
*/
*(nizip[1] + 1) = 2;

printf("%d", nizip[1][1]);

/* Alociramo memoriju za treci element niza nizip. */


nizip[2] = (int*) malloc(sizeof(int));
if (nizip[2] == NULL) {
printf("Nema slobodne memorije\n");
free(nizip[0]);
free(nizip[1]);
exit(1);
}

*(nizip[2]) = 2;

printf("%d", *(nizip[2]));

free(nizip[0]);
free(nizip[1]);
free(nizip[2]);
}

Primer 4.38.2
#include <stdio.h>
#include <stdlib.h>
main()
{
/* Niz karaktera*/
char nizc[5];

/* Niz karaktera od cetiri elementa


(’A’, ’n’, ’a’, ’\0’)*/
char nizcc[]="Ana";
printf("%s", nizcc);

/* Niz od tri pokazivaca. Prvi pokazuje na


nisku karaktera Kruska, drugi na nisku karaktera
Sljiva a treci na Ananas. */
char* nizcp[]={"Kruska", "Sljiva", "Ananas"};

printf("%s", nizcp[0]);
printf("%s", nizcp[1]);
printf("%s", nizcp[2]);
}

103
104 Milena Vujošević–Janičić

4.39 Pokazivači na funkcije


Primer 4.39.1 Program demonstrira upotrebu pokazivača na funkcije.

#include <stdio.h>

int kvadrat(int n)
{
return n*n;
}

int kub(int n)
{
return n*n*n;
}

int parni_broj(int n)
{
return 2*n;
}

/* Funkcija izracunava sumu od 1 do n f(i),


gde je f data funkcija */
int sumiraj(int (*f) (int), int n)
{
int i, suma=0;
for (i=1; i<=n; i++)
suma += (*f)(i);

return suma;
}

main()
{
printf("Suma kvadrata brojeva od jedan do 3 je %d\n", sumiraj(kvadrat,3));
printf("Suma kubova brojeva od jedan do 3 je %d\n", sumiraj(kub,3));
printf("Suma prvih pet parnih brojeva je %d\n", sumiraj(parni_broj,5));
}
/*Izlaz:
Suma kvadrata brojeva od jedan do 3 je 14
Suma kubova brojeva od jedan do 3 je 36
Suma prvih pet parnih brojeva je 30
*/

4.40 Matrice
Primer 4.40.1 Statička alokacija prostora za matricu.

#include <stdio.h>

104
4.40 Matrice 105

main()
{
int a[3][3] = {{0, 1, 2}, {10, 11, 12}, {20, 21, 22}};
int i, j;

/* Alternativni unos elemenata matrice


for(i=0; i<3; i++)
for(j=0; j<3; j++)
{
printf("a[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
*/

a[1][1] = a[0][0] + a[2][2];


/* a[1][1] = 0 + 22 = 22 */

printf("%d\n", a[1][1]); /* 22 */

/* Stampanje elemenata matrice*/


for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
printf("%d\t", a[i][j]);
printf("\n");
}
}

Nama je potrebno da imamo veću fleksibilnost, tj da se dimenzije matrice


mogu uneti kao parametri našeg programa. Zbog toga je neophodno koristiti
dinamicku alokaciju memorije.

Primer 4.40.2 Implementacija matrice preko niza.


#include <stdlib.h>
#include <stdio.h>

/* Makro pristupa clanu na poziciji i, j matrice koja ima


m vrsta i n kolona */
#define a(i,j) a[(i)*n+(j)]

main()
{
/* Dimenzije matrice */
int m, n;

/* Matrica */
int *a;

int i,j;

105
106 Milena Vujošević–Janičić

/* Suma elemenata matrice */


int s=0;

/* Unos i alokacija */
printf("Unesi broj vrsta matrice : ");
scanf("%d",&m);

printf("Unesi broj kolona matrice : ");


scanf("%d",&n);

a=malloc(m*n*sizeof(int));
if (a == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<m; i++)


for (j=0; j<n; j++)
{
printf("Unesi element na poziciji (%d,%d) : ",i,j);
scanf("%d",&a(i,j));
}

/* Racunamo sumu elemenata matrice */


for (i=0; i<m; i++)
for (j=0; j<n; j++)
s+=a(i,j);

/* Ispis unete matrice */


printf("Uneli ste matricu : \n");
for (i=0; i<m; i++)
{ for (j=0; j<n; j++)
printf("%d ",a(i,j));
printf("\n");
}

printf("Suma elemenata matrice je %d\n", s);

/* Oslobadjamo memoriju */
free(a);
}
Primer 4.40.3 Program ilustruje rad sa kvadratnim matricama i relacijama.
Elementi i je u relaciji sa elementom j ako je m[i][j] = 1, a nisu u relaciji ako
je m[i][j] = 0.
#include <stdlib.h>
#include <stdio.h>

/* Dinamicka matrica je odredjena adresom


pocetka niza pokazivaca i dimenzijama tj.

106
4.40 Matrice 107

int** a;
int m,n;
*/

/* Alokacija kvadratne matrice nxn */


int** alociraj(int n)
{
int** m;
int i;
m=malloc(n*sizeof(int*));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<n; i++)


{
m[i]=malloc(n*sizeof(int));
if (m[i] == NULL)
{
int k;
printf("Greska prilikom alokacije memorije!\n");
for(k=0;k<i;k++)
free(m[k]);
free(m);
exit(1);
}
}

return m;
}

/* Dealokacija matrice dimenzije nxn */


void obrisi(int** m, int n)
{
int i;
for (i=0; i<n; i++)
free(m[i]);
free(m);
}

/* Ispis matrice /
void ispisi_matricu(int** m, int n)
{
int i, j;
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf("%d ",m[i][j]);
printf("\n");

107
108 Milena Vujošević–Janičić

}
}

/* Provera da li je relacija predstavljena matricom refleksivna */


int refleksivna(int** m, int n)
{
int i;
for (i=0; i<n; i++)
if (m[i][i]==0)
return 0;

return 1;
}

/* Provera da li je relacija predstavljena matricom simetricna */


int simetricna(int** m, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=i+1; j<n; j++)
if (m[i][j]!=m[j][i])
return 0;
return 1;
}

/* Provera da li je relacija predstavljena matricom tranzitivna*/


int tranzitivna(int** m, int n)
{
int i,j,k;

for (i=0; i<n; i++)


for (j=0; j<n; j++)
for (k=0; k<n; k++)
if ((m[i][j]==1)
&& (m[j][k]==1)
&& (m[i][k]!=1))
return 0;
return 1;
}

/* Pronalazi najmanju simetricnu relaciju koja sadrzi relaciju a */


void simetricno_zatvorenje(int** a, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{
if (a[i][j]==1 && a[j][i]==0)
a[j][i]=1;
if (a[i][j]==0 && a[j][i]==1)

108
4.40 Matrice 109

a[i][j]=1;
}
}

main()
{
int **m;
int n;
int i,j;

printf("Unesi dimenziju matrice : ");


scanf("%d",&n);
m=alociraj(n);

for (i=0; i<n; i++)


for (j=0; j<n; j++)
scanf("%d",&m[i][j]);

printf("Uneli ste matricu : \n");

ispisi_matricu(m,n);

if (refleksivna(m,n))
printf("Relacija je refleksivna\n");
if (simetricna(m,n))
printf("Relacija je simetricna\n");
if (tranzitivna(m,n))
printf("Relacija je tranzitivna\n");

simetricno_zatvorenje(m,n);

ispisi_matricu(m,n);

obrisi(m,n);
}
Primer 4.40.4 Izračunati vrednost determinante matrice preko Laplasovog razvoja.
#include <stdio.h>
#include <stdlib.h>

/* Funkcija alocira matricu dimenzije nxn */


int** allocate(int n)
{
int **m;
int i;
m=(int**)malloc(n*sizeof(int*));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

109
110 Milena Vujošević–Janičić

for (i=0; i<n; i++)


{
m[i]=malloc(n*sizeof(int));
if (m[i] == NULL)
{
int k;
for(k=0;k<i;k++)
free(m[k]);
printf("Greska prilikom alokacije memorije!\n");
free(m);
exit(1);
}
}

return m;
}

/* Funkcija vrsi dealociranje date matrice dimenzije n */


void deallocate(int** m, int n)
{
int i;
for (i=0; i<n; i++)
free(m[i]);
free(m);
}

/* Funkcija ucitava datu alociranu matricu sa standardnog ulaza */


void ucitaj_matricu(int** matrica, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
scanf("%d",&matrica[i][j]);
}

/* Rekurzivna funkcija koja vrsi Laplasov razvoj */


int determinanta(int** matrica, int n)
{
int i;
int** podmatrica;
int det=0,znak;

/* Izlaz iz rekurzije je matrica 1x1 */


if (n==1) return matrica[0][0];

/* Podmatrica ce da sadrzi minore polazne matrice */


podmatrica=allocate(n-1);
znak=1;
for (i=0; i<n; i++)

110
4.41 Strukture 111

{
int vrsta,kolona;
for (kolona=0; kolona<i; kolona++)
for(vrsta=1; vrsta<n; vrsta++)
podmatrica[vrsta-1][kolona] = matrica[vrsta][kolona];
for (kolona=i+1; kolona<n; kolona++)
for(vrsta=1; vrsta<n; vrsta++)
podmatrica[vrsta-1][kolona-1] = matrica[vrsta][kolona];

det+= znak*matrica[0][i]*determinanta(podmatrica,n-1);
znak*=-1;
}
deallocate(podmatrica,n-1);
return det;
}

main()
{
int **matrica;
int n;

scanf("%d", &n);
matrica = allocate(n);
ucitaj_matricu(matrica, n);
printf("Determinanta je : %d\n",determinanta(matrica,n));
deallocate(matrica, n);
}

4.41 Strukture
Informacije kojima se opisuje realni svet retko se predstavljaju u elementarnoj
formi u vidu celih, realnih, znakovnih konstanti itd. Mnogo češće imamo posla
sa složenim objektima koji se sastoje od elemenata raznih tipova. Na primer
jednu osobu karakterišu ime, prezime, datum i mesto ro enja.
Struktura predstavlja skup podataka kojim se opisuju neka bitna svojstva
objekta. Komponente koje obrazuju strukturu nazivaju se elementi strukture.
Sintaksa strukture:

struct ime_strukture
{
tip ime_elementa1;
tip ime_elementa2;
...
};

Primer 4.41.1 Primer jednostavne strukture.

struct licnost
{
char ime[31];

111
112 Milena Vujošević–Janičić

char adresa[41];
unsigned starost;
};

struct licnost osoba1, osoba2;

Deklaraciju osobe1 i osobe2 mogli smo da zapišemo i na sledeći način


struct licnost
{
char ime[31];
char adresa[41];
unsigned starost;
} osoba1, osoba2;
Ukoliko nemamo potrebu da se ličnost koristi dalje u programu mogu se
napraviti dve osobe bez davanja imena strukturi:

struct
{
char ime[31];
char adresa[41];
unsigned starost;
} osoba1, osoba2;

Kada imamo promenljivu strukturnog tipa tada elementima date strukture


pristupamo uz pomoc operatora ’.’.

Primer 4.41.2
osoba1.starost=20;
osoba2.starost=21;
...
if (osoba1.starost == osoba2.starost)
printf(" Osobe su iste starosti");

Dozvoljeno je praviti nizove struktura. Npr. niz od 20 elemenata koji sadrži


ličnosti:
struct licnost nizLicnosti[20];
Tada da bi pročitali starost neke ličnosti u nizu pišemo:
nizLicnosti[5].starost
Može se definisati pokazivač na strukturu.
struct licnost *posoba;
Tada se pristupanje elementima strukture može vršiti upotrebom operatora ’.’
na standardni način:
(*posoba).ime
(*posoba).adresa
(*posoba).starost

112
4.41 Strukture 113

ili korišćenjem specijalnog operatora 0 − >0 na sledeći način:

posoba->ime
posoba->adresa
posoba->starost

Primer 4.41.3 Elementi strukture mogu da budu i druge strukture.

struct datum
{
unsigned dan;
unsigned mesec;
unsigned godina;
};

struct licnost
{
char ime[30];
struct datum datumrodjenja;
};

Sada se danu, mesecu i godini datuma rodjenja pristupa na sledeći način:

osoba.datumrodjenja.dan = 10;
osoba.datumrodjenja.mesec = 5;
osoba.datumrodjenja.godina = 1986;

4.41.1 Operator typedef


Operator typedef omogućava nam da definišemo naša imena za neki od osnovih
ili izvedenih tipova. Na primer, možemo da uradimo sledeće:

typedef double RealanBroj;

Nakon ovoga možemo u tekstu deklarista promenljivu x kao RealanBroj, ona će
zapravo biti tipa double.

RealanBroj x; /* Umesto: double x;*/

Ili, ako želimo da skratimo pisanje za neoznačene duge brojeve tj za unsigned


long int to možemo da uradimo na sledeći način

typedef unsigned long int VelikiBroj;

Sada u kodu možemo da koristimo VelikiBroj kao tip.


Operator typedef je naročito pogodan da bi se izbeglo ponavljalnje reči struct
pri deklarisanju strukturnih promenljivih.

typedef struct _licnost licnost;

Sada deklaracija može da bude:

licnost osoba1, osoba2;


/* umesto: struct _licnost osoba1, osoba2; */

113
114 Milena Vujošević–Janičić

Kao skraćen zapis za

struct _tacka {
float x;
float y;
}

typedef struct _tacka tacka;

može se koristiti:

typedef struct _tacka


{
float x;
float y;
} tacka;

Primer 4.41.4 Struktura artikal.


typedef struct _artikal
{
long bar_kod;
char ime[MAX_IME];
float pdv;
} artikal;

Primer 4.41.5 Program ilustruje osnovne geometrijske algoritme kao i rad sa


strukturama.

#include <math.h>
#include <stdio.h>

typedef struct _tacka


{
float x;
float y;
} tacka;

typedef struct _vektor


{
float x, y;
} vektor;

/* Koordinatni pocetak */
tacka kp={0.0,0.0};

/* Niz tacaka */
tacka niz[100];

/* Pokazivac na strukturu tacke */


tacka *pt;

114
4.41 Strukture 115

void IspisiTacku(tacka A)
{
printf("(%f,%f)\n",A.x,A.y);
}

void IspisiVektor(vektor v)
{
printf("(%f,%f)\n",v.x,v.y);
}

float duzina(vektor v)
{
return sqrt(v.x*v.x+v.y*v.y);
}

vektor NapraviVektor(tacka *pA, tacka *pB)


{
vektor ab;
ab.x=pB->x - pA->x;
ab.y=pB->y - pA->y;
return ab;
}

float rastojanje(tacka A, tacka B)


{
float dx=B.x - A.x;
float dy=B.y - A.y;
return sqrt(dx*dx+dy*dy);
}

/* Heronov obrazac */
float PovrsinaTrougla(tacka A, tacka B, tacka C)
{
float a=rastojanje(B,C);
float b=rastojanje(A,C);
float c=rastojanje(A,B);

float s=(a+b+c)/2.0;
return sqrt(s*(s-a)*(s-b)*(s-c));
}

float PovrsinaKonveksnogPoligona(tacka poligon[], int br_temena)


{
int i;
float povrsina=0.0;
for (i=1; i<br_temena-1; i++)
povrsina+=PovrsinaTrougla(poligon[0], poligon[i], poligon[i+1]);

return povrsina;
}

115
116 Milena Vujošević–Janičić

float Obim(tacka poligon[], int br_temena)


{
int i;
float o=0;

for (i=0; i<br_temena-1; i++)


o+=rastojanje(poligon[i], poligon[i+1]);

o+=rastojanje(poligon[0], poligon[br_temena-1]);
return o;
}

main()
{
tacka poligon[]={{0.0,0.0},
{0.0,1.0},
{1.0,1.0},
{1.0,0.0}};
printf("Obim poligona je %f\n",Obim(poligon,4));
printf("Povrsina poligona je %f\n",
PovrsinaKonveksnogPoligona(poligon,4));
}
Primer 4.41.6 Program koji učitava niz studenata i sortira ih po njihovim
ocenama.
#include <stdio.h>
#include <ctype.h>

#define MAX_IME 20

typedef struct _student


{
char ime[MAX_IME];
char prezime[MAX_IME];
int ocena;
} student;

/* Funkcija ucitava rec i vraca njenu duzinu ili


-1 ukoliko smo dosli do znaka EOF*/
int getword(char word[],int max)
{
int c, i=0;

while (isspace(c=getchar()))
;

while(!isspace(c) && c!=EOF && i<max-1)


{
word[i++]=c;

116
4.41 Strukture 117

c = getchar();
}

word[i]=’\0’;

if (c==EOF) return -1;


else return i;

/* Funkcija ucitava niz studenata, vraca duzinu niza koji ucita */


int UcitajPodatke(student studenti[], int max)
{
int i=0;
while(i<max && getword(studenti[i].ime, MAX_IME)>0)
{
if (getword(studenti[i].prezime, MAX_IME) < 0)
break;
scanf("%d",&studenti[i].ocena);
i++;
}
return i;
}

void IspisiPodatke(student studenti[], int br_studenata)


{
int i;
printf("IME PREZIME OCENA\n");
printf("--------------------------------------\n");
for (i=0; i<br_studenata; i++)
printf("%-20s %-20s %5d\n",studenti[i].
ime, studenti[i].prezime, studenti[i].ocena);
}

/* Sortiranje studenata po ocenama */


void SelectionSort(student studenti[], int br_studenata)
{
int i,j;
for (i=0; i<br_studenata-1; i++)
for (j=i; j<br_studenata; j++)
if (studenti[i].ocena<studenti[j].ocena)
{ student tmp=studenti[i];
studenti[i]=studenti[j];
studenti[j]=tmp;
}
}

main()
{
student studenti[100];

117
118 Milena Vujošević–Janičić

int br_studenata = UcitajPodatke(studenti,100);

SelectionSort(studenti, br_studenata);

IspisiPodatke(studenti, br_studenata);

}
Primer 4.41.7 Dinamički niz.
/* Program za svaku rec unetu sa standardnog
ulaza ispisuje broj pojavljivanja.
Verzija sa dinamickim nizom i realokacijom.
*/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Rec je opisana imenom i brojem pojavljivanja */


typedef struct _rec
{ char ime[80];
int br_pojavljivanja;
} rec;

/* Dinamicki niz reci je opisan pokazivacem na


pocetak, tekucim brojem upisanih elemenata i
tekucim brojem alociranih elemenata */
rec* niz_reci;
int duzina=0;
int alocirano=0;

/* Realokacija se vrsi sa datim korakom */


#define KORAK 10

/* Funkcija ucitava rec i vraca njenu duzinu ili


-1 ukoliko smo dosli do znaka EOF*/
int getword(char word[],int max)
{
int c, i=0;

while (isspace(c=getchar()))
;

while(!isspace(c) && c!=EOF && i<max-1)


{
word[i++]=c;
c = getchar();
}

118
4.41 Strukture 119

word[i]=’\0’;

if (c==EOF) return -1;


else return i;
}

main()
{
char procitana_rec[80];
int i;

while (getword(procitana_rec,80)!=-1)
{
/* Proveravamo da li rec vec postoji u nizu */
for (i=0; i<duzina; i++)
/* Ako bismo uporedili procitana_rec == niz_reci[i].ime
bili bi uporedjeni pokazivaci a ne odgovarajuci sadrzaji!!!
Zato koristimo strcmp. */
if (strcmp(procitana_rec, niz_reci[i].ime)==0)
{
niz_reci[i].br_pojavljivanja++;
break;
}

/* Ukoliko rec ne postoji u nizu */


if (i==duzina)
{
rec nova_rec;
/* Ako bismo dodelili nova_rec.ime = procitana_rec
izvrsila bi se dodela pokazivaca a ne kopiranje niske
procitana_rec u nova_rec.ime. Zato koristimo strcpy!!! */
strcpy(nova_rec.ime,procitana_rec);
nova_rec.br_pojavljivanja=1;

/* Ukoliko je niz "kompletno popunjen" vrsimo realokaciju */


if (duzina==alocirano)
{
alocirano+=KORAK;

/* Sledeca linija zamenjuje blok koji sledi i moze se


koristiti alternativno. Blok je ostavljen samo da bi
demonstrirao korisnu tehniku */
/* niz_reci=realloc(niz_reci, (alocirano)*sizeof(rec)); */
{
/* alociramo novi niz, veci nego sto je bio prethodni */
rec* novi_niz=(rec *)malloc(alocirano*sizeof(rec));

if (novi_niz == NULL)
{
free(niz_reci);

119
120 Milena Vujošević–Janičić

printf("Greska prilikom alokacije memorije");


exit(1);
}

/* Kopiramo elemente starog niza u novi */


for (i=0; i<duzina; i++)
novi_niz[i]=niz_reci[i];

/* Uklanjamo stari niz */


free(niz_reci);

/* Stari niz postaje novi */


niz_reci=novi_niz;
}
}
/* Upisujemo rec u niz */
niz_reci[duzina]=nova_rec;
duzina++;
}
}

/* Ispisujemo elemente niza */


for(i=0; i<duzina; i++)
printf("%s - %d\n",niz_reci[i].ime, niz_reci[i].br_pojavljivanja);

free(niz_reci);
}

4.42 qsort
Primer 4.42.1 Implementacija funkcije qsort.
#include <stdio.h>
#include <string.h>

void printarray(int v[], int left, int right)


{
int i;
for (i=left; i<=right; i++)
printf("%d ",v[i]);
putchar(’\n’);
}

void swap(int v[], int i, int j)


{
int tmp=v[i];
v[i]=v[j];
v[j]=tmp;
}

120
4.43 Sortiranje — generička funkcija 121

/* qsort: sortira v[left]...v[right] u rastucem poretku */


void qsort(int v[], int left, int right)
{
int i, last;

/* ne radi nista ako niz sadrzi */


/* manje od dva elementa */
if (left >= right)
return;
/* prebaci element particioniranja */
/* u v[left] */
swap(v, left, (left + right)/2);
last = left;

/* partition */
for (i = left + 1; i <= right; i++)
if (v[i] < v[left])
swap(v, ++last, i);

/* restore partition elem */


swap(v, left, last);

/* Sortiraj preostala dva dela niza */


qsort(v, left, last-1);
qsort(v, last+1, right);
}

main()
{
int array[]={8, 3, 2, 6, 5, 7, 4, 9, 1};
int n=sizeof(array)/sizeof(int);

printarray(array, 0, n-1);
qsort(array, 0, n-1);
printarray(array, 0, n-1);

4.43 Sortiranje — generička funkcija


Sortiranje niza celih brojeva (jedan od algoritama)
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
int pom=a[i];
a[i]=a[j];
a[j]=pom;
}

121
122 Milena Vujošević–Janičić

Sortiranje iz programa mozemo da izdvojimo u funkciju:

void sort_int(int a[], int n)


{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
int pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Sortiranje niza realnih brojeva:

void sort_float(float a[], int n)


{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
float pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Razlike:

• prvi argument funkcije;

• pomoćna promenljiva;

• pore enje.

Sortiranje studenata po oceni ukoliko je data struktura student:

typedef struct _student {


char ime[MAX_IME];
char prezime[MAX_IME];
int ocena;
} student;

void sort_po_oceni(student a[], int n)


{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i].ocena < a[j].ocena)

122
4.43 Sortiranje — generička funkcija 123

{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Sortiranje studenta po prezimenu:


void sort_po_prezimenu(student a[], int n)
{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(strcmp(a[i].prezime, a[j].prezime)<0)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}
Sortiranje studenta po imenu:
void sort_po_imenu(student a[], int n)
{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(strcmp(a[i].ime, a[j].ime)<0)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}
Kako da napravimo jednu funkciju koja sortira studente bez obzira na kri-
terijum?
Prvo moramo da izdvojimo funkciju pore enja:
int poredi_po_oceni(student st1, student st2)
{
return st1.ocena - st2.ocena;
}

int poredi_po_prezimenu(student st1, student st2)


{
return strcmp(st1.prezime, s2.prezime);
}

int poredi_po_imenu(student st1, student st2)

123
124 Milena Vujošević–Janičić

{
return strcmp(st1.ime, st2.ime);
}
Funkcija pore enja vraća 0 ukoliko su elementi jednaki, broj manji od nule
ukoliko je prvi manji od drugog i broj veći od nule ukolikoje prvi veći od drugog.

void sort_po_imenu(student a[], int n)


{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
/*if(poredi_po_prezimenu(a[i], a[j])<0)*/
/*if(poredi_po_oceni(a[i], a[j])<0)*/
if(poredi_po_imenu(a[i], a[j])<0)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

Sada možemo da dodamo još jedan argument funkciji sortiranja i tako da


dobijemo jednu funkciju umesto tri:
void sort_studente(student a[], int n, int (*f)(student, student))
{
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if((*f)(a[i], a[j])<0)
{
student pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}
Šta dalje? Kako da dobijemo jednu funkciju sortiranja bez obzira na tip
elemenata niza?
Teba da rešimo sledeće stvari:
• razmena mesta elemenata ne sme da zavisi od tipa elemenata koji se raz-
menjuju.
• potpis funkcije pore enja ne sme da zavisi od tipa elemenata koji se porede
kako bi on bio jedinstven.
• prvi argument funkcije ne sme da zavisi od tipa elemenata niza.
Da bi smo razmenili dva elementa potrebna nam je pomoćna promenljiva
u kojoj privremeno čuvamo neku vrednost. Ako ne znamo tip elementa onda
ne možemo da napravimo pomoćnu promenljivu. Ali zato mozemo da koristeći

124
4.43 Sortiranje — generička funkcija 125

funkciju malloc odvojimo neko mesto u memoriji za smestanje elementa koji nam
u datoj situaciji treba. Koliko je to mesto? Nekada 4 bajta, npr za int, a nekada
dosta veće, npr za studenta. Kako funkcija sortiranja zna koliko mesta treba
da odvoji? Znace tako sto ćemo joj tu veličinu proslediti kao argument. Sada,
dakle umesto pomoćne promenljive, imamo blok u memoriji, a umesto naredbe
dodele koristićemo funkciju memcpy koja kopira deo memorije sa jednog mesta
na drugo mesto.
Dakle, razmenu ćemo da radimo na sledeći način:

void* tmp = malloc(size);


if (tmp==NULL) {printf("Greska prilikom alokacije memorije!\n");exit(1);}
memcpy(tmp, adresa_itog, size);
memcpy(adresa_itog, adresa_jtog, size);
memcpy(adresa_jtog, tmp, size);
free(tmp);

Potpis funkcije pore enja ne sme da zavisi od tipa elemenata koji se porede.
To se može postići koristeći pokazivač na tip void.
Na primer, pore enje dva cela broja:

int poredi_br(void* a, void* b)


{
int br_a = *(int*)a;
int br_b = *(int*)b;

return br_a-br_b;
}

Na primer, pore enje dva realna broja:

int poredi_br(void* a, void* b)


{
float br_a = *(float*)a;
float br_b = *(float*)b;

if (br_a > br_b) return 1;


else if (br_a < br_b) return -1;
else return 0;
}

Na primer, pore enje dva studenta po oceni

int poredi_br(void* a, void* b)


{
student student1 = *(studnet*)a;
student student2 = *(studnet*)b;

return student1.ocena-student2.ocena;
}

Sada funkcija pore enja ima uvek potpis

125
126 Milena Vujošević–Janičić

int poredi(void* a, void* b)

i može se kao parametar proslediti našoj funkciji sortiranja.

Primer 4.43.1 /* Genericka funkcija sortiranja -


nezavisna od tipa elemenata niza
koji se sortira */
#include <stdlib.h>

void sort(void* a, int n, int size, int (*poredi)(void*, void*))


{
int i, j;
for (i = 0; i<n-1; i++)
for (j = i+1; j<n; j++)
{
void* adresa_itog = (char*)a+i*size;
void* adresa_jtog = (char*)a+j*size;

if (poredi(adresa_itog, adresa_jtog)<0)
{
void* tmp = malloc(size);
if (tmp==NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}
memcpy(tmp, adresa_itog, size);
memcpy(adresa_itog, adresa_jtog, size);
memcpy(adresa_jtog, tmp, size);
free(tmp);
}

}
}

int poredi_br(void* a, void* b) {


int br_a = *(int*)a;
int br_b = *(int*)b;

return br_a-br_b;
}

int poredi_float(void* a, void* b) {


float br_a = *(float*)a;
float br_b = *(float*)b;

if (br_a > br_b) return 1;


else if (br_a < br_b) return -1;
else return 0;
}

126
4.44 qSort funkcija iz standardne biblioteke 127

main() {
int a[] = {8, 2, 1, 9, 3, 7, 6, 4, 5};
float b[] = {0.3, 2, 5, 5.8, 8}
int n = sizeof(a)/sizeof(int);
int nf = sizeof(b)/sizeof(float);
int i;

sort(a, n, sizeof(int), poredi_br);

for (i = 0; i < n; i++)


printf("%d ", a[i]);
putchar(’\n’);

sort(b, nf, sizeof(float), poredi_float);

for (i = 0; i < n; i++)


printf("%f ", b[i]);
putchar(’\n’);
}

4.44 qSort funkcija iz standardne biblioteke


Primer 4.44.1 qSort-Upotreba.
/* Ilustracija upotrebe funkcije qsort iz stdlib.h
Sortira se niz celih brojeva.
*/

#include <stdlib.h>
#include <stdio.h>

/* const znaci da ono na sta pokazuje a (odnosno b)


nece biti menjano u funkciji */
int poredi(const void* a, const void* b)
{
/* Skracen zapis za
int br_a = *(int*)a;
int br_b = *(int*)b;

return br_a-br_b;
*/
return *((int*)a)-*((int*)b);
}

int poredi_float(const void* a, const void* b)


{
float br_a = *(float*)a;
float br_b = *(float*)b;

127
128 Milena Vujošević–Janičić

if (br_a > br_b) return 1;


else if (br_a < br_b) return -1;
else return 0;
}

main()
{
int i;
int niz[]={3,8,7,1,2,3,5,6,9};
float nizf[]={3.0,8.7,7.8,1.9,2.1,3.3,6.6,9.9};

int n=sizeof(niz)/sizeof(int);
qsort((void*)niz, n, sizeof(int), poredi);
for(i=0; i<n; i++)
printf("%d",niz[i]);

n=sizeof(nizf)/sizeof(float);
qsort((void*)nizf, n, sizeof(float), poredi_float);
for(i=0; i<n; i++)
printf("%f",nizf[i]);

}
Primer 4.44.2 Binarno pretraživanje - korišćenje ugra ene bsearch funkcije.


/* Funkcija ilustruje koriscenje ugradjene funkcije bsearch */


#include <stdlib.h>

int poredi(const void* a, const void *b)


{
return *(int*)a-*(int*)b;
}

main()
{
int x=-1;
int niz[]={1,2,3,4,5,6,7,8,9,10,11,12};

int* elem=(int*)bsearch((void*)&x,
(void*)niz,
sizeof(niz)/sizeof(int),
sizeof(int),
poredi);

if (elem==NULL)
printf("Element nije pronadjen\n");
else
printf("Element postoji na poziciji %d\n",elem-niz);
}

128
4.45 Generičko sortiranje reči 129

4.45 Generičko sortiranje reči


Primer 4.45.1 Sortiranje reči. Ako se sortira niz stringova, onda svaki ele-
ment je sam po sebi pokazivač tipa char *, te funkcija pore enja tada prima


podatke tipa char ** koji se konvertuju u svoj tip i derefenciraju radi dobijanja
podataka tipa char *.

/* Ilustracija upotrebe funkcije qsort iz stdlib.h


Sortira se niz reci i to ili leksikografski
ili po duzini
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int poredi(const void* a, const void* b)


{
char *s1 = *(char **)a;
char *s2 = *(char **) b;
return strcmp(s1, s2);

/* Prethodno je ekvivalentno sa:


return strcmp(*(char**)a,*(char**)b); */
}

int poredi_po_duzini(const void* a, const void* b)


{
char *s1 = *(char **) a;
char *s2 = *(char **) b;
return strlen(s1) - strlen(s2);
/* Prethodno je ekvivalentno sa:
return strlen(*(char**)b)-strlen(*(char**)a); */
}

main()
{
int i;
char* nizreci[]={"Jabuka","Kruska","Sljiva","Dinja","Lubenica"};

qsort((void*)nizreci, 5, sizeof(char*), poredi_po_duzini);

for (i=0; i<5; i++)


printf("%s\n",nizreci[i]);

qsort((void*)nizreci, 5, sizeof(char*), poredi);

for (i=0; i<5; i++)


printf("%s\n",nizreci[i]);

129
130 Milena Vujošević–Janičić

}
Primer 4.45.2 Sa ulaza se unose reči. Program broji pojavljivanja svake od
ključnih reči programskog jezika C. Na kraju se reči ispisuju opadajuće po broju
pojavljivanja.
#include <stdio.h>
#include <stdlib.h>

/* Svaka kljucna rec se odlikuje imenom i brojem pojavljivanja */


typedef struct _keyword
{
char* word;
int num;
} keyword;

/* Kreiramo niz struktura sortiranih leksikografski


po imenu kljucne reci, kako bismo ubrzali pronalazak reci */
keyword keywords[]={ {"break",0},
{"continue",0},
{"float",0},
{"for",0},
{"if",0},
{"return",0},
{"struct",0},
{"while",0}
};

/* Funkcija cita sledecu rec sa standardnog ulaza */


int getword(char word[], int lim)
{
int c, i=0;
while(!isalpha(c=getchar()) && c!=EOF)
;
if (c==EOF)
return -1;
do
{
word[i++]=c;
} while(--lim>0 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

/* Funkcija leksikografskog poredjenja za bsearch */


int cmp(const void* a, const void* b) {
/* Funkcija strcmp prima kao argumente dva
pokazivaca na karaktere. Prvi je rec koju
trazimo u nizu, a drugi je element niza
sa kojim se vrsi poredjenje. Pokazivac

130
4.46 Argumenti komandne linije 131

b konvertujemo u pokazivac na strukturu


keyword a zatim posmatramo rec koja se tu
cuva */
return strcmp((char*)a, (*(keyword*)b).word); }

/* Funkcija numerickog poredjenja za qsort */


int numcmp(const void* a, const void* b)
{
return ((*(keyword*)b).num-(*(keyword*)a).num);
}

main()
{
char word[80];
int i;

/* Broj kljucnih reci */


int num_of_keywords=sizeof(keywords)/sizeof(keyword);

/* Citamo reci */
while (getword(word,80)!=-1)
{
/* Trazimo rec u spisku kljucnih reci binarnom pretragom */
keyword* k=(keyword*)bsearch((void*)word,
(void*)keywords,
num_of_keywords,
sizeof(keyword),
cmp);
/* Ukoliko je pronadjena uvecavamo broj pojavljivanja */
if (k!=NULL)
(*k).num++;
}

/* Sortiramo niz na osnovu broja pojavljivanja */


qsort((void*)keywords, num_of_keywords, sizeof(keyword), numcmp);

/* Vrsimo ispis */
for (i=0; i<num_of_keywords; i++)
printf("%s %d\n", keywords[i].word, keywords[i].num);
}

4.46 Argumenti komandne linije


Primer 4.46.1
/* Argumenti komandne linije programa */

/* Program pozivati sa npr.:


a.out
a.out prvi

131
132 Milena Vujošević–Janičić

a.out prvi drugi treci


a.out -a -bc ime.txt
*/

#include <stdio.h>

/* Imena ovih promenljivih mogu biti proizvoljna.


Npr:
main (int br_argumenata, char* argumenti[]);
ipak, uobicajeno je da se koriste sledeca imena:
*/

main(int argc, char* argv[])


{
int i;
printf("argc = %d\n", argc);

/* Nulti argument uvek je ime programa (a.out)*/


for (i = 0; i<argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
}

4.47 Datoteke
Primer 4.47.1 Program demonstrira otvaranje datoteka ("r" - read i "w" -
write mod) i osnovne tehnike rada sa datotekama.
/* U datoteku se upisuje prvih 10 prirodnih
brojeva, a zatim se iz iste datoteke
citaju brojevi dok se ne stigne do kraja i
ispisuju se na standardni izlaz */

#include <stdio.h>
#include <stdlib.h>

main()
{
int i;

/* Otvaramo datoteku sa imenom podaci.txt za pisanje */


FILE* f = fopen("podaci.txt", "w");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */
if (f == NULL)
{
printf("Greska prilikom otvaranja datoteke podaci.txt za pisanje\n");
exit(1);
}

132
4.47 Datoteke 133

/* Upisujemo u datoteku prvih 10 prirodnih brojeva


(svaki u posebnom redu) */
for (i = 0; i<10; i++)
fprintf(f, "%d\n", i);

/* Zatvaramo datoteku */
fclose(f);

/* Otvaramo datoteku sa imenom podaci.txt za citanje */


f = fopen("podaci.txt", "r");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */
if (f == NULL) {
printf("Greska prilikom otvaranja datoteke podaci.txt za citanje\n");
exit(1);
}

/* Citamo brojeve iz datoteke dok ne stignemo do kraja i ispisujemo ih


na standardni izlaz */
while(1) {
int br;
/* Pokusavamo da procitamo broj */
fscanf(f, "%d", &br);

/* Ukoliko smo dosli do kraja datoteke, prekidamo */


if (feof(f))
break;

/* Ispisujemo procitani broj */


printf("Procitano : %d\n", br);
}

/* Funkciju feof ne treba pozivati pre pokusaja citanja.


Sledeci kod moze dovesti do greske:
while (!feof(f))
fscanf(f,"%d",&br);
*/

/* Zatvaramo datoteku */
fclose(f);
}

Pokazivači stdin, stdout i stderr su definisani u okviru stdio.h.


FILE* stdin;
FILE* stdout;
FILE* stderr;

Primer 4.47.2 Program demonstrira ”a” - append mod datoteka - nadovezi-


vanje.

133
134 Milena Vujošević–Janičić

#include <stdio.h>

main()
{
FILE* datoteka;

/* Otvaramo datoteku za nadovezivanje


i proveravamo da li je doslo do greske */
if ( (datoteka=fopen("dat.txt","a"))==NULL)
{
fprintf(stderr,"Greska prilikom otvaranja dat.txt\n");
return 1;
}

/* Upisujemo sadrzaj u datoteku */


fprintf(datoteka,"Zdravo svima\n");

/* Zatvaramo datoteku */
fclose(datoteka);
}
Primer 4.47.3 Program ilustruje rad sa datotekama. Program kopira datoteku
čije se ime zadaje kao prvi argument komandne linije u datoteku čije se ime
zadaje kao drugi argument komandne linije. Uz svaku liniju se zapisuje i njen
redni broj.
#include <stdio.h>

#define MAX_LINE 256

/* Funkcija fgets definisana je u stdio.h

char* fgets(char *s, int n, FILE* stream)

fgets ucitava najvise sledecih n-1 znakova


u polje niza karaktera s, zaustavljajuci se
ako naidje na novu liniju koju takodje
upisuje u polje. Na kraju upisuje ’\0’.
Funkcija vraca s ili NULL ako dodje do kraja
datoteke ili se pojavi greska

Funkcija getline moze jednostavno da se


realizuje preko funkcije fgets.

int getline(char s[], int lim)


{
char* c = fgets(s, lim, stdin);
return c==NULL ? 0 : strlen(s);
}
*/

134
4.47 Datoteke 135

main(int argc, char* argv[])


{

char line[MAX_LINE];
FILE *in, *out;
int line_num;

if (argc != 3) {
fprintf(stderr,"Upotreba : %s ulazna_datoteka izlazna_datoteka\n",argv[0]);
return 1;
}

if ((in = fopen(argv[1],"r")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke %s\n", argv[1]);
return 1;
}

if ((out = fopen(argv[2],"w")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke %s\n",argv[2]);
return 1;
}

/* Prepisivanje karakter po karakter je moguce ostvariti preko:


int c;
while ((c=fgetc(in)) != EOF)
putc(c,out);
*/

line_num = 1;

/* Citamo liniju po liniju sa ulaza*/


while (fgets(line, MAX_LINE, in) != NULL)
{
/* Ispisujemo broj linije i sadrzaj linije na izlaz */
fprintf(out, "%d :\t", line_num++);
fputs(line, out);
}

/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}
Primer 4.47.4 Prodavnica - ilustruje čitanje niza struktura iz tektsualne da-
toteke.
/* Datoteka, cije se ime zadaje kao argument komandne linije
ili ako se ne zada onda se ime unosi sa standardnog
ulaza, sadrzi podatke o proizvodima koji se prodaju

135
136 Milena Vujošević–Janičić

u okviru odredjene prodavnice. Svaki


proizvod se odlikuje sledecim podacima:
bar-kod - petocifreni pozitivan broj
ime - niska karaktera
cena - realan broj zaokruzen na dve decimale
pdv - stopa poreza - realan broj zaokruzen na dve decimale
Pretpostavljamo da su podaci u datoteci
korektno zadati.

Pretpostavljamo da se u prodavnici ne
prodaje vise od 1000 razlicitih artikala
Na standardni izlaz ispisati podatke o
svim proizvodima koji se prodaju u prodavnici.
Zadatak je moguce resiti i bez koriscenja nizova
(i takvo resenje je bolje). */

#include <stdio.h>

/* Maksimalna duzina imena proizvoda */


#define MAX_IME 30

/* Maksimalni broj artikala */


#define MAX_ARTIKALA 1000

/* Struktura za cuvanje podataka o jednom artiklu */


typedef struct _artikal {
int bar_kod;
char ime[MAX_IME];
float cena;
float pdv;
} artikal;

/* Niz struktura u kome se cuvaju podaci o artiklima */


artikal artikli[MAX_ARTIKALA];

/* Broj trenutno ucitanih artikala */


int br_artikala = 0;

/* Ucitava podatke o jednom artiklu iz date datoteke.


Vraca da li su podaci uspesno procitani */
int ucitaj_artikal(FILE* f, artikal* a)
{
/* Citamo bar kod, ime, cenu, pdv */
fscanf(f, "%d%s%f%f", &(a->bar_kod), a->ime, &(a->cena), &(a->pdv));

/* Ukoliko smo dosli do kraja datoteke prilikom pokusaja ucitavanja


prijavljujemo neuspeh */
if (feof(f))
return 0;

136
4.47 Datoteke 137

/* Prijavljujemo uspeh */
return 1;
}

/* Izracunava ukupnu cenu datog artikla */


float cena(artikal a)
{
return a.cena*(1+a.pdv);
}

/* Ispisuje podatke o svim artiklima */


void ispisi_artikle()
{
int i;
for (i = 0; i<br_artikala; i++)
printf("%-5d %-10s %.2f %.2f = %.2f\n",
artikli[i].bar_kod, artikli[i].ime,
artikli[i].cena, artikli[i].pdv,
cena(artikli[i]));
}

main(int argc, char* argv[])


{
FILE* f;

/* Ukoliko nije navedeno ime kao argument komandne linije, trazimo


od korisnika da ga unese */
if (argc<2) {
/* Ucitavamo ime datoteke */
char ime_datoteke[256];
printf("U kojoj datoteci se nalaze podaci o proizvodima: ");
scanf("%s", ime_datoteke);

/* Otvaramo datoteku i proveravamo da li smo uspeli */


if ( (f = fopen(ime_datoteke, "r")) == NULL)
{
printf("Greska prilikom otvaranja datoteke %s\n", ime_datoteke);
return 1;
}
}
/* Ime datoteke je prvi argument komandne linije */
else {
/* Otvaramo datoteku i proveravamo da li smo uspeli */
if ( (f = fopen(argv[1], "r")) == NULL)
{
printf("Greska : datoteka %s ne moze biti otvorena\n", argv[1]);
return 1;
}

137
138 Milena Vujošević–Janičić

/* Ucitavamo artikle */
while (ucitaj_artikal(f, &artikli[br_artikala]))
br_artikala++;

/* Ispisujemo podatke o svim artiklima */


ispisi_artikle();

/* Zatvara se datoteka*/
fclose(f);
}

4.48 Liste
4.48.1 Red

početak reda (brisanje — get)


kraj reda (dodavanje — add)

A B ... X NULL

novi element

početak reda
novi kraj reda

A B ... X Y NULL

početak reda nakon brisanja kraj reda

B ... X Y NULL

Slika 4.1: Red

Primer 4.48.1 Program formira listu brojeva i demonstrira osnovne elemente


rada sa listom.
#include <stdio.h>

138
4.48 Liste 139

#include <stdlib.h>

typedef struct elem {


int broj;
struct elem *sled;
} Elem;

/* Citanje brojeva i formiranje liste. Funkcija vraca pokazivac


na pocetak liste. */
Elem *citaj (void)
{
Elem *lista = NULL, *poslednji = NULL, *novi;
int broj;

printf("\n\nUnesite elemente liste - 0 za kraj\n");


scanf ("%d", &broj);

while (broj) {
/*Alocira se prostor za novi clan liste*/
novi =(Elem*)malloc (sizeof (Elem));
if (novi == NULL)
{
fprintf(stderr, "Greska prilikom alokacije memorije\n");
exit(1);
}

/* Postavljanje vrednosti */
novi->broj = broj;
novi->sled = NULL;

/* Ukoliko lista nije prazna novi element se postavlja iza


poslednjeg elemnta liste - na koji pokazuje poslednji */
if (poslednji != NULL)
poslednji->sled = novi;
/* Inace se postavlja da bude pocetak liste */
else
lista = novi;

/*Poslednji se postavlja da pokazuje na poslednji element liste */


/*Ekvivalentno je sa
poslednji = poslednji ->sledeci */
poslednji = novi;
/* Ucitavanje novog elementa liste 0 za kraj */
scanf ("%d", &broj);
}
/* Funkcija vraca pokazivac na pocetak liste */
return lista;
}

/* Ispisivanje liste*/

139
140 Milena Vujošević–Janičić

void pisi (Elem *lista)


{
while (lista != NULL)
{
printf ("%d ", lista->broj),
lista = lista->sled;
}
putchar (’\n’);
}

/* Oslobadjanje memorije koju lista zauzima*/


void brisi (Elem* lista)
{
Elem *stari;
while (lista != NULL)
{
stari = lista;
lista = lista->sled;
free (stari);
}
}

/* Izbacivanje (brisanje) zadatog broja iz liste. Kako se


ovime pocetak liste moze izmeniti, vrednost pocetka liste
je povratna vrednost funkcije */
Elem* izbaci(Elem *lista, int k)
{
Elem *preth = NULL, *tekuci = lista, *zaizbacivanje;

while (tekuci != NULL)


/* Ukoliko tekuci pokazuje na clana
liste kojeg treba izbaciti */
if (tekuci->broj == k)
{
zaizbacivanje = tekuci;
tekuci = tekuci->sled;

if (preth != NULL )
preth->sled = tekuci;
/* Ovaj slucaj odnosi se na izbacivanje
elementa sa pocetka liste */
else lista = tekuci;

free (zaizbacivanje);
}
else
{
preth = tekuci;
tekuci = tekuci->sled;
}

140
4.48 Liste 141

return lista;
}

main ()
{
Elem *lista;
int k;

lista = citaj ();


printf ("Ucitani lista = ");
pisi (lista);

printf("Koji element liste zelite da izbacite?\n");


scanf ("%d", &k);
printf ("Izostavlja se = %d\n", k);
printf ("Novi lista = ");
pisi (lista = izbaci (lista, k));
printf ("\n");

printf("Lista mi vise nije potrebna, oslobadjam memoriju!\n");


brisi (lista);
}
Primer 4.48.2 Rad sa listama - celine izdvojene u funkcije.
#include <stdio.h>
#include <stdlib.h>

typedef struct cvor {


int br;
struct cvor* sl;
} CVOR;

/* Pomocna funkcija koja kreira cvor liste sa datim sadrzajem.


Funkcija kreira cvor i postavlja mu sadrzaj na dati broj.
Funkcija vraca pokazivac na kreirani cvor. */
CVOR* napravi_cvor(int br) {
CVOR* novi = (CVOR*)malloc(sizeof(CVOR));
if (novi == NULL)
{
fprintf(stderr, "Greska prilikom alokacije memorije\n");
exit(1);
}
novi->br = br;
novi->sl = NULL;
return novi;
}

/* --------------------------------------------- */
/* Ispisivanje liste: iterativna verzija */
void ispisi_listu_i(CVOR* l) {

141
142 Milena Vujošević–Janičić

CVOR* t;
for (t = l; t != NULL; t=t->sl)
printf("%d ", t->br);
}

/* Ispisivanje liste: rekurzivna verzija */


void ispisi_listu_r(CVOR* l) {
if (l != NULL)
{
printf("%d ", l->br);
ispisi_listu_r(l->sl);
}
}

/* Ispisivanje liste unazad: rekurzivna verzija */


void ispisi_listu_unazad(CVOR* l) {
if (l != NULL)
{
ispisi_listu_unazad(l->sl);
printf("%d ", l->br);
}
}

/* --------------------------------------------- */
/* Oslobadjanje liste : iterativna verzija */
void oslobodi_listu_i(CVOR* l) {
while (l!=NULL)
{
CVOR* tmp = l->sl;
free(l);
l = tmp;
}
}

/* Oslobadjanje liste : rekurzivna verzija */


void oslobodi_listu_r(CVOR* l) {
if (l != NULL)
{
oslobodi_listu_r(l->sl);
/* Prvo se oslobadja poslednji element liste */
free(l);
}
}

/* --------------------------------------------- */
/* Ubacuje dati broj na pocetak date liste.
Funkcija pozivaocu eksplicitno vraca pocetak
rezultujuce liste.*/
CVOR* ubaci_na_pocetak(CVOR* l, int br) {
CVOR* novi = napravi_cvor(br);

142
4.48 Liste 143

novi->sl = l;
return novi;
}

/* Funkcija vraca pocetak rezultujuce liste, a ubacuje


cvor na kraj bez pamcenja pokazivaca na kraj */
CVOR* ubaci_na_kraj(CVOR* l, int br) {
CVOR* novi = napravi_cvor(br);

if (l == NULL)
return novi;
else
{
CVOR* t;
/* Prodjemo do kraja liste */
for (t = l; t->sl!=NULL; t=t->sl)
;
t->sl = novi;

/* Pocetak se nije promenio */


return l;
}
}

/* Rekurzivna varijanta prethodne funkcije.


I ova funkcija vraca pokazivac na pocetak
rezultujuce liste */
CVOR* ubaci_na_kraj_rekurzivno(CVOR* l, int br) {
if (l == NULL)
{
CVOR* novi = napravi_cvor(br);
return novi;
}

l->sl = ubaci_na_kraj_rekurzivno(l->sl, br);


return l;
}

/* --------------------------------------------- */
/* Kljucna ideja u realizaciji ove funkcije je
pronalazenje poslednjeg elementa liste ciji
je kljuc manji od datog elementa br.
*/
CVOR* ubaci_sortirano(CVOR* pl, int br) {
CVOR* novi = napravi_cvor(br);

/* U sledeca dva slucaja ne postoji cvor


ciji je kljuc manji od datog broja (br)
- Prvi je slucaj prazne liste
- Drugi je slucaj kada je br manji od prvog elementa

143
144 Milena Vujošević–Janičić

U oba slucaja ubacujemo na pocetak liste.


*/
if (pl == NULL || br < pl->br)
{
novi->sl = pl;
pl = novi;
}
else
{
/* Krecemo od pocetka i idemo dalje sve dok t nije poslednji
manji element liste ili eventualno bas poslednji */
CVOR* t;
for(t = pl; t->sl!=NULL && t->sl->br < br; t=t->sl)
;
novi->sl = t->sl;
t->sl = novi;
}

return pl;
}

main() {
CVOR* l = NULL;
CVOR* s = NULL;

int i;
for (i = 0; i<5; i++)
l = ubaci_na_kraj(l, i);
for (; i<10; i++)
l = ubaci_na_kraj_rekurzivno(l, i);

for (i = 0; i < 10 ; i++)


l = ubaci_na_pocetak(l, i);

ispisi_listu_i(l);
putchar(’\n’);

ispisi_listu_r(l);
putchar(’\n’);

ispisi_listu_unazad(l);
putchar(’\n’);

oslobodi_listu_i(l);

s = ubaci_sortirano(s, 5);
s = ubaci_sortirano(s, 8);
s = ubaci_sortirano(s, 7);
s = ubaci_sortirano(s, 6);

144
4.48 Liste 145

s = ubaci_sortirano(s, 4);

ispisi_listu_r(s);
putchar(’\n’);

oslobodi_listu_r(s);
}

4.48.2 Kružna lista

početak ciklične liste

A B C ... Z

Slika 4.2: Kružna lista

Primer 4.48.3 (februar 2006.) Grupa od n plesača (na čijim kostimima su


u smeru kazaljke na satu redom brojevi od 1 do n) izvodi svoju plesnu tačku
tako što formiraju krug iz kog najpre izlazi k-ti plesač (odbrojava se počev od
plesača označenog brojem 1 u smeru kretanja kazaljke na satu). Preostali plesači
obrazuju manji krug iz kog opet izlazi k-ti plesač (odbrojava se pocev od sledećeg
suseda prethodno izbačenog, opet u smeru kazaljke na satu). Izlasci iz kruga se
nastavljaju sve dok svi plesači ne budu isključeni. Celi brojevi n, k (k < n) se
učitavaju sa standardnog ulaza. Napisati program koji će na standardni izlaz
ispisati redne brojeve plesača u redosledu napuštanja kruga.
PRIMER: za n = 5, k = 3 redosled izlaska je 3 1 5 2 4.

4.48.3 Stek
Primer 4.48.4 Program proverava da li su zagrade ( i ) dobro uparene.

#include <stdio.h>
#include <stdlib.h>

main()
{
int c;
int br_otv = 0;
while((c=getchar()) != EOF)
{
switch(c)

145
146 Milena Vujošević–Janičić

{
case ’(’:
br_otv++;
break;
case ’)’:
br_otv--;
if (br_otv<0)
{
printf("Visak zatvorenih zagrada\n");
exit(1);
}
}
}

if (br_otv == 0)
printf("Zagrade su u redu\n");
else
printf("Visak otvorenih zagrada\n");
}

Primer 4.48.5 Program proverava da li su zagrade (, [, {, }, ] i ) dobro uparene


- statička implementacija steka.

#include <stdio.h>
#include <stdlib.h>
#define MAX_ZAGRADA 100

int odgovarajuce(char z1, char z2) {


return (z1 == ’(’ && z2 == ’)’) ||
(z1 == ’{’ && z2 == ’}’) ||
(z1 == ’[’ && z2 == ’]’);
}

main()
{
int c;
char otv_zagrade[MAX_ZAGRADA];
int br_otv = 0;

while((c=getchar()) != EOF)
{
switch(c)
{
case ’(’:
case ’{’:
case ’[’:
{
otv_zagrade[br_otv] = c;
br_otv++;
break;

146
4.48 Liste 147

}
case ’]’:
case ’}’:
case ’)’:
if (br_otv>0 && odgovarajuce(otv_zagrade[br_otv-1], c))
{
br_otv--;
}
else
{
printf("Visak zatvorenih zagrada: %c u liniji %d\n", c, br_linija);
exit(1);
}
}
}

if (br_otv == 0)
printf("Zagrade su u redu\n");
else
printf("Visak otvorenih zagrada\n");
}

vrh steka (i dodavanje i brisanje — push i pop)

X Y ... A NULL

novi element

novi vrh steka

Y X V ... A NULL

vrh steka nakon brisanja

X V ... A NULL

Slika 4.3: Stek

147
148 Milena Vujošević–Janičić

Primer 4.48.6 Program ilustruje proveru validnosti HTML datoteke - prover-


ava se da li su etikete dobro uparene pri cemu se stek implementira preko liste.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* Maksimalna duzina etikete */


#define MAX_TAG 100

#define OTVORENA 1
#define ZATVORENA 2
#define GRESKA 0

/* Funkcija ucitava sledecu etiketu i smesta njen naziv u niz s


duzine max. Vraca OTVORENA za otvorenu etiketu, ZATVORENA za
zatvorenu etiketu, odnosno GRESKA inace */
int gettag(char s[], int max) {
int c, i;
int zatvorenost=OTVORENA;

/* Preskacemo sve do znaka ’<’ */


while ((c=getchar())!=EOF && c!=’<’)
;
/* Nismo naisli na etiketu */
if (c==EOF)
return GRESKA;

/* Proveravamo da li je etiketa zatvorena */


if ((c=getchar())==’/’)
zatvorenost=ZATVORENA;
else
/* Funkcija ungetc vraca karakter c na standardni ulaz */
ungetc(c,stdin);

/* Citamo etiketu dok nailaze slova i smestamo ih u nisku */


for (i=0; isalpha(c=getchar()) && i<max-1; s[i++] = c)
;
/* Vracamo poslednji karakter na ulaz jer je to bio neki karakter
koji nije slovo*/
ungetc(c,stdin);

s[i]=’\0’;

/* Preskacemo atribute do znaka > */


while ((c=getchar())!=EOF && c!=’>’)
;

/* Greska ukoliko nismo naisli na ’>’ */


return c==’>’ ? zatvorenost : GRESKA;

148
4.48 Liste 149

/* Stek ce biti implementiran koriscenjem liste */


typedef struct
cvor {
char tag[MAX_TAG];
struct cvor* sledeci;
} CVOR;

CVOR* stek = NULL;

main()
{
char tag[MAX_TAG];
int zatvorenost;
while ((zatvorenost = gettag(tag, MAX_TAG))>0)
{
if (zatvorenost==OTVORENA)
{
/* Svaku otvorenu etiketu stavljamo na stek */

CVOR* tmp = (CVOR*)malloc(sizeof(CVOR));


if (tmp == NULL)
{
printf("Greska prilikom alokacije memorije!\n");
return 1;
}
strcpy(tmp->tag, tag);
tmp->sledeci = stek;
stek = tmp;

printf("Postavio <%s> na stek\n", stek->tag);


}

else
{
/* Za zatvorene etikete proveravamo da li je stek prazan
odnosno da li se na vrhu steka nalazi odgovarajuca
otvorena etiketa */
if (stek != NULL && strcmp(stek->tag, tag) == 0)
{
/* Uklanjamo etiketu sa steka */
CVOR* tmp = stek->sledeci;
free(stek);
stek = tmp;
}
else
{
/* Prijavljujemo gresku */
printf("Neodgovarajuci tag : </%s>!\n",tag);

149
150 Milena Vujošević–Janičić

exit(1);
}
}
}

if (stek == NULL) printf("Datoteka je ispravna\n ");


else
{
printf("Visak otvorenih etiketa!\n");
/* Oslobadjamo memoriju koja je ostala
zarobljena na steku. */
while(stek!=NULL)
{
CVOR* tmp = stek->sledeci;
free(stek);
stek = tmp;
}
}
}

4.48.4 Dvostruko povezane liste

početak dvostruko povezane liste kraj liste

...
NULL A B C ... Z NULL

Slika 4.4: Dvostruko povezana lista

Primer 4.48.7 Napisati funkciju koja omogućava umetanje čvora u dvostruko


povezanu kružnu listu kao i izbacivanje čora iz dvostruko povezane kružne liste.
Omogućiti i štampanje podataka koje čuva lista.

/* Program implementira deciju razbrajalicu eci-peci-pec i sluzi


da ilustruje rad sa dvostruko povezanim kruznim listama */

#include <stdlib.h>
#include <stdio.h>

/* Dvostruko povezana lista */


typedef struct _cvor {
int broj;

150
4.48 Liste 151

struct _cvor* prethodni, *sledeci;


} cvor;

/* Umetanje u dvostruko povezanu listu */


cvor* ubaci(int br, cvor* lista) {
cvor* novi=(cvor*)malloc(sizeof(cvor));
if (novi==NULL)
{ printf("Greska prilikom alokacije memorije \n");
exit(1);
}
novi->broj=br;

if (lista==NULL)
{ novi->sledeci=novi;
novi->prethodni=novi;
return novi;
}
else
{ novi->prethodni=lista;
novi->sledeci=lista->sledeci;
lista->sledeci->prethodni=novi;
lista->sledeci=novi;
return novi;
}
}

/* Ispis liste */
void ispisi(cvor* lista)
{
if (lista!=NULL)
{ cvor* tekuci=lista;
do
{ printf("%d\n",tekuci->broj);
tekuci=tekuci->sledeci;
} while (tekuci!=lista);
}
}

/* Izbacivanje datog cvora iz liste, funkcija


vraca pokazivac na novonastalu listu */
cvor* izbaci(cvor* lista) {
if (lista!=NULL)
{ cvor* sledeci=lista->sledeci;
if (lista==lista->sledeci)
{ printf("Pobednik %d\n",lista->broj);
free(lista);
return NULL;
}

printf("Ispada %d\n",lista->broj);

151
152 Milena Vujošević–Janičić

lista->sledeci->prethodni=lista->prethodni;
lista->prethodni->sledeci=lista->sledeci;
free(lista);
return sledeci;
}
else return NULL;
}

main() {
/* Umecemo petoro dece u listu */
cvor* lista = NULL;
lista=ubaci(1,lista);
lista=ubaci(2,lista);
lista=ubaci(3,lista);
lista=ubaci(4,lista);
lista=ubaci(5,lista);
lista=lista->sledeci;

/*Proverimo da smo dobro formirali listu*/


ispisi(lista);

int smer = 0;
/* Dok ima dece u listi */
while(lista!=NULL)
{ int i;

/* brojimo 13 slogova u krug i u svakom brojanju


menjamo smer obilaska*/
for (i=1; i<=13; i++)
lista = 1-smer ? lista->sledeci : lista->prethodni;

lista=izbaci(lista);
smer = smer ? 0 : 1;
}
}
Primer 4.48.8 Program ispisuje broj pojavljivanja za svaku od reči koja se
pojavila u tekstu unetom sa standardnog ulaza. Verzija sa (sortiranom) listom.
#include <stdlib.h>
#include <stdio.h>

/* Definicija cvora liste */


typedef struct _cvor
{
char ime[80];
int br_pojavljivanja;
struct _cvor* sledeci;
} cvor;

152
4.48 Liste 153

/* Funkcija ispisuje listu rekurzivno, pocevsi od poslednjeg


elementa */
void ispisi_listu(cvor* pocetak)
{
if (pocetak!=NULL)
{
ispisi_listu(pocetak->sledeci);
printf("%s %d\n",pocetak->ime,pocetak->br_pojavljivanja);
}
}

/* Funkcija koja brise listu */


void obrisi_listu(cvor* pocetak)
{
if (pocetak!=NULL)
{
obrisi_listu(pocetak->sledeci);
free(pocetak);
}
}

/* Funkcija ubacuje rekurzivno datu rec u listu koja je


leksikografski sortirana, na odgovarajuce mesto i vraca
pokazivac na novi pocetak liste */
cvor* ubaci_sortirano(cvor* pocetak, char* rec)
{
int cmp;
/* Ukoliko je lista prazna ubacujemo na pocetak liste*/
if (pocetak==NULL)
{ pocetak=(cvor*)malloc(sizeof(cvor));
if (pocetak == NULL)
{
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}
strcpy(pocetak->ime,rec);
pocetak->br_pojavljivanja=1;
return pocetak;
}
/* Ukoliko lista nije prazna poredimo rec sa elementom u glavi */
cmp=strcmp(pocetak->ime,rec);
/* Ukoliko je rec pronadjena samo uvecavamo njen broj
pojavljivanja */
if (cmp==0)
{ pocetak->br_pojavljivanja++;
return pocetak;
}
/* Ukoliko je rec koju ubacujemo veca od tekuce reci, ubacujemo je
rekurzivno u rep */
else if (cmp>0)

153
154 Milena Vujošević–Janičić

{ pocetak->sledeci=ubaci_sortirano(pocetak->sledeci,rec);
return pocetak;
}
/* Ukoliko je rec koju ubacujemo manja od tekuce reci, gradimo novi
cvor i ubacujemo ga ispred pocetka */
else
{ cvor* novi=malloc(sizeof(cvor));
if (novi == NULL)
{
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}
strcpy(novi->ime,rec);
novi->br_pojavljivanja=1;
novi->sledeci=pocetak;
return novi;
}
}

/* Pomocna funkcija koja cita rec sa standardnog ulaza i vraca


njenu duzinu, odnosno -1 ukoliko se naidje na EOF */
int getword(char word[], int lim) {
int c, i=0;
while (!isalpha(c=getchar()) && c!=EOF)
;

if (c==EOF)
return -1;
do
{ word[i++]=c;
}while (i<lim-1 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

/* Funkcija koja rekurzivno pronalazi datu rec u datoj listi.


Funkcija vraca pokazivac na cvor u kome je nadjena rec, ili
NULL ukoliko rec nije nadjena */
cvor* nadji_rec(cvor* lista, char rec[])
{
if (lista==NULL)
return NULL;
if (strcmp(lista->ime,rec)==0)
return lista;

return nadji_rec(lista->sledeci,rec);
}

154
4.49 Drvo 155

main()
{
cvor* lista=NULL;
char procitana_rec[80];
while(getword(procitana_rec,80)!=-1)
{ cvor* pronadjen=nadji_rec(lista,procitana_rec);
if (pronadjen!=NULL)
pronadjen->br_pojavljivanja++;
else
lista=ubaci_sortirano(lista,procitana_rec);
}
ispisi_listu(lista);
obrisi_listu(lista);
}

4.49 Drvo

NULL NULL

NULL NULL NULL

NULL NULL

Slika 4.5: Stablo

155
156 Milena Vujošević–Janičić

Primer 4.49.1 Binarno pretrazivacko drvo - drvo sadrži cele brojeve.

17, 12, 21, 15, 5, 14


17

12 21

NULL NULL

5 15

NULL NULL NULL

inf ix : 5, 12, 14, 15, 17, 21


14 pref ix : 17, 12, 5, 15, 14, 21

postf ix : 5, 14, 15, 12, 21, 17


NULL NULL

Slika 4.6: Ure eno stablo

/* Program demonstrira rad sa binarnim pretrazivackim drvetima.


Drveta sadrze cele brojeve i sortirana su po velicini.
Za svaki cvor, levo podstabla sadrzi manje elemente, dok desno
podstablo sadrzi vece.
*/

#include <stdlib.h>
#include <stdio.h>

typedef struct _cvor


{
int broj;
struct _cvor *l, *d;
} cvor;

156
4.49 Drvo 157

cvor* napravi_cvor(int b) {
cvor* novi = (cvor*)malloc(sizeof(cvor));
if (novi == NULL)
{
fprintf(stderr, "Greska prilikom
alokacije memorije");
exit(1);
}
novi->broj = b;
novi->l = NULL;
novi->d = NULL;
return novi;
}

/* Funkcija umece broj br u drvo ciji je koren dat preko


pokazivaca drvo. Funkcija vraca pokazivac na koren
novog drveta */
cvor* ubaci_u_drvo(cvor* drvo, int b)
{
if (drvo == NULL)
return napravi_cvor(b);

if (b < drvo->broj)
drvo->l = ubaci_u_drvo(drvo->l, b);
else
drvo->d = ubaci_u_drvo(drvo->d, b);

return drvo;
}

/* Funkcija proverava da li dati broj postoji u drvetu */


int pronadji(cvor* drvo, int b)
{
if (drvo == NULL)
return 0;

if (drvo->broj == b)
return 1;

if (b < drvo->broj)
return pronadji(drvo->l, b);
else
return pronadji(drvo->d, b);
}

/* Funkcija ispisuje sve cvorove drveta u infiksnom redosledu */


void ispisi_drvo(cvor* drvo) {
if (drvo != NULL)
{
ispisi_drvo(drvo->l);

157
158 Milena Vujošević–Janičić

printf("%d ", drvo->broj);


ispisi_drvo(drvo->d);
}
}

void obrisi_drvo(cvor* drvo) {


if (drvo != NULL)
{
obrisi_drvo(drvo->l);
obrisi_drvo(drvo->d);
free(drvo);
}
}

/* Funkcija sumira sve vrednosti binarnog stabla */


int suma_cvorova(cvor* drvo)
{
if (drvo == NULL)
return 0;
return suma_cvorova(drvo->l) +
drvo->broj +
suma_cvorova(drvo->d);
}

int broj_cvorova(cvor* drvo)


{
if (drvo == NULL)
return 0;
return broj_cvorova(drvo->l) +
1 +
broj_cvorova(drvo->d);
}

int broj_listova(cvor* drvo)


{
if (drvo == NULL)
return 0;
if (drvo->l == NULL && drvo->d == NULL)
return 1;
return broj_listova(drvo->l) +
broj_listova(drvo->d);
}

int suma_listova(cvor* drvo)


{
if (drvo == NULL)
return 0;

if (drvo->l == NULL && drvo->d == NULL)

158
4.49 Drvo 159

return drvo->broj;

return suma_listova(drvo->l) +
suma_listova(drvo->d);
}

void ispisi_listove(cvor* drvo)


{
if (drvo == NULL)
return;

ispisi_listove(drvo->l);

if (drvo->l == NULL && drvo->d == NULL)


printf("%d ", drvo->broj);

ispisi_listove(drvo->d);
}

/* Funkcija pronalazi maksimalnu vrednost u drvetu


Koristi se cinjenica da je ova vrednost
smestena u najdesnjem listu */
int max_vrednost(cvor* drvo)
{
if (drvo==NULL)
return 0;

if (drvo->d==NULL)
return drvo->broj;

return max_vrednost(drvo->d);
}

/* Iterativna funkcija za pronalazenje maksimalne vrednosti. */


int max_vrednost_nerekurzivno(cvor* drvo)
{
if (drvo==NULL)
return 0;
else
{
cvor* tekuci;
for (tekuci=drvo; tekuci->d!=NULL; tekuci=tekuci->d)
;
return tekuci->broj;
}
}

/* Funkcija racuna "dubinu" binarnog stabla */


#define max(a,b) (((a)>(b))?(a):(b))

159
160 Milena Vujošević–Janičić

int dubina(cvor* drvo)


{
if (drvo==NULL)
return 0;
else
{ int dl=dubina(drvo->l);
int dd=dubina(drvo->d);
return 1+max(dl,dd);
}
}

main()
{
cvor* drvo = NULL;
drvo = ubaci_u_drvo(drvo, 1);
drvo = ubaci_u_drvo(drvo, 8);
drvo = ubaci_u_drvo(drvo, 5);
drvo = ubaci_u_drvo(drvo, 3);
drvo = ubaci_u_drvo(drvo, 7);
drvo = ubaci_u_drvo(drvo, 6);
drvo = ubaci_u_drvo(drvo, 9);

if (pronadji(drvo, 3))
printf("Pronadjeno 3\n");
if (pronadji(drvo, 2))
printf("Pronadjeno 2\n");
if (pronadji(drvo, 7))
printf("Pronadjeno 7\n");

ispisi_drvo(drvo);

putchar(’\n’);
printf("Suma cvorova : %d\n", suma_cvorova(drvo));
printf("Broj cvorova : %d\n", broj_cvorova(drvo));
printf("Broj listova : %d\n", broj_listova(drvo));
printf("Suma listova : %d\n", suma_listova(drvo));
printf("Dubina drveta : %d\n", dubina(drvo));
printf("Maximalna vrednost : %d\n", max_vrednost(drvo));

ispisi_listove(drvo);

obrisi_drvo(drvo);
}

/*
Pronadjeno 3
Pronadjeno 7
1 3 5 6 7 8 9
Suma cvorova : 39

160
4.49 Drvo 161

Broj cvorova : 7
Broj listova : 3
Suma listova : 18
Dubina drveta : 5
Maximalna vrednost : 9
3 6 9
*/
Primer 4.49.2 Program sa ulaza čita tekst i ispisuje broj pojavljivanja svake od
reči koje su se javljale u tekstu. Radi poboljsanja efikasnosti, prilikom brojanja
reci koristi se struktura podataka pogodna za leksikografsku pretragu - u ovom
slucaju binarno pretrazivacko drvo.
#include <stdlib.h>
#include <stdio.h>

/* Cvor drveta sadrzi ime reci i


broj njenih pojavljivanja */
typedef struct _cvor {
char ime[80];
int br_pojavljivanja;
struct _cvor* levo, *desno;
} cvor;

/* Funkcija ispisuje drvo u inorder redosledu */


void ispisi_drvo(cvor* drvo)
{
if (drvo!=NULL)
{
ispisi_drvo(drvo->levo);
printf("%s %d\n",drvo->ime,drvo->br_pojavljivanja);
ispisi_drvo(drvo->desno);
}
}

/* Funkcija uklanja binarno drvo iz memorije */


void obrisi_drvo(cvor* drvo)
{
if (drvo!=NULL)
{
obrisi_drvo(drvo->levo);
obrisi_drvo(drvo->desno);
free(drvo);
}
}

/* Funkcija ubacuje datu rec u dato drvo


i vraca pokazivac na koren drveta */
cvor* ubaci(cvor* drvo, char rec[]) {
/* Ukoliko je drvo prazno gradimo novi cvor */
if (drvo==NULL)

161
162 Milena Vujošević–Janičić

{
cvor* novi_cvor=(cvor*)malloc(sizeof(cvor));
if (novi_cvor==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
strcpy(novi_cvor->ime, rec);
novi_cvor->br_pojavljivanja=1;
return novi_cvor;
}

/* Uporedjujemo rec koju smo ucitali sa recju koja


se nalazi u cvoru drveta*/
int cmp = strcmp(rec, drvo->ime);

/* Ukoliko rec vec postoji u drvetu


uvecavamo njen broj pojavljivanja */
if (cmp==0)
{ drvo->br_pojavljivanja++;
return drvo;
}

/* Ukoliko je rec koju ubacujemo leksikografski


ispred reci koja je u korenu drveta, rec
ubacujemo u levo podstablo */
if (cmp<0)
{ drvo->levo=ubaci(drvo->levo, rec);
return drvo;
}

/* Ukoliko je rec koju ubacujemo


leksikografski iza reci koja je u
korenu drveta, rec ubacujemo u desno
podstablo */
if (cmp>0)
{ drvo->desno=ubaci(drvo->desno, rec);
return drvo;
}
}

/* Pomocna funkcija koja cita rec sa


standardnog ulaza i vraca njenu
duzinu, odnosno -1 ukoliko se naidje na EOF.
Ukoliko umesto funkcije getword koristimo
funkciju gettag program ce ispisivati
broj pojavljivanja svakog od tagova sa ulaza */
int getword(char word[], int lim) {
int c, i=0;
while (!isalpha(c=getchar()) && c!=EOF)

162
4.49 Drvo 163

if (c==EOF)
return -1;
do
{
word[i++]=c;
} while (i<lim-1 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

main() {
/* Drvo je na pocetku prazno */
cvor* drvo=NULL;
char procitana_rec[80];

/* Citamo rec po rec dok ne


naidjemo na kraj datoteke i
ubacujemo ih u drvo */
while(getword(procitana_rec,80)!=-1)
drvo=ubaci(drvo,procitana_rec);

/* Ispisujemo drvo */
ispisi_drvo(drvo);

/* Uklanjamo ga iz memorije */
obrisi_drvo(drvo);
}

Primer 4.49.3 Program iz datoteke čita tekst i ispisuje n najfrekventnijih reči


koje su se javljale u tekstu.
Radi poboljšanja efikasnosti, prilikom brojanja reči koristi se struktura po-
dataka pogodna za leksikografsku pretragu - u ovom slučaju binarno pretraživačko
drvo.
Na kraju rada, čvorovi drveta se ”presortiraju” na osnovu broja pojavljivanja.
Zbog ovoga je potrebno čuvati niz pokazivača na različite čvorove drveta.
Da bismo ispisali 10 najfrekventnijih etiketa, potrebno je zameniti funkciju
getword funkcijom gettag.

#include <stdlib.h>
#include <stdio.h>

/* Cvor drveta sadrzi ime reci i


broj njenih pojavljivanja */
typedef struct _cvor {
char ime[80];
int br_pojavljivanja;
struct _cvor* levo, *desno;

163
164 Milena Vujošević–Janičić

} cvor;

/* Gradimo niz pokazivaca na cvorove drveta koji ce


nam sluziti da po prihvatanju svih reci izvrsimo
sortiranje po broju pojavljivanja */

#define MAX_BROJ_RAZLICITIH_RECI 1000

cvor* razlicite_reci[MAX_BROJ_RAZLICITIH_RECI];

/* Tekuci broj cvorova drveta */


int broj_razlicitih_reci=0;

/* Funkcija uklanja binarno drvo iz memorije */


void obrisi_drvo(cvor* drvo)
{
if (drvo!=NULL)
{ obrisi_drvo(drvo->levo);
obrisi_drvo(drvo->desno);
free(drvo);
}
}

/* Funkcija ubacuje datu rec u dato drvo i vraca pokazivac na


koren drveta */
cvor* ubaci(cvor* drvo, char rec[])
{
/* Ukoliko je drvo prazno gradimo novi cvor */
if (drvo==NULL)
{
cvor* novi_cvor=(cvor*)malloc(sizeof(cvor));
if (novi_cvor==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
strcpy(novi_cvor->ime, rec);
novi_cvor->br_pojavljivanja=1;

/* pokazivac na novo napravljeni cvor smestamo u niz


pokazivaca na sve cvorove drveta */
razlicite_reci[broj_razlicitih_reci++] = novi_cvor;

return novi_cvor;
}
int cmp = strcmp(rec, drvo->ime);

/* Ukoliko rec vec postoji u drvetu


uvecavamo njen broj pojavljivanja */
if (cmp==0)

164
4.49 Drvo 165

{ drvo->br_pojavljivanja++;
return drvo;
}

/* Ukoliko je rec koju ubacujemo leksikografski ispred


reci koja je u korenu drveta, rec ubacujemo
u levo podstablo */
if (cmp<0)
{ drvo->levo=ubaci(drvo->levo, rec);
return drvo;
}

/* Ukoliko je rec koju ubacujemo


leksikografski iza reci koja je u
korenu drveta, rec ubacujemo
u desno podstablo */
if (cmp>0)
{ drvo->desno=ubaci(drvo->desno, rec);
return drvo;
}
}

/* Pomocna funkcija koja cita rec iz date datoteke i vraca


njenu duzinu, odnosno -1 ukoliko se naidje na EOF */
int getword(char word[], int lim, FILE* ulaz)
{
int c, i=0;
/* Umesto funkcije getchar koristimo fgetc
za rad sa datotekama */
while (!isalpha(c=fgetc(ulaz)) && c!=EOF)
;
if (c==EOF)
return -1;
do
{ word[i++]=c;
}while (i<lim-1 && isalpha(c=fgetc(ulaz)));

word[i]=’\0’;
return i;
}

/* Funkcija poredjenja za funkciju qsort. */


int poredi_br_pojavljivanja(const void* a, const void* b)
{
return
/* Konverzija pokazivaca b iz pokazivaca
na tip void u pokazivac na cvor jer
nam je svaki element niza koji sortiramo
tipa pokazivaca na cvor */
(*(cvor**)b)->br_pojavljivanja

165
166 Milena Vujošević–Janičić

-
(*(cvor**)a)->br_pojavljivanja;
}

main(int argc, char* argv[])


{
int i;

/* Drvo je na pocetku prazno */


cvor* drvo=NULL;
char procitana_rec[80];
FILE* ulaz;

if (argc!=2)
{ fprintf(stderr,"Greska :
Ocekivano ime datoteke\n");
exit(1);
}

if ((ulaz=fopen(argv[1],"r"))==NULL)
{
fprintf(stderr,"Greska : nisam uspeo da otvorim datoteku %s\n");
exit(1);
}

/* Citamo rec po rec dok ne naidjemo na kraj datoteke i


ubacujemo ih u drvo */
while(getword(procitana_rec,80,ulaz)!=-1)
drvo=ubaci(drvo,procitana_rec);

/* Sortiramo niz pokazivaca na cvorove


drveta po broju pojavljivanja */
qsort(razlicite_reci,
broj_razlicitih_reci,
sizeof(cvor*),
poredi_br_pojavljivanja);

/* Ispisujemo prvih 10 (ukoliko ih ima)


reci i njihov broj pojavljivanja */
for (i=0; i<10 && i<broj_razlicitih_reci; i++)
printf("%s - %d\n",razlicite_reci[i]->ime,
razlicite_reci[i]->br_pojavljivanja);

/* Uklanjamo drvo iz memorije */


obrisi_drvo(drvo);

fclose(ulaz);
}

166
4.50 Grafovi 167

4.50 Grafovi
Graf1 G=(V,E) sastoji se od skupa V čvorova i skupa E grana. Grane predstavl-
jaju relacije izme u čvorova i odgovara paru čvorova. Graf može biti usmeren
(orijentisan), ako su mu grane ure eni parovi i neusmeren (neorjentisan) ako su
grane neure eni parovi.
Uobičajena su dva načina predstavljanja grafova. To su matrica povezanosti
grafa i lista povezanosti.
Matrica povezanosti je kvadratna matrica dimenzije n, pri čemu je n broj
čvorova u grafu, takva da je element na preseku i-te vrste i j-te kolone jednak
jedinici ukoliko postoji grana u grafu od i-tog do j-tog čvora, inače je nula.
Umesto da se i sve nepostojeće grane eksplicitno predstavljaju u matrici
povezanosti, mogu se formirati povezane liste od jedinica iz i-te vrste za i=1,2,...,n.
To je lista povezanosti. Svakom čvoru se pridružuje povezana lista, koja sadrži
sve grane susedne tom čvoru. Graf je predstavljen vektorom lista. Svaki eleme-
nat vektora sadrži ime (indeks) čvora i pokazivač na njegovu listu čvorova.
Prvi problem na koji se nailazi pri konstrukciji bilo kog algoritma za obradu
grafa je kako pregledati ulaz. Postoje dva osnovna algoritma za obilazak grafa:
pretraga u dubinu (DFS, skraćenica od depth-first-search) i pretraga u širinu
(BFS, skraćenica od breadth-first-search).
Kod DFS algoritma, obilazak započinje iz proizvoljnog zadatog čvora r koji
se naziva koren pretrage u dubinu. Koren se označava kao posećen. Zatim se
bira proizvoljan neoznačen čvor r1, susedan sa r, pa se iz čvora r1 rekurzivno
startuje pretraga u dubinu. Iz nekog nivoa rekurzije izlazi se kad se nai e na
čvor v kome su svi susedi već označeni.

Primer 4.50.1 Primer reprezentovanja grafa preko matrice povezanosti. U


programu se unosi neorijentisan graf i DFS algoritmom se utvr uju čvrovi koji


su dostižni iz čvora 0.

#include <stdlib.h>
#include <stdio.h>

int** alociraj_matricu(int n)
{ int **matrica;
int i;
matrica=malloc(n*sizeof(int*));
if (matrica==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}

for (i=0; i<n; i++)


{
/* Funkcija calloc popunjava rezervisan
prostor u memoriji nulama. */
matrica[i]=calloc(n,sizeof(int));
1 Tekst i primeri preuzeti od Jelene Tomašević, url: www.matf.bg.ac.yu/˜jtomasevic, zas-

novano na materijalu Algoritmi, Miodrag Živković i http://www.matf.bg.ac.yu/˜filip

167
168 Milena Vujošević–Janičić

if (matrica[i]==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
}
return matrica;
}

void oslobodi_matricu(int** matrica, int n)


{ int i;
for (i=0; i<n; i++)
free(matrica[i]);
free(matrica);
}

int* alociraj_niz(int n)
{ int* niz;
niz=calloc(n,sizeof(int));
if (niz==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
return niz;
}

void oslobodi_niz(int* niz)


{ free(niz);
}

void unesi_graf(int** graf, int n)


{ int i,j;
for (i=0; i<n; i++)
for (j=i; j<n; j++)
{ printf("Da li su element %d i %d povezani : ",i,j);
do
{ scanf("%d",&graf[i][j]);
/* Radimo sa neusmerenim grafom */
graf[j][i]=graf[i][j];
} /* Obezbedjujemo ispravan unos */
while (graf[i][j]!=0 && graf[i][j]!=1);
}
}

void ispisi_graf(int** graf, int n)


{ int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
printf("%d",graf[i][j]);

168
4.50 Grafovi 169

printf("\n");
}
}

/* Broj cvorova grafa (dimenzija matrice) */


int n;
/* Matrica povezanosti */
int **graf;

/* Pomocni vektor koji govori o tome koji su cvorovi posecivani


tokom DFS obilaska */
int *posecen;

/* Rekurzivna implementacija DFS algoritma */


void poseti(int i)
{ int j;
posecen[i]=1;
printf("Posecujem cvor %d\n",i);
for (j=0; j<n; j++)
if (graf[i][j] && !posecen[j])
poseti(j);
}

main()
{
int i, j;
printf("Unesi broj cvorova : ");
scanf("%d",&n);

graf=alociraj_matricu(n);
unesi_graf(graf,n);
ispisi_graf(graf,n);

posecen=alociraj_niz(n);
poseti(0);

oslobodi_niz(posecen);
oslobodi_matricu(graf,n);
}
Primer 4.50.2 Primer predstavljanja grafa preko niza listi suseda svakog od
čvorova grafa U programu se unosi graf i DFS algoritmom se utvrdjuje koji su
čvorovi dostižni iz cvora 0.
#include <stdlib.h>
#include <stdio.h>

169
170 Milena Vujošević–Janičić

/* Cvor liste suseda */


typedef struct _cvor_liste
{ int broj; /* Indeks suseda */
struct _cvor_liste* sledeci;
} cvor_liste;

/* Ubacivanje na pocetak liste */


cvor_liste* ubaci_u_listu(cvor_liste* lista, int broj)
{ cvor_liste* novi=malloc(sizeof(cvor_liste));
if (novi==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
novi->broj=broj;
novi->sledeci=lista;
return novi;
}

/* Rekurzivno brisanje liste */


void obrisi_listu(cvor_liste* lista)
{ if (lista)
{ obrisi_listu(lista->sledeci);
free(lista);
}
}

/* Ispis liste */
void ispisi_listu(cvor_liste* lista)
{ if (lista)
{ printf("%d ",lista->broj);
ispisi_listu(lista->sledeci);
}
}

/* Graf predstavlja niz pokazivaca na pocetke listi suseda */


#define MAX_BROJ_CVOROVA 100
cvor_liste* graf[MAX_BROJ_CVOROVA];
int broj_cvorova;

/* Rekurzivna implementacija DFS algoritma */


int posecen[MAX_BROJ_CVOROVA];
void poseti(int i)
{ cvor_liste* sused;
printf("Posecujem cvor %d\n",i);
posecen[i]=1;
for( sused=graf[i]; sused!=NULL; sused=sused->sledeci)
if (!posecen[sused->broj])
poseti(sused->broj);

170
4.51 Razni zadaci 171

main()
{
int i;
printf("Unesi broj cvorova grafa : ");
scanf("%d",&broj_cvorova);
for (i=0; i<broj_cvorova; i++)
{ int br_suseda,j;

graf[i]=NULL;

printf("Koliko cvor %d ima suseda : ",i);


scanf("%d",&br_suseda);
for (j=0; j<br_suseda; j++)
{ int sused;
do
{
printf("Unesi broj %d.-tog suseda cvora %d : ",j,i);
scanf("%d",&sused);
} while (sused<1 && sused>broj_cvorova);
graf[i]=ubaci_u_listu(graf[i],sused-1);
}
}

for (i=0; i<broj_cvorova; i++)


{ printf("%d - ",i);
ispisi_listu(graf[i]);
printf("\n");
}

poseti(0);
}

4.51 Razni zadaci


k
Primer 4.51.1 Stepenovanje prirodnog broja efikasno: nk = (n 2 )2 ako je k
k−1
parno ili nk = n(n 2 )2 ako je k neparno.

int stepen(int n, int k)


{
int p, s;
if (k==1) s=n;
else
{
p=stepen(n,k/2);
if(k%2==0) s=p*p;
else s=p*p*n;

171
172 Milena Vujošević–Janičić

}
return s;
}
Primer 4.51.2 MINESWEEPER - primer jednostavne igrice.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

/* Dimenzija table */
int n;

/* Tabla koja sadrzi 0 i 1 u zavisnosti


od toga da li na polju postoji bomba */
int** bombe;

#define PRAZNO (-1)


#define ZATVORENO 0
#define ZASTAVICA 9

/* Tabla koja opisuje tekuce stanje igre.


Moze da sadrzi sledece vrednosti :
ZATVORENO - opisuje polje
koje jos nije bilo otvarano
PRAZNO - polje na kome ne
postoji ni jedna bomba
BROJ od 1-8 - polje koje je
otvoreno i na kome pise
koliko bombi postoji u okolini
ZASTAVICA - polje koje je korisnik
oznacio zastavicom
*/
int** stanje;

/* Ukupan broj bombi */


int broj_bombi;

/* Ukupan broj postavljenih zastavica */


int broj_zastavica = 0;

/* Pomocne funkcije za rad sa matricama */


int** alociraj(int n)
{
int i;
int** m=(int**)malloc(n*sizeof(int*));
for (i=0; i<n; i++)
m[i]=(int *)calloc(n,sizeof(int));
return m;
}

172
4.51 Razni zadaci 173

void obrisi(int** m, int n)


{ int i;
for (i=0; i<n; i++)
free(m[i]);

free(m);
}

/* Funkcija postavlja bombe */ void postavi_bombe()


{ broj_bombi=(n*n)/6;
int kolona;
int vrsta;
int i;

/* Inicijalizujemo generator slucajnih brojeva */


srand(time(NULL));

for (i=0; i<broj_bombi; i++)


{ /* Racunamo slucajni polozaj bombe */
kolona=rand()%n;
vrsta=rand()%n;

/* Ukoliko bomba vec postoji tu,


opet idemo u istu iteraciju */
if (bombe[vrsta][kolona]==1)
{ i--;
continue;
}

/* Postavljamo bombu */
bombe[vrsta][kolona]=1;
}
}

/* Funkcija ispisuje tablu sa bombama */


void ispisi_bombe()
{
int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
printf("%d",bombe[i][j]);
printf("\n");
}
}

/* Funkcija ispisuje tekuce stanje */


void ispisi_stanje()
{ int i,j;
for (i=0; i<n; i++)

173
174 Milena Vujošević–Janičić

{ for (j=0; j<n; j++)


{ if (stanje[i][j]==ZATVORENO)
printf(".");
else if (stanje[i][j]==PRAZNO)
printf(" ");
else if (stanje[i][j]==ZASTAVICA)
printf("*");
else
printf("%d",stanje[i][j]);
}
printf("\n");
}
}

/* Funkcija postavlja zastavicu na


dato polje ili je uklanja
ukoliko vec postoji */
void postavi_zastavicu(int i, int j)
{
if (stanje[i][j]==ZATVORENO)
{ stanje[i][j]=ZASTAVICA;
broj_zastavica++;
}
else if (stanje[i][j]==ZASTAVICA)
{ stanje[i][j]=ZATVORENO;
broj_zastavica--;
}
}

/* Funkcija izracunava koliko bombi


postoji u okolini date bombe */
int broj_bombi_u_okolini(int v, int k)
{ int i, j;
int br=0;
/* Prolazimo kroz sva okolna polja */
for (i=-1; i<=1; i++)
for(j=-1; j<=1; j++)
{ /* preskacemo centralno polje */
if (i==0 && j==0)
continue;
/* preskacemo polja "van table" */
if (v+i<0 || k+j<0 || v+i>=n || k+j>=n)
continue;
if (bombe[v+i][k+j]==1)
br++;
}

return br;

174
4.51 Razni zadaci 175

/* Centralna funkcija koja vrsi otvaranje


polja i pritom se otvaranje "siri"
i na polja koja su oko datog */

void otvori_polje(int v, int k) {


/* Ukoliko smo "nagazili" bombu
zavrsavamo program */
if (bombe[v][k]==1)
{ printf("BOOOOOOOOOOOOOOOOM!!!!\n");
ispisi_bombe();
exit(1);
}
else
{
/* Brojimo bombe u okolini */
int br=broj_bombi_u_okolini(v,k);

/* Azuriramo stanje ovog polja */


stanje[v][k]=(br==0)?PRAZNO:br;

/* Ukoliko u okolini nema bombi,


rekurzivno otvaramo
sva polja u okolini koja su zatvorena */
if (br==0)
{
/* Petlje indeksiraju sva okolna polja */
int i,j;
for (i=-1; i<=1; i++)
for (j=-1; j<=1; j++)
{
/* Preskacemo centralno polje */
/* if (i==0 && j==0)
continue; */
/* Preskacemo polja van table */
if (v+i<0 || v+i>=n || k+j<0 || k+j>=n)
continue;
/* Ukoliko je okolno polje
zatvoreno, otvaramo ga */
if (stanje[v+i][k+j]==ZATVORENO)
otvori_polje(v+i, k+j);
}
}
}
}

/* Funkcija utrdjuje da li je partija gotova


Partija je gotova u trenutku kada su sve
bombe pokrivene zastavicama i
kada nijedno drugo polje nije

175
176 Milena Vujošević–Janičić

pokriveno zastavicom
*/

int gotova_partija()
{ int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{ /* Ukoliko postoji nepokrivena bomba,
partija nije zavrsena */
if (bombe[i][j]==1 && stanje[i][j]!=ZASTAVICA)
return 0;
}

/* Partija je zavrsena samo ukoliko je


broj zastavica jednak broj bombi */
return broj_zastavica==broj_bombi;

main() {

/* Unosimo dimenziju table */


printf("Unesite dimenziju table : ");
scanf("%d",&n);

/* Alociramo table */
bombe=alociraj(n);
stanje=alociraj(n);

/* Postavljamo bombe */
postavi_bombe();

/* Sve dok partija nije gotova */


while(!gotova_partija())
{ int v,k;
char akcija;

/* Ispisujemo tekuce stanje */


ispisi_stanje();

/* Sve dok korisnik ne unese o ili z


trazimo od njega da upise
odgovarajucu akciju */
do
{
getchar();
printf("Unesi akciju (o - otvaranje polja,
z - postavljanje zastavice) : ");
scanf("%c",&akcija);

176
4.51 Razni zadaci 177

} while (akcija!=’o’ && akcija!=’z’);

/* Trazimo od korisnika da unese koordinate


polja sve dok ih ne unese ispravno
Korisnicke koordinate krecu od 1,
a interne od 0 */
do
{
printf("Unesi koordinate polja : ");
scanf("%d",&v);
scanf("%d",&k);
} while(v<1 || v>n || k<1 || k>n);

/* Reagujemo na akciju */
switch(akcija)
{ case ’o’:
otvori_polje(v-1,k-1);
break;
case ’z’:
postavi_zastavicu(v-1,k-1);
}
}

/* Konstatujemo pobedu */
ispisi_stanje();
printf ("Cestitam! Pobedili ste\n");
obrisi(stanje,n);
obrisi(bombe,n);
}

177
Programiranje 1
Programski jezik C
— Zadaci sa vežbi —

Milena Vujosevic - Janicic 2008/2009


Predgovor

Ovo je prateci materijal za vezbe koje drzim iz predmenta Programi-


ranje 1. On ne moze zameniti pohad̄anje vezbi niti koriscenje druge
preporucene literature.
Deo materijala cine zadaci i resenja mr Filipa Marica (raspolo-
zivi na www.matf.bg.ac.yu/~filip/pp/0405/index.pl). Takod̄e
koriscen je i materijal sa sajta koleginice Jelene Grmuse
www.matf.bg.ac.yu/~jelenagr i kolege Miroslava Marica
www.matf.bg.ac.yu/~maricm. Tekstovi i objasnjenja su uglavnom
zasnovani na knjizi Programski jezik C, autora Kerninghan & Ritchie.
Zahvaljujem svojim studentima na aktivnom ucescu u nastavi
cime su mi pomogli u uoblicavanju ovog materijala.
Svi komentari i sugestije vezane za ovaj materijal bice veoma
dobrodosli.

Milena Vujosevic-Janicic
www.matf.bg.ac.yu/~milena

1
Sadrzaj

1 Programski jezik C 4
1.1 Zdravo svete! . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Imena promenljivih . . . . . . . . . . . . . . . . . . . 5
1.3 Deklaracije . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Tipovi i velicina podataka . . . . . . . . . . . . . . . 5
1.5 Konstante . . . . . . . . . . . . . . . . . . . . . . . . 7
1.6 Funkcije printf i scanf . . . . . . . . . . . . . . . . . . 8
1.7 Aritmeticki operatori . . . . . . . . . . . . . . . . . . 10
1.8 Operatori i izrazi dodeljivanja vrednosti . . . . . . . 12
1.9 Inkrementacija i dekrementacija . . . . . . . . . . . . 12
1.10 Relacioni i logicki operatori . . . . . . . . . . . . . . 14
1.11 Kontrola toka — if, while, do - while, for . . . . . . . 15
1.11.1 if . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.11.2 Else-if . . . . . . . . . . . . . . . . . . . . . . 16
1.11.3 while . . . . . . . . . . . . . . . . . . . . . . . 18
1.11.4 do-while . . . . . . . . . . . . . . . . . . . . . 18
1.11.5 for . . . . . . . . . . . . . . . . . . . . . . . . 18
1.12 Switch . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.13 Uslovni izraz . . . . . . . . . . . . . . . . . . . . . . . 20
1.14 Konverzija . . . . . . . . . . . . . . . . . . . . . . . . 21
1.14.1 Automatska konverzija . . . . . . . . . . . . . 21
1.14.2 Eksplicitna konverzija . . . . . . . . . . . . . 21
1.15 Dvostruka for petlja . . . . . . . . . . . . . . . . . . 22
1.16 Simbolicke konstante . . . . . . . . . . . . . . . . . . 22
1.17 Enumeracija . . . . . . . . . . . . . . . . . . . . . . . 24
1.18 Operator sizeof() . . . . . . . . . . . . . . . . . . . 24
1.19 Znakovni ulaz i izlaz . . . . . . . . . . . . . . . . . . 25
1.20 Makroi . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.21 Pokazivaci . . . . . . . . . . . . . . . . . . . . . . . . 35
1.22 Nizovi . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.23 Pokazivaci i nizovi (polja) . . . . . . . . . . . . . . . 40
1.24 Break i continue . . . . . . . . . . . . . . . . . . . . . 42

2
SADRŽAJ SADRŽAJ

1.25 Funkcije . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.26 Zivotni vek i oblast vazenja promenjivih, staticke promenljive 46
1.27 Funkcije — prenos parametara po vrednosti . . . . . 49
1.28 Pokazivaci i argumenti funkcija . . . . . . . . . . . . 52
1.29 Povratne vrednosti funkcija . . . . . . . . . . . . . . 56
1.30 Rad sa niskama karaktera . . . . . . . . . . . . . . . 58
1.31 Linearna i binarna pretraga . . . . . . . . . . . . . . 69
1.32 Strukture . . . . . . . . . . . . . . . . . . . . . . . . 72
1.33 Operator typedef . . . . . . . . . . . . . . . . . . . . 74
1.34 Unije . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
1.35 Strukture — primeri . . . . . . . . . . . . . . . . . . 76
1.36 Datoteke . . . . . . . . . . . . . . . . . . . . . . . . . 86

3
Glava 1

Programski jezik C

1.1 Zdravo svete!


Primer 1.1.1 Program štampa poruku ”hello, world”.
#include <stdio.h>

main()
/*iskazi f-je main su zatvoreni u zagrade */
{
/*poziv f-je printf da odstampa poruku*/
printf("hello, world\n");
}
Primer 1.1.2 Program štampa poruku ”hello, world”
#include <stdio.h>

main()
{
printf("hello, ");
printf("world");
printf("\n");
}
Specijalni znaci:
\n novi red
\t tabulator
\\ kosa crta
\" navodnici
\a zvuk
\’ jednstruki navodnik

4
Milena Vujošević–Janičić 1.2 Imena promenljivih

1.2 Imena promenljivih


Postoje ogranicenja: u imenu se mogu pojaviti slova i cifre, potcrta
” ” se smatra slovom.
Velika i mala slova se razlikuju.
int x, X; /*To su dve razlicite promenljive!!!*/
Kljucne reci kao sto su if, else, for, while, se ne mogu koristiti za
imena promenljivih.

1.3 Deklaracije
Da bi se promenljiva mogla upotrebljavati ona se mora na pocetku
programa deklarisati. Prilikom deklaracije moze se izvrsiti i pocetna
inicijalizacija.

int broj; /*Deklaracija celog broja*/


int vrednost=5; /*Deklaracija i inicijalizacija celog broja*/

Kvali kator const moze biti dodeljen deklaraciji bilo koje promenljive
da bi oznacio da se ona nece menjati
const double e=2.71828182845905

1.4 Tipovi i veličina podataka


Osnovni tipovi podataka:
int ceo broj
char znak, jedan bajt
float realan broj
double realan broj dvostruke tacnosti
char jedan bajt, sadrzi jedan znak
int celobrojna vrednost, 2 ili 4 bajta
float realan broj, jednostruka tacnost
double dvostruka tacnost
Postoje kvali katori koje pridruzujemo osnovnim tipovima short(16)
i long(32):
short int kratak_broj;
long int dugacak_broj;
short kratak;
long dugacak;

5
Milena Vujošević–Janičić 1.4 Tipovi i veličina podataka

Vazi
broj bajtova(short) <= broj bajtova(int) <= broj bajtova(long)
Tip char zauzima jedan bajt ali u zavisnosti od sistema ovaj
tip moze da se odnosi na oznacene ili na neoznacene brojeve. Zato
Postoje kvali katori signed i unsigned koji preciziraju da li se misli
na oznacene ili neoznacene cele brojeve. Npr.
signed char: -128 do 127
dok je
unsigned char: od 0 do 255.
Velicina za int je razlicita u zavisnosti od sistema i moze biti 2
ili 4 bajta. Med̄utim, ako je promenljiva tipa short int onda ona
sigurno zauzima samo dva bajta a to znaci da u nju mogu da stanu
celobrojne vrednosti iz intervala -32 768 do +32 767, odnosno mogu
se koristiti sledeci sinonimi
short <=> short int <=> signed short int <=> -32 768 do 32 767
Ukoliko se koristi unsigned short int onda je interval
unsigned short int <=> 0 do 65 535
Za realne tipove podataka koriste se float, double i long double.
Njihove velicine mogu da zavise od sistema. Na primer:
float (4 bajta)
float minimalna pozitivna vrednost 1.175494351e-38
float maximalna pozitivna vrednost 3.402823466e+38

double (8 bajta)
double minimalna pozitivna vrednost 2.2250738585072014e-308
double maximalna pozitivna vrednost 1.7976931348623158e+308

long double (10 bajta)


long double minimalna pozitivna 3.3621031431120935063e-4932
long double maximalna pozitivna 1.189731495357231765e+4932
Primer 1.4.1 Uvod̄enje promenljivih u program.
#include <stdio.h>

main()
{
/*deklaracija vise promenljivih
istog tipa */
int rez,pom1,pom2;
pom1=20;

6
Milena Vujošević–Janičić 1.5 Konstante

pom2=15;
rez=pom1-pom2;

/*ispisivanje rezultata*/
printf("Rezultat je %d-%d=%d\n",pom1,pom2,rez);
}
Izlaz iz programa:
Rezultat je 20-15=5
Iskaz dodele:
pom1=20;
pom2=15;
Individualni iskazi se zavrsavaju sa ;

1.5 Konstante
Koji su tipovi konstanti?
Celobrojna konstanta 1234 je tipa int.
Da bi konstanta bila long navodi se iza nje slovo L ili l, npr 123456789L.
Ako zelimo da nam je konstanta unsigned onda na kraju pisemo U
ili u.
Moze i 1234567ul.

Konstante realnih brojeva sadrze decimalnu tacku(123.4) ili


eksponent(1e-2) ili i jedno i drugo. Njihov tip je double osim ako
nemaj su ks f ili F kada je u pitanju oat. L ili l oznacavaju long
double.
Oktalna konstanta pocinje sa 0, a heksadecimalna sa 0x. Npr
broj 31 ili 037 - oktalno ili 0x1f - heksadecimalno. I one mogu da
imaju U i L na kraju.
Znakovna konstanta je celobrojna vrednost napisana izmed̄u
jednostrukih navodnika. Vrednost date konstante je numericka vred-
nost datog znaka u racunarskom setu znakova. Npr mozemo da
pisemo ’0’ umesto 48.
!!!Razlikovati znakovne konstante i niske koje se navode izmed̄u
dvostrukih navodnika!
Posebni znaci su znak za kraj reda ’\n’, tab ’\t’ i slicno. Iako se
zapisuju kao vise znakova, oni oznacavaju samo jedan znak i njima
takod̄e odgovara samo jedan bajt.
Znakovna konstanta ’\0’ predstavlja znak cija je vrednost nula,
treba ga razlikovati od ’0’ koja je znak cija je vrednost 48.
Primer 1.5.1 Koja je vrednost konstantnog izraza

7
Milena Vujošević–Janičić 1.6 Funkcije printf i scanf

1. 0x10 + 020 + ’9’ - ’1’


2. 0x20 + 010 + ’8’ - ’0’

1.6 Funkcije printf i scanf


printf("%d\t%d\n", broj1, broj2);
uvek je prvi argument izmedju " "
%d ceo broj
\t tab izmedju
\n novi red
Svaka % konstrukcija je u paru sa argumentom koji sledi.
Primer 1.6.1
#include <stdio.h>
main()
{
printf("Slova:\n%3c\n%5c\n", ’z’ , ’Z’);
}
Izlaz iz programa:
Slova:
z
Z
%c je za stampanje karaktera
%3c je za stampanje karaktera na tri pozicije
Isto tako smo mogli i %3d za stampanje broja na tri pozicije ili %6d
za stampanje broja na 6 pozicija.
Pravila:
%d stampaj kao ceo broj
%6d stampaj kao ceo broj sirok najvise 6 znakova
%f stampaj kao realan broj
%6f stampaj kao realan broj sirok najvise 6 znakova
%.2f stampaj kao realan broj sa dve decimale
%6.2f stampaj kao realan broj sirok najvise 6 znakova a od toga 2
iza decimalne tacke
%c karakter
%s string
%x heksadecimalni broj
%% je procenat

Primer 1.6.2 Ispisivanje karaktera: %c, ispisivanje asci vrednosti


karaktera %d

8
Milena Vujošević–Janičić 1.6 Funkcije printf i scanf

#include <stdio.h>
main()
{
int vrednost;
vrednost=’A’;
printf("Veliko slovo\n karakter=%3c\nvrednost=%3d\n",vrednost,vrednost);
vrednost=’a’;
printf("Malo\n karakter=%3c\nvrednost=%3d\n",vrednost,vrednost);
}

Izlaz (u slucaju ASCII):


Veliko slovo
karakter= A
vrednost= 65
Malo
karakter= a
vrednost= 97

Primer 1.6.3 Prikazuje unos celog broja koristeci scanf("%d", &x)


#include <stdio.h>

main()
{
int x;
printf("Unesi ceo broj : ");

/* Obratiti paznju na znak &


(operator uzimanja adrese)
pre imena promenljive u funkciji
scanf */
scanf("%d",&x);

/* U funkciji printf nije


potrebno stavljati & */
printf("Uneli ste broj %d\n", x);
}

Primer 1.6.4 Program sabira dva uneta cela broja


#include <stdio.h>

main()
{

9
Milena Vujošević–Janičić 1.7 Aritmetički operatori

int a, b, c;
printf("Unesi prvi broj : ");
scanf("%d", &a);
printf("Unesi drugi broj : ");
scanf("%d", &b);
c = a + b;
printf("%d + %d = %d\n", a, b, c);
}
Ulaz:
Unesi prvi broj : 2 <enter>
Unesi drugi broj : 3 <enter>
Izlaz:
2 + 3 = 5

1.7 Aritmetički operatori


+ - * /
% (samo za celobrojne vrednosti)
unarno + i -

Asocijativnost sleva na desno, prioritet kao u matematici.

Primer 1.7.1 Program ilustruje neke od aritmetičkih operacija.


#include <stdio.h>
main()
{
int a, b;
printf("Unesi prvi broj : ");
scanf("%d",&a);

printf("Unesi drugi broj : ");


scanf("%d",&b);

/* Kada se saberu dva cela broja, rezultat je ceo broj*/


printf("Zbir a+b je : %d\n",a+b);
/* Kada se oduzmu dva cela broja, rezultat je ceo broj*/
printf("Razlika a-b je : %d\n",a-b);
/* Kada se pomnoze dva cela broja, rezultat je ceo broj*/
printf("Proizvod a*b je : %d\n",a*b);
/* Kada se podele dva cela broja, rezultat je ceo broj!!!*/
printf("Celobrojni kolicnik a/b je : %d\n", a/b);
/* Rezultat je ceo broj, bez obzira sto ga ispisujemo kao realan*/

10
Milena Vujošević–Janičić 1.7 Aritmetički operatori

printf("Pogresan pokusaj racunanja realnog kolicnika a/b je : %f\n", a/b);


/* Eksplicitna konverzija, a i b pretvaramo u relane brojeve kako
bi deljenje bilo realno*/
printf("Realni kolicnik a/b je : %f\n", (float)a/(float)b);
/* Ostatak pri deljenju se moze izvrsiti samo nad celim brojevima*/
printf("Ostatak pri deljenju a/b je : %d\n", a%b);
}

Ulaz:
Unesi prvi broj : 2 <enter>
Unesi drugi broj : 3 <enter>
Izlaz:
Zbir a+b je : 5
Razlika a-b je : -1
Proizvod a*b je : 6
Celobrojni kolicnik a/b je : 0
Progresan pokusaj racunanja realnog kolicnika a/b je : 0.000000
Realni kolicnik a/b je : 0.666667
Ostatak pri deljenju a/b je : 2
Primer 1.7.2 Program ilustruje celobrojno i realno deljenje.
#include <stdio.h>

main()
{
int a = 5;
int b = 2;
int d = 5/2; /* Celobrojno deljenje - rezultat je 2 */
float c = a/b; /* Iako je c float, vrsi se celobrojno
deljenje jer su i a i b celi */

/* Neocekivani rezultat 2.000000 */


printf("c = %f\n",c);
printf("Uzrok problema : 5/2 = %f\n", 5/2);
printf("Popravljeno : 5.0/2.0 = %f\n", 5.0/2.0);
printf("Moze i : 5/2.0 = %f i 5.0/2 = %f \n", 5/2.0, 5.0/2);
printf("Za promenljive mora kastovanje : %f\n", (float)a/(float)b);

Izlaz iz programa:
c = 2.000000
Uzrok problema : 5/2 = 2.000000

11
Milena Vujošević–Janičić 1.8 Operatori i izrazi dodeljivanja vrednosti

Popravljeno : 5.0/2.0 = 2.500000


Moze i : 5/2.0 = 2.500000 i 5.0/2 = 2.500000
Za promenljive mora kastovanje : 2.500000

Zadatak 1 Šta će biti ispisano nakon izvršavanja sledećeg programa?


#include <stdio.h>
main()
{
int x=506, y=3, z=21, t=2;
printf("x=%d y=%d\n",x,y);
printf("z - t=%d\n", z-t);
printf("z / t =%d\n",z / t);
printf("-x=%d\n",- x);
printf("x %% y=%d\n", x%y);
}

1.8 Operatori i izrazi dodeljivanja vrednosti


i = i + 2;
ekvivalento je sa
i+=2;

Moze i za:
+ - * / % << >> ^ |
izraz1 op = izraz2
je ekvivalnetno sa
izraz1 = (izraz1) op (izraz2)

x*= y+1 je ekvivalento sa x = x * (y+1)


Takvo pisanje je krace i e kasnije.

1.9 Inkrementacija i dekrementacija


Operatori ++ i --
x=++n; se razlikuje od x=n++;

y=(x++)*(++z);
Primer 1.9.1 Ilustracija prefiksnog i postfiksnog operatora ++

12
Milena Vujošević–Janičić 1.9 Inkrementacija i dekrementacija

#include <stdio.h>
main()
{
int x, y;
int a = 0, b = 0;

printf("Na pocetku : \na = %d\nb = %d\n", a, b);

/* Ukoliko se vrednost izraza ne koristi, prefiksni i


postfiksni operator se ne razlikuju */
a++;
++b;
printf("Posle : a++; ++b; \na = %d\nb = %d\n", a, b);

/* Prefiksni operator uvecava promenljivu, i rezultat


je uvecana vrednost */
x = ++a;

/* Postfiksni operator uvecava promenljivu, i rezultat je


stara (neuvecana) vrednost */
y = b++;

printf("Posle : x = ++a; \na = %d\nx = %d\n", a, x);


printf("Posle : y = b++; \nb = %d\ny = %d\n", b, y);
}

Izlaz iz programa:
Na pocetku:
a = 0
b = 0
Posle : a++; ++b;
a = 1
b = 1
Posle : x = ++a;
a = 2
x = 2
Posle : y = b++;
b = 2
y = 1

13
Milena Vujošević–Janičić 1.10 Relacioni i logički operatori

1.10 Relacioni i logički operatori


Relacioni operatori:
> >= < <= isti prioritet
== != nizi prioritet

(3<5)
(a<=10)
a < 5 != 1 <=> (a < 5)!=1
Logicki operatori:
! unarna negacija (najvisi prioritet)
&& logicko i (visi prioritet od ili)
|| logicko ili izracunavaju se sleva na desno!

5 && 4 vrednost je tacno


10 || 0 vrednost je tacno
0 && 5 vrednost je 0
!1 vrednost je 0
!9 vrednost je 0
!0 vrednost je 1
!(2>3) je 1
a>b && b>c || b>d je isto sto i ((a>b) && (b>c)) || (b>d)
koja je vrednost ako je a=10, b=5, c=1, d=15?

Primer 1.10.1 Ilustracija logičkih i relacijskih operatora.


#include <stdio.h>

main()
{
int a = 3>5, /* manje */
b = 5>3, /* vece */
c = 3==5, /* jednako */
d = 3!=5; /* razlicito */

printf("3>5 - %d\n5>3 - %d\n3==5 - %d\n3!=5 - %d\n", a, b, c, d);

/*Lenjo izracunavanje: kako 3 nije vece od 5 to se vrednost


drugog poredjenja nece racunati jer je netacno u konjunkciji
sa proizvoljnim izrazom sigurno netacno. */
printf("Konjunkcija : 3>5 && 5>3 - %d\n", a && b);

14
Milena Vujošević–Janičić 1.11 Kontrola toka — if, while, do - while, for

/*Lenjo izravunavanje: tacno u disjunkciji sa proizvoljnim


izrazom daje tacno tako da se vrednost izraza 3>5 nece
izracunavati*/
printf("Disjunkcija : 5>3 || 3>5 - %d\n", b || a);
printf("Negacija : !(3>5) - %d\n", !a);

Izlaz iz programa:
3>5 - 0
5>3 - 1
3==5 - 0
3!=5 - 1
Konjunkcija : 3>5 && 5>3 - 0
Disjunkcija : 3>5 || 5>3 - 1
Negacija : !(3>5) - 1

1.11 Kontrola toka — if, while, do - while, for


1.11.1 if
if (izraz)
iskaz1
else
iskaz2

Primer 1.11.1 Program ilustruje if i ispisuje ukoliko je uneti ceo


broj negativan
#include <stdio.h>

main()
{
int b;
printf("Unesi ceo broj:");
scanf("%d", &b);
if (b < 0)
printf("Broj je negativan\n");
}

Else se odnosi na prvi neuparen if, voditi o tome racuna, ako


zelimo drugacije moramo da navedemo viticaste zagrade.
if (izraz)

15
Milena Vujošević–Janičić 1.11 Kontrola toka — if, while, do - while, for

if (izraz1) iskaz 1
else iskaz
ovo else se odnosi na drugo if a ne na prvo if!
if (izraz)
{
if (izraz1) iskaz 1
}
else iskaz
tek sada se else odnosi na prvo if!!!

1.11.2 Else-if
if (izraz1)
iskaz1
else if (izraz2)
iskaz2
else if (izraz3)
iskaz3
else if (izraz4)
iskaz4
else iskaz

npr if (a<5)
printf("A je manje od 5\n");
else if (a=5)
printf("A je jednako 5\n");
else if (a>10)
printf("A je vece od 10\n");
else if (a=10)
printf("A je jednako 10\n");
else printf("A je vece od pet i manje od 10\n");
Primer 1.11.2 Program ilustruje if-else konstrukciju i ispituje znak
broja.
#include <stdio.h>

main()
{
int b;
printf("Unesi ceo broj : ");
scanf("%d", &b);

16
Milena Vujošević–Janičić 1.11 Kontrola toka — if, while, do - while, for

if (b < 0)
printf("Broj je negativan\n");
else if (b == 0)
printf("Broj je nula\n");
else
printf("Broj je pozitivan\n");
}

Ulaz:
Unesi ceo broj:-5
Izlaz:
Broj je negativan

Ulaz:
Unesi ceo broj:5
Izlaz:
Broj je pozitivan

Primer 1.11.3 Pogresan program sa dodelom = umesto poredjenja


==.
#include <stdio.h>

main()
{
int b;
printf("Unesi ceo broj : ");
scanf("%d", &b);

/* Obratiti paznju na = umesto == Analizirati rad programa*/


if (b = 0)
printf("Broj je nula\n");
else if (b < 0)
printf("Broj je negativan\n");
else
printf("Broj je pozitivan\n");
}

Ulaz:
Unesi ceo broj:-5
Izlaz:
Broj je pozitivan

17
Milena Vujošević–Janičić 1.11 Kontrola toka — if, while, do - while, for

1.11.3 while
while(uslov) { ... }
Uslov u zagradi se testira i ako je ispunjen telo petlje se izvrsava.
Zatim se uslov ponovo testira i ako je ispunjen ponovo se izvrsava
telo petlje. I tako sve dok uslov ne bude ispunjen. Tada se izlazi iz
petlje i nastavlja sa prvom sledecom naredbom u programu.
Ukoliko iza while sledi samo jedna naredba nema potrebe za
zagradama.
while (i<j)
i=2*i;

1.11.4 do-while
Ovo je slicno paskalskom repeat-until izrazu.
do iskaz while (izraz)
Primer 1.11.4 Program ilustruje petlju do-while.
#include <stdio.h>

main()
{
int x;

x = 1;
do
{
printf("x = %d\n",x);
x++; /* x++ je isto kao i x=x+1 */
} while (x<=10);
}

1.11.5 for
Primer 1.11.5 Program ilustruje petlju - for.
#include <stdio.h>

main()
{
int x;

/* Inicijalizacija; uslov; inkrementacija*/

18
Milena Vujošević–Janičić 1.12 Switch

for (x = 1; x < 5; x++)


printf("x = %d\n",x);

}
Izlaz:
1
2
3
4

1.12 Switch
switch (iskaz) {
case konstantan_izraz1: iskazi1
case konstantan_izraz2: iskazi2
...
default: iskazi
}
Primer 1.12.1 Voditi računa o upotrebi break-a.
#include <stdio.h> /*
Upotreba switch-a
*/

main() {
char x;
scanf("%c",&x);

switch (x)
{
case ’a’:
case ’e’:
case ’i’:
case ’o’:
case ’u’: printf(" x je samoglasnik");
break;
case ’r’: printf(" x je r");
break;
default: printf(" x je suglasnik");
}
}
Primer 1.12.2 Ilustracija switch konstrukcije.

19
Milena Vujošević–Janičić 1.13 Uslovni izraz

#include<stdio.h>
main()
{
int n;
printf("Unesi paran broj manji od 10\n");
scanf("%d",&n);
switch(n) {
case 0:
printf("Uneli ste nulu\n");
break;
case 2:
printf("Uneli ste dvojku\n");
break;
case 4:
printf("Uneli ste cetvorku\n");
break;
case 6:
printf("Uneli ste sesticu\n");
break;
case 8:
printf("Uneli ste osmicu\n");
break;
defalut:
printf("Uneli ste nesto sto nije paran broj\n");
}
}
Ulaz:
Unesi paran broj manji od 10
2
Izlaz:
Uneli ste dvojku

1.13 Uslovni izraz


Slicno kao if.

izraz1 ? izraz2 : izraz3

z = (a<b)? a : b; /*z=min(a,b)*/
max = (a>b)? a : b;

20
Milena Vujošević–Janičić 1.14 Konverzija

1.14 Konverzija
1.14.1 Automatska konverzija
Ako je jedan od operanada razlizlicit vrsi se konverzija, uvek u smeru
manjeg ka vecem tipu

Naredba dodele:
int i=5;
float f=2.3;
f=i; /* f ce imati vrednost 5.0*/

obrnuto:

int i=5;
float f=2.3;
i=f; /* i ce imati vrednost 2*/

1.14.2 Eksplicitna konverzija


(tip)<izraz>

float x;
x=2.3+4.2; /* x ce imati vrednost 6.5 */
x=(int)2.3+(int)4.2; /* x ce imati vrednost 6 */
x=(int)2.3*4.5; /* x ce imati vrednost 9.0 jer zbog prioriteta
operatora konverzije prvo ce biti izvrsena
konverzija broja 2.3 u 2 pa tek onda izvrseno
mnozenje. */
x=(int)(2.3*4.5) /* x ce imati vrednost 10.0 */
Primer 1.14.1 Kako izbeći celobrojno deljenje
int a,b;
float f;
a = 5;
b = 2;
f = a/b; /* Celobrojno deljenje, f=2*/
f = (1.0*a)/b; /* Implicitna konverzija: 1.0*a je realan
broj pa priliko deljenja sa b dobija se
realan rezultat f=2.5*/
f = (0.0+a)/b; /* Implicitna konverzija: (0.0+a) je realan
broj pa priliko deljenja sa b dobija se
realan rezultat f=2.5*/

21
Milena Vujošević–Janičić 1.15 Dvostruka for petlja

f = (float)a/(float)b; /* Eksplicitna konverzija*/

1.15 Dvostruka for petlja


Primer 1.15.1 Dvostruka for petlja
#include<stdio.h>
int main()
{
int i,j;

for(i=1; i<=10; i++)


{
for(j=1; j<=10; j++)
printf("%d * %d = %d\t", i, j, i*j);
printf("\n");
}
}
Primer 1.15.2 Trostruka for petlja
#include<stdio.h>
int main()
{
int i,j;

for(i=1; i<=10; i++)


for(j=1; j<=10; j++)
{
for(k=1; k<=10; k++)
printf("%d * %d * %d = %d\t", i, j, k, i*j*k);
printf("\n");
}
}
Koliko puta se izvrsi naredba štampanja
printf("%d * %d * %d = %d\t", i, j, k, i*j*k);

1.16 Simboličke konstante


Primer 1.16.1 Konverzija centimetara u inče - while petlja.
#include <stdio.h>

22
Milena Vujošević–Janičić 1.16 Simboličke konstante

/* Definicija simbolickih konstanti preko #define direktiva */


/* U fazi pretprocesiranja se vrsi doslovna zamena konstanti
njihovim vrednostima */

#define POCETAK 0
#define KRAJ 20
#define KORAK 10

main()
{
int a;
a = POCETAK;
while (a <= KRAJ)
{
printf("%d cm = %f in\n", a, a/2.54);
a += KORAK; /* isto sto i a = a + KORAK; */
}
}

Izlaz:
0 cm = 0.000000 in
10 cm = 3.937008 in
20 cm = 7.874016 in

Primer 1.16.2 Konverzija centimetara u inče - for petlja.


#include <stdio.h>
#define POCETAK 0
#define KRAJ 20
#define KORAK 10

main()
{
int a;
for (a = POCETAK; a <= KRAJ; a += KORAK)
printf("%d cm = %f in\n", a, a/2.54);
}

Izlaz:
0 cm = 0.000000 in
10 cm = 3.937008 in
20 cm = 7.874016 in
Zadatak 2 Šta će biti ispisano nakon izvršavanja sledećeg programa?

23
Milena Vujošević–Janičić 1.17 Enumeracija

#include <stdio.h>
#define EURO 85.90
main()
{
printf("4 eura ima vrednost %f dinara\n", 4*EURO);
printf("1 euro ima vrednost %.0f dinara\n",EURO);
}

1.17 Enumeracija
Izvesna alternativa za define
enum boolean {NO, YES};
enum meseci {JAN = 1, FEB, MAR, APR, MAJ, JUN,
JUL, AVG, SEP, OKT, NOV, DEC}
enum boje {CRVENA, ZELENA=5, PLAVA,
LJUBICASTA=10, ZUTA, CRNA}

koriscenje:

int x=0;
boje b;

x=CRVENA+3; /*x ce biti jednako tri*/

b=ZELENA;
x=b+CRNA; /* x = 5 + 12*/

b=0; /*Greska, ovako ne moze!!! b je boja i


moze imati samo vrednosti CRVENA, ZELENA ...*/

1.18 Operator sizeof()


Primer 1.18.1 Demonstracija sizeof operatora. Sizeof operator
izračunava veličinu tipa odnosno promenjive.
#include<stdio.h>
main()
{
int i;
float f;

24
Milena Vujošević–Janičić 1.19 Znakovni ulaz i izlaz

printf("sizeof(int)=%d\n", sizeof(int));
printf("sizeof(long)=%d\n", sizeof(long));
printf("sizeof(short)=%d\n", sizeof(short));
printf("sizeof(signed)=%d\n", sizeof(signed));
printf("sizeof(unsigned)=%d\n", sizeof(unsigned));
printf("sizeof(char)=%d\n", sizeof(char));
printf("sizeof(float)=%d\n", sizeof(float));
printf("sizeof(double)=%d\n", sizeof(double));

printf("sizeof(i)=%d\n", sizeof(i));
printf("sizeof(f)=%d\n", sizeof(f));
}

Izlaz iz programa (u konkretnom slucaju):


sizeof(int)=4
sizeof(long)=4
sizeof(short)=2
sizeof(signed)=4
sizeof(unsigned)=4
sizeof(char)=1
sizeof(float)=4
sizeof(double)=8
sizeof(i)=4
sizeof(f)=4

1.19 Znakovni ulaz i izlaz


Funkcija za citanje jednog znaka sa ulaza
c = getchar()
promenljiva c sadrzi jedan znak sa ulaza i potrebno je da bude
celobrojnog tipa jer je funkcija getchar() tako de nisana da vraca
celobrojnu vrednost (odnosno vrednost koja ima tip int).

Funkcija za stampanje jednog znaka na izlaz


putchar(c)
stampa sadrzaj promenljive c na standardni izlaz.

Konstanta EOF je celobrojna vrednost de nisana u biblioteci <stdio.h>


(najcesce ima vrednost -1). Ovu vrednost vrati funkcija getchar()
kada nema vise ulaza. Nazvana je EOF kao End Of File, kraj da-
toteke. Sa tastature, ovaj znak se moze uneti kombinacijom tastera
ctrl i D.

25
Milena Vujošević–Janičić 1.19 Znakovni ulaz i izlaz

Primer 1.19.1 Program čita jedan karakter i ispisuje ga - demon-


stracija putchar i getchar.
#include <stdio.h>

main()
{
int c; /* Karakter - obratiti paznju na int */
c = getchar(); /* cita karakter sa standardnog ulaza */
putchar(c); /* pise karakter c na standardni izlaz */

putchar(’\n’); /* prelazak u novi red */


putchar(’a’); /* ispisuje malo a */
putchar(97); /* ekvivalentno prethodnom, tj ispisuje
se karakter ciji je asci kod 97 */

putchar(’A’+ 10); /* na izlazu ce biti otstampan znak ciji


je asci kod za deset veci od asci koda
slova A, dakle znak ciji je asci kod
65+10=75, a to je znak koji se nalazi
za deset mesta iza slova A u abecedi,
dakle znak K */
putchar(’a’+ 3); /* znak d */

}
Ulaz:
s
Izlaz iz programa:
s
s
aa
K
d

Primer 1.19.2 Pretpostavimo da se od korisnika zahteva da unese


prvo jedno veliko pa onda jedno malo slove engleske abecede. Sta ce
biti izlaz iz programa ako korisnik unese prvo slovo B a zatim slovo
f?
#include <stdio.h>

main()
{
int c;

26
Milena Vujošević–Janičić 1.19 Znakovni ulaz i izlaz

c = getchar(); /* Ucitavamo jedno veliko slovo */


putchar(c - ’A’ + ’a’); /* sta ce biti ispisano? */

putchar(’\n’); /* prelazak u novi red */

c = getchar(); /* Ucitavamo jedno malo slovo */


putchar(c -’a’+’A’); /* sta ce biti ispisano? */
putchar(c - ’a’ + ’A’ + 1); /* sta ce biti ispisano? */
}

Primer 1.19.3 Program prepisuje standardni ulaz na standardni


izlaz. Ilustracija redirekcije standardnog ulaza i izlaza, pokrenuti
program sa :
./a.out <primer.c
./a.out >tekst.txt
./a.out <primer.c >kopija.c

#include <stdio.h>

main()
{

int c;

/*Ucitava se prvi znak sa ulaza*/


c = getchar();

/*EOF predstavlja celobrojnu vrednost kraja datoteke.


To je konstanta definisana u <stdio.h>*/
while (c != EOF) {
putchar(c);
c = getchar();
}
}

Bilo koje dodeljivanje vrednosti je izraz koji ima vrednost a to je


vrednost leve strane posle dodeljivanja.
Primer 1.19.4 Program koji kopira ulaz na izlaz, skraćeni kod.
#include <stdio.h>

main()
{

27
Milena Vujošević–Janičić 1.19 Znakovni ulaz i izlaz

int c;

/* Obratiti paznju na raspored zagrada


koje su neophodne zbog prioriteta operatora */
while ((c = getchar()) != EOF)
putchar(c);
}

Primer 1.19.5 Brojanje znakova na ulazu.


#include <stdio.h>

main()
{
long broj_znakova;

broj_znakova = 0;
while (getchar() != EOF)
++broj_znakova;
/* %ld odnosi se na tip long. */
printf("%ld\n", broj_znakova);
}

Primer 1.19.6 Brojanje znakova na ulazu korišćenjem for petlje.


#include <stdio.h>

main()
{
long broj_znakova;

/*For petlja mora da ima telo pa makar


ono bilo przno*/
for (broj_znakova = 0; getchar() != EOF; ++broj_znakova)
;
printf("%ld\n", broj_znakova);
}

Primer 1.19.7 Program broji linije i znakove na ulazu.


#include <stdio.h>
main()
{
int znak; /*prihvata znak sa ulaza */
long linije=0 ; /*brojac linija */

28
Milena Vujošević–Janičić 1.19 Znakovni ulaz i izlaz

long br_znak=0; /*brojac znakova na ulazu */

while ( (znak=getchar() ) != EOF)


{
br_znak++;
if (znak==’\n’) linije ++;
}

printf("Prelazaka u novi red: %ld, karaktera: %ld \n",linije,br_znak);


}

Primer 1.19.8 Program broji blankove, horizontalne tabulatore i


linije na ulazu.
#include <stdio.h>
main()
{
int znak; /*prihvata znak sa ulaza */
int Blanks=0; /*brojac blankova */
int Tabs=0; /*brojac horizontalnih tabulatora */
int NewLines=0; /*brojac linija */

/*UOCITI: blok naredbi while ciklusa NIJE OGRADJEN


viticastim zagradama jer postoji samo jedna if naredba! */
while( (znak=getchar()) != EOF )
if( znak==’ ’ ) ++Blanks; /* brojimo blanko simbole */
else if( znak==’\t’ ) ++Tabs; /* brojimo tab-ove */
else if( znak==’\n’ ) ++NewLines; /* brojimo redove */

/* Stampanje rezultata na standardni izlaz*/


printf("Blankova: %d. \n", Blanks);
printf("Tabulatora: %d. \n", Tabs);
printf("Prelazaka u novi red: %d. \n", NewLines);
}

Primer 1.19.9 Program vrši prebrojavanje cifara unetih na ulazu.


#include <stdio.h>

main()
{
int c;
int br_cifara = 0;
while ((c = getchar()) != EOF)

29
Milena Vujošević–Janičić 1.19 Znakovni ulaz i izlaz

if (’0’<=c && c<=’9’)


br_cifara++;

printf("Broj cifara je : %d\n", br_cifara);


}
Primer 1.19.10 Program vrši brojanje pojavljivanja karaktera 0, 1
i 2 (ilustruje switch).
#include <stdio.h>

main()
{
int c;
int br_0=0, br_1=0, br_2=0;

while ((c = getchar()) != EOF)


{
switch(c)
{
/* Obratiti paznju da nije
case 0: */
case ’0’:
br_0++;
break; /* Isprobati veziju bez break */
case ’1’:
br_1++;
break;
case ’2’:
br_2++;
break;
default:
}
}
printf("Br 0 : %d\nBr 1 : %d\nBr 2 : %d\n",br_0, br_1, br_2);
}
Primer 1.19.11 Program prepisuje ulaz na izlaz pri čemu više blanko
znakova zamenjuje jednim.
#include <stdio.h>

main()
{

30
Milena Vujošević–Janičić 1.19 Znakovni ulaz i izlaz

int znak; /*tekuci znak sa ulaza*/


int preth; /*znak koji prethodi tekucem */
preth=’a’; /* inicijalizujemo vrednost prethodnog
da bi prvi prolazak kroz petlju bio ispravan*/
while ( (znak=getchar() ) !=EOF)
{
if (znak !=’ ’ || preth != ’ ’) putchar(znak);
preth=znak;
}
}
Primer 1.19.12 Brojanje reči, linija i karaktera koji se unose sa
ulaza.
#include <stdio.h>

#define IN 1 /* inside a word */


#define OUT 0 /* outside a word */

/* count lines, words, and characters in input */

main()
{
int c, nl, nw, nc, state;

state = OUT;

/*Postavljaju se sve tri promenljive na nulu*/


/*Prvi nacin:
nl = 0;
nw = 0;
nc = 0;*/
/*To je isto kao da smo napisali
nl = (nw = (nc = 0));
A moze i bez zagrada: */

nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == ’\n’)
++nl;

if (c == ’ ’ || c == ’\n’ || c == ’\t’)
state = OUT;

31
Milena Vujošević–Janičić 1.20 Makroi

else if (state == OUT) {


state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}

1.20 Makroi
#define ime tekst_zamene

Zamene se vrse samo na simbolima, a ne obavljaju se u niskama


nutar navodnika.
Moguce je de nisati makroe sa argumentima tako da tekst zamene
bude razlicit za razlicita pojavljivanja makroa.

Primer 1.20.1 Demonstracija pretprocesorske direktive #define


#include<stdio.h>

/* Racuna sumu dva broja */


#define sum(a,b) ((a)+(b))

/* Racuna kvadrat broja - pogresna verzija */


#define square_w(a) a*a

/* Racuna kvadrat broja */


#define square(a) ((a)*(a))

/* Racuna minimum tri broja */


#define min(a, b, c) (a)<(b)? ((a)<(c)? (a) : (c)) : ((b)<(c)? (b) : (c))

main()
{
printf("sum(3,5) = %d\n", sum(3,5));
printf("square_w(5) = %d\n", square_w(5));
printf("square_w(3+2) = %d\n", square_w(3+2));
printf("square(3+2) = %d\n", square(3+2));
printf("min(1,2,3) = %d\n", min(1,2,3));
printf("min(1,3,2) = %d\n", min(1,3,2));
printf("min(2,1,3) = %d\n", min(2,1,3));
printf("min(2,3,1) = %d\n", min(2,3,1));

32
Milena Vujošević–Janičić 1.20 Makroi

printf("min(3,1,2) = %d\n", min(3,1,2));


printf("min(3,2,1) = %d\n", min(3,2,1));
}

Izlaz iz programa:
sum(3,5) = 8
square_w(5) = 25
square_w(3+2) = 11
square(3+2) = 25
min(1,2,3) = 1
min(1,3,2) = 1
min(2,1,3) = 1
min(2,3,1) = 1
min(3,1,2) = 1
min(3,2,1) = 1

Primer 1.20.2
#define max(A, B) ((A)>(B) ? (A) : (B))

na osnovu ovoga ce linija


x=max(p+q, r+s)
biti zamenjena linijom
x=((p+q) > (r+s) ? (p+q) : (r+s));
Treba voditi racuna o sporednim efektima. Sledeca linija koda
pruzrokovace uvecanje vrednosti i ili j za dva.

max(i++, j++)

Takod̄e treba voditi racuna o zagradama. Sledeci makro prouzrokovace


neocekivane rezultate za upotrebu square(a+1)

#define square(x) x*x

Primer 1.20.3 Ilustacija beskonačne petlje:


#define forever for(;;);

Primer 1.20.4
#include <stdio.h>
#define max1(x,y) (x>y?x:y)
#define max2(x,y) ((x)>(y)?(x):(y))
#define swapint(x,y) { int z; z=x; x=y; y=z; }
#define swap(t,x,y) { \

33
Milena Vujošević–Janičić 1.20 Makroi

t z; \
z=x; \
x=y; \
y=z; }

main()
{

int x=2,y=3;

printf( "max1(x,y) = %d\n", max1(x,y) );


/* max1(x,y) = 3 */

/* Zamena makroom se ne vrsi


unutar niski pod navodnicima*/
printf( "max1(x=5,y) = %d\n", max1(x,y) );
/* max1(x=5,y) = 3 */

printf( "max1(x++,y++) = %d\n", max1(x++,y++) );


/* max1(x++,y++) = 4 */

printf( "x = %d, y = %d\n", x, y );


/* x = 3, y = 5 */

swapint(x,y);

printf( "x = %d, y = %d\n", x, y );


/* x = 5, y = 3 */

swap(int,x,y);
printf( "x = %d, y = %d\n", x, y );
/* x = 3, y = 5 */
}

Izlaz:
max1(x,y) = 3
max1(x=5,y) = 3
max1(x++,y++) = 4
x = 3, y = 5
x = 5, y = 3
x = 3, y = 5

34
Milena Vujošević–Janičić 1.21 Pokazivači

1.21 Pokazivači
Pokazivac je promenljiva koja sadrzi adresu promenljive.
int x=1, y=1;
int *ip; /* ip je pokazivac na int,
odnosno *ip je tipa int*/

ip = &x; /* ip sada pokazuje na x */


y=*ip; /* y je sada 1 */
*ip = 0; /* x je sada 0 */

*ip+=10; /* x je sada 10*/


++*ip; /* x je sada 11*/
(*ip)++; /* x je sada 12,
zagrada neophodna zbog prioriteta
operatora*/

Primer 1.21.1 Ilustracija rada sa pokazivačkim promenljivim.


#include <stdio.h>
main()
{
int x = 3;

/* Adresu promenjive x zapamticemo u novoj promeljivoj.


Nova promenljiva je tipa pokazivaca na int (int*) */
int* px;

printf("Adresa promenljive x je : %p\n", &x);


printf("Vrednost promenljive x je : %d\n", x);

px = &x;
printf("Vrednost promenljive px je (tj. px) : %p\n", px);
printf("Vrednost promenljive na koju
ukazuje px (tj. *px) je : %d\n", *px);

/* Menjamo vrednost promenljive na koju ukazuje px */


*px = 6;
printf("Vrednost promenljive na koju
ukazuje px (tj. *px) je : %d\n", *px);

/* Posto px sadrzi adresu promenljive x,


ona ukazuje na x tako da je

35
Milena Vujošević–Janičić 1.22 Nizovi

posredno promenjena i vrednost promenljive x */


printf("Vrednost promenljive x je : %d\n", x);

Izlaz (u konkretnom slucaju):


Adresa promenljive x je : 0012FF88
Vrednost promenljive x je : 3
Vrednost promenljive px je (tj. px) : 0012FF88
Vrednost promenljive na koju ukazuje px (tj. *px) je : 3
Vrednost promenljive na koju ukazuje px (tj. *px) je : 6
Vrednost promenljive x je : 6

1.22 Nizovi
Deklaracija niza:
int niz[5]; /* niz od 5 elemenata tipa int*/
Pristupanje elementima niza:
niz[0] = 4;
niz[1] = 2 * niz[0]; /*niz[1] = 8*/
niz[2] = niz[0] * niz[1]; /*niz[2] = 32*/
niz[3] = 5;
niz[4] = 7;
Unos vrednosti elemenata niza sa tastature:
for(i=0; i<5; i++)
scanf("%d", &a[i]);
Stampanje elemenata niza
for(i=0; i<5; i++)
printf("%d ", a[i]);
Brojanje elemenata niza je od nule!
Pristupanje elementu niza, indeks moze da bude proizvoljan izraz
celobrojne vrednosti: niz[i*2]=5.
Primer 1.22.1 Program ilustruje korišćenje nizova. Ispisuje 10
unetih brojeva unazad.
#include <stdio.h>
#define BR_ELEM 10

36
Milena Vujošević–Janičić 1.22 Nizovi

main()
{
int a[BR_ELEM];
int i;
for (i = 0; i<BR_ELEM; i++)
{
printf("a[%d]=",i);
scanf("%d",&a[i]);
}

printf("Unazad : \n");

for (i = BR_ELEM - 1; i>=0; i--)


printf("a[%d]=%d\n",i,a[i]);
}

Primer 1.22.2 Program pronalazi maksimum brojeva sa ulaza -


verzija sa nizom.
#include <stdio.h>
#define BR_ELEM 5
main()
{
int a[BR_ELEM];
int i;
int max;

/* Ucitavamo niz brojeva */


for (i = 0; i < BR_ELEM; i++)
scanf("%d",&a[i]);

/* Pronalazimo maksimum */
max = a[0];
for (i = 1; i < BR_ELEM; i++)
if (a[i]>max)
max = a[i];

/* Ispisujemo maksimum */
printf("Max = %d\n",max);
}
Primer 1.22.3 Program pronalazi maksimum brojeva sa ulaza -
verzija bez niza. (Ovo rešenje je efikasnije jer je brže i koristi manje
memorije.)

37
Milena Vujošević–Janičić 1.22 Nizovi

#include <stdio.h>
#define BR_ELEM 5

main()
{
int a, max, i;
scanf("%d",&a);
max = a;
for (i = 1; i < BR_ELEM; i++)
{
scanf("%d",&a);
if (a>max)
max = a;
}

printf("Max : %d\n", max);


}
Primer 1.22.4 Program ilustruje inicijalizaciju nizova.
#include <stdio.h>

main()
{
/* Niz inicijalizujemo tako sto mu navodimo vrednosti
u viticasnim zagradama. Dimenzija niza se odredjuje
na osnovu broja inicijalizatora */
int a[] = {1, 2, 3, 4, 5, 6};

/* Isto vazi i za niske karaktera */


char s[] = {’a’, ’b’, ’c’};

/* Ekvivalentno prethodnom bi bilo


char s[] = {97, 98, 99};
*/

/* Broj elemenata niza */


int a_br_elem = sizeof(a)/sizeof(int);
int s_br_elem = sizeof(s)/sizeof(char);

/* Ispisujemo nizove */

int i;
for (i = 0; i < a_br_elem; i++)

38
Milena Vujošević–Janičić 1.22 Nizovi

printf("a[%d]=%d\n",i, a[i]);

for (i = 0; i < s_br_elem; i++)


printf("s[%d]=%c\n",i, s[i]);

}
Primer 1.22.5 Brojanje pojavljivanja svake od cifara. Korišćenje
niza brojača.
#include <stdio.h>

/* zbog funkcije isdigit */


#include <ctype.h>

main()
{
/* Niz brojaca za svaku od cifara */
int br_cifara[10];
int i, c;

/* Resetovanje brojaca */
for (i = 0; i < 10; i++)
br_cifara[i] = 0;

/* Citamo sa ulaza i povecavamo odgovarajuce brojace */


while ((c = getchar()) != EOF)
if (isdigit(c))
br_cifara[c-’0’]++;

/* Ispis rezultata */
for (i = 0; i < 10; i++)
printf("Cifra %d se pojavila %d put%s\n",
i, br_cifara[i], br_cifara[i] == 1 ? "" : "a");
}

Konstantne niske
Konstantna niska: ”Ja sam niska”
ili
”” /*prazna niska*/
Navodnici nisu deo niske vec se koriste da bi je ogranicili. Ako ih
zelimo unutar niske, oni se navode sa \".

39
Milena Vujošević–Janičić 1.23 Pokazivači i nizovi (polja)

Konstantna niska je polje znakova. Da bi se znalo gde je kraj


niske, zicko memorisanje liste zahteva da postoji jedan znak vise
koji oznacava kraj, to je ’\0’. Da bi se odredila duzina niske mora
se proci kroz celu nisku.
!!!Vazno:

Koja je razlika izmed̄u ”x” i ’x’ ?

Primer 1.22.6 Program uvodi niske karaktera terminisane nulom.


#include <stdio.h>

main()
{
/* Poslednji bajt niske karaktera se postavlja na ’\0’ tj. 0 */
char s[] = {’a’, ’b’, ’c’, ’\0’ };

/* Kraci nacin da se postigne prethodno */


char t[] = "abc";

/* Ispis niske s karakter po karakter*/


int i;
for (i = 0; s[i] != ’\0’; i++)
putchar(s[i]);
putchar(’\n’);

/* Ispis niske s koristeci funkciju printf */


printf("%s\n", s);

/* Ispis niske t karakter po karakter*/


for (i = 0; t[i] != ’\0’; i++)
putchar(t[i]);
putchar(’\n’);

/* Ispis niske t koristeci funkciju printf */


printf("%s\n", t);
}

1.23 Pokazivači i nizovi (polja)


U C-u postoji cvrsta veza izmed̄u pokazivaca i nizova. Bilo koja
operacija koja se moze ostvariti dopisivanjem indeksa niza moze se
uraditi i sa pokazivacima.

40
Milena Vujošević–Janičić 1.23 Pokazivači i nizovi (polja)

Deklaracija
int a[10];
de nise niz a velicine 10 koji predstavlja blok od 10 uzastopnih
objekata nazvanih a[0], a[1], ..., a[9]. Notacija a[i] odgo-
vara i-tom elementu niza.
Ako je pa pokazivac na ceo broj
int *pa;
tada iskaz pa = &a[0];
podesava da pa pokaze na nulti element niza a, odnosno pa sadrzi
adresu od a[0].
Ako pa pokazuje na odred̄eni element polja, onda po de niciji
pa+1 pokazuje na sledeci element, pa+i pokazuje na i-ti element
posle pa. Stoga, ako pa pokazuje na a[0] tada
*(pa+1)
se odnosi na sadrzaj od a[1].
pa+i je adresa od a[i], a
*(pa+i)
je sadrzaj od a[i]. Dozvoljeno je upotrebljavati i sintaksu kao
kod nizova:
*(pa+i) <==> pa[i]
Ovo sve vazi bez obzira na tip ili velicinu elemenata u polju a.
Iskaz pa=&a[0] se moze napisati kao pa=a jer je ime niza
sinonim za lokaciju početnog elementa.

Primer 1.23.1 Veza izmed̄u pokazivača i nizova.


#include <stdio.h>

main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int num_of_elements = sizeof(a)/sizeof(int);
int* pa;

/* Niz je isto sto i adresa prvog elementa */


printf("Niz a : %p\n", a);
printf("Adresa prvog elementa niza a (&a[0]) : %p\n", &a[0]);
/* Niz a : 0012FF5C
Adresa prvog elementa niza a (&a[0]) : 0012FF5C */

/* Moguce je dodeliti niz pokazivacu odgovarajuceg tipa */


pa = a;

41
Milena Vujošević–Janičić 1.24 Break i continue

printf("Pokazivac pa ukazuje na adresu : %p\n", pa);


/* Pokazivac pa ukazuje na adresu : 0012FF5C */

/* Nizu nije moguce dodeliti pokazivacku promenljivu


(nizove mozemo smatrati KONSTANTNIM pokazivacima na prvi element) */
/* a = pa; */

/* Pokazivace je dalje moguce indeksirati kao nizove */


printf("pa[0] = %d\n", pa[0]);
printf("pa[5] = %d\n", pa[5]);
/* pa[0] = 1
pa[5] = 6 */

/* Medjutim, sizeof(pa) je samo velicina pokazivaca, a ne niza */


printf("sizeof(a) = %d\n", sizeof(a));
printf("sizeof(pa) = %d\n", sizeof(pa));
/* sizeof(a) = 40
sizeof(pa) = 4 */
}

1.24 Break i continue


break moze da se koristi unutar switch naredbe ali i unutar petlje
(ukljucujuci sve tri vrste petlje). Kada se koristi unutar petlje,
break prouzrokuje nasilan izlazak iz petlje. Na primer:
/* Ako se neki clan niza nula,
petlja ce biti nasilno zavrsena,
sto znaci da preostali elementi niza
nece biti razmatrani, na primer ako je niz
1 2 3 0 4 5
tada ce za i=0, i=1 i i=2 biti izvrseno
mnozenje i proizvod ce biti 6,
za i=3 vazice uslov da je a[i]==0 i break
ce da prekine petlju, program ce se nastaviti
nakon for petlje i proizvod ce biti 6*/
prizvod = 1;
for(i=0; i<n; i++)
{
if (a[i]==0) break;
proizvod *= a[i];
}

42
Milena Vujošević–Janičić 1.25 Funkcije

Continue se red̄e koristi, on prouzrokuje da se pred̄e na sledecu


iteraciju u petlji.

/* Izracunace se proizvod nenula elemenata niza*/


prizvod = 1;
for(i=0; i<n; i++)
{
if (a[i]==0) continue;
prizvod *= a[i];
}

1.25 Funkcije
Primer 1.25.1 sum - najjednostavnija funkcija koja sabira dva broja
/* Definicija funkcije */
int sum(int a, int b)
{
int c;
c = a + b;
return c;
/* Ovo je krace moglo da bude napisano
kao return a+b; */
}

main()
{

int c;
/* Poziv funkcije */
c = sum(3,5);
printf("%d\n", c);

/* Ovo smo krace mogli da napisemo kao


printf("%d\n", sum(3,5)); */
}

Primer 1.25.2 Deklaracija funkcije moze da stoji nezavisno od defini-


cije funkcije. Deklaracija je neophodna u situacijama kada se defini-
cija funkcije navodi nakon upotrebe date funkcije u kodu.
/* Deklaracija funkcije*/
int zbir(int, int);

43
Milena Vujošević–Janičić 1.25 Funkcije

main()
{
/* Poziv funkcije */
printf("%d\n", zbir(3,5));
}

/* Definicija funkcije */
int zbir(int a, int b)
{
return a+b;
}

Primer 1.25.3 power - funkcija koja stepenuje realan broj na celo-


brojni izlozilac
#include <stdio.h>

/* stepenuje x^k tako sto k puta pomnozi x */


float power(float x, int k)
{
int i;
float rezultat = 1;
for (i = 0; i<k; i++)
rezultat*=x;

return rezultat;
}

Primer 1.25.4 Verzija koja radi i za negativne izlozioce


float power(float x, int k)
{
int i;
float s = 1;
int negativan = (k<0);
float rezultat;

if (negativan)
k = -k;

for (i = 0; i<k; i++)


s*=x;

rezultat = negativan ? 1.0/s : s;

44
Milena Vujošević–Janičić 1.25 Funkcije

return rezultat;
}

main()
{
/* Poziv funkcije */
float s = power(2.0,8);
printf("%f\n", s);
}

Primer 1.25.5 Funkcija koja konvertuje velika slova u mala slova.


#include<stdio.h>

/* Konvertuje karakter iz velikog u malo slovo */


char lower(char c)
{
if (c >= ’A’ && c <= ’Z’)
return c - ’A’ + ’a’ ;
else
return c;
}

main()
{
char c;
printf("Unesi neko veliko slovo:\n");
scanf("%c", &c);
printf("Odgovarajuce malo slovo je %c\n", lower(c));
}

Primer 1.25.6 Funkcija koja proverava da li je broj prost i program


koji ispisuje sve proste brojeve manje od 100.
#include<stdio.h>
#include<math.h>

int prost(int p)
{
int i, koren, ind;
koren=sqrt(p);
ind=(p%2) || (p==2);
i=3;
while (ind && i<=koren)

45
Milena Vujošević–Janičić
1.26 Životni vek i oblast važenja promenjivih, statičke promenljive

{
ind=p%i;
i+=2;
}
return ind;
}

main()
{
int k;
for(k=2;k<=100;k++)
if (prost(k)) printf("%d ",k);
}

1.26 Životni vek i oblast važenja promenjivih,


statičke promenljive
Primer 1.26.1
/* Ilustruje vidljivost imena*/
#include <stdio.h>

int i=10;

void main() {
{
int i=3;
{
int i=1;
printf("%d\n", i);
}
printf("%d\n",i);
}
printf("%d\n",i);
}
Primer 1.26.2 Demonstracija životnog veka i oblasti važenja promen-
jivih.
#include <stdio.h>

/* Globalna promenjiva */
int a = 0;

46
Milena Vujošević–Janičić
1.26 Životni vek i oblast važenja promenjivih, statičke promenljive

/* Uvecava se globalna promenjiva a */


void increase()
{
a++;
printf("increase::a = %d\n", a);
}

/* Umanjuje se lokalna promenjiva a.


Globalna promenjiva zadrzava svoju vrednost. */
void decrease()
{
/* Ovo a je nezavisna promenjiva u odnosu na globalno a */
int a = 0;
a--;
printf("decrease::a = %d\n", a);

void nonstatic_var()
{
/* Nestaticke promenjive ne cuvaju vrednosti kroz pozive funkcije */
int s=0;
s++;
printf("nonstatic::s=%d\n",s);
}

void static_var()
{
/* Staticke promenjive cuvaju vrednosti kroz pozive funkcije.
Inicijalizacija se odvija samo u okviru prvog poziva. */
static int s=0;
s++;
printf("static::s=%d\n",s);
}

main()
{
/* Promenjive lokalne za funkciju main */
int i;
int x = 3;

printf("main::x = %d\n", x);

47
Milena Vujošević–Janičić
1.26 Životni vek i oblast važenja promenjivih, statičke promenljive

for (i = 0; i<3; i++)


{
/* Promenjiva u okviru bloka je nezavisna od spoljne promenjive.
Ovde se koristi promenjiva x lokalna za blok petlje koja ima
vrednost 5, dok originalno x i dalje ima vrednost 3*/
int x = 5;
printf("for::x = %d\n", x);
}

/* U ovom bloku x ima vrednost 3 */


printf("main::x = %d\n", x);

increase();
decrease();

/* Globalna promenjiva a */
printf("main::a = %d\n", a);

/* Demonstracija nestatickih promenjivih */


for (i = 0; i<3; i++)
nonstatic_var();

/* Demonstracija statickih promenjivih */


for (i = 0; i<3; i++)
static_var();
}

Izlaz iz programa:
main::x = 3
for::x = 5
for::x = 5
for::x = 5
main::x = 3
increase::a = 1
decrease::a = -1
main::a = 1
nonstatic::s=1
nonstatic::s=1
nonstatic::s=1
static::s=1
static::s=2
static::s=3

48
Milena Vujošević–Janičić 1.27 Funkcije — prenos parametara po vrednosti

1.27 Funkcije — prenos parametara po vred-


nosti
Primer 1.27.1 Demonstracija prenosa parametara po vrednosti -
preneti parametri se ne mogu menjati
#include <stdio.h>
void f(int x)
{
x++;
}

main()
{
int x=3;
f(x);
printf("%d\n", x);
}

Primer 1.27.2 Funkcija za ispis niza brojeva - demonstrira prenos


nizova brojeva u funkciju.
#include <stdio.h>

/* Nizovi se prenose tako sto se prenese adresa njihovog pocetka.


Uglaste zagrade ostaju prazne!

Nizove je neophodno prenositi zajedno sa dimenzijom niza


(osim za niske karaktera, jer tamo vazi konvencija da
se kraj niza obelezava znakom ’\0’)
*/
void print_array(int a[], int n)
{
int i;
for (i = 0; i < n; i++)
printf("%d ",a[i]);
putchar(’\n’);

/* Obratite paznju na ovo : */


printf("sizeof(a) - u okviru fje : %d\n", sizeof(a));
}

main()
{

49
Milena Vujošević–Janičić 1.27 Funkcije — prenos parametara po vrednosti

int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

printf("sizeof(a) - u okviru main : %d\n", sizeof(a));


print_array(a, sizeof(a)/sizeof(int));
}
Primer 1.27.3 Funkcija za ispis niske karaktera - demonstrira prenos
niske karaktera u funkciju.
#include <stdio.h>

/* Uz nisku karaktera nije potrebno prenositi dimenziju


ukoliko se postuje dogovor
da se svaka niska zavrsava karakterom ’\0’.*/
void print_string(char s[])
{
int i;
for (i = 0; s[i]!=’\0’; i++)
putchar(s[i]);
}

main()
{
string str[] = "Zdravo\n"
print_string(str);
}

Primer 1.27.4 Konvertovanje niske cifara u ceo broj.


#include<stdio.h>

/* atoi: konvertuje s u ceo broj */


int atoi(char s[])
{
int i, n;
n = 0;
for (i = 0; (s[i] >= ’0’) && (s[i] <= ’9’); ++i)
n = 10 * n + (s[i] - ’0’);
return n;
}

main()
{
int n;

50
Milena Vujošević–Janičić 1.27 Funkcije — prenos parametara po vrednosti

char broj[]="234"
n = atoi(broj);
printf("\nN je : %d\n",n);
}
Primer 1.27.5 Demonstrira prenos nizova u funkciju - preneti niz
se moze menjati.
#include <stdio.h>
#include <ctype.h>

/* Funkcija ucitava rec sa standardnog ulaza


i smesta je u niz karaktera s.
Ovo uspeva zbog toga sto se po vrednosti
prenosi adresa pocetka niza,
a ne ceo niz */
void get_word(char s[])
{
int c, i = 0;
while (!isspace(c=getchar()))
s[i++] = c;
s[i] = ’\0’;
}

main()
{
/* Obavezno je alocirati memoriju za niz karaktera */
char s[100];

get_word(s);
printf("%s\n", s);
}
Primer 1.27.6 Veza izmed̄u pokazivača i nizova u funkcijama.
#include <stdio.h>

/* Deklaracija funkcije print_array */


void print_array(int* pa, int n);

main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int num_of_elements = sizeof(a)/sizeof(int);

51
Milena Vujošević–Janičić 1.28 Pokazivači i argumenti funkcija

int* pa;

pa = a;

/* Pozivamo funkciju za stampanje niza i saljemo joj niz */


print_array(a, num_of_elements);

/* Pozivamo funkciju za stampanje niza


i saljemo joj pokazivac na pocetak niza */
print_array(pa, num_of_elements);
}

/* Prosledjivanje niza u funkciju


void print_array(int pa[], int n);
je ekvivalentno prosledjivanju pokazivaca u funkciju
void print_array(int* pa, int n);
Izmedju ovih konstrukcija nema nikakve razlike!
*/
void print_array(int* pa, int n)
{
int i;
printf("%d\n", sizeof(pa));
for (i = 0; i<n; i++)
printf("%d ", pa[i]);
putchar(’\n’);
}

1.28 Pokazivači i argumenti funkcija


C prosled̄uje argumente u funkcije pomocu vrednosti. To znaci da
sledeca funkcija nece uraditi ono sto zelimo:
void swap (int x, int y) /* POGRESNO!!!!!!!!*/
{
int temp;
temp = x;
x=y;
y=temp;
}
Zbog prenosa parametara preko vrednosti swap ne moze da utice
na argumente a i b u funkciji koja je pozvala swap. Ova swap
funkcija samo zamenjuje kopije od a i b.

52
Milena Vujošević–Janičić 1.28 Pokazivači i argumenti funkcija

Da bi se dobio zeljeni efekat, potrebno je da se proslede pokazivaci:


/* Zameni *px i *py */
void swap (int *px, int *py)
{
int temp;
temp =*px;
*px = *py;
*py = temp;
}
a poziv funkcije swap izlgeda sada ovako
swap(&a, &b);
Primer 1.28.1 Prethodni primer može se testirati uz pomoć sledećeg
programa.
#include <stdio.h>

/* Pogresna verzija funkcije swap. Zbog prenosa po vrednosti, funkcija


razmenjuje kopije promenljivih iz main-a, a ne samih promenljivih */
void swap_wrong(int x, int y)
{
int tmp;
printf("swap_wrong: ");
printf("Funkcija menja vrednosti promenljivim na adresama : \n");
printf("x : %p\n", &x);
printf("y : %p\n", &y);
tmp = x;
x = y;
y = tmp;
}

/* Resenje je prenos argumenata preko pokazivaca */


void swap(int* px, int* py)
{
int tmp;
printf("swap : Funkcija menja vrednosti promenljivim na adresama : \n");
printf("px = %p\n", px);
printf("py = %p\n", py);
tmp = *px;
*px = *py;
*py = tmp;
}

53
Milena Vujošević–Janičić 1.28 Pokazivači i argumenti funkcija

main()
{
int x = 3, y = 5;
printf("Adresa promenljive x je %p\n", &x);
printf("Vrednost promenljive x je %d\n", x);
printf("Adresa promenljive y je %p\n", &y);
printf("Vrednost promenljive y je %d\n", y);

/* Pokusavamo zamenu koristeci pogresnu verziju funkcije */


swap_wrong(x, y);
printf("Posle swap_wrong:\n");
printf("Vrednost promenljive x je %d\n", x);
printf("Vrednost promenljive y je %d\n", y);

/* Vrsimo ispravnu zamenu. Funkciji swap saljemo adrese promenljvih


x i y, a ne njihove vrednosti */
swap(&x, &y);
printf("Posle swap:\n");
printf("Vrednost promenljive x je %d\n", x);
printf("Vrednost promenljive y je %d\n", y);
}

Izlaz u konkretnom slucaju:


Adresa promenljive x je 0012FF88
Vrednost promenljive x je 3
Adresa promenljive y je 0012FF84
Vrednost promenljive y je 5
swap_wrong: Funkcija menja vrednosti promenljivim na adresama :
x : 0012FF78
y : 0012FF7C
Posle swap_wrong:
Vrednost promenljive x je 3
Vrednost promenljive y je 5
swap : Funkcija menja vrednosti promenljivim na adresama :
px = 0012FF88
py = 0012FF84
Posle swap:
Vrednost promenljive x je 5
Vrednost promenljive y je 3
Primer 1.28.2 Demonstracija više povratnih vrednosti funkcije ko-
risteći prenos preko pokazivača.

54
Milena Vujošević–Janičić 1.28 Pokazivači i argumenti funkcija

/* Funkcija istovremeno vraca dve vrednosti - kolicnik i ostatak


dva data broja. Ovo se postize tako sto se funkciji predaju
vrednosti dva broja (x i y) koji se dele
i adrese dve promenljive na koje ce se smestiti rezultati */

void div_and_mod(int x, int y, int* pdiv, int* pmod)


{
printf("Kolicnik postavljam na adresu : %p\n", pdiv);
printf("Ostatak postavljam na adresu : %p\n", pmod);
*pdiv = x / y;
*pmod = x % y;
}

main()
{
int div, mod;
printf("Adresa promenljive div je %p\n", &div);
printf("Adresa promenljive mod je %p\n", &mod);

/* Pozivamo funkciju tako sto joj saljemo


vrednosti dva broja (5 i 2)
i adrese promenljvih div i mod na koje
ce se postaviti rezultati */
div_and_mod(5, 2, &div, &mod);

printf("Vrednost promenljive div je %d\n", div);


printf("Vrednost promenljive mod je %d\n", mod);

Izlaz u konkretnom slucaju:


Adresa promenljive div je 0012FF88
Adresa promenljive mod je 0012FF84
Kolicnik postavljam na adresu : 0012FF88
Ostatak postavljam na adresu : 0012FF84
Vrednost promenljive div je 2
Vrednost promenljive mod je 1
Primer 1.28.3 Ilustracija lenjog izračunavanja logičkih operatora.
Prilikom izracunavanja izraza - A && B, ukoliko je A netačno,
izraz B se ne izračunava. Prilikom izračunavanja izraza - A k B,
ukoliko je A tačno, izraz B se ne izračunava.
#include <stdio.h>

55
Milena Vujošević–Janičić 1.29 Povratne vrednosti funkcija

/* Globalna promenljiva, vidljiva i iz funkcije main() i


iz funkcije izracunaj*/
int b = 0;

/* Funkcija ispisuje da je pozvana i uvecava promenjivu b.


Funkcija uvek vraca vrednost 1 (tacno)
*/
int izracunaj()
{
printf("Pozvano izracunaj()\n");
b++;
return 1;
}

main()
{
/* Funkcija izracunaj() ce biti pozvana
samo za parne vrednosti a */
int a;
for (a = 0; a < 10; a++)
if (a%2 == 0 && izracunaj())
printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
else
printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);

printf("----------------------------\n");

/* Funkcija izracunaj() ce se pozivati samo


za neparne vrednosti a */
b = 0;
for (a = 0; a < 10; a++)
if (a%2 == 0 || izracunaj())
printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
else
printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);
}

1.29 Povratne vrednosti funkcija


Funkcije mogu da nemaju povratnu vrednost (onda se to oznacava
kljucnom reci void) ili da vrate bilo koji osnovni tip podataka, struk-

56
Milena Vujošević–Janičić 1.29 Povratne vrednosti funkcija

turu, uniju ili pokazivac. U sledecim primerima date su deklaracije


funkcija bez argumenata sa razlicitim povratnim vrednostima:
void f1(); /*Funkcija nema povratnu vrednost*/
void f2(void); /*Funkcija nema povratnu vrednost*/

int f3(); /*Povratna vrednost celobrojna*/


unsigned int f4(); /*Povratna vrednost tipa unsigned int*/
long int f5(); /*Povratna vrednost tipa long int*/

float f6(); /*Povratna vrednost tipa float*/


double f7(); /*Povratna vrednost tipa double*/

int* f8(); /*Povratna vrednost je pokazivac na int*/


struct licnost f9(); /*Povratna vrednost je struktura*/
struct licnost* f10(); /*Povratna vrednost je pokazivac na strukturu*/
Funkcija ne moze da vrati niz, dakle deklaracija sledeceg oblika
je neispravna:
/* Sintaksno neispravna deklaracija funkcije*/
int[] funkcija();
Moguce je vratiti adresu prvog elementa niza, i to se radi koriscenjem
funkcije koja ima za povratnu vrednost pokazivac. Na primer,
int* funkcija();
Treba voditi racuna da iako je sledeci kôd sintaksno ispravan, on
je potpuno semanticki neispravan i moze izazvati prekid rada pro-
grama:

/*Neispravna upotreba pokazivaca */


int* funkcija()
{
int i;
int a[20];
for(i=0; i<20; i++)
a[i] = i;
return a;
}
Do greske dolazi jer se kao povratna vrednost funkcije vraca adresa
niza a koji je lokalna promenljiva u funkciji i cija se memorija

57
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

oslobad̄a zavrsavanjem rada funkcije (tj. niz a prestaje da postoji


kada funkcija zavrsi rad tako da pokazivac ukazuje na adresu objekta
koji na tom mestu vise ne postoji). Dakle, nije moguce kreirati
lokalni niz u funkciji, sracunati njegove vrednosti i onda vratiti
pokazivac na prvi element tog niza. Da bi funkcija f sracunala
elemente nekog niza, potrebno je da se taj niz alocira u funkciji
koja poziva funkciju f, a da se samoj funkciji proslede adresa prvog
elementa niza i broj elemenata niza. Dakle,
void funkcija(int a[], int n)
{
int i;
for(i=0; i<20; i++)
a[i] = i;
}
main()
{
int a[20];
funkcija(a, 20);
...
}

1.30 Rad sa niskama karaktera


Primer 1.30.1 Primer funkcije koja izračunava dužinu niske znakova.
#include <stdio.h>

/* Ova funkcija racuna duzinu date niske karaktera.


Umesto nje, moguce je koristiti standardnu funkciju strlen
za cije je koriscenje potrebno ukljuciti zaglavlje
<string.h>
*/
int strlen(char s[])
{
int i=0;
while (s[i] != ’\0’)
++i;
return i;
}

main()
{

58
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

printf("Duzina ove niske je: %d \n",strlen("Duzina ove niske je:"));


}

Primer 1.30.2 Funkcija uklanja beline, tabulatore ili znak za kraj


reda sa kraja stringa.
int trim(char s[])
{
int n;
for (n = strlen(s)-1; n >= 0; n--)
if (s[n] != ’ ’ && s[n] != ’\t’ && s[n] != ’\n’)
break;
s[n+1] = ’\0’;
return n;
}

Primer 1.30.3 string_reverse - obrće nisku karaktera.


#include <stdio.h>

/* Ova funkcija racuna duzinu date niske karaktera.


Umesto nje, moguce je koristiti standardnu funkciju strlen
za cije je koriscenje potrebno ukljuciti zaglavlje
<string.h>
*/
int string_length(char s[])
{
int i;
for (i = 0; s[i]!=’\0’; i++)
;

return i;
}

/* Funkcija obrce nisku karaktera */


void string_reverse(char s[])
{
int i, j;
for (i = 0, j = string_length(s)-1; i<j; i++, j--)
{
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}

59
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

/* Napomena : razlikovati prethodnu petlju od dve ugnjezdjene petlje:


for ( i = 0; ....)
for ( j = duzina(s)-1; ...
*/

main()
{
char s[] = "Zdravo svima";
string_reverse(s);
printf("%s\n", s);
}
/*
Izlaz:
amivs ovardZ
*/
Primer 1.30.4 strlen, strcpy, strcat, strcmp, strchr, strstr
- manipulacija niskama karaktera. Vezbe radi, implementirane su
funkcije biblioteke string.h
#include <stdio.h>

/* Izracunava duzinu stringa */


int string_length(char s[])
{
int i;
/* Uslov s[i] je ekvivalentan uslovu
s[i]!=’\0’ ili uslovu s[i]! = 0*/
for (i = 0; s[i]; i++)
;
return i;
}

/* Kopira string src u string dest.


Pretpostavlja da u dest ima dovoljno prostora. */
void string_copy(char dest[], char src[])
{
/* Kopira karakter po karakter, sve dok nije
iskopiran karakter ’\0’ */
int i;
for (i = 0; (dest[i]=src[i]) != ’\0’; i++)

60
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

/* Uslov != ’\0’ se, naravno, moze izostaviti :

for (i = 0; dest[i]=src[i]; i++)


;
*/
}

/* Vrsi leksikografsko poredjenje dva stringa.


Vraca :
0 - ukoliko su stringovi jednaki
<0 - ukoliko je s leksikografski ispred t
>0 - ukoliko je s leksikografski iza t
*/
int string_compare(char s[], char t[])
{
/* Petlja tece sve dok ne naidjemo na prvi razliciti karakter */
int i;
for (i = 0; s[i]==t[i]; i++)
if (s[i] == ’\0’) /* Naisli smo na kraj oba stringa,
a nismo nasli razliku */
return 0;

/* s[i] i t[i] su prvi karakteri u kojima se niske razlikuju.


Na osnovu njihovog odnosa, odredjuje se odnos stringova */
return s[i] - t[i];
}

/* Nadovezuje string t na kraj stringa s.


Pretpostavlja da u s ima dovoljno prostora. */
void string_concatenate(char s[], char t[])
{
int i, j;
/* Pronalazimo kraj stringa s */
for (i = 0; s[i]; i++)
;

/* Vrsi se kopiranje, slicno funkciji string_copy */


for (j = 0; s[i] = t[j]; j++, i++)
;
}

61
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

/* Pronalazi prvu poziciju karaktera c u stringu s, odnosno -1


ukoliko s ne sadrzi c */
int string_char(char s[], char c)
{
int i;
for (i = 0; s[i]; i++)
if (s[i] == c)
return i;
/* nikako
else
return -1;
*/
/* Nije nadjeno */
return -1;
}

/* Pronalazi poslednju poziciju karaktera c u stringu s, odnosno -1


ukoliko s ne sadrzi c */
int string_last_char(char s[], char c)
{
/* Pronalazimo kraj stringa s */
int i;
for (i = 0; s[i]; i++)
;

/* Krecemo od kraja i trazimo c unazad */


for (i--; i>=0; i--)
if (s[i] == c)
return i;

/* Nije nadjeno */
return -1;

/*
Koristeci string_length :

for (i = string_length(s) - 1; i>0; i--)


if (s[i] == c)
return i;

return -1;

62
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

*/
}

/* Proverava da li string str sadrzi string sub.


Vraca poziciju na kojoj sub pocinje, odnosno -1 ukoliko ga nema
*/
int string_string(char str[], char sub[])
{
int i, j;
/* Proveravamo da li sub pocinje na svakoj poziciji i */
for (i = 0; str[i]; i++)
/* Poredimo sub sa str pocevsi od poziciji i
sve dok ne naidjemo na razliku */
for (j = 0; str[i+j] == sub[j]; j++)
/* Nismo naisli na razliku a ispitali smo
sve karaktere niske sub */
if (sub[j+1]==’\0’)
return i;
/* Nije nadjeno */
return -1;
}

main()
{
char s[100];
char t[] = "Zdravo";
char u[] = " svima";

string_copy(s, t);
printf("%s\n", s);

string_concatenate(s, u);
printf("%s\n", s);

printf("%d\n",string_char("racunari", ’n’));
printf("%d\n",string_last_char("racunari", ’a’));

printf("%d\n",string_string("racunari", "rac"));
printf("%d\n",string_string("racunari", "ari"));
printf("%d\n",string_string("racunari", "cun"));
printf("%d\n",string_string("racunari", "cna"));
}

63
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

/*
Izlaz:
Zdravo
Zdravo svima
4
5
0
5
2
-1*/

Primer 1.30.5 Funkcija koja uklanja proizvoljan znak c kad god se


pojavi u stringu s.
#include <stdio.h>

void squeeze(char s[], char c)


{
int i,j;
for(i=j=0; s[i]!=’\0’;i++)
if(s[i]!=c) s[j++]=s[i];
s[j]=’\0’;
}

main()
{
char niz[20];
char c;

printf("Unesi karakter\n\n");
scanf("%c", &c);

scanf("%s", niz);
squeeze(niz, c);
printf("%s\n", niz);
}
Primer 1.30.6 Obrtanje stringa i pretvaranje broja u string
#include <stdio.h>
#include <string.h>

/* reverse: obrce string, npr string "1234" postaje "4321" */


void reverse(char s[])

64
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

{
int c, i, j;

for (i = 0, j = strlen(s)-1; i < j; i++, j--)


{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}

/* itoa: konvertuje broj n u niz karaktera s */


void itoa(int n, char s[])
{
int i, sign;

if ((sign = n) < 0) /* sacuvaj znak */


n = -n; /* napravi da je n pozitivno */
i = 0;
do {
/* generisanje cifara u obrnutom smeru */
s[i++] = n % 10 + ’0’; /* izracunaj sledecu cifru */
} while ((n /= 10) > 0); /* izbaci cifru iz zapisa */
if (sign < 0)
s[i++] = ’-’;
s[i] = ’\0’;
reverse(s);
}

main()
{
int n=-44;
char nst[100];
itoa(n,nst);
printf("%s\n",nst);
}
Primer 1.30.7 Konvertovanje stringa u broj u pokretnom zarezu.
#include <ctype.h>
#include <stdio.h>
#define MAXLINE 100

/* getline: get line into s, return length */

65
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

int getline(char s[], int lim)


{
int c, i;

i = 0;
while (--lim > 0 && (c=getchar()) != EOF && c != ’\n’)
s[i++] = c;
if (c == ’\n’)
s[i++] = c;
s[i] = ’\0’;
return i;
}

/* atof: convert string s to double */


double atof(char s[])
{
double val, power;
int i, sign;

/* skip white space */


for (i = 0; isspace(s[i]); i++)
;

/* Postavlja se znak broja*/


sign = (s[i] == ’-’) ? -1 : 1;

/* Preskace se jedno mesto ukoliko je bio upisan znak u broj*/


if (s[i] == ’+’ || s[i] == ’-’)
i++;

/* Racuna se vrednost broja dok se ne naidje na tacku */


for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - ’0’);

if (s[i] == ’.’)
i++;

/* Racuna se vrednost broja iza tacke*/


for (power = 1.0; isdigit(s[i]); i++)
{
val = 10.0 * val + (s[i] - ’0’);
power *= 10;
}

66
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

return sign * val / power;


}

/* Program sabira brojeve u pokretnom zarezu koji se unose sa ulaza*/


main()
{
double sum;
char line[MAXLINE];

sum = 0;
while (getline(line, MAXLINE) > 0)
printf("\t%g\n", sum += atof(line));
}
Primer 1.30.8 Program učitava linije sa ulaza i pamti najdužu lin-
iju.
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */

int getline(char line[], int maxline);


void copy(char to[], char from[]);

/* print the longest input line */


main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */

max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
}

/* getline: read a line into s, return length */


int getline(char s[],int lim)
{

67
Milena Vujošević–Janičić 1.30 Rad sa niskama karaktera

int c, i;

for (i=0; i < lim-1 && (c=getchar())!=EOF && c!=’\n’;++i)


s[i] = c;
if (c == ’\n’) {
s[i] = c;
++i;
}
s[i] = ’\0’;
return i;
}

/* copy: copy ’from’ into ’to’;


assume to is big enough */
void copy(char to[], char from[])
{
int i;

i = 0;
while ((to[i] = from[i]) != ’\0’)
++i;
}

Primer 1.30.9 btoi - konverzija iz datog brojnog sistema u dekadni.


#include <stdio.h>
#include <ctype.h>

/* Pomocna funkcija koja izracunava vrednost


koju predstavlja karakter u datoj osnovi
Funkcija vraca -1 ukoliko cifra nije validna.

Npr.
cifra ’B’ u osnovi 16 ima vrednost 11
cifra ’8’ nije validna u osnovi 6
*/

int digit_value(char c, int base)


{
/* Proveravamo obicne cifre */
if (isdigit(c) && c < ’0’+base)
return c-’0’;

68
Milena Vujošević–Janičić 1.31 Linearna i binarna pretraga

/* Proveravamo slovne cifre za mala slova */


if (’a’<=c && c < ’a’+base-10)
return c-’a’+10;

/* Proveravamo slovne cifre za velika slova */


if (’A’<=c && c < ’A’+base-10)
return c-’A’+10;

return -1;
}

/* Funkcija izracunava vrednost celog broja koji je zapisan u datom


nizu karaktera u datoj osnovi.
*/
int btoi(char s[], int base)
{
int sum = 0;

/* Obradjuju se karakteri sve dok su to validne cifre */


int i, vr;
for (i = 0; (vr = digit_value(s[i], base)) != -1; i++)
sum = base*sum + vr;

return sum;
}

main()
{
char bin[] = "11110000";
char hex[] = "FF";

printf("Dekadna vrednost binarnog broja %s je %d\n", bin, btoi(bin, 2));


printf("Dekadna vrednost heksadekadnog
broja %s je %d\n", hex, btoi(hex, 16));
}

1.31 Linearna i binarna pretraga


Primer 1.31.1 Linearna pretraga
#include <stdio.h>

/* Funkcija proverava da li se dati element x nalazi

69
Milena Vujošević–Janičić 1.31 Linearna i binarna pretraga

u datom nizu celih brojeva.


Funkcija vraca poziciju u nizu na kojoj je x pronadjen
odnosno -1 ukoliko elementa nema.
*/
int linearna_pretraga(int niz[], int br_elem, int x)
{
int i;
for (i = 0; i<br_elem; i++)
if (niz[i] == x)
return i;
/* nikako else return -1; !!!!*/
return -1;
}

main()
{
/* Inicijalizacija niza */
int a[] = {4, 3, 2, 6, 7, 9, 11};

/* Da bi smo odredili koliko clanova ima niz mozemo


koristiti operator sizeof*/
int br_elem = sizeof(a)/sizeof(int);
int x;
int i;

printf("Unesite broj koji trazimo : ");


scanf("%d",&x);

i = linearna_pretraga(a, br_elem, x);


if (i == -1)
printf("Element %d nije nadjen\n",x);
else
printf("Element %d je nadjen na poziciji %d\n",x, i);
}
Primer 1.31.2 Binarna pretraga niza — iterativna verzija.
#include <stdio.h>

/* Funkcija proverava da li se element x javlja unutar niza


celih brojeva a.
Funkcija vraca poziciju na kojoj je element nadjen odnosno
-1 ako ga nema.

70
Milena Vujošević–Janičić 1.31 Linearna i binarna pretraga

!!!!! VAZNO !!!!!


Pretpostavka je da je niz a uredjen rastuce po velicini
*/

int binarna_pretraga(int a[], int n, int x)


{
/* Pretrazujemo interval [l, d] */
int l = 0;
int d = n-1;

/* Sve dok interval [l, d] nije prazan */


while (l <= d)
{
/* Srednja pozicija intervala [l, d] */
int s = (l+d)/2;

/* Ispitujemo odnos x i a[srednjeg elementa] */


if (x == a[s])
/* Element je pronadjen */
return s;
else if (x < a[s])
{
/* Pretrazujemo interval [l, s-1] */
d = s-1;
}
else
{
/* Pretrazujemo interval [s+1, d] */
l = s+1;
}
}

/* Element nije nadjen */


return -1;
}

main()
{
int a[] = {3, 5, 7, 9, 11, 13, 15};
int x;
int i;

printf("Unesi element koji trazimo : ");

71
Milena Vujošević–Janičić 1.32 Strukture

scanf("%d",&x);
i = binarna_pretraga(a, sizeof(a)/sizeof(int), x);

if (i==-1)
printf("Elementa %d nema u nizu!\n", x);
else
printf("Element %d je pronadjen na poziciji %d\n", x, i);
}

1.32 Strukture
Informacije kojima se opisuje realni svet retko se predstavljaju u
elementarnoj formi u vidu celih, realnih, znakovnih konstanti itd.
Mnogo cesce imamo posla sa slozenim objektima koji se sastoje od
elemenata raznih tipova. Na primer jednu osobu karakterisu ime,
prezime, datum i mesto rod̄enja.
Struktura predstavlja skup podataka kojim se opisuju neka bitna
svojstva objekta. Komponente koje obrazuju strukturu nazivaju se
elementi strukture.
Sintaksa strukture:

struct ime_strukture
{
tip ime_elementa1;
tip ime_elementa2;
...
};
Za svaki element strukture odvaja se odgovarajuci blok memorije.

Primer 1.32.1 Primer jednostavne strukture.


struct licnost
{
char ime[31];
char adresa[41];
unsigned starost;
};
Sada možemo deklarisati dve osobe na sledeći način:
struct licnost osoba1, osoba2;
Kada imamo promenljivu strukturnog tipa tada elementima date
strukture pristupamo uz pomoc operatora ’.’.

72
Milena Vujošević–Janičić 1.32 Strukture

Primer 1.32.2
osoba1.starost=20;
osoba2.starost=21;
...
if (osoba1.starost == osoba2.starost)
printf("Osobe su iste starosti\n");

/* Sledece poredjenje poredi samo adrese


na kojima se nalaze imena osoba, i kako su
osobe na razlicitim adresama, pa time i njihova
imena, to znaci da ce rezultat ovog
poredjenja uvek biti "netacno"
if(osoba1.ime == osoba2.ime)
*/
/* Ispravno poredjenje imena je: */
if(strcmp(osoba1.ime, osoba2.ime) == 0)
printf("Osobe se isto zovu!\n");

Dozvoljeno je praviti nizove struktura. Na primer, niz od 20


elemenata koji sadrzi licnosti:
struct licnost nizLicnosti[20];
Tada da bi procitali starost neke licnosti u nizu pisemo:
nizLicnosti[5].starost
Moze se de nisati pokazivac na strukturu.
struct licnost *posoba;
Tada se pristupanje elementima strukture moze vrsiti upotrebom
operatora ’.’ na standardni nacin (upotreba zagrada je vazna zbog
prioriteta operatora):
(*posoba).ime
(*posoba).adresa
(*posoba).starost
ili koriscenjem specijalnog operatora 0
>0 na sledeci nacin:
posoba->ime
posoba->adresa
posoba->starost

Primer 1.32.3 Elementi strukture mogu da budu i druge strukture.

73
Milena Vujošević–Janičić 1.33 Operator typedef

struct datum
{
unsigned dan;
unsigned mesec;
unsigned godina;
};

struct licnost
{
char ime[30];
struct datum datumrodjenja;
};
Sada se danu, mesecu i godini datuma rodjenja pristupa na sledeći
način:
osoba.datumrodjenja.dan = 10;
osoba.datumrodjenja.mesec = 5;
osoba.datumrodjenja.godina = 1986;

1.33 Operator typedef


Operator typedef omogucava nam da de nisemo nasa imena za neki
od osnovih ili izvedenih tipova. Na primer, mozemo da uradimo
sledece:
typedef double RealanBroj;
Nakon ovoga mozemo u tekstu deklarista promenljivu x kao Realan-
Broj, ona ce zapravo biti tipa double.
RealanBroj x; /* Umesto: double x;*/
Ili, ako zelimo da skratimo pisanje za neoznacene duge brojeve tj
za unsigned long int to mozemo da uradimo na sledeci nacin
typedef unsigned long int VelikiBroj;
Sada u kodu mozemo da koristimo VelikiBroj kao tip, na primer:
VelikiBroj x /* Umesto: unsigned long int x; */;
Operator typedef je narocito pogodan da bi se izbeglo ponavl-
jalnje reci struct pri deklarisanju strukturnih promenljivih.
typedef struct _licnost licnost;
Sada deklaracija moze da bude:

74
Milena Vujošević–Janičić 1.34 Unije

licnost osoba1, osoba2;


/* umesto: struct _licnost osoba1, osoba2; */
Kao skracen zapis za
struct _tacka {
float x;
float y;
};

typedef struct _tacka tacka;


moze se koristiti:
typedef struct _tacka
{
float x;
float y;
} tacka;

Primer 1.33.1 Struktura artikal.


typedef struct _artikal
{
long bar_kod;
char ime[MAX_IME];
float pdv;
} artikal;

1.34 Unije
Unije se kreiraju koristeci kljucnu rec union a elementima unija se
pristupa uz pomoc operatora . (tacka). Osnovna razlika izmed̄u
unija i struktura je u tome sto unije koriste manju koicinu memorije
u odnosu na odgovarajuce strukture. Na primer, struktura koja ima
dva elementa, jedan tipa double i jedan tipa int zauzima 8+4=12
bajtova u memoriji dok odgovarajuca unija zauzima samo 8 bajtova.
To je zato sto se za uniju odvaja onoliko prostora koliko je potrebno
za najveci element unije, dok se u strukturi odvaja memorija za
svaki element pojedinacno. Usteda u memoriji se placa time sto
programer mora da vodi racuna na koji nacin u kom trenutku moze
da koristi uniju.
Primer 1.34.1
#include<stdio.h>

75
Milena Vujošević–Janičić 1.35 Strukture — primeri

typedef union num


{
double d;
int i;
} NUM;

main()
{
NUM n;
/* Nakon naredne dodele n.d ima vrednost 3.14*/
n.d = 3.14;

/* Nakon naredne dodele n.i ima vrednost 5.


Vrednost n.d (3.14) je prepisana vrednoscu 5
i n.d se ne moze ispravno koristiti sa desne
strane jednakosti. To je zato sto n.d i n.i
dele isti memorijski prostor.*/
n.i = 5;
}

1.35 Strukture — primeri


Primer 1.35.1 Ulustracija deklaracije i inicijalizacije strukture.
#include <stdio.h>

/* Tacke su predstavljene sa dve koordinate.


Strukturom gradimo novi tip podataka. */
typedef struct _point
{
int x;
int y;
} point;

main()
{
/* Deklarisemo neinicijalizovanu tacku */
point a;

/* Deklarisemo i inicijalizujemo tacku b na (1,2) */


point b = {1, 2};

76
Milena Vujošević–Janičić 1.35 Strukture — primeri

/* Postavljamo vrednosti koordinata tacke a (posto ona


nije bila inicijalizovana prilikom deklaracije).*/
a.x = 0;
a.y = 0;

/* Ispisujemo velicinu strukture tacka */


printf("sizeof(point) = %d\n", sizeof(point));

/* Ispisujemo vrednosti koordinata tacaka */


printf("x koordinata tacke a je %d\n", a.x);
printf("y koordinata tacke a je %d\n", a.y);
printf("x koordinata tacke b je %d\n", b.x);
printf("y koordinata tacke b je %d\n", b.y);
}

Izlaz:
sizeof(point) = 8
x koordinata tacke a je 0
y koordinata tacke a je 0
x koordinata tacke b je 1
y koordinata tacke b je 2

Primer 1.35.2 Program omogućava unos tačaka sa standardnog ulaza


i izračunava kvadrate rastojanja svih tačaka od koordinatnog početka,
zbir kvadrata rastojanja i tačku koja je najdalja od koordinatnog
početka.
#include <stdio.h>

#define MAXDUZ 100

typedef struct _tacka


{
int x, y;
} tacka;

main()
{
tacka Tacke[MAXDUZ];

/*Brojac i velicina niza*/


int i, n;

77
Milena Vujošević–Janičić 1.35 Strukture — primeri

/*Pomocne promenljive za cuvanje trazenih vrednosti*/


int pozicija, maxRastojanje, kvRastojanje, zbir;

printf("Unesite broj tacaka (manji od %d):\n", MAXDUZ);


scanf("%d",&n);

/* Ucitava se niz tacaka*/


for(i=0; i<n; i++)
{
printf("Unesi x koordinatu %d. tacke\n", i+1);
scanf("%d", &Tacke[i].x);
printf("Unesi y koordinatu %d. tacke\n", i+1);
scanf("%d", &Tacke[i].y);
}

pozicija = 0;
maxRastojanje = 0;
zbir = 0;

/*Izracunavaju se trazene vrednosti*/


for(i=0; i<n; i++)
{
/*Racunamo kvadrat rastojanja tekuce tacke*/
kvRastojanje = Tacke[i].x*Tacke[i].x + Tacke[i].y*Tacke[i].y;
printf("Kvadrat rastojanja %d. tacke je %d\n", i+1, kvRastojanje);

/*Poredimo maksimalno rastojanje sa rastojanjem tekuce tacke */


if (kvRastojanje > maxRastojanje)
{
maxRastojanje = kvRastojanje;
pozicija = i;
}

/*Racunamo trazeni zbir*/


zbir += kvRastojanje;
}

/*Stampaju se trazene vrednosti*/


printf("Zbir kvadrata rastojanja je %d\n", zbir);
printf("Najdalja tacka od koordinatnog pocetka\n");
printf("je tacka (%d,%d)\n", Tacke[pozicija].x, Tacke[pozicija].y);
}

78
Milena Vujošević–Janičić 1.35 Strukture — primeri

/* Izlaz iz programa:
Unesite broj tacaka (manji od 100):
4
Unesi x koordinatu 1. tacke
1
Unesi y koordinatu 1. tacke
1
Unesi x koordinatu 2. tacke
0
Unesi y koordinatu 3. tacke
1
Unesi x koordinatu 3. tacke
2
Unesi y koordinatu 3. tacke
2
Unesi x koordinatu 4. tacke
1
Unesi y koordinatu 4. tacke
0
Kvadrat rastojanja 1. tacke je 2
Kvadrat rastojanja 2. tacke je 1
Kvadrat rastojanja 3. tacke je 8
Kvadrat rastojanja 4. tacke je 1
Zbir kvadrata rastojanja je 12
Najdalja tacka od koordinatnog pocetka
je tacka (2,2)
*/
Primer 1.35.3 Napisati funkcije koje izračunavaju površinu i obim
proizvoljnog poligona čija su temena zadatak kao nizovi tačaka i pro-
gram koji testira te funkcije i izračunava obim i povrvšinu trougla i
kvadrata.
#include <stdio.h>

/* Zbog funkcije sqrt. */


#include <math.h>

/* Upozorenje: pod linux-om je potrebno program prevoditi sa


gcc -lm primer.c
kada god se koristi <math.h>
*/

/* Tacke su predstavljene sa dve koordinate.

79
Milena Vujošević–Janičić 1.35 Strukture — primeri

Strukturom gradimo novi tip podataka. */


typedef struct _point
{
int x;
int y;
} point;

/* Izracunava duzinu duzi zadatu sa dve tacke */


float segment_length(point A, point B)
{
int dx, dy;
dx = A.x - B.x;
dy = A.y - B.y;
return sqrt(dx*dx + dy*dy);
}

/* Izracunava povrsinu trougla Heronovim obrascem.


Argumenti funkcije su tri tacke koje predstavljaju
temena trougla */
float Heron(point A, point B, point C)
{
/* Duzine stranica */
float a = segment_length(B, C);
float b = segment_length(A, C);
float c = segment_length(A, B);

/* Poluobim */
float s = (a+b+c)/2;
return sqrt(s*(s-a)*(s-b)*(s-c));
}

/* Izracunava obim poligona. Argumenti funkcije su niz tacaka


koje predstavljaju temena poligona kao i njihov broj */
float obimPoligona(point polygon[], int num)
{
int i;
float obim = 0.0;

/* Dodajemo duzine stranica koje spajaju susedna temena */


for (i = 0; i<num-1; i++)
obim += segment_length(polygon[i], polygon[i+1]);

/* Dodajemo duzinu stranice koja spaja prvo i poslednje teme */

80
Milena Vujošević–Janičić 1.35 Strukture — primeri

obim += segment_length(polygon[num-1], polygon[0]);

return obim;
}

/* Izracunava povsinu konveksnog poligona. Argumenti funkcije


su niz tacaka koje predstavljaju temena poligona kao i njihov
broj */
float area(point polygon[], int num)
{
/* Povrsina */
float a = 0.0;
int i;

/* Poligon delimo na trouglove i posebno izracunavamo


povrsinu svakoga od njih */
for (i = 1; i < num -1; i++)
a += Heron(polygon[0], polygon[i], polygon[i+1]);

return a;
}

main()
{
/* Definisemo dva poligona: trougao i kvadrat. */

/* triangle je niz od tri tacke - trougao (0,0), (0,1), (1,0)


inicijalizaciju vrsimo naknadno */
point triangle[3];

/* square je niz od cetiri tacke - jedinicni kvadrat.


Obratiti paznju na nacin inicijalizacije niza struktura */
point square[4] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};

/* Gradimo trougao (0,0), (0,1), (1,0) */


triangle[0].x = 0; triangle[0].y = 0;
triangle[1].x = 0; triangle[1].y = 1;
triangle[2].x = 1; triangle[2].y = 0;

/* Stampamo obim trougla i obim kvadrata. */


printf("Obim trougla je %f\n", obimPoligona(triangle, 3));
printf("Obim kvadrata je %f\n", obimPoligona(square, 4));

81
Milena Vujošević–Janičić 1.35 Strukture — primeri

/* Stampamo povrsine trougla i kvadrata. */


printf("Povrsina trougla je %f\n",
Heron(triangle[0], triangle[1], triangle[2]));

/* Broj tacaka je moguce odrediti i putem sizeof */


printf("Povrsina kvadrata je %f\n",
area(square, sizeof(square)/sizeof(point)));
}
Izlaz:
Obim trougla je 3.414214
Obim kvadrata je 4.000000
Povrsina trougla je 0.500000
Povrsina kvadrata je 1.000000
Primer 1.35.4 Napisati program koji izračunava broj pojavljivanja
imena u datoteci koja se preusmeravanjem učitava sa standardnog
ulaza i na standardni izlaz štampa ono ime koje se pojavilo najveći
broj puta. Razmatrati pojavljivanja sledećih imena Jelena, Ivana,
Milena, Ruzica, Ana, Milos, Petar, Janko i Pedja.
Program pokrećemo sa
a.out < datoteka.txt
da bi odredili koje se ime pojavilo najveći broj puta u datoteci datoteka.txt
(odnosno, vršimo preusmeravanje standardnog ulaza).
#include <stdio.h>
#include <ctype.h>
#include <string.h>

/* Velicina reci. */
#define SIZE 100

typedef struct _ime


{
char rec[SIZE];
int broj_pojavljivanja;
} ime;

/* Funkcija get_word ucitava narednu rec sa standardnog ulaza.


Pretpostavlja se da je za s rezervisana dovoljna kolicina memorije.
Funkcija vraca poslednji procitan karakter ili EOF
*/
int get_word(char s[])
{

82
Milena Vujošević–Janičić 1.35 Strukture — primeri

int c, i = 0;

/* Preskoci blanko znake */


while (((c=getchar())!=EOF) && isspace(c))
;

/* Ako je doslo do kraja datoteke a nije ucitana rec


vrati EOF. */
if (c == EOF)
return c;

/* Upisuje se prvi karakter u rec. */


s[i++] = c;

/* Ucitava se i ostatak reci */


while (((c=getchar())!=EOF) && !isspace(c))
s[i++] = c;
s[i] = ’\0’;
return c;
}

main()
{
ime niz[] = { {"Jelena", 0}, {"Ivana", 0}, {"Milena", 0},
{"Ruzica", 0}, {"Ana", 0}, {"Milos", 0},
{"Petar", 0}, {"Janko", 0}, {"Pedja", 0}
};

char s[SIZE]; /* Tekuca ucitana rec. */


int c, i, max, pozicija;

/* Ucitava se jedna po jedna rec*/


while ((c = get_word(s)) != EOF)
{
/* Proverava se da li je ucitana rec ime*/
for (i=0; i < sizeof(niz)/sizeof(ime); i++)
if ((strcmp(s, niz[i].rec) == 0))
{
/* Ukoliko je u pitanju trazeno ime, povecava se
njen broj pojavljivanja. */
niz[i].broj_pojavljivanja++;
break;
}

83
Milena Vujošević–Janičić 1.35 Strukture — primeri

max = 0;
pozicija = 0;
/* Izracunava se maksimalan broj pojavljivanja. */
for (i=0; i < sizeof(niz)/sizeof(ime); i++)
if (niz[i].broj_pojavljivanja > max)
{
max = niz[i].broj_pojavljivanja;
pozicija = i;
}

printf("Makslimalan broj pojavljivanja je: %d, za ime %s\n",


niz[pozicija].broj_pojavljivanja, niz[pozicija].rec);
}
Primer 1.35.5 Napisati program koji izračunava broj pojavljivanja
svake od reči u datoteci koja se preusmeravanjem učitava sa stan-
dardnog ulaza. Program treba da odštampa broj pojavljivanja svake
od reči i da odštampa posebno onu reč koja se pojavila najveći broj
puta. Pretpostaviti da reči nisu duže od 30 karaktera i da u datoteci
neće biti više od 500 različitih reči.
#include<stdio.h>
#include<ctype.h>
#include<string.h>

typedef struct _rec


{
char ime[30];
int brpoj;
} rec;

/*Funkcija koja ucitava jednu rec*/


int getword(char s[])
{
int c, i=0;
while (((c=getchar())!=EOF) && isspace(c));

if (c==EOF) return c;

s[i++]=c;

while (((c=getchar())!=EOF) && !isspace(c))

84
Milena Vujošević–Janičić 1.35 Strukture — primeri

s[i++]=c;

s[i]=’\0’;
return c;
}

main()
{
char s[30];
rec r[500];
int i,c,max, pozicija;
int n=0; /*Broj elemenata u nizu reci*/

/*Ucitava se jedna po jedna rec*/


while ((c=getword(s))!=EOF)
{
/*Proverava se da li dati niz sadrzi ucitanu rec*/
for(i=0;i<n;i++)
/*Ukoliko pronadjemo rec, povecavamo njen brojac*/
if (strcmp(s,r[i].ime)==0)
{
(r[i].brpoj)++;
break;
}

/*Ukoliko rec nismo pronasli*/


if(i==n)
{
/*Dodajemo je u niz i postavljamo njen
brojac na 1*/
strcpy(r[n].ime,s);
r[n].brpoj=1;
/*Povecavamo tekuci broj elemenata niza*/
n++;
}
}

/*Izracunava se maksimalan broj pojavljivanja*/


max=r[0].brpoj;
printf("rec: %s se pojavila: %d puta\n",r[0].ime, r[0].brpoj);
for(i=1;i<n;i++)
{
if (r[i].brpoj>max)

85
Milena Vujošević–Janičić 1.36 Datoteke

{
max=r[i].brpoj;
pozicija = i;
}
printf("rec: %s se pojavila %d puta\n",r[i].ime,r[i].brpoj);
}
printf("Max broj pojavljivanja je %d za rec %s",max.r[pozicija].ime);
}

1.36 Datoteke
Primer 1.36.1 Program demonstrira otvaranje datoteka ("r" - read
i "w" - write mod) i osnovne tehnike rada sa datotekama.
/* U datoteku se upisuje prvih 10 prirodnih
brojeva, a zatim se iz iste datoteke
citaju brojevi dok se ne stigne do kraja i
ispisuju se na standardni izlaz */

#include <stdio.h>
#include <stdlib.h>

main()
{
int i;

/* Otvaramo datoteku sa imenom podaci.txt za pisanje */


FILE* f = fopen("podaci.txt", "w");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */
if (f == NULL)
{
printf("Greska prilikom otvaranja datoteke podaci.txt za pisanje\n");
exit(1);
}

/* Upisujemo u datoteku prvih 10 prirodnih brojeva


(svaki u posebnom redu) */
for (i = 0; i<10; i++)
fprintf(f, "%d\n", i);

/* Zatvaramo datoteku */

86
Milena Vujošević–Janičić 1.36 Datoteke

fclose(f);

/* Otvaramo datoteku sa imenom podaci.txt za citanje */


f = fopen("podaci.txt", "r");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */
if (f == NULL) {
printf("Greska prilikom otvaranja datoteke podaci.txt za citanje\n");
exit(1);
}

/* Citamo brojeve iz datoteke dok ne stignemo do kraja i ispisujemo ih


na standardni izlaz */
while(1) {
int br;
/* Pokusavamo da procitamo broj */
fscanf(f, "%d", &br);

/* Ukoliko smo dosli do kraja datoteke, prekidamo */


if (feof(f))
break;

/* Ispisujemo procitani broj */


printf("Procitano : %d\n", br);
}

/* Funkciju feof ne treba pozivati pre pokusaja citanja.


Sledeci kod moze dovesti do greske:
while (!feof(f))
fscanf(f,"%d",&br);
*/

/* Zatvaramo datoteku */
fclose(f);
}
Pokazivaci stdin, stdout i stderr su de nisani u okviru stdio.h
i mogu se koristiti za pisanje na standardni ulaz, izlaz i izlaz za
gresku.
FILE* stdin;
FILE* stdout;
FILE* stderr;

87
Milena Vujošević–Janičić 1.36 Datoteke

Primer 1.36.2 Program demonstrira ”a” - append mod datoteka -


nadovezivanje.
#include <stdio.h>
#include <stdlib.h>

main()
{
FILE* datoteka;

/* Otvaramo datoteku za nadovezivanje


i proveravamo da li je doslo do greske */
if ( (datoteka=fopen("dat.txt","a"))==NULL)
{
/*Funkcija fprintf u odnosu na funkciju printf ima
jedan argument vise --- prvi argument je pokazivac
na datoteku u koju treba upisati poruku*/
fprintf(stderr,"Greska prilikom otvaranja dat.txt\n");

/*exit je funkcija iz biblioteke stdlib koja omogucava


trenutno zaustavljanje rada programa*/
exit(1);
}

/* Upisujemo sadrzaj u datoteku */


fprintf(datoteka,"Zdravo svima\n");

/* Zatvaramo datoteku */
fclose(datoteka);
}

Primer 1.36.3 Program kopira sadrzaj datoteke ulaz.txt u da-


toteku izlaz.txt.
#include <stdio.h>
#include <stdlib.h>

main()
{
int c;
FILE *in, *out;

if ((in = fopen("ulaz.txt","r")) == NULL)


{

88
Milena Vujošević–Janičić 1.36 Datoteke

fprintf(stderr, "Neuspesno otvaranje datoteke ulaz.txt\n");


exit(1);
}

if ((out = fopen("izlaz.txt","w")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke izlaz.txt\n");
exit(1);
}

/*Funkcija fgetc ucitava iz datoteke jedan karakter.


Funkcija fputc upisuje jedan karakter u datoteku. */
while ((c=fgetc(in)) != EOF)
fputc(c,out);

/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}

89
Programiranje 2
Programski jezik C
— Zadaci sa vezbi —

Milena Vujosevic - Janicic 2008/2009


Predgovor

Ovo je prateci materijal za vezbe koje drzim iz predmenta Programiranje 2. On ne


moze zameniti pohad̄anje vezbi niti koriscenje druge preporucene literature.
Deo materijala cine zadaci i resenja mr Filipa Marica (raspolozivi na
www.matf.bg.ac.yu/~filip/pp/0405/index.pl).
Takod̄e koriscen je i materijal sa sajta koleginice Jelene Grmuse
www.matf.bg.ac.yu/~jelenagr
kolege Miroslava Marica
www.matf.bg.ac.yu/~maricm
i kolege Milana Bankovica
www.matf.bg.ac.yu/~milan.
Tekstovi i objasnjenja su uglavnom zasnovani na knjizi Programski jezik C, autora
Kerninghan & Ritchie.
Zahvaljujem svojim studentima na aktivnom ucescu u nastavi cime su mi pomogli
u uoblicavanju ovog materijala.
Svi komentari i sugestije vezane za ovaj materijal bice veoma dobrodosli.

Milena Vujosevic-Janicic
www.matf.bg.ac.yu/~milena

1
Sadrzaj

1 Argumenti komandne linije 4

2 Datoteke 7

3 Bitski operatori 19

4 Vežbanje 30
4.1 Polinomi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.2 Veliki brojevi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

5 Sortiranje 40
5.1 Vremenska slozenost . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.2 Selection sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.3 Bubble sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.4 Insertion sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.5 Razni zadaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

6 Pokazivači 58
6.1 Pokazivacka aritmetika — primeri . . . . . . . . . . . . . . . . . . . . 59
6.2 Niska karaktera i pokazivac na konstantnu nisku . . . . . . . . . . . . 64
6.3 Pokazivaci na pokazivace . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.4 Nizovi pokazivaca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

7 Rekurzija 69
7.1 Osnovni primeri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.2 Binarna pretraga . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
7.3 MergeSort algoritam . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
7.4 QuickSort algoritam . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

8 Pokazivači na funkcije 86
8.1 Funkcija qsort iz standardne biblioteke . . . . . . . . . . . . . . . . . 89
8.2 Funkcija bsearch iz standardne biblioteke . . . . . . . . . . . . . . . 93
8.3 Funkcije lsearch i lfind . . . . . . . . . . . . . . . . . . . . . . . . 97
8.4 Pokazivaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

2
SADRŽAJ SADRŽAJ

9 Dinamička alokacija memorije 99


9.1 Matrice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
9.2 Realokacija memorije . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

10 Liste 118
10.1 Implementacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
10.2 Kruzna (ciklicna) lista . . . . . . . . . . . . . . . . . . . . . . . . . . 143
10.3 Red . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
10.4 Stek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10.5 Dvostruko povezane liste . . . . . . . . . . . . . . . . . . . . . . . . . 160

11 Stabla 166
11.1 Binarno pretrazivacko stablo . . . . . . . . . . . . . . . . . . . . . . . 167

12 Grafovi 209

3
Glava 1

Argumenti komandne linije

Primer 1.1 Argumenti komandne linije programa.


/* Program pozivati sa npr.:
a.out
a.out prvi
a.out prvi drugi treci
a.out -a -bc ime.txt
*/

#include <stdio.h>

/* Imena ovih promenljivih mogu biti proizvoljna.


Npr:
main (int br_argumenata, char** argumenti);
ipak, uobicajeno je da se koriste sledeca imena:
main(int argc, char** argv)
Cesto se koristi i sledeca (ekvivalentna) notacija
main(int argc, char* argv[])
*/

main(int argc, char* argv[])


{
int i;
printf("argc = %d\n", argc);

/* Nulti argument uvek je ime programa (a.out)*/


for (i = 0; i<argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
}

Primer 1.2 Program ispisuje opcije navedene u komandnoj liniji.


/* Opcije se navode koriscenjem znaka -, pri cemu je moguce da

4
Milena Vujošević–Janičić Argumenti komandne linije

iza jednog znaka - sledi i nekoliko opcija.


Npr. za
a.out -abc -d -fg dat.txt -vxy
su prisutne opcije a b c d f g */

#include <stdio.h>
main(int argc, char** argv)
{
/* Za svaki argument komande linije, pocevsi od argv[1]
(preskacemo ime programa) */
int i;
for (i = 1; i < argc; i++)
{
/* Ukoliko i-ti argument pocinje crticom */
if (argv[i][0] == ’-’)
{
/* Ispisujemo sva njegova slova pocevsi od pozicije 1 */
int j;
for (j = 1; argv[i][j] != ’\0’; j++)
printf("Prisutna je opcija : %c\n", argv[i][j]);
}
/* Ukoliko ne pocinje crticom, prekidamo */
else
break;
}
}
Izlaz:
Prisutna opcija : a
Prisutna opcija : b
Prisutna opcija : c
Prisutna opcija : d
Prisutna opcija : f
Prisutna opcija : g
Primer 1.3 Program ispisuje opcije navedene u komandnoj liniji. K&R rešenje.
#include <stdio.h>

/* Resnje se intenzivno zasniva na pokazivackoj aritmetici


i prioritetu operatora */
main(int argc, char** argv)
{
char c;
/* Dok jos ima argumenata i dok je karakter na poziciji
0 upravo crtica */
while(--argc>0 && (*++argv)[0]==’-’)

5
Milena Vujošević–Janičić Argumenti komandne linije

/* Dok god ne dodjemo do kraja tekuceg stringa */


while (c=*++argv[0])
printf("Prisutna opcija : %c\n",c);
}

6
Glava 2

Datoteke

Primer 2.1 Program demonstrira otvaranje datoteka ("r" - read i "w" - write mod)
i osnovne tehnike rada sa datotekama.
/* U datoteku se upisuje prvih 10 prirodnih
brojeva, a zatim se iz iste datoteke
citaju brojevi dok se ne stigne do kraja i
ispisuju se na standardni izlaz */

#include <stdio.h>
#include <stdlib.h>

main()
{
int i;

/* Otvaramo datoteku sa imenom podaci.txt za pisanje */


FILE* f = fopen("podaci.txt", "w");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */
if (f == NULL)
{
printf("Greska prilikom otvaranja datoteke podaci.txt za pisanje\n");
exit(1);
}

/* Upisujemo u datoteku prvih 10 prirodnih brojeva


(svaki u posebnom redu) */
for (i = 0; i<10; i++)
fprintf(f, "%d\n", i);

/* Zatvaramo datoteku */

7
Milena Vujošević–Janičić Datoteke

fclose(f);

/* Otvaramo datoteku sa imenom podaci.txt za citanje */


f = fopen("podaci.txt", "r");

/* Ukoliko otvaranje nije uspelo, fopen vraca NULL.


U tom slucaju, prijavljujemo gresku i zavrsavamo program */
if (f == NULL) {
printf("Greska prilikom otvaranja datoteke podaci.txt za citanje\n");
exit(1);
}

/* Citamo brojeve iz datoteke dok ne stignemo do kraja i ispisujemo ih


na standardni izlaz */
while(1) {
int br;
/* Pokusavamo da procitamo broj */
fscanf(f, "%d", &br);

/* Ukoliko smo dosli do kraja datoteke, prekidamo */


if (feof(f))
break;

/* Ispisujemo procitani broj */


printf("Procitano : %d\n", br);
}

/* Funkciju feof ne treba pozivati pre pokusaja citanja.


Sledeci kod moze dovesti do greske:
while (!feof(f))
fscanf(f,"%d",&br);
*/

/* Zatvaramo datoteku */
fclose(f);
}
Pokazivaci stdin, stdout i stderr su de nisani u okviru stdio.h i mogu se
koristiti za pisanje na standardni ulaz, izlaz i izlaz za gresku.
FILE* stdin;
FILE* stdout;
FILE* stderr;
Primer 2.2 Program demonstrira ”a” - append mod datoteka - nadovezivanje.
#include <stdio.h>

8
Milena Vujošević–Janičić Datoteke

#include <stdlib.h>

main()
{
FILE* datoteka;

/* Otvaramo datoteku za nadovezivanje


i proveravamo da li je doslo do greske */
if ( (datoteka=fopen("dat.txt","a"))==NULL)
{
/*Funkcija fprintf u odnosu na funkciju printf ima
jedan argument vise --- prvi argument je pokazivac
na datoteku u koju treba upisati poruku*/
fprintf(stderr,"Greska prilikom otvaranja dat.txt\n");

/*exit je funkcija iz biblioteke stdlib koja omogucava


trenutno zaustavljanje rada programa*/
exit(1);
}

/* Upisujemo sadrzaj u datoteku */


fprintf(datoteka,"Zdravo svima\n");

/* Zatvaramo datoteku */
fclose(datoteka);
}
Primer 2.3 Program kopira sadrzaj datoteke ulaz.txt u datoteku izlaz.txt.
#include <stdio.h>
#include <stdlib.h>

main()
{
int c;
FILE *in, *out;

if ((in = fopen("ulaz.txt","r")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke ulaz.txt\n");
exit(1);
}

if ((out = fopen("izlaz.txt","w")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke izlaz.txt\n");

9
Milena Vujošević–Janičić Datoteke

exit(1);
}

/*Funkcija fgetc ucitava iz datoteke jedan karakter.


Funkcija fputc upisuje jedan karakter u datoteku. */
while ((c=fgetc(in)) != EOF)
fputc(c,out);

/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}
Primer 2.4 Program kopira n puta sadrzaj datoteke ulaz.txt u datoteku izlaz.txt.
#include <stdio.h>
#include <stdlib.h>

main()
{
int c, n;
FILE *in, *out;

if ((in = fopen("ulaz.txt","r")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke ulaz.txt\n");
exit(1);
}

if ((out = fopen("izlaz.txt","w")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke izlaz.txt\n");
exit(1);
}

printf("Unesi prirodan broj\n");


scanf("%d", &n);

for(i=0; i<n; i++)


{
/* Prepisuje se sadrzaj datoteke*/
while ((c=fgetc(in)) != EOF)
fputc(c,out);

/* in se pozicionira na pocetak datoteke*/


rewind(in);

10
Milena Vujošević–Janičić Datoteke

}
/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}
Primer 2.5 Program ilustruje rad sa datotekama. Program kopira datoteku čije se
ime zadaje kao prvi argument komandne linije u datoteku čije se ime zadaje kao
drugi argument komandne linije. Uz svaku liniju se zapisuje i njen redni broj.
#include <stdio.h>
#include <stdlib.h>

#define MAX_LINE 256

/* Funkcija fgets definisana je u stdio.h

char* fgets(char *s, int n, FILE* stream)

fgets ucitava najvise sledecih n-1 znakova


u polje niza karaktera s, zaustavljajuci se
ako naidje na novu liniju koju takodje
upisuje u polje. Na kraju upisuje ’\0’.
Funkcija vraca s ili NULL ako dodje do kraja
datoteke ili se pojavi greska.

Funkcija fputs definisana je u stdio.h

int fputs(char *s, FILE *stream)

fputs upisuje nisku s u datoteku na koju


pokazuje stream, vraca nenegativnu vrednost ili
EOF ako se pojavi greska
*/

main(int argc, char* argv[])


{

char line[MAX_LINE];
FILE *in, *out;
int line_num;

if (argc != 3) {
fprintf(stderr,"Neispravna upotreba programa!\n
Pravilna upotreba:
%s ulazna_datoteka izlazna_datoteka\n",argv[0]);

11
Milena Vujošević–Janičić Datoteke

exit(1);
}

if ((in = fopen(argv[1],"r")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke %s\n", argv[1]);
exit(1);
}

if ((out = fopen(argv[2],"w")) == NULL)


{
fprintf(stderr, "Neuspesno otvaranje datoteke %s\n", argv[2]);
exit(1);
}

line_num = 1;

/* Citamo liniju po liniju sa ulaza*/


while (fgets(line, MAX_LINE, in) != NULL)
{
/* Ispisujemo broj linije i sadrzaj linije na izlaz */
fprintf(out, "%d :\t", line_num++);
fputs(line, out);
}

/* Zatvaramo datoteke */
fclose(in);
fclose(out);
}
Primer 2.6 Prodavnica - ilustruje čitanje niza struktura iz tektsualne datoteke.
/* Datoteka, cije se ime zadaje kao argument komandne linije
ili ako se ne zada onda se ime unosi sa standardnog
ulaza, sadrzi podatke o proizvodima koji se prodaju
u okviru odredjene prodavnice. Svaki
proizvod se odlikuje sledecim podacima:
bar-kod - petocifreni pozitivan broj
ime - niska karaktera
cena - realan broj zaokruzen na dve decimale
pdv - stopa poreza - realan broj zaokruzen na dve decimale
Pretpostavljamo da su podaci u datoteci
korektno zadati.
Pretpostavljamo da se u prodavnici ne
prodaje vise od 1000 razlicitih artikala
Na standardni izlaz ispisujemo podatke o

12
Milena Vujošević–Janičić Datoteke

svim proizvodima koji se prodaju u prodavnici.

Zadatak je moguce resiti i bez koriscenja nizova


(i takvo resenje je bolje). */

#include <stdio.h>
#include <stdlib.h>

/* Maksimalna duzina imena proizvoda */


#define MAX_IME 30

/* Maksimalni broj artikala */


#define MAX_ARTIKALA 1000

/* Struktura za cuvanje podataka o jednom artiklu */


typedef struct _artikal {
int bar_kod;
char ime[MAX_IME];
float cena;
float pdv;
} artikal;

/* Ucitava podatke o jednom artiklu iz date datoteke.


Vraca da li su podaci uspesno procitani */
int ucitaj_artikal(FILE* f, artikal* a)
{
/* Citamo bar kod, ime, cenu, pdv */
fscanf(f, "%d%s%f%f", &(a->bar_kod), a->ime, &(a->cena), &(a->pdv));

/* Ukoliko smo dosli do kraja datoteke prilikom pokusaja ucitavanja


prijavljujemo neuspeh */
if (feof(f))
return 0;

/* Prijavljujemo uspeh */
return 1;
}

/* Izracunava ukupnu cenu datog artikla */


float cena(artikal a)
{
return a.cena*(1+a.pdv);
}

13
Milena Vujošević–Janičić Datoteke

/* Ispisuje podatke o svim artiklima */


void ispisi_artikle(artikal artikli[], int br_artikala)
{
int i;
for (i = 0; i<br_artikala; i++)
printf("%-5d %-10s %.2f %.2f = %.2f\n",
artikli[i].bar_kod, artikli[i].ime,
artikli[i].cena, artikli[i].pdv,
cena(artikli[i]));
}

main(int argc, char* argv[])


{
FILE* f;

/* Niz struktura u kome se cuvaju podaci o artiklima */


artikal artikli[MAX_ARTIKALA];

/* Broj trenutno ucitanih artikala */


int br_artikala;

/* Ukoliko nije navedeno ime kao argument komandne linije, trazimo


od korisnika da ga unese */
if (argc<2) {
/* Ucitavamo ime datoteke */
char ime_datoteke[256];
printf("U kojoj datoteci se nalaze podaci o proizvodima: ");
scanf("%s", ime_datoteke);

/* Otvaramo datoteku i proveravamo da li smo uspeli */


if ( (f = fopen(ime_datoteke, "r")) == NULL)
{
printf("Greska prilikom otvaranja datoteke %s\n", ime_datoteke);
exit(1);
}
}
/* Ime datoteke je prvi argument komandne linije */
else {
/* Otvaramo datoteku i proveravamo da li smo uspeli */
if ( (f = fopen(argv[1], "r")) == NULL)
{
printf("Greska : datoteka %s ne moze biti otvorena\n", argv[1]);
exit(1);
}

14
Milena Vujošević–Janičić Datoteke

br_artikala=0;
/* Ucitavamo artikle */
while (ucitaj_artikal(f, &artikli[br_artikala]))
br_artikala++;

/* Ispisujemo podatke o svim artiklima */


ispisi_artikle(artikli, br_artikala);

/* Zatvara se datoteka*/
fclose(f);
}
Primer 2.7 Program u datoteku čije se ime zadaje kao prvi argument komandne
linije upisuje prvih N prirodnih brojeva (N se zadaje sa standardnog ulaza) i zatim
izračunava dužinu datoteke u bajtovima.
#include <stdio.h>
#include <stdlib.h>

/*Deklaracija funkcije za racunanje duzine datoteke*/


long filesize(FILE *f);

void main()
{
FILE *f;
int i, n;

/* Ukoliko nije navedeno ime datoteke kao


argument komandne linije, zavrsavamo rad programa*/
if (argc<2)
{
printf("Program se pokrece sa a.out ime_datoteke!\n");
exit(1);
}

/* Otvaramo datoteku i proveravamo da li smo uspeli */


if ( (f = fopen(argv[1], "w+")) == NULL)
{
printf("Greska: datoteka %s ne moze biti otvorena\n", argv[1]);
exit(1);
}

printf("Unesi prirodan broj\n");


scanf("%d", &n);

15
Milena Vujošević–Janičić Datoteke

/* Upisuje se sadrzaj u datoteku*/


for(i=0; i<n; i++)
fprintf(f, "%d ", i);

printf("Velicina datoteke je %ld bajtova\n", filesize(f));


fclose(f);
}

/*Funkcija koja racuna duzinu datoteke*/


long filesize(FILE *f)
{
long trenutna_pozicija, duzina;

/*Funkcija ftell vraca trenutnu poziciju u datoteci*/


/*Pamti se trenutna pozicija da bismo
mogli na nju da se vratimo*/
trenutna_pozicija = ftell(f);

/* Funkcija fseek se pozicionira na odredjeno


mesto u datoteci i ima sledece argumente
1. FILE* f - datoteka sa kojom se radi
2. int offset - rastojanje u bajtovima
od odgovarajuce pozicije
3. int origin - pozicija u odnosu na koju se gleda offset
i moze da ima vrednost jedne od
sledecih konstanti
SEEK_END - kraj
SEEK_SET - pocetak
SEEK_CUR - trenutna pozicija */

/*pozicioniranje na kraj fajla*/


fseek(f, 0, SEEK_END);

/*uzimamo poziciju u broju bajtova od


pocetka fajla, to je duzina*/
duzina = ftell(f);

/*vracamo se nazad na zapamcenu poziciju*/


fseek(f, trenutna_pozicija, SEEK_SET);
return duzina;
}

Primer 2.8 Napisati program koji u datoteci čije se ime zadaje kao prvi argument

16
Milena Vujošević–Janičić Datoteke

komandne linije zamenjuje sva pojavljivanja niske koja se zadaje kao drugi argument
komandne linije niskom koja se zadaje kao treći argument komandne linije (pret-
postaviti da ce obe niske iste dužine i da nisu duze od 20 karaktera). Na primer, ako
se program pokrene sa
a.out datoteka.txt ana Ana
tada se svako pojavljivanje reči ana u datoteci datoteka.txt zamenjuje sa Ana.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[])


{
FILE *f;
int c;
int i;
long pos;
int duzina;
char rec1[20];
char rec2[20];

/* Ukoliko nisu navedeni odgovarajuci


argumenti program se zavrsava */
if (argc<4)
{
printf("Program se pokrece sa a.out datoteka rec zamena!\n");
exit(1);
}

/* Otvaramo datoteku i proveravamo da li smo uspeli */


if ( (f = fopen(argv[1], "r+")) == NULL)
{
printf("Greska: datoteka %s ne moze biti otvorena\n", argv[1]);
exit(1);
}

/*Prepisujemo argumente komandne linije u rec1 i rec2*/


strcpy(rec1, argv[2]);
strcpy(rec2, argv[3]);

while ((c = fgetc(f))!=EOF)


{
/*ako smo naisli na prvi karakter niske*/
if (c == rec1[0])
{

17
Milena Vujošević–Janičić Datoteke

pos = ftell(f); /*zapamtimo trenutnu poziciju*/


duzina = strlen(rec1);

/*petlja koja prepoznaje rec*/


for(i=1; i<duzina; i++)
/*ako se karakteri ne poklapaju izlazimo iz petlje
if (rec1[i]!=fgetc(f))
break;

/*ako je bila pronadjena cela rec prepisujemo


je zamenom*/
if (i==duzina)
{
/*vracamo se na pocetak reci da bismo je prepisali
fseek(f,pos-1,SEEK_SET);
for(i=0; rec2[i]; i++)
fputc(rec2[i], f);
fseek(f,0,SEEK_CUR); /*pozicionira na tu poziciju
(jer inace fputc smatra da upisuje
na kraj fajla pa fseek pocisti taj
fleg*/
}
else
/*vracamo se na pocetak reci ali iza prvog slova*/
fseek(f, pos, SEEK_SET);
}
}
fclose(f);
}

18
Glava 3

Bitski operatori

Bitski operatori su operatori koji deluju nad bitovima i vazno je razlikovati ih od


logickih operatora.
& bitsko AND
| bitsko OR
^ bitsko ekskluzivno OR
<< levo pomeranje
>> desno pomeranje
~ jedinicni komplement
Primer 3.1 Demonstracija bitskih operatora
#include <stdio.h>

main()
{ printf("%o %o\n",255,15);
printf( "255 & 15 = %d\n", 255 & 15 );
printf( "255 | 15 = %d\n", 255 | 15 );
printf( "255 ^ 15 = %d\n", 255 ^ 15 );
printf( "2 << 2 = %d\n", 2 << 2 );
printf( "16 >> 2 = %d\n", 16 >> 2 );
}

Izlaz iz programa je:


377 17
255 & 15 = 15
255 | 15 = 255
255 ^ 15 = 240
2 << 2 = 8
16 >> 2 = 4
Primer 3.2 print bits - stampa bitove u zapisu datog celog broja x.
#include <stdio.h>

19
Milena Vujošević–Janičić Bitski operatori

/* Funkcija stampa bitove datog celog broja x.


Vrednost bita na poziciji i je 0 ako i
samo ako se pri konjunkciji broja x sa maskom
000..010....000 - sve 0 osim 1 na poziciji i,
dobija 0.
Funkcija krece od pozicije najvece tezine
kreirajuci masku pomeranjem jedinice u levo
za duzina(x) - 1 mesto, i zatim pomerajuci
ovu masku za jedno mesto u levo u svakoj
sledecoj iteraciji sve dok maska ne postane 0.
*/

void print_bits(int x)
{
/* Broj bitova tipa unsigned */
int wl = sizeof(int)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

main()
{
print_bits(127);
print_bits(128);
print_bits(0x00FF00FF);
print_bits(0xFFFFFFFF);
}

Izlaz iz programa:
00000000000000000000000001111111
00000000000000000000000010000000
00000000111111110000000011111111
11111111111111111111111111111111
Primer 3.3 Program proverava da li se na k-tom mestu broja n nalazi bit koji ima
vrednost 1.
#include <stdio.h>

/* Pozicije brojimo kao u sledecem primeru:


poz: ... 10 9 8 7 6 5 4 3 2 1 0

20
Milena Vujošević–Janičić Bitski operatori

bit: ... 0 0 0 1 1 1 0 0 1 1 0 */

main()
{
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da proverite:\n");
scanf("%d%d",&n,&k);
if ((n & (1 << k))!=0)
printf("Bit je 1\n");
else
printf("Bit je 0\n");
}
Primer 3.4 Program postavlja na k-to mesto broja n bit 1.
#include <stdio.h>

void print_bits(int x)
{
/* Broj bitova tipa unsigned */
int wl = sizeof(int)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

main(){
int n,k;
printf("Unesite broj i poziciju tog broja koju zelite da postavite na 1:\n");
scanf("%d%d",&n,&k);
printf("Binarno, uneseni broj je\n");
print_bits(n);
printf("Novi broj je %d\n",(n |(1<<k)));
printf("Binarno, novi broj je\n");
print_bits((n |(1<<k)));
}
Izrazom a>>b vrsi se pomeranje sadrzaja operanda a predstavljenog u binarnom
obliku za b mesta u desno. Popunjavanje upraznjenih mesta na levoj strani zavisi od
tipa podataka i vrste racunara. Ako se pomeranje primenjuje nad operandom tipa
unsigned popunjavanje je nulama. Ako se radi o oznacenom operandu popunjavanje
je jedinicama kada je u krajnjem levom bitu jedinica, a nulama kada je u krajnjem
levom bitu nula.

21
Milena Vujošević–Janičić Bitski operatori

Da li vazi sledeca jednakost (za prirodan broj k):


((~0) >> k) == (~0)?
Posto je 0 konstanta celobrojnog tipa, to je ~0 takodje tipa int, pri cemu je to
broj koji je zapisan svim jedinicama. Prema tome, njegovim siftovanjem u desno
dobijamo isti taj broj, jer se upraznjen prostor sa desne strane popunjava jedinicama.
VAŽNO:
Vrednost izraza a<<b je jednaka vrednosti a · 2b .
Vrednost izraza a>>b je jednaka vrednosti a/2b .
Bitovski operatori su e kasniji od operacija * i / tako da svaki put kad se javi
potreba za mnozenjem ili deljenjem stepenom broja dva, treba koristiti operacije <<
i >>.
Primer 3.5 sum of bits - izračunava sumu bitova datog neoznačenog broja.
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

int sum_of_bits(unsigned x)
{
int br;
for (br = 0; x; x>>=1)
if (x&1)
br++;

/* Drugo resenje:
int wl = sizeof(unsigned)*8;
int br = 0;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
if(x&mask) br++ ;
*/
return br;
}

22
Milena Vujošević–Janičić Bitski operatori

main()
{
printf("Binarni zapis broja 127 je\n");
print_bits(127);
printf("Suma bitova broja 127 je %d\n",sum_of_bits(127));
printf("Binarni zapis broja 128 je\n");
print_bits(128);
printf("Suma bitova broja 128 je %d\n",sum_of_bits(128));
printf("Binarni zapis broja 0x00FF00FF je\n");
print_bits(0x00FF00FF);
printf("Suma bitova broja 0x00FF00FF je %d\n",sum_of_bits(0x00FF00FF));
printf("Binarni zapis broja 0xFFFFFFFF je\n");
print_bits(0xFFFFFFFF);
printf("Suma bitova broja 0xFFFFFFFF je %d\n",sum_of_bits(0xFFFFFFFF));
}

Izlaz iz programa:
Binarni zapis broja 127 je
00000000000000000000000001111111
Suma bitova broja 127 je 7
Binarni zapis broja 128 je
00000000000000000000000010000000
Suma bitova broja 128 je 1
Binarni zapis broja 0x00FF00FF je
00000000111111110000000011111111
Suma bitova broja 0x00FF00FF je 16
Binarni zapis broja 0xFFFFFFFF je
11111111111111111111111111111111
Suma bitova broja 0xFFFFFFFF je 32
Primer 3.6 get_bits, set_bits, invert_bits - izdvajanje, postavljanje i inver-
tovanje pojedinačnih bitova.
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

23
Milena Vujošević–Janičić Bitski operatori

/* Funkcija vraca n bitova broja x koji pocinju na poziciji p */


unsigned get_bits(unsigned x, int p, int n)
{
/* Gradimo masku koja ima poslednjih n jedinica
0000000...00011111
tako sto sve jedinice ~0 pomerimo u levo za n mesta
1111111...1100000
a zatim komplementiramo
*/
unsigned last_n_1 = ~(~0 << n);

/* x pomerimo u desno za odgovarajuci broj mesta, a zatim


konjunkcijom sa konstruisanom maskom obrisemo pocetne cifre */

return (x >> p+1-n) & last_n_1;


}

/* Funkcija vraca modifikovano x tako sto mu je izmenjeno n bitova


pocevsi od pozicije p i na ta mesta je upisano poslednjih n bitova
broja y */
unsigned set_bits(unsigned x, int p, int n, unsigned y)
{
/* Maska 000000...000111111 - poslednjih n jedinica */
unsigned last_n_1 = ~(~0 << n);

/* Maska 1111100..000111111 - n nula pocevsi od pozicije p */


unsigned middle_n_0 = ~(last_n_1 << p+1-n);

/* Brisemo n bitova pocevsi od pozicije p */


x = x & middle_n_0;

/* Izdvajamo poslednjih n bitova broja y i pomeramo ih


na poziciju p */
y = (y & last_n_1) << p+1-n;

/* Upisujemo bitove broja y u broj x i vracamo rezultat */


return x | y;
}

/* Invertuje n bitova broja x pocevsi od pozicije p */


unsigned invert_bits(unsigned x, int p, int n)
{
/* Maska 000000111...1100000 - n jedinica pocevsi od pozicije p */

24
Milena Vujošević–Janičić Bitski operatori

unsigned middle_n_1 = ~(~0 << n) << p+1-n;

/* Invertujemo koristeci ekskluzivnu disjunkciju */


return x ^ middle_n_1;
}

main()
{
unsigned x = 0x0AA0AFA0;
print_bits(x);

print_bits(get_bits(x, 15, 8));


print_bits(set_bits(x, 15, 8, 0xFF));
print_bits(invert_bits(x, 15, 8));
}

Izlaz iz programa:
00001010101000001010111110100000
00000000000000000000000010101111
00001010101000001111111110100000
00001010101000000101000010100000
Primer 3.7 right_rotate_bits, mirror_bits - rotiranje i simetrija bitova.
#include <stdio.h>

/* Pomocna funkcija - stampa bitove neoznacenog broja */


void print_bits(unsigned x)
{
int wl = sizeof(unsigned)*8;

unsigned mask;
for (mask = 1<<wl-1; mask; mask >>= 1)
putchar(x&mask ? ’1’ : ’0’);

putchar(’\n’);
}

/* Funkcija vrsi rotaciju neoznacenog broja x za n pozicija u desno */


unsigned right_rotate(unsigned x, int n)
{
int i;
int wl = sizeof(unsigned)*8;

/* Postupak se ponavlja n puta */


for (i = 0; i < n; i++)

25
Milena Vujošević–Janičić Bitski operatori

{
/* Poslednji bit broja x */
unsigned last_bit = x & 1;

/* x pomeramo za jedno mesto u desno */


x >>= 1;

/* Zapamceni poslednji bit stavljamo na pocetak broja x*/

x |= last_bit<<wl-1;
}

return x;
}

/* Funkcija obrce binarni zapis neoznacenog broja x tako sto bitove


cita unatrag */
unsigned mirror(unsigned x)
{
int i;
int wl = sizeof(unsigned)*8;

/* Rezultat inicijalizujemo na poslednji bit broja x */


unsigned y = x & 1;

/* Postupak se ponavlja wl-1 puta */


for (i = 1; i<wl; i++)
{
/* x se pomera u desno za jedno mesto */
x >>= 1;
/* rezultat se pomera u levo za jedno mesto */
y <<= 1;

/* Poslednji bit broja x upisujemo na poslednje


mesto rezultata */
y |= x & 1;
}
return y;
}

main()
{
unsigned x = 0xFAF0FAF0;
print_bits(x);

26
Milena Vujošević–Janičić Bitski operatori

print_bits(mirror(x));
print_bits(right_rotate(x, 2));
}

Izlaz iz programa:
11111010111100001111101011110000
00001111010111110000111101011111
00111110101111000011111010111100
Primer 3.8 Promeljiva c je tipa char. Šta ce biti vrednost promenljive c posle izraza
dodele
 c=(15|3)>>1;?
 c=(15 & 3)<<1; ?
Primer 3.9 Napisati program koji sa standardnog ulaza učcitava pozitivan ceo broj,
a na standardni izlaz ispisuje vrednost tog broja sa razmenjenim vrednostima bitova
na pozicijama i, j. Pozicije i, j se učitavaju kao parametri komandne linije. Sma-
trati da je krajnji desni bit binarne reprezentacije 0-ti bit. Pri rešavanju nije dozvol-
jeno koristiti pomoćni niz niti aritmeticke operatore +,-,/,*,%.
#include <stdio.h>
#include <stdlib.h>

int razmeni(unsigned n, unsigned i, unsigned j)


{
int rezultat = n;

/* Broj bitova tipa unsigned */


int wl = sizeof(int)*8;

unsigned mask_i = (1 << i);


unsigned mask_j = (1 << j);

if(n & mask_i)


/* Ako je na i-tom mestu 1, upisujemo
to na j-to mesto*/
rezultat |= mask_j;
/* Ako je na i-tom mestu 0, upisujemo
to na j-to mesto*/
else
rezultat &= ~mask_j;

if(n & mask_j)


/* Ako je na j-tom mestu 1, upisujemo
to na i-to mesto*/

27
Milena Vujošević–Janičić Bitski operatori

rezultat |= mask_i;
/* Ako je na j-tom mestu 0, upisujemo
to na i-to mesto*/
else
rezultat &= ~mask_i;

return rezultat;
}

int main(int argc, char** argv)


{
unsigned n, i, j, m;
if(argc < 3)
{
fprintf(stderr, "Neispravna upotreba programa!\n");
exit(1);
}

printf("Unesi broj\n");
scanf("%u", &n);

/* Racunaju se brojevi na osnovu argumenata


komandne linije.
*/
i = atoi(argv[1]);
j = atoi(argv[2]);

m = razmeni(n, i, j);

printf("Broj nastao razmenom bitova (%u, %u) broja %u je %u\n",


i, j, n, m);
return 0;
}
Primer 3.10 Napisati funkciju koja prima ceo broj n i ispisuje razliku broja jedinica
na parnim i neparnim pozicijama u binarnom zapisu broja n.
PRIMER: za n = 19 = (10011)2 izlaz je 1.
Napisati program koji pozivom ove funkcije računa i štampa razliku broja jedinica
za sve argumente komandne linije (pretpostavka je da su argumenti komandne linije
zadati korektno).
#include <stdio.h>
#include <stdlib.h>

int par_nepar(int n)
{

28
Milena Vujošević–Janičić Bitski operatori

int br1_par = 0; /* int rezultat=0;*/


int br1_nepar = 0;

/* Broj bitova tipa unsigned */


int wl = sizeof(int)*8;
unsigned mask=1;
char par = 1;
for( ; mask; mask <<= 1)
{
if(mask&n)
if(par) br1_par++; /* if(par) rezultat++; */
else br1_nepar++; /* else rezultat--; */
par = 1 - par;
}
return br1_par - br1_nepar; /* return rezultat;*/
}

main(int argc, char** argv)


{
unsigned n, i, m;
if(argc < 2)
{
fprintf(stderr, "Neispravna upotreba programa!\n");
exit(1);
}
for(i=1; i<argc; i++)
{
n = atoi(argv[i]);
m = par_nepar(n);
printf("Razlika jedinica na parnim i neparnim za broj %u je %d\n", n, m);
}
}

29
Glava 4

Vezbanje

4.1 Polinomi
Primer 4.1 Program ilustruje rad sa polinomima.
#include <stdio.h>
#include <math.h>
#define max(a, b) ((a) > (b) ? (a) : (b))

/*
* Polinom 3*x^3 + 2*x + 1.5 se predstavlja kao:
* stepen -> 3
* koeficijenti -> 1.5 2 0 3 x x x x x ... x
*/
typedef struct polinom
{
float koeficijenti[21];
int stepen;
} Polinom;

/*
* Funkcija vraca koeficijent uz x^i u polinomu p
* Zbog efikasnosti ne prenosimo celu strukturu vec
* samo pokazivac na strukturu.
*/
float vratiKoeficijent(Polinom* p, int i)
{
return i <= p->stepen ? p->koeficijenti[i] : 0.0f;
}

/*
* Funkcija postavlja koeficijent uz x^i u polinomu p na
* dati koeficijent k

30
Milena Vujošević–Janičić 4.1 Polinomi

*/
void postaviKoeficijent(Polinom* p, int i, float k)
{
int j;

/*
Ukoliko je stepen polinoma bio manji, postavljamo
sve koeficijente izmedju na 0.0 i uvecavamo stepen
*/
if (i > p->stepen)
{
for (j = p->stepen+1; j < i; j++)
p->koeficijenti[j] = 0.0f;
p->stepen = i;
}
p->koeficijenti[i] = k;
}

/*
* Funkcija kreira polinom datog stepena sa datim nizom
* koeficijenata. Pretpostavlja se da su koeficijenti
* u datom nizu koeficijenti[] uredjeni opadajuce po stepenima
* polinoma.
*/
Polinom napraviPolinom(int stepen, float koeficijenti[])
{
int i;
Polinom p;
p.stepen = stepen;
for (i = 0; i <= stepen; i++)
{
postaviKoeficijent(&p, i, koeficijenti[stepen - i]);
}
return p;
}

/*
* Funkcija ispisuje polinom u citljivijem obliku.
* Na primer: 3.0*x^3 + 0.0*x^2 + 2.0*x^1 + 1.5*x^0
*/
void ispisiPolinom(Polinom* p)
{
int i;
for (i = p->stepen; i >= 0; i--)

31
Milena Vujošević–Janičić 4.1 Polinomi

{
printf("%.2f*x^%d", vratiKoeficijent(p, i), i);
if (i > 0)
printf(" + ");
}
printf("\n");
}

/*
* Funkcija izracunava vrednost polinoma u tacki x
* Hornerovom shemom. Na primer,
* 3*x^3 + 2*x + 1.5 =
* (((0*x + 3)*x + 0)*x + 2)*x + 1.5
* Postupak izracunavanja p(10):
* 0.0
* 10 * 0.0 + 3 = 3.0
* 10 * 3.0 + 0 = 30.0
* 10 * 30.0 + 2 = 302.0
* 10 * 302.0 + 1.5 = 3021.5
*/
float vrednost(Polinom* p, float x)
{
int i;
float suma = 0.0f;
for (i = p->stepen; i >= 0; i--)
{
suma = suma*x + vratiKoeficijent(p, i);
}
return suma;
}

/*
* Funkcija sabira dva polinoma
*/
Polinom saberi(Polinom* p, Polinom* q)
{
int i;
Polinom zbir;
zbir.stepen = max(p->stepen, q->stepen);
for (i = 0; i <= zbir.stepen; i++)
postaviKoeficijent(&zbir, i,
vratiKoeficijent(p, i)
+ vratiKoeficijent(q, i));
return zbir;

32
Milena Vujošević–Janičić 4.1 Polinomi

/*
* Funkcija mnozi dva polinoma. Na primer,
*
* 1*x^2 + 2*x + 3
* 4*x + 7
*
* 0.0*x^3 + 0.0*x^2 + 0.0*x + 0.0
* 0.0*x^3 + 0.0*x^2 + 0.0*x + 21.0 i=0 j=0
* 0.0*x^3 + 0.0*x^2 + 12.0*x + 21.0 i=0 j=1
* 0.0*x^3 + 0.0*x^2 + 26.0*x + 21.0 i=1 j=0
* 0.0*x^3 + 8.0*x^2 + 26.0*x + 21.0 i=1 j=1
* 0.0*x^3 + 15.0*x^2 + 26.0*x + 21.0 i=2 j=0
* 4.0*x^3 + 15.0*x^2 + 26.0*x + 21.0 i=2 j=1
*/
Polinom pomnozi(Polinom* p, Polinom* q)
{
int i, j;
Polinom proizvod;
proizvod.stepen = p->stepen + q->stepen;
for (i = 0; i <= proizvod.stepen; i++)
{
postaviKoeficijent(&proizvod, i, 0.0f);
}
for (i = 0; i <= p->stepen; i++)
{
for (j = 0; j <= q->stepen; j++)
{
/* r[i+j] = r[i+j] + p[i]*q[j] */
postaviKoeficijent(&proizvod, i+j,
vratiKoeficijent(&proizvod, i+j) +
vratiKoeficijent(p, i) * vratiKoeficijent(q, j));
}
}
return proizvod;
}
main()
{
float pkoeficijenti[] = {1.0f, 2.0f, 1.0f};
Polinom p = napraviPolinom(2, pkoeficijenti);
float qkoeficijenti[] = {1.0f, 1.0f};
Polinom q = napraviPolinom(1, qkoeficijenti);
Polinom r = pomnozi(&p, &q);

33
Milena Vujošević–Janičić 4.2 Veliki brojevi

ispisiPolinom(&r);
}

4.2 Veliki brojevi


Primer 4.2 Program ilustruje rad sa velikim celim brojevima. Brojevi se interno
reprezentuju preko niza svojih cifara.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX_CIFRE 100

/* Funkcija obrce cifre prosledjenog niza */


void obrni_cifre (int cifre[], int duzina)
{
int i, j;
for (i=0, j=duzina-1; i<j; i++, j--)
{
int pom = cifre[i];
cifre[i] = cifre[j];
cifre[j] = pom;
}
}

/* Funkcija sa standardnog ulaza ucitava niz cifara, duzine


najvise max_cifre i smesta ga u niz brojeva cifre[]. Zatim
se niz cifre[] obrce kako bi cifre najmanje tezine bile
na pocetku niza.
Kao rezultat, funkcija vraca broj cifara ucitanog broja */
int uzmi_broj (int cifre[], int max_cifre)
{
int duzina = 0;
char c;
while ( --max_cifre>0 && isdigit(c=getchar()))
cifre[duzina++]=c-’0’;
obrni_cifre(cifre, duzina);
return duzina;
}

/* Funkcija ispisuje "veliki" broj predstavljen


nizom cifara cifre, duzine duzina, na standardni
izlaz imajuci u vidu da su cifre u nizu zapisane
"naopako" tj. pocevsi od cifre najmanje tezine */
void ispisi_broj(int cifre[],int duzina)

34
Milena Vujošević–Janičić 4.2 Veliki brojevi

{
int i;
for (i=duzina-1; i>=0; i--)
printf("%d",cifre[i]);
putchar(’\n’);
}

/* Da li su dva broja data svojim nizovima cifara i duzinama jednaka?


Funkcija vraca 1 ako jesu, a 0 ako nisu */
int jednaki(int a[], int duzina_a, int b[], int duzina_b)
{
int i;
/* Poredimo duzine */
if (duzina_a != duzina_b)
return 0;

/* Ako su brojevi iste duzine, poredimo cifru po cifru*/


for (i=0; i<duzina_a; i++)
if (a[i] != b[i])
return 0;

return 1;
}

/* Funckija poredi dva broja a i b, data svojim nizovima cifara i duzinama


i vraca:
1 ako je a>b
0 ako je a=b
-1 ako je b>a
*/
int uporedi(int a[], int duzina_a, int b[], int duzina_b)
{
int i;
/* Uporedjujemo duzine brojeva a i b */
if (duzina_a > duzina_b)
return 1;
if (duzina_a < duzina_b)
return -1;
/* U ovom trenutku znamo da su brojevi iste duzine, tako da
prelazimo na poredjenje cifre po cifre, pocevsi od cifre
najvece tezine */
for (i=duzina_a-1; i>=0; i--)
{
if (a[i] > b[i])

35
Milena Vujošević–Janičić 4.2 Veliki brojevi

return 1;
if (a[i] < b[i])
return -1;
}
return 0;
}

/* Funkcija sabira dva broja data svojim nizovima cifara


i duzinama */
void saberi(int a[], int duzina_a, int b[], int duzina_b,
int rezultat[],
int* duzina_rezultata)
{
int i;

/* Prenos sa prethodne pozicije */


int prenos = 0;

/* Sabiranje vrsimo dok ne prodjemo sve cifre duzeg od brojeva a i b */


for(i=0; i<duzina_a || i<duzina_b; i++)
{
/* Sabiramo i-tu cifra broja a (ako postoji) sa i-tom cifrom
broja b (ako postoji) i prenos sa prethodne pozicije */
int cifra_rezulata = ((i<duzina_a)? a[i] : 0) +
((i<duzina_b)? b[i] : 0) +
prenos;

/* Nova cifra rezultata */


rezultat[i] = cifra_rezulata%10;

/* Prenos na sledecu poziciju */


prenos = cifra_rezulata/10;
}

/* Kada smo zavrsili sa svim ciframa brojeva a i b moguce je da je


postojao prenos na sledecu poziciju u kom slucaju uvecavamo duzinu
rezultata. Inace duzinu rezultata postavljamo na duzinu duzeg od
brojeva a i b, koja se nalazi trenutno u promenjivoj i */
if (prenos != 0)
{
if (i>=MAX_CIFRE)
{printf("Doslo je do prekoracenja!\n"); exit(1);}
else
{

36
Milena Vujošević–Janičić 4.2 Veliki brojevi

rezultat[i] = prenos;
*duzina_rezultata = i+1;
}
}
else
*duzina_rezultata=i;

return;
}

/* Funkcija mnozi broj, dat svojim nizom cifara i duzinom, datom cifrom c */
void pomnozi_cifrom (int a[], int duzina_a, int cifra,
int rezultat[],
int* duzina_rezultata)
{
int i, prenos = 0;

for (i=0; i<duzina_a; i++)


{
/* Svaku cifru broja a mnozimo cifrom c, dodajemo na to
prenos sa prethodne pozicije i to smestamo u promenljivu
pom */
int pom = a[i]*cifra + prenos;
/* Nova cifra rezultata */
rezultat[i] = pom%10;
/* Prenos na sledecu poziciju */
prenos = pom/10;
}

/* Kada smo zavrsili sa svim ciframa broja a, moguce je da je


postojao prenos na sledecu poziciju u kom slucaju uvecavamo
duzinu rezultata. Inace duzinu rezultata postavljamo na duzinu
broja a, koja se nalazi trenutno u promenjivoj i */
if (prenos != 0)
{
if (i>=MAX_CIFRE)
{printf("Doslo je do prekoracenja !\n"); exit(1);}
else
{
rezultat[i] = prenos;
*duzina_rezultata = duzina_a+1;
}
}
else

37
Milena Vujošević–Janičić 4.2 Veliki brojevi

*duzina_rezultata = duzina_a;
}

/* Funkcija mnozi dva broja data svojim nizovima cifara i duzinama*/


void pomnozi (int a[], int duzina_a, int b[], int duzina_b,
int rezultat[],
int* duzina_rezultata)
{
/* Ova funkcija se gradi kombinovanjem algoritama mnozenja broja cifrom i
sabiranja dva broja */
int i,j,k;

/* Broj pom ce da sadrzi rezultat mnozenja broja a jednom po jednom


cifrom broja b, dok ce na broj rezultat da se dodaje svaki
put (10^i)*pom */
int pom[MAX_CIFRE], duzina_pom, prenos;

*duzina_rezultata = 0;

/*
b=351 * a=123
---------------
1 korak ===> rez: 351 * 3 = 1053
2 korak ===> 351 * 2 = 702
------------------
rez: 8073
3 korak ===> 351 * 1 = 351
------------------
rez: 43173
*/
/* Za svaku cifru broja a */
for (i=0; i<duzina_a; i++)
{
/* vrsimo mnozenje broja b i-tom cifrom broja a */
pomnozi_cifrom(b, duzina_b, a[i], pom, &duzina_pom);

/* Zatim dodajemo broj pom na rezultat, ali dodavanje pocinjemo od


i-te cifre rezultata.*/
prenos = 0;
for (k=0; k<duzina_pom; k++)
{
int pm=((i+k<*duzina_rezultata) ? rezultat[i+k] : 0) + pom[k] + prenos;
rezultat[i+k] = pm%10;
prenos = pm/10;

38
Milena Vujošević–Janičić 4.2 Veliki brojevi

}
if (prenos)
{
rezultat[i+k] = prenos;
*duzina_rezultata = i+k+1;
}
else
*duzina_rezultata = i+k;
}
}

/* Primer koriscenja funkcija */


main()
{
/* duzina brojeva a i b */
int duzina_a, duzina_b;

/* nizovi cifara brojeva a i b */


int a[MAX_CIFRE], b[MAX_CIFRE], zbir[MAX_CIFRE], proizvod[MAX_CIFRE];

/* Ucitavaju se brojevi */
printf("Unesite prvi broj : ");
duzina_a = uzmi_broj(a,MAX_CIFRE);

printf("Unesite drugi broj : ");


duzina_b = uzmi_broj(b, MAX_CIFRE);

/* Sabiraju se i ispisuje se zbir */


saberi(a, duzina_a, b, duzina_b, zbir, &duzina_zbira);
printf("Zbir je : ");
ispisi_broj(zbir, duzina_zbira);

/* Mnoze se i ispisuje se proizvod */


pomnozi(a, duzina_a, b, duzina_b, proizvod, &duzina_proizvoda);
printf("Proizvod je : ");
ispisi_broj(proizvod, duzina_proizvoda);
}

39
Glava 5

Sortiranje

Niz moze biti sortiran ili ured̄jen u


 opadajucem poretku:
niz[0] > niz[1] > ... > niz[i] > niz[i + 1] > ... > niz[n 1]

 rastucem poretku:
niz[0] < niz[1] < ... < niz[i] < niz[i + 1] < ... < niz[n 1]

 neopadajucem poretku:
niz[0]  niz[1]  ...  niz[i]  niz[i + 1]  ...  niz[n 1]

 nerastucem poretku:
niz[0] ≥ niz[1] ≥ ... ≥ niz[i] ≥ niz[i + 1] ≥ ... ≥ niz[n 1]

U nastavku su dati primeri algoritama za sortiranje u nerastucem poretku celobro-


jnog niza. Jednostavnim modi kacijama svakim od ovih algoritama niz se moze
sortirati i u opadajucem, rastucem ili neopadajucem poretku.

5.1 Vremenska složenost


Pogledati slike koje oslikavaju vremensku slozenost za razlicite algoritme i razlicite
nizove:
 Rezultati dobijeni za slucajno generisane nizove:
http://www.matf.bg.ac.yu/~filip/pp/0405/random-sort.gif
 Rezultati dobijeni za vec sortirane nizove:
http://www.matf.bg.ac.yu/~filip/pp/0405/sorted-sort.gif
 Rezultati dobijeni za naopako sortirane nizove:
http://www.matf.bg.ac.yu/~filip/pp/0405/reverse-sorted-sort.gif

40
Milena Vujošević–Janičić 5.2 Selection sort

5.2 Selection sort


Primer 5.1 (Selection sort) U prvom prolazu se razmenjuju vrednosti a[0] sa
onim članovima ostatka niza koji su veći od njega. Na taj način će se posle prvog
prolaza kroz niz a[0] postaviti na najveći element niza. U svakom sledećem prolazu,
postavlja se na i-to mesto najveci element niza a[i], a[i+1] ... a[n-1].
Primer sortiranja:
n = 6 a: 1 3 5 2 6 8
-------------
i = 0 j = 1 => a: 3 1 5 2 6 8
i = 0 j = 2 => a: 5 1 3 2 6 8
i = 0 j = 3 => a: 5 1 3 2 6 8
i = 0 j = 4 => a: 6 1 3 2 5 8
i = 0 j = 5 => a: 8 1 3 2 5 6
-------------
i = 1 j = 2 => a: 8 3 1 2 5 6
i = 1 j = 3 => a: 8 3 1 2 5 6
i = 1 j = 4 => a: 8 5 1 2 3 6
i = 1 j = 5 => a: 8 6 1 2 3 5
...
#include<stdio.h>
#include<stdlib.h>

#define MAXDUZ 100

void selection(int a[], int n)


{
/* pomocna i brojacke promenljive */
int pom,i,j;

/*Sortiranje*/
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]<a[j])
{
pom=a[i];
a[i]=a[j];
a[j]=pom;
}
}

main()
{
/* Niz od maksimalno MAXDUZ elemenata*/

41
Milena Vujošević–Janičić 5.2 Selection sort

int a[MAXDUZ];

/* Dimenzija niza, pomocna i brojacke promenljive */


int n,i;

printf("Unesite dimenziju niza\n");


scanf("%d",&n);

if (n>MAXDUZ)
{
printf("Nedozvoljena vrednost za n\n");
exit(1);
}

/* Unos clanova niza */


for(i=0; i<n; i++)
{
printf("Unesite %d. clan niza\n",i+1);
scanf("%d",&a[i]);
}

selection(a,n);

/* Ispis niza */
printf("Sortirani niz:\n");
for(i=0; i<n; i++)
printf("%d\t",a[i]);

putchar(’\n’);

}
Primer 5.2 (Selection sort2) Modifikacija prethodnog rešenja radi dobijanja na
efikasnosti. Ne vrše se zamene svaki put već samo jednom, kada se pronad̄e odgo-
varajući element u nizu sa kojim treba izvršiti zamenu tako da u nizu bude postavljen
trenutno najveći element na odgovarajuće mesto.
Primer sortiranja:
n = 6 a: 1 3 5 2 6 8
-------------
i = 0 => a: 8 1 5 2 6 3
-------------
i = 1 => a: 8 6 5 2 1 3
-------------
i = 2 => a: 8 6 5 2 1 3
-------------

42
Milena Vujošević–Janičić 5.3 Bubble sort

...
void selection2(int a[], int n)
{
int i, j, max;

/*Sortiranje - bez stalnih zamena vec se


pronalazi indeks trenutno najveceg clana niza*/
for(i=0; i<n-1; i++)
{
max = i;
for(j=i+1; j<n; j++)
if(a[max]<a[j])
max=j;

/* Vrsi se zamena onda kada na i-tom mestu


nije najveci element. Tada se na i-to mesto
postavlja najveci element koji se nalazio na
mestu ind. */
if(i != max)
{
pom=a[max];
a[max]=a[i];
a[i]=pom;
}
}
}

5.3 Bubble sort


Primer 5.3 (Bubble sort) Algoritam sortiranja buble sort poredi dva susedna el-
ementa niza i ako su pogrešno raspored̄eni zamenjuje im mesta. Posle pored̄enja
svih susednih parova najmanji od njih će isplivati na kraj niza. Zbog toga se ovaj
metod naziva metod mehurića. Da bi se najmanji broj nesortiranog dela niza doveo
na svoje mesto treba ponoviti postupak.
Primer sortiranja:
n = 6 a: 1 3 5 2 6 8
-------------
i = 5 j = 0 => a: 3 1 5 2 6 8
i = 5 j = 1 => a: 3 5 1 2 6 8
i = 5 j = 2 => a: 3 5 2 1 6 8
i = 5 j = 3 => a: 3 5 2 6 1 8
i = 5 j = 4 => a: 3 5 2 6 8 1
-------------

43
Milena Vujošević–Janičić 5.3 Bubble sort

i = 4 j = 0 => a: 5 3 2 6 8 1
...

void bubble(int a[], int n)


{
int i, j, pom;

for(i=n-1; i>0; i--)


for(j=0; j<i; j++)
if(a[j]<a[j+1])
{
pom=a[j];
a[j]=a[j+1];
a[j+1]=pom;
}
}
Primer 5.4 (Bubble sort 2) Unapredjujemo prethodni algoritam kako bismo obezbedli
da se ne vrše provere onda kada je niz već sortiran nego da se u tom slučaju prekine
rad.
void bubble2(int a[], int n)
{
/* Promenljiva koja govori da li je izvrsena
zamena u i-tom prolazu kroz niz pa ako nije
sortiranje je zavrseno jer su svaka dva
susedna elementa niza u odgovarajucem poretku */
int zam;

zam=1;
for(i=n-1; zam && i>0; i--)
for(zam=0,j=0; j<i; j++)
if(a[j]<a[j+1])
{
/* Zamena odgovarajucih clanova niza */
pom=a[j];
a[j]=a[j+1];
a[j+1]=pom;

/* Posto je u i-tom prolazu


izvrsena bar ova zamena zam
se postavlja na 1 sto
nastavlja sortiranje */
zam=1;
}

44
Milena Vujošević–Janičić 5.4 Insertion sort

5.4 Insertion sort


Primer 5.5 (Insertion sort) U svakom trenutku je početak niza sortiran, a sorti-
ranje se vrši tako što se jedan po jedan element niza sa kraja ubacuje na odgovarajuće
mesto.
Primer sortiranja:
n = 6 a: 1 3 5 2 6 8
-------------
i = 1 j = 1 => a: 3 1 5 2 6 8
-------------
i = 2 j = 2 => a: 3 5 1 2 6 8
i = 2 j = 1 => a: 5 3 1 2 6 8
-------------
i = 3 j = 3 => a: 5 3 2 1 6 8
-------------
i = 4 j = 4 => a: 5 3 2 6 1 8
...
void insertion(int a[], int n)
{
/* Pomocna i brojacke promenljive */
int pom,i,j;

for(i=1; i<n; i++)


for(j=i; (j>0) && (a[j]>a[j-1]); j--)
{
pom=a[j];
a[j]=a[j-1];
a[j-1]=pom;
}
}

Primer 5.6 (Insertion sort 2) Broj dodela se moze redukovati tako sto se umesto
stalnih zamena koristi dodela privremenoj promenljivoj — elemente niza pomeramo
za jedno mesto sve dok ne nad̄emo poziciju na koju treba da postavimo dati element
(koji je sačuvan u privremenoj promenljivoj).
void insertion2(int a[], int n)
{
int i, j, tmp;
for (i = 1; i < n; i++)
{
int tmp = a[i];

45
Milena Vujošević–Janičić 5.5 Razni zadaci

for (j = i; j > 0 && a[j-1] < tmp; j--){


a[j] = a[j-1];
}
a[j] = tmp;
}
}

5.5 Razni zadaci


Primer 5.7 Napisati funkciju koja od dva sortirana niza formira treći sortiran niz
(nizovi su sortirani neopadajućie).
#include <stdio.h>

/* Funkcija spaja dva uredjena niza:


a koji ima na elemenata i
b koji ima nb elemenata
i na osnovu njih gradi uredjeni niz c ciji
broj elemenata vraca.
Pretpostavlja se da u nizu c ima dovoljno prostora.
*/
int merge(int a[], int na, int b[], int nb, int c[])
{
/* Dok god ima elemenata u oba niza uzima se
manji od dva tekuca i prepisuje u niz c */
int i = 0, j = 0, k = 0;
while(i < na && j < nb)
{
if (a[i] < b[j])
c[k++] = a[i++];
else
c[k++] = b[j++];
}

/* Prepisujemo eventualno preostale elemente niza a */


for (; i < na; i++, k++)
c[k] = a[i];

/* Prepisujemo eventualno preostale elemente niza b */


for (; j < nb; j++, k++)
c[k] = b[j];

return k;
}

46
Milena Vujošević–Janičić 5.5 Razni zadaci

main() {
int a[] = {1, 5, 6, 9, 13};
int b[] = {2, 3, 7, 11, 12, 15};
int c[30];
int na = sizeof(a)/sizeof(int);
int nb = sizeof(b)/sizeof(int);
int nc = merge(a, na, b, nb, c);
int i;

for (i = 0; i < nc; i++)


printf("%d ", c[i]);
printf("\n");
}
Primer 5.8 Program učitava niz studenata i sortira ih po njihovim ocenama.
#include <stdio.h>
#include <ctype.h>

#define MAX_IME 20

typedef struct _student


{
char ime[MAX_IME];
char prezime[MAX_IME];
int ocena;
} student;

/* Funkcija ucitava rec i vraca njenu duzinu ili


-1 ukoliko smo dosli do znaka EOF*/
int getword(char word[],int max)
{
int c, i=0;

while (isspace(c=getchar()))
;

while(!isspace(c) && c!=EOF && i<max-1)


{
word[i++]=c;
c = getchar();
}

word[i]=’\0’;

if (c==EOF) return -1;

47
Milena Vujošević–Janičić 5.5 Razni zadaci

else return i;

/* Funkcija ucitava niz studenata, vraca duzinu niza koji ucita */


int UcitajPodatke(student studenti[], int max)
{
int i=0;
while(i<max && getword(studenti[i].ime, MAX_IME)>0)
{
if (getword(studenti[i].prezime, MAX_IME) < 0)
break;
scanf("%d",&studenti[i].ocena);
i++;
}
return i;
}

void IspisiPodatke(student studenti[], int br_studenata)


{
int i;
printf("IME PREZIME OCENA\n");
printf("--------------------------------------\n");
for (i=0; i<br_studenata; i++)
printf("%-20s %-20s %5d\n",studenti[i].
ime, studenti[i].prezime, studenti[i].ocena);
}

/* Sortiranje studenata po ocenama */


void SelectionSort(student studenti[], int br_studenata)
{
int i,j;
for (i=0; i<br_studenata-1; i++)
for (j=i; j<br_studenata; j++)
if (studenti[i].ocena<studenti[j].ocena)
{ student tmp=studenti[i];
studenti[i]=studenti[j];
studenti[j]=tmp;
}
}

main()
{
student studenti[100];

48
Milena Vujošević–Janičić 5.5 Razni zadaci

int br_studenata = UcitajPodatke(studenti,100);

SelectionSort(studenti, br_studenata);
IspisiPodatke(studenti, br_studenata);
}
Primer 5.9 Program učitava informacije o studentima iz datoteke čije se ime zadaje
iz komandne linije, i koja je u formatu:
n
prezime1 ime1 smer1 prosek1
prezime2 ime2 smer2 prosek2
...
prezimen imen smern prosekn
Studenti se sortiraju leksikografski po prezimenima i imenima, a zatim se njihovi
podaci tako sortirani ispisuju na izlaz, ili u izlazni fajl, ako je njegovo ime zadato u
komandnoj liniji.
#include <stdio.h>
#include <string.h>

#define MAX_IME 20
#define MAX_PREZIME 30
#define MAX_SMER 10

#define MAX_STUDENATA 100

/* Struktura koja predstavlja informacije o studentu */


typedef struct student {

char ime[MAX_IME];
char prezime[MAX_PREZIME];
char smer[MAX_SMER];
double prosek;

} Student;

/* Funkcija uporedjuje dva studenta po leksikografskom poretku


njihovih imena i prezimena. Funkcija vraca vrednost manju od
nule ako je prvi student "manji" od drugog, vrednost vecu
od nule ako je prvi student "veci" od drugog, dok nulu vraca
ako se studenti zovu isto. */
int uporedi(Student *s, Student *p)
{
int t;

49
Milena Vujošević–Janičić 5.5 Razni zadaci

/* Najpre poredimo prezimena. Ako su prezimena ista, onda poredimo


i imena. */
if((t = strcmp(s->prezime, p->prezime)) != 0)
return t;
else
return strcmp(s->ime, p->ime);
}

/* Funkcija sortira niz studenata u leksikografskom poretku */


void sortiraj(Student studenti[], int n)
{
int i, j;
int min;
Student pom;

/* Studenti se porede funkcijom uporedi(). Zamena elemenata


niza se obavlja na uobicajen nacin, zato sto je dodela
struktura legitimna operacija i zato sto struktura ne
sadrzi pokazivace za koje je memorija alocirana dinamicki. */

for (i = 0; i < n - 1; i++)


{
min = i;
for (j = i + 1; j < n; j++)
if (uporedi(&studenti[j], &studenti[min]) < 0)
min = j;

if (min != i)
{
pom = studenti[i];
studenti[i] = studenti[min];
studenti[min] = pom;
}
}
}

/* Funkcija ucitava podatke o studentu */


void ucitaj(FILE *in, Student *s)
{
fscanf(in, "%s", s->prezime);
fscanf(in, "%s", s->ime);
fscanf(in, "%s", s->smer);

50
Milena Vujošević–Janičić 5.5 Razni zadaci

fscanf(in, "%lf", &s->prosek);


}

/* Ispisujemo informacije o studentu */


void ispisi(FILE *out, Student *s)
{
fprintf(out, "%s %s %s %f\n", s->prezime, s->ime, s->smer, s->prosek);
}

/* Funkcija main */
int main (int argc, char ** argv)
{

int n, i;
FILE *in = stdin, *out = stdout;
Student studenti[MAX_STUDENATA];

/* Ako je korisnik uneo ime ulaznog fajla...*/


if(argc > 1)
if((in = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Greska prilikom otvaranja fajla!\n");
return 1;
}

/* Ako je korisnik uneo i ime izlaznog fajla...*/


if(argc > 2)
if((out = fopen(argv[2], "w")) == NULL)
{
fprintf(stderr, "Greska prilikom otvaranja fajla!\n");
return 1;
}

/* Ucitavamo broj studenata */


fscanf(in, "%d", &n);

/* Ucitavamo informacije o studentima */


for(i = 0; i < n; i++)
ucitaj(in, &studenti[i]);

/* Sortiramo niz studenata */


sortiraj(studenti, n);

/* Ispisujemo niz studenata */

51
Milena Vujošević–Janičić 5.5 Razni zadaci

for(i = 0; i < n; i++)


ispisi(out, &studenti[i]);

fclose(in);
fclose(out);

return 0;
}
Primer 5.10 Program utvrd̄uje da li su dve niske karaktera anagrami. Dve niske
su anagrami ako se sastoje od istog broja istih karaktera. Na primer, niske ”trave”
i ”vetar” jesu anagrami, dok ”vetar” i ”vatra” nisu.
#include <stdio.h>
#include <string.h>

#define MAX 1024

/* Funkcija sortira karaktere stringa s */


void sortiraj (char s[])
{
int i, j;
int min;
char pom;
int n;

/* Racunamo duzinu stringa */


for (n = 0; s[n] != ’\0’; n++)
;

/* Ostatak funkcije je identican funkciji


za sortiranje celih brojeva. */
for (i = 0; i < n - 1; i++)
{
min = i;
for (j = i + 1; j < n; j++)
if (s[j] < s[min])
min = j;

if (min != i)
{
pom = s[i];
s[i] = s[min];
s[min] = pom;
}
}

52
Milena Vujošević–Janičić 5.5 Razni zadaci

/* Funkcija utvrdjuje da li su reci s i t anagrami.


Za reci kazemo da su anagrami, ako se jedna rec
moze dobiti od druge premestanjem slova u reci */
int anagrami (char *s, char *t)
{
char sp[MAX];
char tp[MAX];

/* Kopiramo stringove (reci) u pomocne nizove sp i tp


zato sto ne zelimo da nasa funkcija promeni originalne
nizove. */
strcpy (sp, s);
strcpy (tp, t);

/* Sortiramo karaktere stringova u pomocnim nizovima */


sortiraj (sp);
sortiraj (tp);

/* Ako su stringovi nakon sortiranja jednaki, tada su polazne reci


bile anagrami */
return strcmp (sp, tp) == 0;
}

/* Test program */
int main ()
{

char s[MAX], t[MAX];

/* Ucitavamo dve reci */


printf ("Uneti prvu rec: ");
scanf ("%s", s);
printf ("Uneti drugu rec: ");
scanf ("%s", t);

/* Utvrdjujemo da li su anagrami i ispisujemo poruku */


if (anagrami (s, t))
printf ("Reci %s i %s su anagrami\n", s, t);
else
printf ("Reci %s i %s nisu anagrami\n", s, t);

53
Milena Vujošević–Janičić 5.5 Razni zadaci

return 0;
}
Primer 5.11 Interpolaciona pretraga se može porediti sa pretragom rečnika:
ako neko traži reč na slovo B, sigurno neće da otvori rečnik na polovini, već verovatno
negde bliže početku.
/* Funkcija trazi u SORTIRANOM nizu a[] duzine n
broj x. Vraca indeks pozicije nadjenog elementa
ili -1, ako element nije pronadjen */
int interpolaciona_pretraga (int a[], int n, int x)
{
int l = 0;
int d = n - 1;
int s;

/* Dokle god je indeks l levo od indeksa d... */


while (l <= d)
{

/* Ako je element manji od pocetnog ili veci od poslednjeg


clana u delu niza a[l],...,a[d] tada nije u tom delu niza.
Ova provera je neophodna, da se ne bi dogodilo da se prilikom
izracunavanja indeksa s izadje izvan opsega indeksa [l,d]
*/
if(x < a[l] || x > a[d])
return -1;
/* U suprotnom, x je izmedju a[l] i a[d], pa ako su a[l] i a[d]
jednaki, tada je jasno da je x jednako ovim vrednostima, pa
vracamo indeks l (ili indeks d, sve jedno je).Ova provera je
neophodna, zato sto bismo inace prilikom izracunavanja s imali
deljenje nulom.
*/
else if(a[l] == a[d])
return l;

/* Indeks s je uvek izmedju l i d, ali ce


verovatno biti blize trazenoj vrednosti nego da
smo prosto uvek uzimali srednji element.*/
/* Racunamo sredisnji indeks */
s = l + ((double)(x - a[l]) / (a[d] - a[l])) * (d - l);

/* Ako je sredisnji element veci od x,


tada se x mora nalaziti u levoj polovini niza */
if (x < a[s])
d = s - 1;

54
Milena Vujošević–Janičić 5.5 Razni zadaci

/* Ako je sredisnji element manji od x,


tada se x mora nalaziti u desnoj polovini niza
*/
else if (x > a[s])
l = s + 1;
else
/* Ako je sredisnji element jednak x,
tada smo pronasli x na poziciji s
*/
return s;
}

/* ako nije pronadjen vracamo -1 */


return -1;
}
Primer 5.12 Data su dva rastuća niza A i B, napisati funkciju koja formira niz C
koji sadrži:
(a) zajedničke elemente nizova A i B (presek skupova A i B).
(b) elemente koje sadrži niz A a ne sadrži niz B (razlika skupova A i B).
(c) sve elemente koje sadrže nizovi A i B (unija skupova A i B) — ovo je ekvivalentno
spajanju dva ured̄ena niza — primer 5.7.
/* Funkcija kreira presek dva rastuca niza a i b i rezultat smesta u
niz c (takodje u rastucem radosledu). Funkcija vraca broj elemenata
preseka */
int kreiraj_presek(int a[], int n_a, int b[], int n_b, int c[])
{
int i = 0, j = 0, k = 0;

/* Dokle god ima elemenata u oba niza... */


while (i < n_a && j < n_b)
{
/* Ako su jednaki, ubacujemo vrednost u presek,
i prelazimo na sledece elemente u oba niza. */
if(a[i] == b[j])
{
c[k++] = a[i];
i++;
j++;
}
/* Ako je element niza a manji, tada u tom nizu prelazimo
na sledeci element */
else if(a[i] < b[j])

55
Milena Vujošević–Janičić 5.5 Razni zadaci

i++;
/* Ako je element niza b manji, tada u tom nizu prelazimo
na sledeci element */
else
j++;
}
/* Vracamo broj elemenata preseka */
return k;

/* Funkcija kreira razliku dva rastuca niza a i b i rezultat smesta u


niz c (takodje u rastucem radosledu). Funkcija vraca broj elemenata
razlike */
int kreiraj_razliku (int a[], int n_a, int b[], int n_b, int c[])
{
int i = 0, j = 0 , k = 0;

/* Sve dok ima elemenata u oba niza...*/


while(i < n_a && j < n_b)
{
/* Ako je tekuci element niza a manji, tada
je on u razlici, jer su svi sledeci elementi
niza b jos veci. Ubacujemo ga u razliku i
prelazimo na sledeci element niza a */
if(a[i] < b[j])
c[k++] = a[i++];
/* Ako je tekuci element niza b manji, tada
prelazimo na sledeci element u nizu b */
else if (a[i] > b[j])
j++;
/* Ako su jednaki, tada ih oba preskacemo. Tekuci
element niza a ocigledno nije u razlici. */
else
{
i++;
j++;
}
}

/* Ako su preostali elementi niza a, tada su oni u razlici


jer su svi elementi niza b bili manji od tekuceg elementa
niza a, i svih koji za njim slede */
while (i < n_a)

56
Milena Vujošević–Janičić 5.5 Razni zadaci

c[k++] = a[i++];

/* Vracamo broj elemenata u razlici */


return k;
}

57
Glava 6

Pokazivaci

Pokazivac je promenljiva koja sadrzi adresu promenljive.


int x=1, y=1;
int *ip; /* ip je pokazivac na int, odnosno *ip je tipa int */

ip = &x; /* ip cuva adresu promenljive x, tj ip pokazuje na x */


y=*ip; /* y dobija vrednost onoga sto se nalazi na adresi koju
cuva promenljiva ip, tj posto ip cuva adresu promenljive
x, a x ima vrednost 1 to je i y sada 1 */
*ip = 0; /* preko pokazivaca njema se sadrzaj na adresi koju cuva ip,
prema tome, x je sada 0 */

*ip+=10; /* x je sada 10*/


++*ip; /* x je sada 11*/
(*ip)++; /* x je sada 12,
zagrada neophodna zbog prioriteta operatora*/
Pored pokazivaca na osnovne tipove, postoji i pokazivac na prazan tip — void.
void *pp;
Njemu moze da se dodeli da pokazuje na int, char, float ili na bilo koji drugi tip
ali je neophodno eksplicitno naglasiti na koji tip ukazuje pokazivac svaki put kada
zelimo da koristimo sadrzaj adrese koju pokazivac cuva.
Primer 6.1 Upotreba pokazivača na prazan tip.
#include<stdio.h>

main()
{
void *pp; /* Ovaj pokazivac moze da pokazuje na adrese
na kojima se nalaze razliciti tipovi
podataka. */
int x=2;

58
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri

char c=’a’;

pp = &x; /* Pokazivac sada sadrzi adresu promenljive tipa int*/


*(int *)pp = 17; /* x postaje 17, kroz pokazivac pp je
promenjena vrednost promenljive x.
Kastovanje (int *) ukazuje na to da se prilikom
citanja vrednosti koja se nalazi na
adresi koju cuva pokazivac pp, ovaj pokazivac
tretira kao pokazivac na tip int */
printf("Adresa od x je %p\n ", &x);
printf("%d i %p\n",*(int*)pp,(int * )pp);

pp = &c; /* Pokazivac sada sadrzi adresu promenljive tipa char*/


printf("Adresa od c je %p\n", &c);
printf("%c i %p\n",*(char*)pp,(char * )pp);
/* Kastovanje (char *) ukazuje na to da se prilikom
citanja vrednosti koja se nalazi na
adresi koju cuva pokazivac pp, ovaj pokazivac
tretira kao pokazivac na tip char */
}

/*
Adresa od x je 0012FF78
17 i 0012FF78
Adresa od c je 0012FF74
a i 0012FF74
*/

Posebna konstanta koja se koristi da se oznaci da pokazivac ne pokazuje na neko


mesto u memoriji je NULL. Ova konstanta je de nisana u biblioteci stdio.h i ima
vrednost 0.

6.1 Pokazivačka aritmetika — primeri


Primer 6.2 Funkcija proverava da li se neka vrednost x nalazi u nizu niz dimenzije
n, bez korišćenja indeksiranja. Funkcija vraća pokazivač na poziciju pronadjenog
elementa ili NULL ukoliko element nije pronad̄en.

#include <stdio.h>

int* nadjiint(int* niz, int n, int x)


{
while (--n >= 0 && *niz != x)
niz++;

59
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri

return (n>=0) ? niz : NULL;


}

main()
{
int a[]={1,2,3,4,5,6,7,8};
int* poz=nadjiint(a,sizeof(a)/sizeof(int),4);

if (poz!=NULL)
printf("Element pronadjen na poziciji %d\n",poz-a);
}

Primer 6.3 Funkcije izračunavaju dužinu niske korišćenjem pokazivača.


int string_length1(char *s)
{
int n;
for(n=0; *s != ’\0’; s++)
n++;
return n;
}

/* Druga varijanta iste funkcije */


int string_length2(char *s)
{
char* t;
for (t = s; *t; t++)
;
return t - s;
}

Primer 6.4 Funkcija kopira string t u string s (podrazumeva se da je za string s


rezervisano dovoljno mesta).
void copy(char* dest, char* src)
{
while (*dest++=*src++)
;
}

/* Ovo je bio skraceni zapis za sledeci kod


while(*src != ’\0’)
{
*dest=*src;
dest++;
src++;

60
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri

}
*dest = ’\0’;
*/
Primer 6.5 Nadovezuje string t na kraj stringa s. Pretpostavlja da u s ima do-
voljno prostora.
void string_concatenate(char *s, char *t)
{
/* Pronalazimo kraj stringa s */
while (*s) /* while (*s != 0)*/
s++;
/* Nakon prethodne petlje, s pokazuje na ’\0’, kopiranje
pocinje od tog mesta, tako da ce znak ’\0’ biti prepisan. */
/* Kopiranje se vrisi slicno funkciji string_copy */
while (*s++ = *t++)
;
}
Primer 6.6 Funkcija strcmp vrši leksikografsko pored̄enje dva stringa. Vraća:
0 — ukoliko su stringovi jednaki
<0 — ukoliko je s leksikografski ispred t
>0 — ukoliko je s leksikografski iza t

int strcmp(char *s, char *t)


{
/* Petlja tece sve dok ne naidjemo
na prvi razliciti karakter */
for (; *s == *t; s++, t++)
if (*s == ’\0’) /* Naisli smo na kraj
oba stringa, a nismo nasli razliku */
return 0;

/* *s i *t su prvi karakteri u kojima se niske


razlikuju. Na osnovu njihovog odnosa,
odredjuje se odnos stringova */

return *s - *t;
}
Primer 6.7 Pronalazi prvu poziciju karaktera c u stringu s, i vraća pokazivač na
nju, odnosno NULL ukoliko s ne sadrži c.
char* string_char(char *s, char c)
{

61
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri

int i;
for (; *s; s++)
if (*s == c)
return s;

/* Nije nadjeno */
return NULL;
}

Primer 6.8 Pronalazi poslednju poziciju karaktera c u stringu s, i vraća pokazivač


na nju, odnosno NULL ukoliko s ne sadrži c.
char* string_last_char(char *s, char c)
{
char *t = s;
/* Pronalazimo kraj stringa s */
while (*t)
t++;

/* Krecemo od kraja i trazimo c unazad */


for (t--; t >= s; t--)
if (*t == c)
return t;

/* Nije nadjeno */
return NULL;
}

Primer 6.9 Za svaku liniju ucitanu sa ulaza proverava se da li sadrži reč zdravo.
#include <stdio.h>

/* Proverava da li se niska t nalazi unutar niske s


Vraca poziciju na kojoj string pocinje odnosno
-1 ukoliko niska t nije podniska niske s. */
int sadrzi_string(char s[], char t[])
{
int i;
for (i = 0; s[i]; i++)
{
int j;
for (j=0, k=0; s[i+j]==t[j]; j++)
if (t[j+1]==’\0’)
return i;
}
return -1;

62
Milena Vujošević–Janičić 6.1 Pokazivačka aritmetika — primeri

/* Proverava da li string str sadrzi string sub.


Vraca pokazivac na kojoj sub pocinje,
odnosno NULL ukoliko ga nema. */
char* string_string(char *str, char *sub)
{
char *s, *t;

/* Proveravamo da li sub pocinje na svakoj poziciji i */


for (; *str; str++)
/* Poredimo sub sa str pocevsi od pozicije na koju ukazuje
str sve dok ne naidjemo na razliku */
for (s = str, t = sub; *s == *t; s++, t++)
/* Nismo naisli na razliku a ispitali smo sve
karaktere niske sub */
if (*(t+1) == ’\0’)
return str;

/* Nije nadjeno */
return NULL;
}

/* Cita liniju sa stadnardnog ulaza i vraca njenu duzinu */


int getline(char* line, int max)
{
char *s=line;
int c;
while ( max-->0 && (c=getchar())!=’\n’ && c!=EOF)
*s++ = c; /* ekvivalentno sa *s=c; s++; */

if (c==’\n’)
*s++ = c;

*s = ’\0’;
return s - line;
}

main()
{
char rec[]="zdravo";
char linija[100];
while (getline(linija, 100))
if (sadrzi_string_pok(linija, rec))

63
Milena Vujošević–Janičić 6.2 Niska karaktera i pokazivač na konstantnu nisku

printf("%s",linija);
}

6.2 Niska karaktera i pokazivač na konstantnu nisku


Prilikom deklaracije treba praviti razliku izmed̄u niza znakova i pokazivaca na kon-
stantnu nisku. Ukoliko su date deklaracije:
char poruka[]="danas je lep dan!";
char *pporuka = "danas je lep dan!";
tada vazi:
 poruka je niz znakova koji sadrzi tekst danas je lep dan!. Pojedine znake
moguce je promeniti, na primer, nakon naredbe
poruka[0] = ’D’;
poruka ce sadrzati tekst Danas je lep dan!. Niska poruka se uvek odnosi na
novo mesto u memoriji.
 pporuka je pokazivac, koji je inicijalizovan da pokazuje na konstantnu nisku,
on moze biti preusmeren da pokazuje na nesto drugo, na primer, moguce je
preusmeriti ovaj pokazivac sledecom naredbom
pporuka = poruka;
i u ovom slucaju ce pokazivac pporuka pokazivati na mesto u memoriji na
kojem se nalazi poruka. Pokusaj modi kacije elementa niske karaktera na koju
ukazuje pporuka nije de nisan (jer je to konstantna niska). Na primer, rezultat
naredbe pporuka[0]=’D’ je nede nisan.
Ako deklarisemo
char *pporuka1 = "danas je lep dan!";
char *pporuka2 = "danas je lep dan!";
char *pporuka3 = "danas pada kisa";
tada ce pokazivaci pporuka1 i pporuka2 pokazivati na isto mesto u memoriji, a
pporuka3 na drugo mesto u memoriji.
Ako uporedimo
(pporuka1==pporuka3)
uporedice se vrednosti pokazivaca. Ako uporedimo
(pporuka1 < pporuka2)
uporedice se vrednosti pokazivaca. Ako dodelimo
pporuka1=pporuka3
tada ce pporuka1 dobiti vrednost pokazivaca pporuka3 i pokazivace na isto mesto
u memoriji. Nece se izvrsiti kopiranje sadrzaja memorije.
Primer 6.10 Nakon deklaracije
char a[] = "informatika";
char *p = "informatika";

64
Milena Vujošević–Janičić 6.3 Pokazivači na pokazivače

 Loliko elemenata ima niz a?


 Koju vrednost ima a?
 Da li se može promeniti vrednost a?
 Koju vrednost ima a[0]?
 Da li se može promeniti vrednost a[0]?
 Koju vrednost ima p?
 Da li se može promeniti vrednost p?
 Koju vrednost ima p[0]?
 Da li se može promeniti vrednost p[0]?

6.3 Pokazivači na pokazivače


Pokazivacke promenljive su podaci kao i svi drugi, pa samim tim imaju svoju adresu
u memoriji. Zbog toga je moguce govoriti o pokazivacima na pokazivace. Na primer,
ako je de nisan pokazivac na int:
int *p;
tada mozemo de nisati pokazivac na pokazivac na int:
int **pp;
Ovaj pokazivac moze uzeti adresu pokazivacke promenljive p:
pp = &p;
Nakon toga se pokazivackoj promenljivoj p moze pristupiti i indirektno, preko pokazivaca
na pokazivac pp, zato sto je *pp ekvivalentno sa p. Takod̄e, celom broju na koji
pokazuje p moze se pristupiti i sa **pp zato sto je **pp ekvivalentno sa *p.

6.4 Nizovi pokazivača


Elementi nizova mogu biti bilo kog tipa, pa i pokazivaci. Na primer, niz pokazivaca
na karaktere se moze de nisati na sledeci nacin:
char * pokazivaci[100];
Ovim se rezervise prostor za niz od 100 pokazivaca na karaktere. Njima se pris-
tupa putem indeksa, kako je i uobicajeno. S obzirom da se ime niza uvek ponasa
kao adresa prvog objekta u nizu, sledi da je izraz pokazivaci tipa ”pokazivac na
pokazivac na char”. Otuda se uobicajena pokazivacka aritmetika moze primenjivati
i na nizove pokazivaca.

65
Milena Vujošević–Janičić 6.4 Nizovi pokazivača

Primer 6.11 Program ucitava linije iz fajla ulaz.txt i zatim ih ispisuje na stan-
dardnom izlazu sortirane po dužini, počev od najkraće linije.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define MAX_RED 1024


#define MAX_REDOVA 1024

/* Funkcija sortira niz pokazivaca na karaktere, pri cemu


je kriterijum sortiranja duzina stringova na koje pokazuju
ti pokazivaci. */
void sortiraj(char *redovi[], int n);

int main()
{
char redovi[MAX_REDOVA][MAX_RED];
char *p_redovi[MAX_REDOVA];

int i, n;
FILE * in;

/* Otvaramo fajl */
in = fopen("ulaz.txt", "r");

/* Proveravamo da li smo uspesno otvorili fajl */


if(in == NULL)
{
printf("Greska! Fajl nije uspesno otvoren!\n");
exit(1);
}

/* Citamo linije, i smestamo ih u dvodimenzioni niz karaktera redovi[] (i-tu


liniju smestamo u niz redovi[i]). Citamo najvise MAX_REDOVA. Pokazivac
p_redovi[i] postavljamo da pokazuje na prvi karakter u nizu redovi[i]. */
for(i = 0; i < MAX_REDOVA; i++)
if(fgets(redovi[i], MAX_RED, in) != NULL)
p_redovi[i] = redovi[i];
else
break;

n = i;

66
Milena Vujošević–Janičić 6.4 Nizovi pokazivača

/* Zatavaramo fajl */
fclose(in);

/* NAPOMENA: Umesto da sortiramo niz nizova, sto podrazumeva zamenu


vrednosti citavih nizova, efikasnije je da definisemo niz pokazivaca
na karaktere koje cemo da usmerimo najpre na odgovarajuce stringove
koji se nalaze u nizu nizova redovi[] (Pokazivac p_redovi[i] se
se usmerava na string u nizu redovi[i]). Nakon toga se sortira niz
pokazivaca, tj. pokazivaci se ispremestaju tako da redom pokazuju
na stringove po rastucim duzinama. Ovim je sortiranje bitno efikasnije
jer je brze razmeniti dva pokazivaca nego citave nizove. */

/* Sortiramo niz pokazivaca */


sortiraj(p_redovi, n);

/* Prikazujemo linije u poretku rasta duzina */


for(i = 0; i < n; i++)
fputs(p_redovi[i], stdout);

return 0;
}

/* Funkcija razmenjuje vrednosti dva pokazivaca na karaktere.


S obzirom da je potrebno preneti adrese ovih promenljivih,
parametri su tipa "pokazivac na pokazivac na char". */
void razmeni(char **s, char **t)
{
char *p;

p = *s;
*s = *t;
*t = p;
}

/* Funkcija implementira uobicajeni algoritam sortiranja izborom


najmanjeg elementa, pri cemu se pod najmanjim elementom ovde
podrazumeva pokazivac koji pokazuje na string koji je najkraci */
void sortiraj(char *redovi[], int n)
{

int i,j, min;

67
Milena Vujošević–Janičić 6.4 Nizovi pokazivača

for(i = 0; i < n - 1; i++)


{
min = i;
for(j = i + 1; j < n; j++)
if(strlen(redovi[j]) < strlen(redovi[min]))
min = j;

if(min != i)
{
razmeni(&redovi[min], &redovi[i]);
}
}
}

68
Glava 7

Rekurzija

Funkcija1 moze da poziva samu sebe, neposredno ili posredno. Ova pojava se zove
rekurzija. Ovakav pristup se cesto koristi prilikom resavanja problema koji imaju
prirodnu rekurzivnu de niciju, tj. kod kojih se problem dimenzije n moze jednos-
tavno svesti na problem dimenzije n-1 ili neke druge manje dimenzije. Rekurzija je
analogna matematickoj indukciji.
Ono sto je potencijalni problem kod razumevanja rekurzije je to sto se u jednom
trenutku mogu izvrsavati vise poziva jedne iste funkcije. Na primer, ako funkcija
f() prilikom svog izvrsavanja pozove samu sebe, tada se zapocinje novi poziv iste
funkcije. Prethodni poziv ceka da se zavrsi tekuci, a zatim nastavlja sa radom. Poziv
rekurzivne funkcije koji je zapocet, a cije izvrsavanje jos nije zavrseno nazivamo
aktivni poziv. Svaki poziv funkcije izvrsava se nezavisno od svih ostalih aktivnih
poziva u tom trenutku, zahvaljujuci cinjenici da svaki od aktivnih poziva ima svoje
sopostvene kopije formalnih parametara i lokalnih podataka. Kada se neki od poziva
zavrsi, njegove kopije nestaju iz memorije, ali kopije ostalih poziva i dalje postoje u
memoriji. Posledica ovog pristupa je da kada rekurzivna funkcija promeni vrednosti
svojih lokalnih podataka, ove promene ne uticu na ostale aktivne pozive, zato sto
oni imaju svoje lokalne kopije istih podataka.
Kreiranje i odrzavanje lokalnih kopija se jednostavno i e kasno ostvaruje zah-
valjujuci tome sto su parametri funkcije i lokalne nestaticke promenljive smestene
na sistemskom steku — u pitanju je struktura podataka u kojoj se novi podaci uvek
smestaju na vrh a prilikom uklanjanja podataka takodje se uklanja podatak sa vrha,
tj. podatak koji je poslednji dodat (LIFO struktura — last in, rst out). Prilikom
pozivanja bilo koje funkcije najpre se na stek smeste njeni argumenti (one vrednosti
koje su predate prilikom poziva) a zatim se na vrh steka smeste i lokalne promenljive.
Nakon toga se zapocne izvrsavanje tela funkcije. Ako se tom prilikom pozove neka
druga funkcija (ili ta ista, ako je rekurzija u pitanju) tada se na vrh steka dodaju
argumenti ovog poziva, kao i lokalne promenljive te funkcije, itd. Kada se funkci-
jski poziv zavrsi, tada se sa vrha steka skidaju njegove lokalne promenljive, kao i
parametri poziva, nakon cega na vrhu steka ostaju lokalne promenljive prethodnog
poziva itd.
1 Tekst preuzet sa www.matf.bg.ac.rs/m̃ilan

69
Milena Vujošević–Janičić 7.1 Osnovni primeri

Lokalni staticki podaci (promenljive deklarisane kao static unutar funkcije) se


ne kreiraju na steku, vec u statickoj zoni memorije, i zajednicki su za sve pozive.
Zato se promene vrednosti ovih promenljivih u jednom pozivu vide i iz drugih ak-
tivnih poziva iste funkcije. Zato treba biti oprezan prilikom koriscenja statickih
promenljivih u rekurzivnim funkcijama (obicno se to i ne radi).
Svaka rekurzivna funkcija mora imati izlaz iz rekurzije kao i rekurzivni poziv
kojim se problem svodi na problem nizeg reda. Izlaz iz rekurzije je najcesce jednos-
tavan, ali ne mora uvek da bude tako.

7.1 Osnovni primeri


Primer 7.1 Računanje faktorijela prirodnog broja.
#include<stdio.h>

unsigned long faktorijel_iterativno(int n)


{
long f = 1;
int i;
for (i = 1; i<=n; i++)
f *= i;
return f;
}

unsigned long faktorijel(int n)


{
if(n==0)
return 1;
else
return n*faktorijel(n-1);

/* Alternativni zapis:
return n == 0 ? 1 : n*faktorijel(n-1); */

main()
{
int n;
unsigned long f;

printf("Unesite n\n");
scanf("%d", &n);

f = faktorijel(n);

70
Milena Vujošević–Janičić 7.1 Osnovni primeri

printf("f = %d\n",f);
}

Primer 7.2 Računanje sume prvih n prirodnih brojeva.


#include<stdio.h>
unsigned suma(unsigned n)
{
if(n==0)
return 0;
else
return (n + suma(n-1));

/* Najefikasniji nacin za resavanje ovog problema je


return (n*(n+1))/2; */
}

main()
{
int s,n;
printf("Unesite n\n");
scanf("%d", &n);
s = suma(n);
printf("s = %d\n",s);
}

Primer 7.3 Iterativna i rekurzivna varijanta računanja sume niza.


int suma_niza_iterativno(int a[], int n)
{
int suma = 0;
int i;
for (i = 0; i<n; i++)
suma+=a[i];
return suma;
}

int suma_niza(int a[], int n)


{
if (n == 1)
return a[0];
else
return suma_niza(a,n-1) + a[n-1];

/* Skracen zapis je:

71
Milena Vujošević–Janičić 7.1 Osnovni primeri

return n == 1 ? a[0] : suma_niza(a,n-1) + a[n-1];*/


}
Primer 7.4 Štampanje celog broja.
#include<stdio.h>
void printb(long int n)
{
if(n<0)
{
putchar(’-’);
n=-n;
}
if(n>=10)
printb(n/10);
putchar(n % 10 + ’0’);
}

int main()
{
long int b=-1234;
printb(b);
putchar(’\n’);
return 0;
}
Kad funkcija rekurzivno pozove sebe, svakim pozivom pojavljuje se novi skup svih
automatskih promenljivih, koji je nezavisan od prethodonog skupa. Prva funkcija
printb kao argument dobija broj -12345, ona prenosi 1234 u drugu printb funkciju,
koja dalje prenosi 123 u treću, i tako redom do poslednje koja prima 1 kao argument.
Ta funkcija štampa 1 i završava sa radom tako da se vraća na prethodni nivo, na
kome se štampa dva i tako redom.
Primer 7.5 Stepenovanje prirodnog broja
 iterativno
 rekurzivno, koristeći činjenicu da je xk = x · xk−1 i x0 = 1
k k 1
 rekurzivno, koristeći činjenicu da je xk = (x2 ) 2 ako je k parno ili xk = x(x2 ) 2

ako je k neparno, i x0 = 1 i x1 = x.
#include <stdio.h>

/* Iterativna verzija prethodne funkcije */


int stepen_iterativno(int x, int k)
{
int i;

72
Milena Vujošević–Janičić 7.1 Osnovni primeri

int s = 1;
for (i = 0; i<k; i++)
s*=x;
return s;
}

int stepen(int x, int k)


{
printf("Racunam stepen(%d, %d)\n",x,k); /* Ilustracije radi! */

if (k == 0)
return 1;
else
return x*stepen(x, k-1);

/* Krace se moze zapisati na sledeci nacin


return k==0 ? 1 : x*stepen(x, k-1); */
}

/* Efikasnija verzija rekurzivne funkcije. */


int stepen2(int x, int k)
{
printf("Racunam stepen2(%d, %d)\n",x,k); /* Ilustracije radi! */
if (k == 0)
return 1;
else
if (k == 1)
return x;
else
/* Ako je stepen paran*/
if((k%2)==0)
return stepen2(x*x, k/2);
else
return x * stepen2(x*x, k/2);
}

/* Alternativna funkcija stepen2


int stepen2(int n, int k)
{
int p, s;
if (k == 0) s = 1;
else
if (k == 1) s = n;
else

73
Milena Vujošević–Janičić 7.1 Osnovni primeri

{
p = stepen(n, k/2);
if(k%2 == 0) s = p*p;
else s = p*p*n;
}
return s;
}
*/

main()
{
printf("Stepen je: %d\n", stepen(2, 8));
printf("------------------\n");
printf("Stepen je: %d\n", stepen2(2, 8));
}
/* Izlaz iz programa:
Racunam stepen(2, 8)
Racunam stepen(2, 7)
Racunam stepen(2, 6)
Racunam stepen(2, 5)
Racunam stepen(2, 4)
Racunam stepen(2, 3)
Racunam stepen(2, 2)
Racunam stepen(2, 1)
Racunam stepen(2, 0)
Stepen je: 256
------------------
Racunam stepen2(2, 8)
Racunam stepen2(4, 4)
Racunam stepen2(16, 2)
Racunam stepen2(256, 1)
Stepen je: 256
*/
Primer 7.6 Fibonačijevi brojevi se definišu rekurentno na sledeći način:
f(0) = 1, f(1) = 1, f(n) = f(n-1) + f(n-2)
Napisati funkciju koja izračunava n-ti Fibonačijev broj.
#include <stdio.h>
#include <stdlib.h>

/* Rekurzivna implementacija - obratiti paznju na neefikasnost funkcije */


int Fib(int n)
{
printf("Racunam Fib(%d)\n",n); /* Ilustracije radi! */

74
Milena Vujošević–Janičić 7.1 Osnovni primeri

if((n==0)||(n==1))
return 1;
else
return(Fib(n-1)+Fib(n-2));

/* Alternativni zapis:
return (n == 0 || n == 1) ? 1 : Fib(n-1) + Fib(n-2); */
}

/* Iterativna verzija bez niza */


int Fib_iterativno(int n)
{
/* Promenljiva pp cuva pretposlednji, a p poslednji element niza */
int pp = 1, p = 1;
int i;
for (i = 0; i <= n-2; i++)
{
int pom = pp;
pp = p;
p = p + pom;
}
return p;
}
main()
{
printf("Fib(5) = %d\n", Fib(5));
}
/*
Izlaz iz programa:
Racunam Fib(5)
Racunam Fib(4)
Racunam Fib(3)
Racunam Fib(2)
Racunam Fib(1)
Racunam Fib(0)
Racunam Fib(1)
Racunam Fib(2)
Racunam Fib(1)
Racunam Fib(0)
Racunam Fib(3)
Racunam Fib(2)
Racunam Fib(1)
Racunam Fib(0)

75
Milena Vujošević–Janičić 7.1 Osnovni primeri

Racunam Fib(1)
Fib(5) = 8

Kako se izvrsava program za vrednost 5:


_______________________________________________________________

Fib(5)?
=> 8 = 5+3
/ \
/ \
/ \
Fib(4)? Fib(3)?
=> 5=3+2 => 3=2+1
/ \ / \
Fib(3)? Fib(2)? Fib(2)? Fib(1)?
=> 3=2+1 => 2=1+1 => 2=1+1 |
/ \ / \ / \ 1
Fib(2)? Fib(1) Fib(1) Fib(0) Fib(1) Fib(0)
=> 2=1+1 | | | | |
/ \ 1 1 1 1 1
Fib(1) Fib(0)
| |
1 1
_______________________________________________________________

*/
Primer 7.7 U slučaju da se rekurzijom problem svodi na više manjih podproblema
koji se mogu preklapati, postoji opasnost da se pojedini podproblemi manjih dimenz-
ija rešavaju veći broj puta. Na primer,
fibonacci(20) = fibonacci(19) + fibonacci(18)
fibonacci(19) = fibonacci(18) + fibonacci(17)
tj. problem fibonacci(18) se resava dva puta. Problemi manjih dimenzija će se
rešavati još veći broj puta. Rešenje za ovaj problem je kombinacija rekurzije sa tzv.
”dinamičkim programiranjem” – podproblemi se rešavaju samo jednom, a njihova
rešenja se pamte u memoriji (obično u nizovima ili matricama), odakle se koriste
ako tokom rešavanja ponovo budu potrebni.
#include <stdio.h>
#include <stdlib.h>

#define MAX 50

/* Niz koji cuva resenja podproblema. */


int f[MAX];

76
Milena Vujošević–Janičić 7.1 Osnovni primeri

/* Funkcija izracunava n-ti fibonacijev broj */


int fibonacci(int n)
{

/* Ako je podproblem vec resen, uzimamo gotovo resenje! */


if(f[n] != 0)
return f[n];

/* Izlaz iz rekurzije */
if(n < 2)
return f[n] = 1;
else
/* Rekurzivni pozivi */
return f[n] = fibonacci(n - 1) + fibonacci(n - 2);
}

/* Test program */
int main()
{
int n, i;

/*Inicijalizuje se niz*/
for(i=0; i<MAX; i++)
f[i] = 0;

scanf("%d", &n);
printf("%d\n", fibonacci(n));

return 0;
}

Primer 7.8 Program rešava problem tzv. ”hanojskih kula”: data su tri vertikalna
štapa, na jednom se nalazi n diskova poluprečnika 1,2,3,... do n, tako da se najveći
nalazi na dnu, a najmanji na vrhu. Ostala dva štapa su prazna. Potrebno je pre-
mestiti diskove na drugi štap tako da budu u istom redosledu, premeštajući jedan po
jedan disk, pri čemu se ni u jednom trenutku ne sme staviti veći disk preko manjeg.

77
Milena Vujošević–Janičić 7.1 Osnovni primeri

/*
| | |
=== | |
===== | |
======= | |
========= | |
----------- ----------- -----------
X Y Z
===>
...
| | |
| | |
| | ===
| | =====
========= | =======
----------- ----------- -----------
X Y Z
...
===>

| | |
| === |
| ===== |
| ======= |
| ========= |
----------- ----------- -----------
X Y Z
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_TOWER 100


#define MAX_NAME 64

/* Stuktura definise jednu hanojsku kulu */


typedef struct {
int s[MAX_TOWER]; /* Stap sa diskovima */
int n; /* Broj diskova na stapu */
char name[MAX_NAME]; /* Naziv kule */
} Tower;

/* Funkcija postavlja naziv kule na dato ime, a zatim na stap postavlja

78
Milena Vujošević–Janičić 7.1 Osnovni primeri

diskove velicine n, n-1, ..., 2, 1 redom */


void init_tower(Tower * tower, char * name, int n)
{
int i;
strcpy(tower->name, name);
tower->n = n;
for(i = 0; i < n; i++)
tower->s[i] = n - i;
}

/* Funkcija prikazuje sadrzaj na datoj kuli */


void print_tower(Tower * tower)
{
int i;

printf("%s: ", tower->name);


for(i = 0; i < tower->n; i++)
printf("%d ", tower->s[i]);
putchar(’\n’);
}

/* Funkcija premesta jedan disk sa vrha prve kule na vrh druge kule */
void move(Tower *from, Tower * to)
{
/* Proveravamo da li je potez ispravan */
if(from->n == 0 || (to->n > 0 && from->s[from->n - 1] >= to->s[to->n - 1]))
{

printf("Ilegal move: %d from %s to %s!!\n",


from->s[from->n - 1],
from->name,
to->name );
exit(1);
}
else
{
/* Prikaz opisa poteza */
printf("Moving disc %d from %s to %s\n",
from->s[from->n - 1],
from->name,
to->name);

/* Premestanje diska */
to->s[to->n++] = from->s[--from->n];

79
Milena Vujošević–Janičić 7.1 Osnovni primeri

}
}

/* Rekurzivna funkcija koja premesta n diska sa kule x na kulu y. Kao


pomocna kula koristi se kula z. */
void hanoi(Tower *x, Tower *y, Tower * z, int n)
{
/* Izlaz iz rekurzije */
if(n == 0)
return;

/* Rekurzivno premestamo n - 1 disk sa x na z, pomocu kule y */


hanoi(x, z, y, n - 1);

/* Premestamo jedan disk sa x na y */


move(x,y);

/* Prikaz stanja kula nakon poteza */


print_tower(x);
print_tower(y);
print_tower(z);

/* Premestamo n - 1 disk sa z na y, pomocu kule x */


hanoi(z, y, x, n - 1);
}

/* Test program */
int main()
{
Tower x, y, z;
int n;

/* Ucitavamo dimenziju problema */


scanf("%d", &n);

/* Inicijalizujemo kule. Kula x ima n diskova, ostale su prazne */


init_tower(&x, "X", n);
init_tower(&y, "Y", 0);
init_tower(&z, "Z", 0);

/* Prikaz kula na pocetku */


print_tower(&x);
print_tower(&y);

80
Milena Vujošević–Janičić 7.2 Binarna pretraga

print_tower(&z);

/* Poziv funkcije hanoi() */


hanoi(&x, &y, &z, n);

return 0;
}

7.2 Binarna pretraga


Primer 7.9 Rekurzivna varijanta algoritma binarne pretrage.
#include <stdio.h>

/* Funkcija proverava da li se element x javlja unutar niza


celih brojeva a.
Funkcija vraca poziciju na kojoj je element nadjen odnosno
-1 ako ga nema.

!!!!! VAZNO !!!!!


Pretpostavka je da je niz a uredjen po velicini
*/

int binary_search(int a[], int l, int d, int x)


{
/* Ukoliko je interval prazan, elementa nema */
if (l > d)
return -1;

/* Srednja pozicija intervala [l, d] */


int s = (l+d)/2;

/* Ispitujemo odnos x-a i srednjeg elementa */


if (x == a[s])
/* Element je pronadjen */
return s;
else if (x < a[s])
/* Pretrazujemo interval [l, s-1] */
return binary_search(a, l, s-1, x);
else
/* Pretrazujemo interval [s+1, d] */
return binary_search(a, s+1, d, x);
}

main()

81
Milena Vujošević–Janičić 7.3 MergeSort algoritam

{
int a[] = {3, 5, 7, 9, 11, 13, 15};
int x;
int i;

printf("Unesi element kojega trazimo : ");


scanf("%d",&x);
i = binary_search(a, 0, sizeof(a)/sizeof(int)-1, x);

if (i==-1)
printf("Elementa %d nema\n", x);
else
printf("Pronadjen na poziciji %d\n", i);
}

7.3 MergeSort algoritam


Primer 7.10 Sortiranje niza celih brojeva učešljavanjem - MergeSort algoritam.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100

/* sortiranje ucesljavanjem */
void merge_sort (int a[], int l, int d)
{
int s;
int b[MAX]; /* pomocni niz */
int i, j, k;

/* Izlaz iz rekurzije */
if (l >= d)
return;

/* Odredjujemo sredisnji indeks */


s = (l + d) / 2;

/* rekurzivni pozivi */
merge_sort (a, l, s);
merge_sort (a, s + 1, d);

/* Inicijalizacija indeksa. Indeks i prolazi


krozi levu polovinu niza, dok indeks j

82
Milena Vujošević–Janičić 7.3 MergeSort algoritam

prolazi kroz desnu polovinu niza. Indeks


k prolazi kroz pomocni niz b[] */
i = l;
j = s + 1;
k = 0;

/* "ucesljavanje" koriscenjem pomocnog niza b[] */


while(i <= s && j <= d)
{
if(a[i] < a[j])
b[k++] = a[i++];
else
b[k++] = a[j++];
}

while(i <= s)
b[k++] = a[i++];

while(j <= d)
b[k++] = a[j++];

/* prepisujemo "ucesljani" niz u originalni niz */


for (k = 0, i = l; i <= d; i++, k++)
a[i] = b[k];
}

/* Test program */
int main(int argc, char ** argv)
{
int a[MAX];
int n, i;
int x;

/* Niz brojeva se zadaje na komandnoj liniji */


for(n = 0; n + 1 < argc && n < MAX; n++)
a[n] = atoi(argv[n + 1]);

/* Poziv funkcije */
merge_sort(a, 0, n - 1);

/* Prikaz niza */
for(i = 0; i < n; i++)
printf("%d ", a[i]);

83
Milena Vujošević–Janičić 7.4 QuickSort algoritam

putchar(’\n’);

return 0;
}

7.4 QuickSort algoritam


Primer 7.11 Sortiranje niza celih brojeva - QuickSort algoritam.
/* Funkcija menja mesto i-tom i j-tom elementu niza a */
void swap(int a[], int i, int j)
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}

/* Funkcija particionise interval [l, r] niza a, tako da levo od pivota


budu svi elementi manji od njega, a desno svi veci od njega.
Ovi podnizovi ne moraju biti sortirani.
Funkcija vraca poziciju pivota.
*/
int partition(int a[], int l, int r)
{
int last, i;

/* Srednji element uzimamo za pivot i postavljamo ga na pocetak */


swap(a, l, (l + r)/2);

/* Niz organizujemo tako da pivot postavimo na pocetak, zatim da iza


njega budu svi elementi manji od njega, pa zatim svi elementi koji
su veci od njega tj.
pivot < < < < > > > >
*/

/* last je pozicija poslednjeg elementa niza za koji znamo da je


manji od pivota. U pocetku takvih elemenata nema */
last = l;
for (i = l+1; i <= r; i++)
/* Ukoliko je element na poziciji i manji od pivota,
postavljamo ga iza niza elemenata manjih od pivota,
menjajuci mu mesto sa prvim sledecim */
if (a[i] < a[l])
swap(a, ++last, i);

84
Milena Vujošević–Janičić 7.4 QuickSort algoritam

/* Zahtevanu konfiguraciju < < < < pivot > > > > dobijamo tako
sto zamenimo mesto pivotu i poslednjem elementu manjem od njega */
swap(a, l, last);

/* Pivot se sada nalazi na poziciji last */


return last;
}

/* Funkcija sortira deo niza brojeva a izmedju pozicija l i r*/


void quick_sort(int a[], int l, int r)
{
int i, last;

/* Ukoliko je interval [l, r] prazan nema nista da se radi */


if (l >= r)
return;

/* Particionisemo interval [l, r] */


int pivot = partition(a, l, r);

/* Rekurzivno sortiramo elemente manje od pivota */


quick_sort(a, l, pivot-1);
/* Rekurzivno sortiramo elemente vece pivota */
quick_sort(a, pivot+1, r);
}

main()
{
int a[] = {5, 8, 2, 4, 1, 9, 3, 7, 6};
int n = sizeof(a)/sizeof(int);
int i;

quick_sort(a, 0, n-1);

for (i = 0; i < n; i++)


printf("%d ", a[i]);
printf("\n");
}

85
Glava 8

Pokazivaci na funkcije

Binarne instrukcije koje cine funkciju su takod̄e negde u memoriji, i imaju svoju
adresu. Zato je moguce je de nisati pokazivac na funkciju. Na primer, deklaracija:
int (*fp)(int);
de nise promenljivu f, koja je tipa ”pokazivac na funkciju koja prihvata argument
tipa int, i vraca vrednost tipa int”. Ova promenljiva sadrzi adresu neke funkcije
tog tipa. Na primer, ako je deklarisana funkcija:
int f(int a);
Tada je moguce dodeliti:
fp = &f; /* Operator adrese nije neophodan. */
Promenljiva fp sadrzi adresu funkcije f. Funkcija f se sada moze pozivati derefer-
enciranjem pokazivaca fp:
(*fp)(3);
Zagrade oko izraza *fp su neophodne zbog prioriteta operatora. Dereferenciranjem
pokazivaca na funkciju dobija se funkcija, koja se onda poziva na uobicajen nacin.

Primer 8.1 Program demonstrira upotrebu pokazivača na funkcije.


#include <stdio.h>

int kvadrat(int n)
{
return n*n;
}

int kub(int n)
{
return n*n*n;
}

86
Milena Vujošević–Janičić Pokazivači na funkcije

int parni_broj(int n)
{
return 2*n;
}

/* Funkcija izracunava sumu brojeva f(i) za i iz intervala [1, n].


int (*f) (int) u argumentu funkcije sumiraj je pokazivac
na funkciju sa imenom f, koja kao argument prima promenljivu
tipa int i vraca kao rezultat vrednost tipa int
*/
int sumiraj(int (*f) (int), int n)
{
int i, suma=0;
for (i=1; i<=n; i++)
suma += (*f)(i);

return suma;
}

main()
{

/* U pozivu funkcije sumiraj, imena funkcija kvadrat, kub i parni_broj su


zapravo istovremneo i adrese funkcija pa operator & nije neophodan
ali nije greska ukoliko se se operator & ipak koristi ispred
imena funkcije. */

printf("Suma kvadrata brojeva od jedan do 3 je %d\n", sumiraj(kvadrat,3));


printf("Suma kubova brojeva od jedan do 3 je %d\n", sumiraj(kub,3));
printf("Suma prvih pet parnih brojeva je %d\n", sumiraj(parni_broj,5));

/* Ili:
printf("Suma kvadrata brojeva od jedan do 3 je %d\n", sumiraj(&kvadrat,3));
printf("Suma kubova brojeva od jedan do 3 je %d\n", sumiraj(&kub,3));
printf("Suma prvih pet parnih brojeva je %d\n", sumiraj(&parni_broj,5));
*/
}
/*Izlaz:
Suma kvadrata brojeva od jedan do 3 je 14
Suma kubova brojeva od jedan do 3 je 36
Suma prvih pet parnih brojeva je 30
*/

Primer 8.2 Program tabelarno ispisuje vrednosti raznih matematičkih funkcija u

87
Milena Vujošević–Janičić Pokazivači na funkcije

tačkama datog intervala sa datim korakom.


#include <stdio.h>
#include <math.h>

/*
Zaglavlje math.h sadrzi deklaracije razih matematickih funkcija. Izmedju
ostalog, to su sledece funkcije:
double sin(double x);
double cos(double x);
double tan(double x);
double asin(double x);
double acos(double x);
double atan(double x);
double atan2(double y, double x);
double sinh(double x);
double cosh(double x);
double tanh(double x);
double exp(double x);
double log(double x);
double log10(double x);
double pow(double x, double y);
double sqrt(double x);
double ceil(double x);
double floor(double x);
double fabs(double x);
*/

/* Funkcija tabeliraj() prihvata granice intervala a i b, korak h, kao i


pokazivac f koji pokazuje na funkciju koja prihvata double argument, i
vraca double rezultat. Za tako datu funkciju ispisuje njene vrednosti u
intervalu [a,b] sa korakom h */

void tabeliraj(double a, double b, double h, double (*f)(double))


{
double x;

printf("-----------------------\n");
for(x = a; x <= b; x+=h)
printf("| %8.3f | %8.3f |\n", x, (*f)(x));
printf("-----------------------\n");

88
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke

/* Funkcija main */
int main()
{
double a, b, h;

/* Unosimo granice intervala */


printf("Uneti granice intervala: ");
scanf("%lf%lf", &a, &b);

/* Unosimo korak */
printf("Uneti korak: ");
scanf("%lf", &h);

/* Testiramo funkciju tabeliraj() za sin(), cos() i exp() */


printf("sin(x)\n");
tabeliraj(a, b, h, &sin);
printf("cos(x)\n");
tabeliraj(a, b, h, &cos);
printf("exp(x)\n");
tabeliraj(a, b, h, &exp);

return 0;
}

8.1 Funkcija qsort iz standardne biblioteke


Prototip funkcije qsort iz stdlib.h je:
void qsort(void *niz, int duzina_niza, int velicina_elementa_niza,
int (*poredi)(const void*, const void*) )
Ova funkcija sortira niz
niz[0], niz[1], ..., niz[duzina_niza - 1]
elemenata velicine velicina_elementa_niza koriscenjem funkcije poredi koja upored̄uje
dva elementa niza.
Posto je void* tip niza niz to obezbed̄uje mogucnost koriscenja ove funkcije za
nizove razlicitih tipova podataka. Da bi funkcija qsort znala sa kakvim elementima
barata, potrebno joj je proslediti i velicinu jednog elementa u nizu (ovo je kljucno
za korak u kome se vrisi razmena elemenata niza — funkcija qsort mora da zna
koliko bajtova zauzima jedan element niza kako bi mogla adekvatno da vrsi kopiranje
memorije).
Funkcija poredi vrsi pored̄enje dva elementa niza. Kada ova funkcija vraca
pozitivnu vrednost ako je prvi element veci od drugog, 0 ako su jednaki i negativnu
vrednost ako je prvi element manji, tada ce se niz sortirati u rastucem poretku.
Modi kacijom ove funkcije niz se moze sortirati u opadajucem poretku (ukoliko

89
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke

vraca pozitivnu vrednost ako je prvi manji, 0 ako su jednaki i negativnu vrednost
ako je prvi veci).

Kvalifikator const
Kljucna rec const u programskom jeziku C sluzi za de nisanje konstanti. Ako
napisemo:
const int a = 2;
tada se u daljem toku programa promenljivoj a ne moze dodeljivati vrednost. Za
razliku od konstanti de nisanih de ne direktivom ova konstanta ima jasno de nisan
tip koji prevodilac proverava prilikom upotrebe.
Treba naglasiti, medjutim, da ako se napise:
const int * p = &a;
tada se const ne odnosi na promenljivu p, vec na podatak tipa int na koji p
pokazuje. Dakle, nije pokazivac konstantan, vec on pokazuje na konstantan podatak.
Na primer:
int b;
p = &b;
je dozvoljeno, ali:
*p = 4;
nije dozvoljeno, zato sto je p pokazivac na konstantan int (odnosno, kroz pokazivac
p nije moguce menjati vrednost koja se nalazi na adresi na koju on ukazuje). Ovo
se moze razumeti tako sto se deklaracija procita sa desna u levo:
const int * p; /* p je pokazivac na int koji je konstantan*/
Slicno bi bilo i ako napisemo:
int const * p; /* p je pokazivac na konstantan int. */
Med̄utim, ako napisemo:
int * const p; /* p je konstantan pokazivac na int. */
Kombinacija ovoga je:
const int * const p; /* p je konstantan pokazivac na int
koji je konstantan.*/
Dakle, u ovom poslednjem slucaju konstantni su i pokazivac i ono na sta on pokazuje.

90
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke

Upotreba qsort
Primer 8.3 Upotrebom qsort funkcije iz standardne biblioteke izvršiti sortiranje
niza celih i niza realnih brojeva.
/* Ilustracija upotrebe funkcije qsort iz stdlib.h
Sortira se niz celih brojeva.
*/

#include <stdlib.h>
#include <stdio.h>

/* const znaci da ono na sta pokazuje a (odnosno b)


nece biti menjano u funkciji */
int poredi(const void* a, const void* b)
{
/* Skracen zapis za
int br_a = *(int*)a;
int br_b = *(int*)b;

return br_a-br_b;
*/
return *((int*)a)-*((int*)b);
}

int poredi_float(const void* a, const void* b)


{
float br_a = *(float*)a;
float br_b = *(float*)b;

if (br_a > br_b) return 1;


else if (br_a < br_b) return -1;
else return 0;
}

main()
{
int i;
int niz[]={3,8,7,1,2,3,5,6,9};
float nizf[]={3.0,8.7,7.8,1.9,2.1,3.3,6.6,9.9};

int n=sizeof(niz)/sizeof(int);
qsort((void*)niz, n, sizeof(int), poredi);
for(i=0; i<n; i++)
printf("%d",niz[i]);

91
Milena Vujošević–Janičić 8.1 Funkcija qsort iz standardne biblioteke

n=sizeof(nizf)/sizeof(float);
qsort((void*)nizf, n, sizeof(float), poredi_float);
for(i=0; i<n; i++)
printf("%f",nizf[i]);
}
Primer 8.4 Sortiranje reči. Ako se sortira niz stringova, onda svaki element je
sam po sebi pokazivač tipa char *, te funkcija pored̄enja tada prima podatke tipa
char ** koji se konvertuju u svoj tip i derefenciraju radi dobijanja podataka tipa
char *.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/* Funkcija koja vrsi leksikografsko poredjenje dve reci.


Vraca kao rezultat >0 ukoliko je prva rec veca, 0 ako su jednake
i <0 ako je prva rec manja. Sortiranje ce biti u rastucem poretku.*/
int poredi_leksikografski(const void* a, const void* b)
{
char *s1 = *(char **)a;
char *s2 = *(char **) b;
return strcmp(s1, s2);

/* Prethodno je ekvivalentno sa:


return strcmp(*(char**)a,*(char**)b); */
}

/* Funkcija koja vrsi poredjenje po duzini dve reci,


sortiranje koje koristiovu funkciju ca biti opadajuce!*/
int poredi_po_duzini(const void* a, const void* b)
{
char *s1 = *(char **) a;
char *s2 = *(char **) b;
return strlen(s1) - strlen(s2);
/* Prethodno je ekvivalentno sa:
return strlen(*(char**)b)-strlen(*(char**)a); */
}

main()
{
int i;
char* nizreci[]={"Jabuka","Kruska","Sljiva","Dinja","Lubenica"};

qsort((void*)nizreci, sizeof(nizreci)/sizeof(char *),


sizeof(char*), poredi_po_duzini);

92
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke

for (i=0; i<5; i++)


printf("%s\n",nizreci[i]);

qsort((void*)nizreci, sizeof(nizreci),
sizeof(char*), poredi_leksikografski);

printf("Sortirano:\n");
for (i=0; i<sizeof(nizreci); i++)
printf("%s\n",nizreci[i]);
}
/*
Izlaz:
Dinja Jabuka Kruska Lubenica Sljiva
Sortirano:
Lubenica Kruska Jabuka Sljiva Dinja
*/

8.2 Funkcija bsearch iz standardne biblioteke


Prototip funkcije bsearch iz stdlib.h je:
void *bsearch (const void *kljuc, const void *niz, int duzina_niza,
int velicina_elementa_niza,
int (*poredi)(const void*, const void*) )
Ova funkcija u nizu
niz[0], niz[1], ..., niz[duzina_niza - 1]
elemenata velicine velicina_elementa_niza trazi element koji ima krakteristiku
na koju ukazuje pokazivac kljuc.
Funkcija poredi moze da se razlikuje od funkcije poredi koju prima funkcija
qsort. Njen prvi argument je kljuc pretrage, a drugi argument je element niza. To
znaci da ova dva argumenta mogu ali i ne moraju da budu istog tipa. Na primer,
ako u nizu studenata trazimo onog studenta koji ima indeks mm08123 tada je kljuc
tipa char* a element niza je tipa strukture student, znaci kljuc pretrage i element
niza su razlicitog tipa, pa u skladu sa tim funkcija pored̄enja prima dva argumenta
razlicitog tipa. S druge strane, ako u nizu studenata trazimo onog studenta koji ima
indeks mm08123, i ime Pera i prezime Peric, tada je kljuc istog tipa kao i element
niza, i tada funkcija pored̄enja prima argumente istog tipa (i analogna je funkciji
pored̄enja koja se pise za funkciju qsort). Dakle, pored̄enje se vrsi po kljucu koji
moze biti istog tipa kao i elementi niza ali i ne mora.
Funkcija poredi treba da vrati vrednost 0 ako je prvi argument (kljuc pretrage)
veći (u smislu kljuca pretrage) od drugog argumenta (koji je element niza), 0 ako su
jednaki (u smislu kljuca pretrage) i broj manji od 0 ako je prvi argument manji (u
smislu kljuca pretrage) od drugog argumenta, ukoliko su elementi u nizu niz ured̄eni

93
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke

u rastucem redosledu u odnosu na dati kljuc. Funkcija bsearch vraca pokazivac na


pronad̄eni element ili NULL ukoliko element sa datom vrednoscu kljuca ne postoji.

Primer 8.5 Binarno pretraživanje - korišćenje ugrad̄ene bsearch funkcije.

/* Funkcija ilustruje koriscenje ugradjene funkcije bsearch */


#include <stdlib.h>

int poredi(const void* a, const void *b)


{
return *(int*)a-*(int*)b;
}

main()
{
int x=-1;
int niz[]={1,2,3,4,5,6,7,8,9,10,11,12};

int* elem=(int*)bsearch((void*)&x,
(void*)niz,
sizeof(niz)/sizeof(int),
sizeof(int),
poredi);

if (elem==NULL)
printf("Element nije pronadjen\n");
else
printf("Element postoji na poziciji %d\n",elem-niz);
}

Primer 8.6 Sa ulaza se unose reči. Program broji pojavljivanja svake od ključnih
reči programskog jezika C. Na kraju se reči ispisuju opadajuće po broju pojavljivanja.
#include <stdio.h>
#include <stdlib.h>

/* Svaka kljucna rec se odlikuje imenom i brojem pojavljivanja */


typedef struct _keyword
{
char word[20];
int num;
} keyword;

/* Kreiramo niz struktura sortiranih leksikografski


po imenu kljucne reci, kako bismo ubrzali pronalazak reci */

94
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke

keyword keywords[]={ {"break",0},


{"continue",0},
{"float",0},
{"for",0},
{"if",0},
{"return",0},
{"struct",0},
{"while",0}
};

/* Funkcija cita sledecu rec sa standardnog ulaza */


int getword(char word[], int lim)
{
int c, i=0;
while(!isalpha(c=getchar()) && c!=EOF)
;
if (c==EOF)
return -1;
do
{
word[i++]=c;
} while(--lim>0 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

/* Funkcija leksikografskog poredjenja za bsearch */


int cmp(const void* a, const void* b) {
/* Funkcija strcmp prima kao argumente dva
pokazivaca na karaktere. U ovom slucaju, prvi argument je
rec koju trazimo u nizu --- prilikom poziva funkcije
bsearch funkciji se kao prvi argument prosledjuje pokazivac
na kljuc pretrage - to znaci da ukoliko se funkciji prosledi
adresa podatka tipa char* tada bi bilo potrebno uraditi
dereferenciranje sa *(char **)a; medjutim, ukoliko se prosledi
samo promenljiva tipa char* tada je potrebno uraditi
dereferenciranje sa (char *)a. Drugi argument funkcije
je element niza sa kojim se vrsi poredjenje. Pokazivac
b konvertujemo u pokazivac na strukturu
keyword a zatim posmatramo rec koja se tu
cuva */
return strcmp((char*)a, (*(keyword*)b).word); }

95
Milena Vujošević–Janičić 8.2 Funkcija bsearch iz standardne biblioteke

/* Funkcija numerickog poredjenja za qsort */


int numcmp(const void* a, const void* b)
{
return ((*(keyword*)b).num-(*(keyword*)a).num);
}

main()
{
char word[80];
int i;

/* Broj kljucnih reci */


int num_of_keywords=sizeof(keywords)/sizeof(keyword);

/* Citamo reci */
while (getword(word,80)!=-1)
{
/* Trazimo rec u spisku kljucnih reci binarnom pretragom */
/* Prvi argument funkcije bsearch treba da bude pokazivac
na rec koju trazimo. Posto je word tipa niza karaktera, tada
uzimanjem adrese od word dobijamo istu vrednost kao i word,
tj nema razlike izmedju word i &word. Zbog toga se u funkciji
poredjenja koristi dreferenciranje na sledeci nacin
strcmp((char*)a, (*(keyword*)b).word); }
Da je word tipa char*, tada bi poziv funkcije bsearch
sa argumentom &word povlacilo da funkcija poredjenja
koristi dereferenciranje na sledeci nacin
strcmp(*(char**)a, (*(keyword*)b).word); }
*/
keyword* k=(keyword*)bsearch((void*)word,
(void*)keywords,
num_of_keywords,
sizeof(keyword),
cmp);
/* Ukoliko je pronadjena uvecavamo broj pojavljivanja */
if (k!=NULL)
(*k).num++;
}

/* Sortiramo niz na osnovu broja pojavljivanja */


qsort((void*)keywords, num_of_keywords, sizeof(keyword), numcmp);

/* Vrsimo ispis */
for (i=0; i<num_of_keywords; i++)

96
Milena Vujošević–Janičić 8.3 Funkcije lsearch i lfind

printf("%s %d\n", keywords[i].word, keywords[i].num);


}

8.3 Funkcije lsearch i lfind


Funkcije za linearnu pretragu standardne biblioteke su funkcije lsearch i lfind.
Funkcija lsearch ima sledece argumente
void *lsearch(const void *kljuc, void *niz, int *duzina_niza,
int velicina_elementa_niza,
int (*comp)(const void *, const void *));
Ova funkcija ima iste argumente kao i funkcija bsearch() — jedina razlika je u tome
sto se kao treci argument ne predaje duzina niza vec adresa celobrojne promenljive
u kojoj se nalazi duzina niza. Ovo je zato sto funkcija lsearch() ukoliko linearnom
pretragom ne pronad̄e element koji se trazi, umece trazeni element na kraj niza,
a duzinu niza uvecava za jedan (sto cini tako sto promenljivoj pozivajuce funkcije
pristupa preko pokazivaca i menja je). Takod̄e, posto postiji mogucnost umetanja
elementa u niz, kao kljuc pretrage potrebno je koristiti kljuc koji je istog tipa kao sto
su to elementi niza. Funkcija za uporedjivanja elemenata na koju pokazuje pokazi-
vac comp treba da zadovoljava ista pravila kao i kod funkcije bsearch. Medjutim,
s obzirom da se kod linearne pretrage koristi iskljucivo pored̄enje na jednakost, do-
voljno je da funkcija za uporedjivanje vraca 0 ako su objekti koji se uporedjuju
jednaki, a razlicito od nule u suprotnom.
Funkcija lfind:
void *lfind(const void *kljuc, void *niz, int *duzina_niza,
int velicina_elementa_niza,
int (*comp)(const void *, const void *));
funkcionise isto kao i lsearch, s tom razlikom sto ne umece novi element u slucaju
neuspesne pretrage, vec vraca NULL (funkcija lsearch u slucaju neuspesne pretrage
umece trazeni element na kraj i vraca njegovu adresu). Za funkciju lfind moguce je
koristiti kljuc pretrage koji nije istog tipa kao elementi niza, u tom slucaju potrebno
je adekvatno de nisati funkciju pored̄enja.

8.4 Pokazivači
Primer 8.7 Različite deklaracije:
int *p; pokazivac na int
int **p; pokazivac na pokazivac na tip int

int* p[10]; niz od 10 elemenata tipa pokazivaca na int


int *p[10]; niz od 10 elemenata tipa pokazivaca na int

97
Milena Vujošević–Janičić 8.4 Pokazivači

int p[5][10]; pet nizova od po 10 elemenata tipa int


int (*p)[10]; pokazivac na niz od deset celobrojnih vrednosti

int* p(); funkcija bez argumenata koja vraca pokazivac na int


int *p(); funkcija bez argumenata koja vraca pokazivac na int

int (*p)(); pokazivac na funkciju bez argumenata koja vraca int


int *(*p)(); pokazivac na funkciju bez argumenata koja vraca pokazivac na int
int* (*p)(); pokazivac na funkciju bez argumenata koja vraca pokazivac na int
Razlika izmed̄u int** t i int (*t)[5]
int x;
int (*t)[5];
int aa[4][5];
t = aa;
x=t[2][2]; /*Da je t tipa int** ova dodela ne bi bila moguca!*/

98
Glava 9

Dinamicka alokacija memorije

Do sada smo memoriju za podatke rezervisali na dva nacina1 :


Statička alokacija — podaci se kreiraju staticki prilikom pokretanja programa
i ostaju u memoriji do kraja njegovog izvrsavanja. Ovakvu alokaciju imaju
globalne promenljive (promenljive de nisane van svake funkcije ili bloka) kao i
staticke lokalne promenljive (deklarisane kljucnom recju static unutar funkcije
ili bloka).
Automatska alokacija — podaci se kreiraju automatski prilikom ulaska u funkciju
ili blok, i nestaju kada se iz funkcije/bloka izad̄e. Ovakvo ponasanje imaju
sve lokalne promenljive koje nisu deklarisane kao static. Prostor za ove
promenljive se rezervise na programskom steku.
Glavni nedostatak oba ova pristupa je to sto programer u vreme pisanja programa
mora da predvidi koliko ce mu prostora biti potrebno za podatke. Cesto tako nesto
nije moguce, jer dimenzije problema mogu varirati. Drugi nedostatak je to sto je
zivotni vek svakog podatka jasno de nisan gornjim pravilima. Programer moze zeleti
da nakon kreiranja nekog objekta u memoriji on ostane tu dokle god je potreban,
te da ga kasnije ukloni kada vise za njim nema potrebe.
Svi ovi problemi resavaju se dinamičkom alokacijom memorije. Pored staticke
zone i steka, u memoriji postoji i odred̄eni prostor koji se naziva hip (eng. heap). U
ovom prostoru se po potrebi mogu kreirati objekti proizvoljne velicine. Taj prostor
se kasnije moze (i treba) osloboditi, kada programer vise nema potrebu da koristi
taj prostor.
U programskom jeziku C, ovo se moze ostvariti pozivom funkcije standardne
biblioteke malloc() koja je deklarisana u zaglavlju stdlib.h:
void * malloc(int n);
Ova funkcija alocira na hipu kontinualni prostor od n bajtova, i vraca adresu pocetka
tog prostora ili vraca vrednost NULL ukoliko zahtev ne moze da se ispuni. Jedini nacin
da se ovom prostoru pristupi je preko pokazivaca (jer ne postoji ime promenljive kao
kod statickih i automatskih promenljivih).
Osim funkcije malloc() postoje i druge funkcije za alokaciju, na primer:
1 Tekst preuzet sa sajta www.matf.bg.ac.rs/~milan

99
Milena Vujošević–Janičić Dinamička alokacija memorije

void * calloc(int n, int s);


Ova funkcija alocira prostor za n susednih elemenata velicine s bajtova (zapravo
alocira n*s bajtova). Ova funkcija jos i inicijalizuje rezervisani prostor na vrednost
0, za razliku od malloc() funkcije koja prostor ostavlja neinicijalizovan. Funkcija
void * realloc(void *p, int n);
vrsi realokaciju prostora na koji pokazuje pokazivac p za koji je memorija prethodno
bila dinamicki alocirana. Alocira se n bajtova, kopira se stari sadrzaj u novi prostor,
a zatim se stari prostor oslobad̄a. Ova funkcija se obicno koristi da bi se prosirio
postojeci dinamicki alocirani prostor.
Prostor alociran prethodnim funkcijama se moze dealocirati pozivom funkcije:
void free(void *p);
koja je takod̄e deklarisana u zaglavlju stdlib.h, i koja za argument mora imati
adresu koju je funkcija (m|c|re)alloc() vratila u nekom od prethodnih poziva
(drugim recima, ne moze se proizvoljan prostor oslobad̄ati ovom funkcijom, vec
samo prostor na hipu alociran (m|c|re)alloc()-om). Kada se jednom dealocira,
prostor vise ne sme da se koristi (vrlo je verovatno da ce ga kasnije funkcija koja
vrsi alokaciju dodeliti nekom drugom).
Trenutak oslobad̄anja prostora na hipu odred̄uje programer. Nebitno je da li
smo izasli iz funkcije ili bloka u kome je funkcija za alokaciju memorije pozvana,
prostor ostaje rezervisan dokle god ne pozovemo free() sa argumentom adrese tog
prostora. Ova memorija se moze koristiti i u drugim funkcijama sve dok imamo
pokazivac kojim mozemo da joj pristupimo.
Tiha greska je ako ”izgubimo” pokazivac na dinamicki alocirani prostor, a da ga
nismo prethodno dealocirali. U ovom slucaju taj prostor ostaje rezervisan do kraja
izvrsavanja programa, bez mogucnosti da ga koristimo ili da ga kasnije obrisemo
(jer nemamo njegovu adresu). Ovaj fenomen se naziva ”curenje memorije” (eng.
memory leak). Odgovornost je programera kao i odlika dobrog stila da se dinamicki
prostor uvek oslobodi kada vise nije potreban. Takod̄e, greska je i ukoliko programer
pokusa dva puta da oslobodi istu memoriju ili da pristupi memoriji koja je vec
oslobod̄ena (ovo dovodi do greske prilikom izvrsavanja programa).
Primer 9.1 Dinamička alokacija memorije za niz.
#include <stdio.h>
#include <stdlib.h>

main()
{
int n;
int i;
int *a;

/* Ranije smo alocirali konstantan prostor za niz,

100
Milena Vujošević–Janičić Dinamička alokacija memorije

sada cemo alocirati tacno onoliko koliko nam je


potrebno. */
printf("Unesi broj clanova niza : ");
scanf("%d", &n);

/* Kao da smo mogli da deklarisemo


int a[n];
Alocira se n mesta za podatke tipa int.
Funkcija malloc vraca vrednost tipa void*
tako da vrsimo kastovanje.
*/
a = (int*)malloc(n*sizeof(int));

/* Kad god se vrsi alokacija memorije mora se


proveriti da li je alokacija uspesno izvrsena!!! */
if (a == NULL)
{
printf("Nema slobodne memorije\n");
exit(1);
}

/* Od ovog trenutka a koristimo kao obican niz */


for (i = 0; i<n; i++)
scanf("%d",&a[i]);

/* Stampamo niz u obrnutom redosledu */


for(i = n-1; i>=0; i--)
printf("%d",a[i]);

/* Oslobadjamo memoriju*/
free(a);
}
Primer 9.2 Demonstracija funkcije calloc - funkcija inicijalizuje sadrzaj memo-
rije na 0.
#include <stdio.h>
#include <stdlib.h>

main()
{
int *m, *c, i, n;

printf("Unesi broj clanova niza : ");


scanf("%d", &n);

101
Milena Vujošević–Janičić Dinamička alokacija memorije

/* Niz m NE MORA garantovano da ima sve nule */


m = (int*) malloc(n*sizeof(int));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

/* Niz c MORA garantovano da ima sve nule */


c = (int*) calloc(n, sizeof(int));
if (c == NULL) {
printf("Greska prilikom alokacije memorije!\n");
free(m);
exit(1);
}

/*Odstampace se sadrzaj neinicijalizovane memorije*/


for (i = 0; i<n; i++)
printf("m[%d] = %d\n", i, m[i]);

/*Odstampace se nule*/
for (i = 0; i<n; i++)
printf("c[%d] = %d\n", i, c[i]);

/* Oslobadja se rezervisana memorija. */


free(m);
free(c);
}
Primer 9.3 Da bi funkcija omogućila pozivajućoj funkciji da koristi vrednosti niza
koji je kreirala, neophodno je da memorija kreiranog niza bude dinamički alocirana
kako bi nastavila da postoji i nakon završetka rada funkcije. U tom slučaju, pozi-
vajuća funkcija ima odgovornost i da se brine o dealokaciji rezervisanog prostora.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 1000

/* Funkcija dinamicki kreira niz karaktera u koji smesta rezultat


nadovezivanja stringova s i t. Adresa niza se vraca kao povratna
vrednost. */
char * nadovezi_stringove(char *s, char *t)
{
/* Dinamicki kreiramo prostor dovoljne velicine */
char *p = (char*) malloc((strlen(s) + strlen(t) + 1) * sizeof(char));

102
Milena Vujošević–Janičić Dinamička alokacija memorije

/* Proveravamo uspeh alokacije */


if(p == NULL)
{
fprintf(stderr, "malloc() greska!\n");
exit(1);
}

/* Kopiramo i nadovezujemo stringove */


strcpy(p,s);
strcat(p,t);

/* Vracamo p */
return p;
}

int main()
{
char * p = NULL;
char s[MAX], t[MAX];

/* Ucitavamo stringove */
scanf("%s", s);
scanf("%s", t);

/* Nadovezujemo stringove */
p = nadovezi_stringove(s,t);

/* Prikazujemo rezultat */
printf("%s\n", p);

/* Oslobadjamo memoriju*/
free(p);

return 0;
}
Primer 9.4 Niz pokazivača na nizove različitih dužina.
#include <stdio.h>
#include <stdlib.h>
main()
{
/* Niz od tri elemenata tipa int*/
int nizi[3];

103
Milena Vujošević–Janičić Dinamička alokacija memorije

/* Niz od tri elemenata tipa int*, dakle


niz od tri pokazivaca na int*/
int* nizip[3];

/* Alociramo memoriju za prvi element niza*/


nizip[0] = (int*) malloc(sizeof(int));
if (nizip[0] == NULL)
{
printf("Nema slobodne memorije\n");
exit(1);
}
/* Upisujemo u prvi element niza broj 5*/
*nizip[0] = 5;
printf("%d", *nizip[0]);

/* Alociramo memoriju za drugi element niza.


Drugi element niza pokazuje na niz od dva
elementa*/
nizip[1] = (int*) malloc(2*sizeof(int));
if (nizip[1] == NULL) {
printf("Nema slobodne memorije\n");
free(nizip[0]);
exit(1);
}

/* Pristupamo prvom elementu na koji pokazuje


pokazivac nizip[1]*/
*(nizip[1]) = 1;

/* Pristupamo sledecem elementu u nizu na koji pokazuje


nizip[1].
*/
*(nizip[1] + 1) = 2;

printf("%d", nizip[1][1]);

/* Alociramo memoriju za treci element niza nizip. */


nizip[2] = (int*) malloc(sizeof(int));
if (nizip[2] == NULL) {
printf("Nema slobodne memorije\n");
free(nizip[0]);
free(nizip[1]);
exit(1);
}

104
Milena Vujošević–Janičić 9.1 Matrice

*(nizip[2]) = 2;

printf("%d", *(nizip[2]));

/* Oslobadjamo memoriju. */
free(nizip[0]);
free(nizip[1]);
free(nizip[2]);
}

9.1 Matrice
Primer 9.5 Statička alokacija prostora za matricu.
#include <stdio.h>

main()
{
int i, j;

/* Deklaracija i inicijalizacija elemenata matrice */


int a[3][3] = {{0, 1, 2}, {10, 11, 12}, {20, 21, 22}};

/* Alternativni unos elemenata matrice


for(i=0; i<3; i++)
for(j=0; j<3; j++)
{
printf("a[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
*/

/*Pristup elementima matrice */


a[1][1] = a[0][0] + a[2][2];
/* a[1][1] = 0 + 22 = 22 */

printf("%d\n", a[1][1]); /* 22 */

/* Stampanje elemenata matrice*/


for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
printf("%d\t", a[i][j]);
printf("\n");

105
Milena Vujošević–Janičić 9.1 Matrice

}
}
Ukoliko je potrebna veca eksibilnost, tj. da se dimenzije matrice mogu uneti kao
parametri programa, tada je neophodno koristiti dinamicku alokaciju memorije.
Primer 9.6 Implementacija matrice preko niza.
#include <stdlib.h>
#include <stdio.h>

/* Makro pristupa clanu na poziciji i, j matrice koja ima


m vrsta i n kolona */
#define a(i,j) a[(i)*n+(j)]

main()
{
/* Dimenzije matrice */
int m, n;

/* Matrica */
int *a;

int i,j;

/* Suma elemenata matrice */


int s=0;

/* Unos i alokacija */
printf("Unesi broj vrsta matrice : ");
scanf("%d",&m);

printf("Unesi broj kolona matrice : ");


scanf("%d",&n);

/*Rezervise se prostor za niz a*/


a=(int*)malloc(m*n*sizeof(int));
if (a == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<m; i++)


for (j=0; j<n; j++)
{
printf("Unesi element na poziciji (%d,%d) : ",i,j);

106
Milena Vujošević–Janičić 9.1 Matrice

scanf("%d",&a(i,j));
}

/* Racunamo sumu elemenata matrice */


for (i=0; i<m; i++)
for (j=0; j<n; j++)
s+=a(i,j);

/* Ispis unete matrice */


printf("Uneli ste matricu : \n");
for (i=0; i<m; i++)
{ for (j=0; j<n; j++)
printf("%d ",a(i,j));
printf("\n");
}

printf("Suma elemenata matrice je %d\n", s);

/* Oslobadjamo memoriju */
free(a);
}
Primer 9.7 Druga opcija za implementaciju matrice je koristći pokazivač na pokazivač.
1. Definišemo pokazivač na pokazivač na int:
int **p;
Ovaj pokazivač će čuvati adresu prvog u nizu dinamički alociranih pokazivača
na int-ove.
2. Dinamički alociramo niz od m pokazivača na int-ove, i adresu prvog u nizu
smeštamo u promenljivu p:
p = (int**) malloc(sizeof(int*) * m));
Ovi pokazivači služe da pokazuju na prve elemente nizova int-ova koji pred-
stavljaju dinamički alocirane vrste.
3. Svaku vrstu alociramo posebnim malloc-om, i povratnu adresu smeštamo u i-ti
pokazivač u malopre alociranom nizu pokazivača.
for(i = 0; i < m; i++)
p[i] = malloc(sizeof(int) * n);
Primetimo da nizovi int-ova koji se alociraju nisu morali biti jednakih dimen-
zija (ne moraju svi biti duzine n, kao što je ovde rečeno). Ovo može da bude
korisno, ako znamo da će u nekoj vrsti biti korišćeno samo nekoliko prvih ele-
menata, tada možemo alocirati manje za tu vrstu, i tako uštedeti prostor.

107
Milena Vujošević–Janičić 9.1 Matrice

4. U toku rada se elementima ovako alocirane matrice pristupa sa p[i][j] – p[i]


je i-ti pokazivač u nizu, a kako on pokazuje na početni element u i-toj vrsti,
tada je p[i][j] upravo j-ti element u i-toj vrsti.
5. Dealokacija se sastoji u brisanju svih vrsta, nakon čega se obriše i niz pokazivača
(dakle, dealokacija ide u suprotnom redosledu od redosleda alokacije):

for(i = 0; i < m; i++)


free(p[i]);
free(p);

#include <stdio.h>
#include <stdlib.h>

int main()
{
int **p;
int m, n;
int i, j;

printf("Uneti broj vrsta matrice: ");


scanf("%d", &m);
printf("Unesite broj kolona matrice: ");
scanf("%d", &n);

/* Alociramo m pokazivaca na vrste matrice */


if((p = (int**)malloc(sizeof(int*) * m)) == NULL)
{
fprintf(stderr, "malloc() greska\n");
exit(1);
}

/* Alociramo m vrsta od po n int-ova */


for(i = 0; i < m; i++)
if((p[i] = (int*)malloc(sizeof(int) * n)) == NULL)
{
fprintf(stderr, "malloc() greska\n");
exit(1);
}

/* Postavljamo p[i][j] na vrednost abs(i - j) */


for(i = 0; i < m ; i++)
for(j = 0; j < n; j++)
p[i][j] = i - j >=0 ? i - j : j - i;

108
Milena Vujošević–Janičić 9.1 Matrice

/* Ispis matrice */
for(i = 0; i < m ; i++)
{
for(j = 0; j < n; j++)
printf("%3d ", p[i][j]);
putchar(’\n’);
}

/* Oslobadjanje vrsta matrice */


for(i = 0; i < m; i++)
free(p[i]);

/* Oslobadjanje niza pokazivaca */


free(p);

return 0;
}
Primer 9.8 Program ilustruje rad sa kvadratnim matricama i relacijama. Kôd za
alokaciju i dealokaciju memorije je izdvojen u funkcije. Element i je u relaciji sa
elementom j ako je m[i][j] = 1, a nisu u relaciji ako je m[i][j] = 0.
#include <stdlib.h>
#include <stdio.h>

/* Dinamicka matrica je odredjena adresom


pocetka niza pokazivaca i dimenzijama tj.
int** a;
int m,n;
*/

/* Alokacija kvadratne matrice nxn */


int** alociraj(int n)
{
int** m;
int i;
m = (int**)malloc(n*sizeof(int*));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<n; i++)


{
m[i]=(int*)malloc(n*sizeof(int));
if (m[i] == NULL)

109
Milena Vujošević–Janičić 9.1 Matrice

{
int k;
printf("Greska prilikom alokacije memorije!\n");
for(k=0;k<i;k++)
free(m[k]);
free(m);
exit(1);
}
}

return m;
}

/* Dealokacija matrice dimenzije nxn */


void obrisi(int** m, int n)
{
int i;
for (i=0; i<n; i++)
free(m[i]);
free(m);
}

/* Ispis matrice /
void ispisi_matricu(int** m, int n)
{
int i, j;
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf("%d ",m[i][j]);
printf("\n");
}
}

/* Provera da li je relacija predstavljena matricom refleksivna */


int refleksivna(int** m, int n)
{
int i;
for (i=0; i<n; i++)
if (m[i][i]==0)
return 0;

return 1;
}

110
Milena Vujošević–Janičić 9.1 Matrice

/* Provera da li je relacija predstavljena matricom simetricna */


int simetricna(int** m, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=i+1; j<n; j++)
if (m[i][j]!=m[j][i])
return 0;
return 1;
}

/* Provera da li je relacija predstavljena matricom tranzitivna*/


int tranzitivna(int** m, int n)
{
int i,j,k;

for (i=0; i<n; i++)


for (j=0; j<n; j++)
for (k=0; k<n; k++)
if ((m[i][j]==1)
&& (m[j][k]==1)
&& (m[i][k]!=1))
return 0;
return 1;
}

/* Pronalazi najmanju simetricnu relaciju koja sadrzi relaciju a */


void simetricno_zatvorenje(int** a, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{
if (a[i][j]==1 && a[j][i]==0)
a[j][i]=1;
if (a[i][j]==0 && a[j][i]==1)
a[i][j]=1;
}
}

main()
{
int **m;

111
Milena Vujošević–Janičić 9.1 Matrice

int n;
int i,j;

printf("Unesi dimenziju matrice : ");


scanf("%d",&n);
m=alociraj(n);

for (i=0; i<n; i++)


for (j=0; j<n; j++)
scanf("%d",&m[i][j]);

printf("Uneli ste matricu : \n");

ispisi_matricu(m,n);

if (refleksivna(m,n))
printf("Relacija je refleksivna\n");
if (simetricna(m,n))
printf("Relacija je simetricna\n");
if (tranzitivna(m,n))
printf("Relacija je tranzitivna\n");

simetricno_zatvorenje(m,n);

ispisi_matricu(m,n);

obrisi(m,n);
}
Primer 9.9 Izračunati vrednost determinante matrice preko Laplasovog razvoja.
#include <stdio.h>
#include <stdlib.h>

/* Funkcija alocira matricu dimenzije nxn */


int** allocate(int n)
{
int **m;
int i;
m=(int**)malloc(n*sizeof(int*));
if (m == NULL) {
printf("Greska prilikom alokacije memorije!\n");
exit(1);
}

for (i=0; i<n; i++)

112
Milena Vujošević–Janičić 9.1 Matrice

{
m[i]=malloc(n*sizeof(int));
if (m[i] == NULL)
{
int k;
for(k=0;k<i;k++)
free(m[k]);
printf("Greska prilikom alokacije memorije!\n");
free(m);
exit(1);
}
}

return m;
}

/* Funkcija vrsi dealociranje date matrice dimenzije n */


void deallocate(int** m, int n)
{
int i;
for (i=0; i<n; i++)
free(m[i]);
free(m);
}

/* Funkcija ucitava datu alociranu matricu sa standardnog ulaza */


void ucitaj_matricu(int** matrica, int n)
{
int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
scanf("%d",&matrica[i][j]);
}

/* Rekurzivna funkcija koja vrsi Laplasov razvoj */


int determinanta(int** matrica, int n)
{
int i;
int** podmatrica;
int det=0,znak;

/* Izlaz iz rekurzije je matrica 1x1 */


if (n==1) return matrica[0][0];

113
Milena Vujošević–Janičić 9.2 Realokacija memorije

/* Podmatrica ce da sadrzi minore polazne matrice */


podmatrica=allocate(n-1);
znak=1;
for (i=0; i<n; i++)
{
int vrsta,kolona;
for (kolona=0; kolona<i; kolona++)
for(vrsta=1; vrsta<n; vrsta++)
podmatrica[vrsta-1][kolona] = matrica[vrsta][kolona];
for (kolona=i+1; kolona<n; kolona++)
for(vrsta=1; vrsta<n; vrsta++)
podmatrica[vrsta-1][kolona-1] = matrica[vrsta][kolona];

det+= znak*matrica[0][i]*determinanta(podmatrica,n-1);
znak*=-1;
}
deallocate(podmatrica,n-1);
return det;
}

main()
{
int **matrica;
int n;

scanf("%d", &n);
matrica = allocate(n);
ucitaj_matricu(matrica, n);
printf("Determinanta je : %d\n",determinanta(matrica,n));
deallocate(matrica, n);
}

9.2 Realokacija memorije


Primer 9.10 Dinamički niz.
/* Program za svaku rec unetu sa standardnog
ulaza ispisuje broj pojavljivanja.
Verzija sa dinamickim nizom i realokacijom.
*/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

114
Milena Vujošević–Janičić 9.2 Realokacija memorije

/* Rec je opisana imenom i brojem pojavljivanja */


typedef struct _rec
{ char ime[80];
int br_pojavljivanja;
} rec;

/* Realokacija se vrsi sa datim korakom */


#define KORAK 10

/* Funkcija ucitava rec i vraca njenu duzinu ili


-1 ukoliko smo dosli do znaka EOF*/
int getword(char word[],int max)
{
int c, i=0;

while (isspace(c=getchar()))
;

while(!isspace(c) && c!=EOF && i<max-1)


{
word[i++]=c;
c = getchar();
}

word[i]=’\0’;

if (c==EOF) return -1;


else return i;
}

main()
{

/* Dinamicki niz reci je opisan pokazivacem na


pocetak, tekucim brojem upisanih elemenata i
tekucim brojem alociranih elemenata */
rec* niz_reci;
int duzina=0;
int alocirano=0;

char procitana_rec[80];
int i;

115
Milena Vujošević–Janičić 9.2 Realokacija memorije

while (getword(procitana_rec,80)!=-1)
{
/* Proveravamo da li rec vec postoji u nizu */
for (i=0; i<duzina; i++)
/* Ako bismo uporedili procitana_rec == niz_reci[i].ime
bili bi uporedjeni pokazivaci a ne odgovarajuci sadrzaji.
Zato koristimo strcmp. */
if (strcmp(procitana_rec, niz_reci[i].ime)==0)
{
niz_reci[i].br_pojavljivanja++;
break;
}

/* Ukoliko rec ne postoji u nizu */


if (i==duzina)
{
rec nova_rec;
/* Ako bismo dodelili nova_rec.ime = procitana_rec
izvrsila bi se dodela pokazivaca a ne kopiranje niske
procitana_rec u nova_rec.ime. Zato koristimo strcpy. */
strcpy(nova_rec.ime,procitana_rec);
nova_rec.br_pojavljivanja=1;

/* Ukoliko je niz "kompletno popunjen" vrsimo realokaciju */


if (duzina==alocirano)
{
alocirano+=KORAK;

/* Sledeca linija zamenjuje blok koji sledi i moze se


koristiti alternativno. Blok je ostavljen samo da bi
demonstrirao korisnu tehniku */
/* niz_reci=realloc(niz_reci, (alocirano)*sizeof(rec)); */
{
/* alociramo novi niz, veci nego sto je bio prethodni */
rec* novi_niz=(rec *)malloc(alocirano*sizeof(rec));

if (novi_niz == NULL)
{
free(niz_reci);
printf("Greska prilikom alokacije memorije");
exit(1);
}

/* Kopiramo elemente starog niza u novi */

116
Milena Vujošević–Janičić 9.2 Realokacija memorije

for (i=0; i<duzina; i++)


novi_niz[i]=niz_reci[i];

/* Uklanjamo stari niz */


free(niz_reci);

/* Stari niz postaje novi */


niz_reci=novi_niz;
}
}
/* Upisujemo rec u niz */
niz_reci[duzina]=nova_rec;
duzina++;
}
}

/* Ispisujemo elemente niza */


for(i=0; i<duzina; i++)
printf("%s - %d\n",niz_reci[i].ime, niz_reci[i].br_pojavljivanja);

free(niz_reci);
}

117
Glava 10

Liste

Jednostruko povezana lista1 je struktura podataka koja se sastoji od sekvence cvorova.


Svaki cvor sadrzi podatak (odred̄enog tipa) i pokazivac na sledeci cvor u sekvenci.
Prvi cvor u sekvenci naziva se glava liste. Ostatak liste (bez glave) je takod̄e lista,
i naziva se rep liste. Lista koja ne sadrzi cvorove naziva se prazna lista. Prilikom
baratanja listom mi cuvamo pokazivac na glavu liste. Kada pristupimo glavi liste, u
njoj imamo zapisanu adresu sledeceg elementa, pa mu samim tim mozemo pristupiti.
Kada mu pristupimo, u njemu je sadrzana adresa sledeceg elementa, pa preko tog
pokazivaca mozemo da mu pristupimo, itd. Poslednji element u listi nema sledeci
element: u tom slucaju se njegov pokazivac na sledeci postavlja na NULL. Takod̄e,
prazna lista se predstavlja NULL pokazivacem.
Prednost koriscenja povezanih lista u odnosu na dinamicki niz je u tome sto se
elementi mogu e kasno umetati i brisati sa bilo koje pozicije u nizu, bez potrebe
za realokacijom ili premestanjem elemenata. Nedostatak ovakvog pristupa je to sto
ne mozemo nasumicno pristupiti proizvoljnom elementu, vec se elementi moraju
obrad̄ivati redom (iteracijom kroz listu).

10.1 Implementacija
Prilikom promene liste (dodavanje novog elementa, brisanje elementa, premestanje
elemenata, itd.) postoji mogucnost da glava liste bude promenjena, tj. da to postane
neki drugi cvor (sa drugom adresom). U tom slucaju se pokazivac na glavu liste mora
azurirati. Kada promenu liste obavljamo u posebnoj funkciji (kao sto je bio slucaj u
prethodnom primeru, gde smo za dodavanje i brisanje imali posebne funkcije) onda
je potrebno da se pozivajucoj funkciji vrati informacija o promeni adrese glave,
kako bi pozivajuca funkcija mogla da azurira svoju pokazivacku promenljivu. Ovo
se moze uraditi na dva nacina:
1. Pozvana funkcija koja vrsi promenu na listi vraca kao povratnu vrednost adresu
glave nakon promene. Ova adresa moze biti ista kao i pre promene (ako glava
nije dirana) a moze se i razlikovati. U svakom slucaju, ta adresa treba da se
dodeli pokazivackoj promenljivoj koja cuva adresu glave u pozivajucoj funkciji.
1 Tekst preuzet sa sajta www.matf.bg.ac.rs/ milan

118
Milena Vujošević–Janičić 10.1 Implementacija

Zbog toga se funkcija za promenu liste uvek poziva na sledeci nacin:


pok = funkcija_za_promenu(pok, ...);
tj. promenljivoj cija se vrednost predaje kao adresa glave u pozivu mora se do-
deliti povratna vrednost funkcije, za slucaj da je adresa glave interno promen-
jena.
2. Pozvana funkcija koja vrsi promenu na listi prihvata kao argument pokazivac
na pokazivacku promenljivu koja u pozivajucoj funkciji cuva adresu glave i
koju eventalno treba azurirati. Sada pozvana funkcija moze interno da preko
dobijenog pokazivaca promeni promenljivu pozivajuce funkcije direktno. Na
primer:
funkcija_za_promenu(&pok, ...);
Funkcija koja se poziva je po pravilu tipa void. Prednost drugog metoda je
jednostavnije pozivanje, dok je prednost prvog metoda jednostavnija sintaksa
unutar pozvane funkcije.
U prethodnom primeru je demonstriran prvi pristup. Naredni primer ilustruje drugi
pristup.
Primer 10.1 Osnovne funkcije za rad sa listama.
#include <stdio.h>
#include <stdlib.h>

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
int vrednost; /* podatak koji cvor sadrzi */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;

/* Pomocna funkcija koja kreira cvor. Funkcija vrednost


novog cvora inicijalizuje na broj, dok pokazivac na
sledeci cvor u novom cvoru postavlja na NULL. Funkcija
ispisuje poruku o gresci i prekida program u slucaju
da malloc() funkcija ne uspe da alocira prostor.
Funkcija vraca pokazivac na novokreirani cvor */
Cvor* napravi_cvor(int broj)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}

novi->vrednost = broj;
novi->sledeci = NULL;

119
Milena Vujošević–Janičić 10.1 Implementacija

return novi;
}

/* Funkcija dodaje novi cvor na pocetak liste. Funkcija


kreira novi cvor koriscenjem funkcije napravi_cvor().
Funkcija vraca pokazivac na novu glavu liste */
Cvor* dodaj_na_pocetak_liste(Cvor *glava, int broj)
{
Cvor * novi = napravi_cvor(broj);
novi->sledeci = glava;
return novi;
}

/*void dodaj_na_pocetak_liste(Cvor **glava, int broj)


{
Cvor *novi = napravi_cvor(broj);
novi->sledeci = *glava;
*glava = novi;
}
*/

/* Funkcija dodaje novi cvor na kraj liste. Funkcija


kreira novi cvor koriscenjem funkcije napravi_cvor().
Funkcija vraca pokazivac na glavu liste (koji moze
biti promenjen u slucaju da je lista inicijalno bila
prazna). */
Cvor* dodaj_na_kraj_liste(Cvor *glava, int broj)
{
Cvor * novi = napravi_cvor(broj);
Cvor *tekuci = glava;

/* slucaj prazne liste. U tom slucaju je glava nove liste


upravo novi cvor. */
if(glava == NULL) return novi;

/* Ako lista nije prazna, tada se krecemo duz liste sve dok
ne dodjemo do poslednjeg cvora (tj. do cvora ciji pokazivac
na sledeci pokazuje na NULL) */
while(tekuci->sledeci != NULL)
tekuci = tekuci->sledeci;

/* Dodajemo novi element na kraj preusmeravanjem pokazivaca */


tekuci->sledeci = novi;

120
Milena Vujošević–Janičić 10.1 Implementacija

/* Vracamo pokazivac na glavu liste */


return glava;
}

/*void dodaj_na_kraj_liste(Cvor **glava, int broj)


{
Cvor *novi = napravi_cvor(broj);
Cvor *tekuci = *glava;

/* slucaj prazne liste. U tom slucaju je glava nove liste


upravo novi cvor. */
if(*glava == NULL)
{
*glava = novi;
return;
}

/* Ako lista nije prazna, tada se krecemo duz liste sve dok
ne dodjemo do poslednjeg cvora (tj. do cvora ciji pokazivac
na sledeci pokazuje na NULL) */
while(tekuci->sledeci != NULL)
tekuci = tekuci->sledeci;

/* Dodajemo novi element na kraj preusmeravanjem pokazivaca */


tekuci->sledeci = novi;
}
*/

/* Funkcija trazi u listi element cija je vrednost jednaka


datom broju. Funkcija vraca pokazivac na cvor liste u
kome je sadrzan trazeni broj ili NULL u slucaju da takav
element ne postoji u listi */
Cvor* pretrazi_listu(Cvor *glava, int broj)
{
for(; glava != NULL ; glava = glava->sledeci)
if(glava->vrednost == broj)
return glava;

return NULL;
}

/* Funkcija prikazuje elemente liste pocev


od glave ka kraju liste */
void prikazi_listu(Cvor *glava)

121
Milena Vujošević–Janičić 10.1 Implementacija

{
putchar(’[’);
for(;glava != NULL; glava = glava->sledeci)
printf("%d ", glava->vrednost);
putchar(’]’);

putchar(’\n’);
}

/* Funkcija oslobadja dinamicku memoriju zauzetu


od strane liste. Funkcija vraca NULL, tj.
vrednost koju treba dodeliti pokazivackoj
promenljivoj, s obzirom da je sada lista prazna. */
Cvor* oslobodi_listu(Cvor *glava)
{
Cvor *pomocni;

while(glava != NULL)
{
/* moramo najpre zapamtiti adresu sledeceg
elementa, a tek onda osloboditi glavu */
pomocni = glava->sledeci;
free(glava);
glava = pomocni;
}
return NULL;
}

/*void oslobodi_listu(Cvor **glava)


{
Cvor *pomocni;

while(*glava != NULL)
{
/* moramo najpre zapamtiti adresu sledeceg
elementa, a tek onda osloboditi glavu */
pomocni = (*glava)->sledeci;
free(*glava);
*glava = pomocni;
}
}
*/

/* Funkcija dodaje novi element u sortiranu listu tako da i nova

122
Milena Vujošević–Janičić 10.1 Implementacija

lista ostane sortirana. Funkcija kreira novi cvor koriscenjem


funkcije napravi_cvor(). Funkcija vraca pokazivac na glavu liste
(koji moze biti promenjen u slucaju da je novi element dodat na
pocetak liste) */
Cvor* dodaj_sortirano(Cvor *glava, int broj)
{
Cvor *novi = napravi_cvor(broj);
Cvor *tekuci = glava;

/* u slucaju prazne liste glava nove liste je


upravo novi element */
if(glava == NULL) return novi;

/* ako je novi element manji ili jednak od glave,


tada novi element mora da bude nova glava */
if(glava->vrednost >= novi->vrednost)
{
novi->sledeci = glava;
return novi;
}

/* u slucaju da je glava manja od novog elementa, tada se krecemo kroz


listu sve dok se ne dodje do elementa ciji je sledeci element veci ili
jednak od novog elementa, ili dok se ne dodje do poslednjeg elementa. */
while(tekuci->sledeci != NULL && tekuci->sledeci->vrednost < novi->vrednost)
tekuci = tekuci->sledeci;

/* U svakom slucaju novi element dodajemo IZA tekuceg elementa */


novi->sledeci = tekuci->sledeci;
tekuci->sledeci = novi;

/* vracamo pokazivac na glavu liste*/


return glava;
}

/* void dodaj_sortirano(Cvor **glava, int broj)


{
Cvor *novi = napravi_cvor(broj);
Cvor *tekuci = *glava;

/* u slucaju prazne liste glava nove liste je


upravo novi element */
if(*glava == NULL)
{

123
Milena Vujošević–Janičić 10.1 Implementacija

*glava = novi;
return;
}

/* ako je novi element manji ili jednak od glave,


tada novi element mora da bude nova glava */
if((*glava)->vrednost >= novi->vrednost)
{
novi->sledeci = *glava;
*glava = novi;
return;
}

/* u slucaju da je glava manja od novog elementa, tada se krecemo kroz


listu sve dok se ne dodje do elementa ciji je sledeci element veci ili
jednak od novog elementa, ili dok se ne dodje do poslednjeg elementa. */
while(tekuci->sledeci != NULL && tekuci->sledeci->vrednost < novi->vrednost)
tekuci = tekuci->sledeci;

/* U svakom slucaju novi element dodajemo IZA tekuceg elementa */


novi->sledeci = tekuci->sledeci;
tekuci->sledeci = novi;
}
*/

/* Funkcija brise iz liste sve cvorove koji sadrze dati broj.


Funkcija vraca pokazivac na glavu liste (koji moze biti
promenjen u slucaju da se obrise stara glava) */
Cvor* obrisi_element(Cvor *glava, int broj)
{
Cvor *tekuci;
Cvor *pomocni;

/* Brisemo sa pocetka liste sve eventualne cvorove


koji su jednaki datom broju, i azuriramo pokazivac
na glavu */
while(glava != NULL && glava->vrednost == broj)
{
pomocni = glava->sledeci;
free(glava);
glava = pomocni;
}

/* Ako je nakon toga lista ostala prazna vracamo

124
Milena Vujošević–Janičić 10.1 Implementacija

NULL */
if(glava == NULL) return NULL;

/* Od ovog trenutka se u svakom koraku nalazimo


na tekucem cvoru koji je razlicit od trazenog
broja (kao i svi levo od njega). Poredimo
vrednost sledeceg cvora (ako postoji) sa trazenim
brojem i brisemo ga ako je jednak, a prelazimo na
sledeci cvor ako je razlicit. Ovaj postupak ponavljamo
dok ne dodjemo do poslednjeg cvora. */
tekuci = glava;
while(tekuci->sledeci != NULL)
if(tekuci->sledeci->vrednost == broj)
{
pomocni = tekuci->sledeci;
tekuci->sledeci = tekuci->sledeci->sledeci;
free(pomocni);
}
else tekuci = tekuci->sledeci;

/* vracamo novu glavu */


return glava;
}

/* void obrisi_element(Cvor **glava, int broj)


{
Cvor *tekuci;
Cvor *pomocni;

/* Brisemo sa pocetka liste sve eventualne cvorove


koji su jednaki datom broju, i azuriramo pokazivac
na glavu */
while(*glava != NULL && (*glava)->vrednost == broj)
{
pomocni = (*glava)->sledeci;
free(*glava);
*glava = pomocni;
}

/* Ako je nakon toga lista ostala prazna prekidamo


funkciju */
if(*glava == NULL) return;

/* Od ovog trenutka se u svakom koraku nalazimo

125
Milena Vujošević–Janičić 10.1 Implementacija

na tekucem cvoru koji je razlicit od trazenog


broja (kao i svi levo od njega). Poredimo
vrednost sledeceg cvora (ako postoji) sa trazenim
brojem i brisemo ga ako je jednak, a prelazimo na
sledeci cvor ako je razlicit. Ovaj postupak ponavljamo
dok ne dodjemo do poslednjeg cvora. */
tekuci = *glava;
while(tekuci->sledeci != NULL)
if(tekuci->sledeci->vrednost == broj)
{
pomocni = tekuci->sledeci;
tekuci->sledeci = tekuci->sledeci->sledeci;
free(pomocni);
}
else tekuci = tekuci->sledeci;

return;
}
*/
/* test program */
int main()
{

Cvor *glava = NULL;


Cvor *pomocni = NULL;
int broj;

/* Testiranje dodavanja na pocetak */


printf("-------------------------------------------------------\n");
printf("---------- Testiranje dodavanja na pocetak ------------\n");
do {
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja liste:\n");
prikazi_listu(glava);
printf("-------------------------------------------------------\n");
printf("Dodati element na pocetak liste (ctrl-D za kraj unosa):\n");
} while(scanf("%d", &broj) > 0 &&
(glava = dodaj_na_pocetak_liste(glava, broj)) );
/* dodaj_na_pocetak_liste(&glava, broj);*/
printf("-------------------------------------------------------\n");
putchar(’\n’);

/* Testiranje pretrage elementa */

126
Milena Vujošević–Janičić 10.1 Implementacija

printf("-------------------------------------------------------\n");
printf("---------------- Testiranje pretrage ------------------\n");
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja liste:\n");
prikazi_listu(glava);
printf("-------------------------------------------------------\n");
printf("Uneti broj koji se trazi: ");
scanf("%d",&broj);

if((pomocni = pretrazi_listu(glava, broj)) == NULL)


printf("Trazeni broj nije u listi\n");
else
printf("Trazeni element %d je u listi\n", pomocni->vrednost);
printf("-------------------------------------------------------\n");
putchar(’\n’);

glava = oslobodi_listu(glava);
/*oslobodi_listu(&glava);*/

/* Testiranje dodavanja na kraj */


printf("-------------------------------------------------------\n");
printf("------------ Testiranje dodavanja na kraj -------------\n");
do{
printf("-------------------------------------------------------\n");
printf("Prikaz liste:\n");
prikazi_listu(glava);
printf("-------------------------------------------------------\n");
printf("Dodati element na kraj liste (ctrl-D za kraj unosa):\n");
} while(scanf("%d",&broj) > 0 &&
(glava = dodaj_na_kraj_liste(glava, broj)));
/*(dodaj_na_kraj_liste(&glava,broj)));*/
printf("-------------------------------------------------------\n");
putchar(’\n’);

/* Testiranje brisanja elemenata */


printf("-------------------------------------------------------\n");
printf("--------------- Testiranje brisanja -------------------\n");
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja liste:\n");
prikazi_listu(glava);
printf("-------------------------------------------------------\n");
printf("Uneti broj koji se brise: ");
scanf("%d", &broj);

127
Milena Vujošević–Janičić 10.1 Implementacija

glava = obrisi_element(glava, broj);


/* obrisi_element(&glava, broj); */
printf("-------------------------------------------------------\n");
printf("Lista nakon izbacivanja:\n");
prikazi_listu(glava);
printf("-------------------------------------------------------\n");
putchar(’\n’);

glava = oslobodi_listu(glava);
/*oslobodi_listu(&glava);*/

/* Testiranje sortiranog dodavanja */


printf("-------------------------------------------------------\n");
printf("----------- Testiranje sortiranog dodavanja -----------\n");
do{
printf("-------------------------------------------------------\n");
printf("Prikaz liste:\n");
prikazi_listu(glava);
printf("-------------------------------------------------------\n");
printf("Dodati element sortirano (ctrl-D za kraj unosa):\n");
} while(scanf("%d",&broj) > 0 &&
(glava = dodaj_sortirano(glava, broj)));
/*(dodaj_sortirano(&glava, broj)));*/
printf("-------------------------------------------------------\n");
putchar(’\n’);

glava = oslobodi_listu(glava);
/*oslobodi_listu(&glava);*/

return 0;
}
Primer 10.2 Sve funkcije iz prethodnih primera, za koje to ima smisla, definisane
su rekurzivno. Primetno je da su ove rekurzivne varijante mnogo jednostavnije.
Razlog je to što su liste po svojoj prirodi rekurzivne strukture. Naime, liste se mogu
rekurzivno definisati na sledeći način:
 objekat označen sa [] je lista (prazna lista)
 ako je L lista, i G neki element, tada je ured̄eni par (G,L) takod̄e lista. Element
G nazivamo glavom liste, a listu L repom liste.
Na primer, uredjeni par (2, []) je lista, i po dogovoru cemo je zapisivati kao [2].
Takodje par (3,[2]) je lista koju možemo zapisati kao [3 2], itd.
U opstem slucaju, ako je L=[a1 a2 a3 ... an] lista, i ako je b neki element,
tada je uredjeni par (b,L) takod̄e lista, koju možemo zapisati kao [b a1 a2 ... an].

128
Milena Vujošević–Janičić 10.1 Implementacija

Glava liste je b, a rep liste je lista L. Sada se obrada liste može razdvojiti na dva
dela:
 Izvršiti operaciju nad glavom liste
 Izvršiti rekurzivni postupak nad repom liste (koji je takod̄e lista).
Za testiranje narednog programa može se koristiti main funkcija iz primera 10.1.
#include <stdio.h>
#include <stdlib.h>

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
int vrednost; /* podatak koji cvor sadrzi */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;

/* Pomocna funkcija koja kreira cvor. Funkcija vrednost


novog cvora inicijalizuje na broj, dok pokazivac na
sledeci cvor u novom cvoru postavlja na NULL. Funkcija
ispisuje poruku o gresci i prekida program u slucaju
da malloc() funkcija ne uspe da alocira prostor.
Funkcija vraca pokazivac na novokreirani cvor */
Cvor* napravi_cvor(int broj)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}

novi->vrednost = broj;
novi->sledeci = NULL;
return novi;
}

/* Funkcija dodaje novi cvor na pocetak liste. Funkcija


kreira novi cvor koriscenjem funkcije napravi_cvor().
Funkcija vraca pokazivac na novu glavu liste */
Cvor* dodaj_na_pocetak_liste(Cvor *glava, int broj)
{
Cvor * novi = napravi_cvor(broj);
novi->sledeci = glava;
return novi;

129
Milena Vujošević–Janičić 10.1 Implementacija

}
/*
void dodaj_na_pocetak_liste(Cvor **glava, int broj)
{
Cvor * novi = napravi_cvor(broj);
novi->sledeci = *glava;
*glava = novi;
}
*/

/* Funkcija dodaje novi cvor na kraj liste. Funkcija


kreira novi cvor koriscenjem funkcije napravi_cvor().
Funkcija vraca pokazivac na glavu liste (koji moze
biti promenjen u slucaju da je lista inicijalno bila
prazna). Funkcija koristi rekurziju. */
Cvor* dodaj_na_kraj_liste(Cvor *glava, int broj)
{
/* Izlaz iz rekurzije: slucaj prazne liste.
U tom slucaju je glava nove liste upravo novi cvor. */
if(glava == NULL) return napravi_cvor(broj);

/* U slucaju da je lista neprazna, tada ona ima glavu i rep,


pri cemu je rep opet lista. Tada je dodavanje na kraj
liste ekvivalentno dodavanju na kraj repa liste, sto
radimo rekurzivnim pozivom. Povratna vrednost rekurzivnog
poziva je adresa glave modifikovanog repa liste koja se
treba sacuvati u pokazivacu na sledeci u glavi */
glava->sledeci = dodaj_na_kraj_liste(glava->sledeci, broj);

/* Vracamo glavu liste, koja je mozda izmenjena */


return glava;
}

/*
void dodaj_na_kraj_liste(Cvor **glava, int broj)
{
/* Izlaz iz rekurzije: slucaj prazne liste.
U tom slucaju je glava nove liste upravo novi cvor. */
if(*glava == NULL)
*glava = napravi_cvor(broj);
else
/* U slucaju da je lista neprazna, tada ona ima glavu i rep,
pri cemu je rep opet lista. Tada je dodavanje na kraj
liste ekvivalentno dodavanju na kraj repa liste, sto

130
Milena Vujošević–Janičić 10.1 Implementacija

radimo rekurzivnim pozivom. */


dodaj_na_kraj_liste(&(*glava->sledeci), broj);
}

*/

/* Funkcija dodaje novi element u sortiranu listu tako da i nova


lista ostane sortirana. Funkcija kreira novi cvor koriscenjem
funkcije napravi_cvor(). Funkcija vraca pokazivac na glavu liste
(koji moze biti promenjen u slucaju da je novi element dodat na
pocetak liste). Funkcija koristi rekurziju. */
Cvor* dodaj_sortirano(Cvor *glava, int broj)
{
/* u slucaju da je lista prazna, ili da je vrednost
glave veca ili jednaka od vrednosti broja koji
umecemo, tada se novi cvor umece na pocetak liste. */
if(glava == NULL || glava->vrednost >= broj)
{
Cvor *novi = napravi_cvor(broj);
novi->sledeci = glava;
return novi;
}

/* U slucaju da je lista neprazna, i da je vrednost


glave manja od vrednosti broja koji umecemo u listu,
tada je sigurno da se novi element umece DESNO od glave,
tj. u rep liste. Dakle, mozemo rekurzivno pozvati istu
funkciju za rep liste. S obzirom da po induktivnoj
pretpostavci rep nakon toga ostaje sortiran, a svi
elementi u repu ukljucujuci i element koji je dodat
su jednaki ili veci od glave, tada ce i cela lista
biti sortirana. Povratna vrednost rekurzivnog poziva
predstavlja adresu glave modifikovanog repa liste,
pa se ta adresa mora sacuvati u pokazivacu na sledeci
u glavi liste. */
glava->sledeci = dodaj_sortirano(glava->sledeci, broj);

/* vracamo staru - novu glavu */


return glava;
}

/*
void dodaj_sortirano(Cvor **glava, int broj)
{

131
Milena Vujošević–Janičić 10.1 Implementacija

/* u slucaju da je lista prazna, ili da je vrednost


glave veca ili jednaka od vrednosti broja koji
umecemo, tada se novi cvor umece na pocetak liste. */
if(*glava == NULL || *glava->vrednost >= broj)
{
Cvor *novi = napravi_cvor(broj);
novi->sledeci = *glava;
*glava = novi;
}
else
/* U slucaju da je lista neprazna, i da je vrednost
glave manja od vrednosti broja koji umecemo u listu,
tada je sigurno da se novi element umece DESNO od glave,
tj. u rep liste. Dakle, mozemo rekurzivno pozvati istu
funkciju za rep liste. S obzirom da po induktivnoj
pretpostavci rep nakon toga ostaje sortiran, a svi
elementi u repu ukljucujuci i element koji je dodat
su jednaki ili veci od glave, tada ce i cela lista
biti sortirana.*/
dodaj_sortirano(&(*glava->sledeci), broj);
}
*/

/* Funkcija trazi u listi element cija je vrednost jednaka


datom broju. Funkcija vraca pokazivac na cvor liste u
kome je sadrzan trazeni broj ili NULL u slucaju da takav
element ne postoji u listi. Funkcija koristi rekurziju. */
Cvor* pretrazi_listu(Cvor *glava, int broj)
{
/* Izlaz iz rekurzije: prazna lista */
if(glava == NULL) return NULL;

/* ako je glava jednaka datom broju, vracamo adresu glave */


if(glava->vrednost == broj)
return glava;
/* u suprotnom pretrazujemo rep rekurzivnim pozivom i vracamo
ono sto taj rekurzivni poziv vrati */
else
return pretrazi_listu(glava->sledeci, broj);

/* Funkcija brise iz liste sve cvorove koji sadrze dati broj.


Funkcija vraca pokazivac na glavu liste (koji moze biti

132
Milena Vujošević–Janičić 10.1 Implementacija

promenjen u slucaju da se obrise stara glava). Funkcija


koristi rekurziju. */
Cvor* obrisi_element(Cvor *glava, int broj)
{

/* Izlaz iz rekurzije: prazna lista ostaje prazna nakon


brisanja elemenata koji su jednaki sa brojem */
if(glava == NULL) return NULL;

/* Rekurzivno iz repa uklanjamo sve pojave datog broja.


Rekurzivni poziv vraca adresu glave tako modifikovanog
repa, koja se cuva u pokazivacu na sledeci u okviru glave */
glava->sledeci = obrisi_element(glava->sledeci, broj);

/* Nakon ovoga znamo da u repu nema pojava datog broja. Jedino


ostaje da proverimo jos i glavu, i da je po potrebi obrisemo */
if(glava->vrednost == broj)
{
Cvor *pomocni = glava;
glava = glava->sledeci;
free(pomocni);
}

/* vracamo novu glavu */


return glava;
}

/*
void obrisi_element(Cvor **glava, int broj)
{

/* Izlaz iz rekurzije: prazna lista ostaje prazna nakon


brisanja elemenata koji su jednaki sa brojem */
if(*glava == NULL) return;

/* Rekurzivno iz repa uklanjamo sve pojave datog broja.


Rekurzivni poziv vraca adresu glave tako modifikovanog
repa, koja se cuva u pokazivacu na sledeci u okviru glave */
obrisi_element(&(*glava->sledeci), broj);

/* Nakon ovoga znamo da u repu nema pojava datog broja. Jedino


ostaje da proverimo jos i glavu, i da je po potrebi obrisemo */

133
Milena Vujošević–Janičić 10.1 Implementacija

if(*glava->vrednost == broj)
{
Cvor *pomocni = *glava;
*glava = *glava->sledeci;
free(pomocni);
}
}
*/

/* Pomocna rekurzivna funkcija koja prikazuje


listu. Definisana je kao static, cime se
sprecava njeno koriscenje od strane funkcija
koje nisu definisane u ovom fajlu */
static void prikazi_listu_r(Cvor *glava)
{

/* Izlaz iz rekurzije */
if(glava == NULL) return;

/* Prikaz glave */
printf("%d ", glava->vrednost);

/* Prikaz repa (rekurzivnim pozivom) */


prikazi_listu_r(glava->sledeci);

/* Funkcija prikazuje elemente liste pocev od glave


ka kraju liste. Koristi rekurzivnu funkciju
prikazi_listu_r(). Ova funkcija prosto dodaje
uglaste zagrade i novi red na kraju ispisa. */
void prikazi_listu(Cvor *glava)
{
putchar(’[’);

prikazi_listu_r(glava);

putchar(’]’);

putchar(’\n’);
}

/* Funkcija oslobadja dinamicku memoriju zauzetu


od strane liste. Funkcija koristi rekurziju. */

134
Milena Vujošević–Janičić 10.1 Implementacija

Cvor* oslobodi_listu(Cvor *glava)


{
/* Izlaz iz rekurzije */
if(glava == NULL) return NULL;

/* Oslobadjamo rep liste */


oslobodi_listu(glava->sledeci);

/* Oslobadjamo glavu liste */


free(glava);

return NULL;
}

/*
void oslobodi_listu(Cvor **glava)
{
/* Izlaz iz rekurzije */
if(*glava == NULL) return;

/* Oslobadjamo rep liste */


oslobodi_listu(&(*glava->sledeci));

/* Oslobadjamo glavu liste */


free(*glava);

*glava = NULL;
}
*/
Primer 10.3 Program ispisuje broj pojavljivanja za svaku od reči koja se pojavila u
tekstu unetom sa standardnog ulaza. Verzija sa (sortiranom) listom.
#include <stdlib.h>
#include <stdio.h>

/* Definicija cvora liste */


typedef struct _cvor
{
char ime[80];
int br_pojavljivanja;
struct _cvor* sledeci;
} cvor;

/* Pomocna funkcija koja kreira cvor.


Funkcija vraca pokazivac na novokreirani cvor */

135
Milena Vujošević–Janičić 10.1 Implementacija

cvor* napravi_cvor(char* rec)


{
cvor *novi = NULL;
if((novi = (cvor *) malloc(sizeof(cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}

strcpy(novi->ime, rec);
novi->br_pojavljivanja = 1;
novi->sledeci = NULL;
return novi;
}

/* Funkcija ispisuje listu rekurzivno, pocevsi od poslednjeg


elementa */
void ispisi_listu(cvor* pocetak)
{
if (pocetak!=NULL)
{
ispisi_listu(pocetak->sledeci);
printf("%s %d\n",pocetak->ime,pocetak->br_pojavljivanja);
}
}

/* Funkcija koja brise listu */


void obrisi_listu(cvor* pocetak)
{
if (pocetak!=NULL)
{
obrisi_listu(pocetak->sledeci);
free(pocetak);
}
}

/* Funkcija ubacuje rekurzivno datu rec u listu koja je


leksikografski sortirana, na odgovarajuce mesto i vraca
pokazivac na novi pocetak liste */
cvor* ubaci_sortirano(cvor* pocetak, char* rec)
{
int cmp;
/* Ukoliko je lista prazna ubacujemo na pocetak liste*/
if (pocetak==NULL)

136
Milena Vujošević–Janičić 10.1 Implementacija

return napravi_cvor(rec);

/* Ukoliko lista nije prazna poredimo rec sa elementom u glavi */


cmp=strcmp(pocetak->ime,rec);
/* Ukoliko je rec pronadjena samo uvecavamo njen broj
pojavljivanja */
if (cmp==0)
{ pocetak->br_pojavljivanja++;
return pocetak;
}
/* Ukoliko je rec koju ubacujemo veca od tekuce reci, ubacujemo je
rekurzivno u rep */
else if (cmp>0)
{ pocetak->sledeci=ubaci_sortirano(pocetak->sledeci,rec);
return pocetak;
}
/* Ukoliko je rec koju ubacujemo manja od tekuce reci, gradimo novi
cvor i ubacujemo ga ispred pocetka */
else
{
cvor* novi=napravi_cvor(rec);
novi->sledeci=pocetak;
return novi;
}
}

/* Pomocna funkcija koja cita rec sa standardnog ulaza i vraca


njenu duzinu, odnosno -1 ukoliko se naidje na EOF */
int getword(char word[], int lim) {
int c, i=0;
while (!isalpha(c=getchar()) && c!=EOF)
;

if (c==EOF)
return -1;
do
{ word[i++]=c;
}while (i<lim-1 && isalpha(c=getchar()));

word[i]=’\0’;
return i;
}

/* Funkcija koja rekurzivno pronalazi datu rec u datoj listi.

137
Milena Vujošević–Janičić 10.1 Implementacija

Funkcija vraca pokazivac na cvor u kome je nadjena rec, ili


NULL ukoliko rec nije nadjena. */
cvor* nadji_rec(cvor* lista, char rec[])
{
if (lista==NULL)
return NULL;
if (strcmp(lista->ime,rec)==0)
return lista;
/* Da bi pretrazivanje u sortiranoj listi
bilo efikasnije:
if (strcmp(lista->ime,rec)<0)
return NULL;
*/
return nadji_rec(lista->sledeci,rec);
}

main()
{
cvor* lista=NULL;
char procitana_rec[80];
cvor* pronadjen;

while(getword(procitana_rec,80)!=-1)
lista=ubaci_sortirano(lista,procitana_rec);

pronadjen=nadji_rec(lista,"programiranje");
if (pronadjen!=NULL)
printf("Rec programiranje se javlja u listi!\n");
else
printf("Rec programiranje se ne javlja u listi!\n");

ispisi_listu(lista);
obrisi_listu(lista);
}
Primer 10.4 Primer ilustruje sortiranje liste. Lista moze biti sortirana na dva
načina. Prvi način je da se premeštaju čvorovi u listi (što zahteva prevezivanje
pokazivača), a drugi je da se premeštaju vrednosti koje čvorovi sadrže. Prvi način
je komplikovaniji, ali je često efikasniji, naročito ako su objekti koji se čuvaju kao
podaci u čvorovima veliki.
U oba slučaja se može koristiti rekurzija, a može se realizovati i iterativno. U
ovom primeru ilustrujemo oba načina sortiranja lista (prvi rekurzivno, a drugi iter-
ativno).
#include <stdio.h>
#include <stdlib.h>

138
Milena Vujošević–Janičić 10.1 Implementacija

#include <time.h>

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
int vrednost; /* podatak koji cvor sadrzi */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;

/* Pomocna funkcija koja kreira cvor. Funkcija vrednost


novog cvora inicijalizuje na broj, dok pokazivac na
sledeci cvor u novom cvoru postavlja na NULL. Funkcija
ispisuje poruku o gresci i prekida program u slucaju
da malloc() funkcija ne uspe da alocira prostor.
Funkcija vraca pokazivac na novokreirani cvor */
Cvor* napravi_cvor(int broj)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}

novi->vrednost = broj;
novi->sledeci = NULL;
return novi;
}

/* Funkcija dodaje novi cvor na pocetak liste. Funkcija


kreira novi cvor koriscenjem funkcije napravi_cvor().
Funkcija vraca pokazivac na novu glavu liste */
Cvor * dodaj_na_pocetak_liste(Cvor *glava, int broj)
{
Cvor * novi = napravi_cvor(broj);
novi->sledeci = glava;
return novi;
}

/* Pomocna rekurzivna funkcija koja prikazuje


listu. Definisana je kao static, cime se
sprecava njeno koriscenje od strane funkcija
koje nisu definisane u ovom fajlu */
static void prikazi_listu_r(Cvor *glava)

139
Milena Vujošević–Janičić 10.1 Implementacija

/* Izlaz iz rekurzije */
if(glava == NULL) return;

/* Prikaz glave */
printf("%d ", glava->vrednost);

/* Prikaz repa (rekurzivnim pozivom) */


prikazi_listu_r(glava->sledeci);
}

/* Funkcija prikazuje elemente liste pocev od glave


ka kraju liste. Koristi rekurzivnu funkciju
prikazi_listu_r(). Ova funkcija prosto dodaje
uglaste zagrade i novi red na kraju ispisa. */
void prikazi_listu(Cvor *glava)
{
putchar(’[’);

prikazi_listu_r(glava);

putchar(’]’);

putchar(’\n’);
}

/* Funkcija oslobadja dinamicku memoriju zauzetu


od strane liste. Funkcija koristi rekurziju. */
Cvor* oslobodi_listu(Cvor *glava)
{
/* Izlaz iz rekurzije */
if(glava == NULL) return NULL;

/* Oslobadjamo rep liste */


oslobodi_listu(glava->sledeci);

/* Oslobadjamo glavu liste */


free(glava);

return NULL;
}

Cvor* dodaj_cvor_sortirano(Cvor * glava, Cvor * novi)

140
Milena Vujošević–Janičić 10.1 Implementacija

{
/* u slucaju da je lista prazna, ili da je vrednost
glave veca ili jednaka od vrednosti broja koji
umecemo, tada se novi cvor umece na pocetak liste. */
if(glava == NULL || glava->vrednost >= novi->vrednost)
{
novi->sledeci = glava;
return novi;
}

/* U slucaju da je lista neprazna, i da je vrednost


glave manja od vrednosti broja koji umecemo u listu,
tada je sigurno da se novi element umece DESNO od glave,
tj. u rep liste. Dakle, mozemo rekurzivno pozvati istu
funkciju za rep liste. S obzirom da po induktivnoj
pretpostavci rep nakon toga ostaje sortiran, a svi
elementi u repu ukljucujuci i element koji je dodat
su jednaki ili veci od glave, tada ce i cela lista
biti sortirana. Povratna vrednost rekurzivnog poziva
predstavlja adresu glave modifikovanog repa liste,
pa se ta adresa mora sacuvati u pokazivacu na sledeci
u glavi liste. */
glava->sledeci = dodaj_cvor_sortirano(glava->sledeci, novi);

/* vracamo glavu */
return glava;
}

/* Sortira listu i vraca adresu glave liste. Lista se sortira


rekurzivno, prevezivanjem cvorova. */
Cvor* sortiraj_listu(Cvor * glava)
{
Cvor * pomocni;

/* Izlaz iz rekurzije */
if(glava == NULL)
return NULL;

/* Odvajamo cvor glave iz liste, a za glavu proglasavamo


sledeci cvor */
pomocni = glava;
glava = glava->sledeci;
pomocni->sledeci = NULL;

141
Milena Vujošević–Janičić 10.1 Implementacija

/* Sortiramo ostatak liste */


glava = sortiraj_listu(glava);
glava = dodaj_cvor_sortirano(glava, pomocni);

/* Vracamo novu glavu */


return glava;
}

/* Funkcija sortira listu i vraca adresu glave liste. Lista se


sortira iterativno, zamenom vrednosti u cvorovima. */
Cvor* sortiraj_listu2(Cvor * glava)
{
int t;
Cvor * pi, * pj, * min;

/* Slucaj prazne liste */


if(glava == NULL)
return glava;

/* Simuliramo selection sort */


for(pi = glava; pi->sledeci != NULL ; pi = pi->sledeci)
{
min = pi;
for(pj = pi->sledeci; pj != NULL; pj = pj->sledeci)
{
if(pj->vrednost < min->vrednost)
min = pj;
}
t = min->vrednost;
min->vrednost = pi->vrednost;
pi->vrednost = t;
}

/* Vracamo glavu */
return glava;
}

/* test program */
int main()
{
Cvor *glava = NULL;
int n = 10;

/* Inicijalizujemo sekvencu slucajnih brojeva. */

142
Milena Vujošević–Janičić 10.2 Kružna (ciklična) lista

srand(time(NULL));

/* Generisemo n slucajnih brojeva i dodajemo ih na pocetak liste */


while(n--)
glava = dodaj_na_pocetak_liste(glava, (int) (100 * (rand()/(double)RAND_MAX)));

/* Prikazujemo generisanu listu */


printf("Generisana lista:\n");
prikazi_listu(glava);

/* Sortiramo listu */
glava = sortiraj_listu(glava);
/* glava = sortiraj_listu2(glava); */

/* Prikazujemo listu nakon sortiranja */


printf("Lista nakon sortiranja:\n");
prikazi_listu(glava);

/* Oslobadjamo listu */
glava = oslobodi_listu(glava);

return 0;
}

10.2 Kružna (ciklična) lista

pocetak ciklicne liste

A B C ... Z

Slika 10.1: Kruzna lista

Primer 10.5 (februar 2006.) Grupa od n plesača (na čijim kostimima su u smeru
kazaljke na satu redom brojevi od 1 do n) izvodi svoju plesnu tačku tako što formiraju
krug iz kog najpre izlazi k-ti plesač (odbrojava se počev od plesača označenog brojem
1 u smeru kretanja kazaljke na satu). Preostali plesači obrazuju manji krug iz kog
opet izlazi k-ti plesač (odbrojava se pocev od sledećeg suseda prethodno izbačenog,
opet u smeru kazaljke na satu). Izlasci iz kruga se nastavljaju sve dok svi plesači

143
Milena Vujošević–Janičić 10.3 Red

ne budu isključeni. Celi brojevi n, k (k < n) se učitavaju sa standardnog ulaza.


Napisati program koji će na standardni izlaz ispisati redne brojeve plesača u redosledu
napuštanja kruga.
PRIMER: za n = 5, k = 3 redosled izlaska je 3 1 5 2 4.

10.3 Red

pocetak reda (brisanje — get)


kraj reda (dodavanje — add)

A B ... X NULL

novi element

pocetak reda
novi kraj reda

A B ... X Y NULL

pocetak reda nakon brisanja kraj reda

B ... X Y NULL

Slika 10.2: Red

Red (eng. queue) je struktura podataka nad kojom su de nisane sledece operacije:
 Dodavanje elementa – kazemo da je element dodat na kraj reda (eng. enqueue()
operacija)
 Uklanjanje elementa koji je prvi dodat – kazemo da je element skinut sa pocetka
reda (eng. dequeue() operacija)
 Ocitavanje vrednosti elementa koji je na pocetku reda (eng. front() operacija)
Red spada u FIFO strukture (eng. First In First Out). Moze se implementirati
na vise nacina. Najjednostavniji nacin je da se de nise kao niz. Medjutim, tada
je ogranicen max. broj elemenata u redu dimenzijom niza. Zbog toga se obicno
pribegava koriscenju lista za implementaciju reda, gde se enqueue() operacija svodi
na dodavanje na kraj liste, a dequeue() operacija se svodi na uklanjanje glave liste.

144
Milena Vujošević–Janičić 10.3 Red

Obe operacije se izvode u konstantnom vremenu, pod uslovom da se osim pokazivaca


na glavu liste cuva i pokazivac na poslednji element u listi.
Primer 10.6 Skupovi brojeva su predstavljeni tekstualnim fajlovima koji sadrze bro-
jeve i imena drugih fajlova. Ako se broj x nalazi u fajlu S, tada broj x pripada skupu
S. Ako se ime fajla S1 nalazi u fajlu S2, tada je skup S1 podskup skupa S2. Program
za dati skup S i dati broj x proverava da li x pripada S.
U ovom zadatku ce red biti koriscen na sledeci nacin: inicijalno se u red stavlja
ime fajla koji predstavlja dati skup S. Iz reda se zatim u petlji uzima sledeci fajl i
otvara za citanje. Prilikom citanja, svaki put kada se u fajlu koji se trenutno cita
naidje na ime drugog fajla, to ime ce biti dodato u red. Kada se zavrsi sa citanjem
tekuceg fajla, isti se zatvara, skida se sa reda sledeci fajl i citanje se nastavlja u
njemu. Ovaj proces se ponavlja dok se ne naidje na trazeni broj, ili dok se ne
isprazni red.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
char ime_fajla[MAX]; /* Sadrzi ime fajla */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;

/* Funkcija kreira novi cvor, upisuje u njega etiketu


i vraca njegovu adresu */
Cvor * napravi_cvor(char * ime_fajla)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}

strcpy(novi->ime_fajla, ime_fajla);
novi->sledeci = NULL;
return novi;
}

/* Funkcija dodaje na kraj reda novi fajl */

145
Milena Vujošević–Janičić 10.3 Red

void dodaj_u_red(Cvor **pocetak, Cvor **kraj, char *ime_fajla)


{
Cvor * novi = napravi_cvor(ime_fajla);

if(*kraj != NULL)
{
(*kraj)->sledeci = novi;
*kraj = novi;
}
else /* ako je red prazan */
{
*pocetak = novi;
*kraj = novi;
}
}

/* Funkcija skida sa pocetka reda fajl. Ako je poslednji argument


pokazivac razlicit od NULL, tada u niz karaktera na koji on
pokazuje upisuje ime fajla koji je upravo skinut sa reda
dok u suprotnom ne radi nista. Funkcija vraca 0 ako je red
prazan (pa samim tim nije bilo moguce skinuti vrednost sa
reda) ili 1 u suprotnom. */
int skini_sa_reda(Cvor **pocetak, Cvor ** kraj, char * ime_fajla)
{
Cvor * pomocni;

if(*pocetak == NULL)
return 0;

if(ime_fajla != NULL)
strcpy(ime_fajla, (*pocetak)->ime_fajla);

pomocni = *pocetak;
*pocetak = (*pocetak)->sledeci;
free(pomocni);

if(*pocetak == NULL)
*kraj = NULL;

return 1;
}

/* Funkcija vraca pokazivac na string koji sadrzi ime fajla

146
Milena Vujošević–Janičić 10.3 Red

na pocetku reda. Ukoliko je red prazan, vraca NULL */


char * pocetak_reda(Cvor *pocetak)
{
if(pocetak == NULL)
return NULL;
else
return pocetak->ime_fajla;
}

/* Funkcija prazni red */


void oslobodi_red(Cvor **pocetak, Cvor **kraj)
{
Cvor *pomocni;

while(*pocetak != NULL)
{
pomocni = *pocetak;
*pocetak = (*pocetak)->sledeci;
free(pomocni);
}
*kraj = NULL;
}

/* Glavni program */
int main(int argc, char ** argv)
{
Cvor * pocetak = NULL, * kraj = NULL;
FILE *in = NULL;
char ime_fajla[MAX];
int x, y;
int pronadjen = 0;

/* NAPOMENA: Pretpostavlja se da nema cirkularnih zavisnosti, tj. da ne moze


da se desi slucaj: S2 podskup od S1, S3 podskup S2,...,S1 podskup od Sn,
u kom slucaju bismo imali beskonacnu petlju. */

/* Ime fajla i broj se zadaju sa komandne linije */


if(argc < 3)
{
fprintf(stderr, "koriscenje: %s fajl broj\n", argv[0]);
exit(1);
}

/* Dodajemo skup S u red */

147
Milena Vujošević–Janičić 10.3 Red

dodaj_u_red(&pocetak, &kraj, argv[1]);

/* Trazeni broj x */
x = atoi(argv[2]);

/* Dokle god broj nije pronadjen, a ima jos fajlova u redu */


while(!pronadjen && skini_sa_reda(&pocetak, &kraj, ime_fajla))
{
/* Otvaramo sledeci fajl sa reda */
if((in = fopen(ime_fajla, "r")) == NULL)
{
fprintf(stderr, "Greska prilikom otvaranja fajla: %s\n", ime_fajla);
exit(1);
}

/* Dokle god nismo stigli do kraja fajla i nismo pronasli broj */


while(!feof(in) && !pronadjen)
{
/* Ako je broj sledeci podatak u fajlu */
if(fscanf(in, "%d", &y) == 1)
{
/* Ako je nadjen trazeni broj */
if(x == y)
{
printf("Broj x=%d pripada skupu!\n", x);
pronadjen = 1;
}
}
/* Ako je ime fajla sledeci podatak u fajlu */
else if(fscanf(in, "%s", ime_fajla) == 1)
{
/* Dodajemo ga u red */
dodaj_u_red(&pocetak, &kraj, ime_fajla);
}

}
/* Zatvaramo fajl */
fclose(in);
}

/* Ako do kraja nije pronadjen */


if(!pronadjen)
printf("Broj x=%d ne pripada skupu!\n", x);

148
Milena Vujošević–Janičić 10.3 Red

/* Oslobadjamo red */
oslobodi_red(&pocetak, &kraj);

return 0;
}
Primer 10.7 Program formira celobrojni red i ispisuje sadržaj reda na standardni
izlaz.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
int broj; /* broj */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;

/* Funkcija kreira novi cvor, upisuje u njega broj


i vraca njegovu adresu */
Cvor * napravi_cvor(int broj)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}
novi->broj = broj;
novi->sledeci = NULL;
return novi;
}

/* Funkcija dodaje na kraj reda broj */


void dodaj_u_red(Cvor **pocetak, Cvor **kraj, int broj)
{
Cvor * novi = napravi_cvor(broj);

if(*kraj != NULL)
{

149
Milena Vujošević–Janičić 10.3 Red

(*kraj)->sledeci = novi;
*kraj = novi;
}
else /* ako je red prazan */
{
*pocetak = novi;
*kraj = novi;
}
}

/* Funkcija skida sa pocetka reda broj */


int skini_sa_reda(Cvor **pocetak, Cvor ** kraj, int *broj)
{
Cvor * pomocni;

if(*pocetak == NULL)
return 0;

if(broj != NULL)
*broj = (*pocetak)->broj);

pomocni = *pocetak;
*pocetak = (*pocetak)->sledeci;
free(pomocni);

if(*pocetak == NULL)
*kraj = NULL;

return 1;
}

main()
{
Cvor * pocetak = NULL, * kraj = NULL;
int i, broj;
/*Formiranje jednostavnog reda*/
for(i=0; i<100; i++)
dodaj_u_red(&pocetak, &kraj, i);

/*Ispis elemenata reda koristeci operacije nad redom*/


while(skini_sa_reda(&pocetak, &kraj, &broj))
printf("Element uzet sa pocetka reda je %d\n", broj);

150
Milena Vujošević–Janičić 10.4 Stek

/*Nema potrebe da se oslobadja memorija jer je memorija koju


je red zauzimao oslobodjena prilikom ispisa elemenata
reda - nakon ispisa red je ostao prazan!*/
}

10.4 Stek
Stek (eng. stack) je struktura podataka nad kojom su de nisane sledece operacije:
 Dodavanje elementa – kazemo da je element potisnut na vrh steka (eng. push()
operacija).
 Uklanjanje elementa koji je poslednji dodat – kazemo da je element skinut sa
vrha steka (eng. pop() operacija).
 Ocitavanje vrednosti elementa koji je poslednji dodat (eng. top() operacija).
Stek spada u LIFO strukture (eng. Last In First Out). Moze se implementirati
na vise nacina. Najjednostavniji nacin je da se de nise kao niz. Medjutim, tada
je ogranicen max. broj elemenata na steku dimenzijom niza. Zbog toga se obicno
pribegava koriscenju lista za implementaciju steka, gde se push() operacija svodi
na dodavanje na pocetak, a pop() operacija se svodi na uklanjanje glave liste. Obe
operacije se izvode u konstantnom vremenu.
Primer 10.8 Program proverava da li su zagrade (, [, {, }, ] i ) dobro uparene —
statička implementacija steka (pretpostavka da se na ulazu neće naći više od 100
otvorenih zagrada za redom).
#include <stdio.h>
#include <stdlib.h>
#define MAX_ZAGRADA 100

int odgovarajuce(char z1, char z2) {


return (z1 == ’(’ && z2 == ’)’) ||
(z1 == ’{’ && z2 == ’}’) ||
(z1 == ’[’ && z2 == ’]’);
}

main()
{
int c;
char otv_zagrade[MAX_ZAGRADA];
int br_otv = 0;

while((c=getchar()) != EOF)
{
switch(c)

151
Milena Vujošević–Janičić 10.4 Stek

{
case ’(’:
case ’{’:
case ’[’:
{
otv_zagrade[br_otv] = c;
br_otv++;
break;
}
case ’]’:
case ’}’:
case ’)’:
if (br_otv>0 && odgovarajuce(otv_zagrade[br_otv-1], c))
{
br_otv--;
}
else
{
printf("Visak zatvorenih zagrada: %c u liniji %d\n", c, br_linija);
exit(1);
}
}
}

if (br_otv == 0)
printf("Zagrade su u redu\n");
else
printf("Visak otvorenih zagrada\n");
}

Primer 10.9 Program proverava da li su etikete u datom HTML fajlu dobro up-
arene.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX 100

#define OTVORENA 1
#define ZATVORENA 2

#define VAN_ETIKETE 0
#define PROCITANO_MANJE 1

152
Milena Vujošević–Janičić 10.4 Stek

vrh steka (i dodavanje i brisanje — push i pop)

X Y ... A NULL

novi element

novi vrh steka

Y X V ... A NULL

vrh steka nakon brisanja

X V ... A NULL

Slika 10.3: Stek

#define U_ETIKETI 2

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
char etiketa[MAX]; /* Sadrzi ime etikete */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;

/* Funkcija kreira novi cvor, upisuje u njega etiketu


i vraca njegovu adresu */
Cvor * napravi_cvor(char * etiketa)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}

strcpy(novi->etiketa, etiketa);
novi->sledeci = NULL;

153
Milena Vujošević–Janičić 10.4 Stek

return novi;
}

/* Funkcija postavlja na vrh steka novu etiketu */


void potisni_na_stek(Cvor **vrh, char *etiketa)
{
Cvor * novi = napravi_cvor(etiketa);
novi->sledeci = *vrh;
*vrh = novi;
}

/* Funkcija skida sa vrha steka etiketu. Ako je drugi argument


pokazivac razlicit od NULL, tada u niz karaktera na koji on
pokazuje upisuje ime etikete koja je upravo skinuta sa steka
dok u suprotnom ne radi nista. Funkcija vraca 0 ako je stek
prazan (pa samim tim nije bilo moguce skinuti vrednost sa
steka) ili 1 u suprotnom. */
int skini_sa_steka(Cvor **vrh, char * etiketa)
{
Cvor * pomocni;

if(*vrh == NULL)
return 0;

if(etiketa != NULL)
strcpy(etiketa, (*vrh)->etiketa);

pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);

return 1;
}

/* Funkcija vraca pokazivac na string koji sadrzi etiketu


na vrhu steka. Ukoliko je stek prazan, vraca NULL */
char * vrh_steka(Cvor *vrh)
{
if(vrh == NULL)
return NULL;
else
return vrh->etiketa;
}

154
Milena Vujošević–Janičić 10.4 Stek

/* Funkcija prazni stek */


void oslobodi_stek(Cvor **vrh)
{
Cvor *pomocni;

while(*vrh != NULL)
{
pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);
}
}

/* Funkcija iz fajla na koji pokazuje f cita sledecu


etiketu, i njeno ime upisuje u niz na koji pokazuje
pokazivac etiketa. Funkcija vraca EOF u slucaju da
se dodje do kraja fajla pre nego sto se procita
etiketa, vraca OTVORENA ako je procitana otvorena
etiketa, odnosno ZATVORENA ako je procitana zatvorena
etiketa. */
int uzmi_etiketu(FILE *f, char * etiketa)
{
int c;
int stanje = VAN_ETIKETE;
int i = 0;
int tip;

while((c = fgetc(f)) != EOF)


{
switch(stanje)
{
case VAN_ETIKETE:
if(c == ’<’)
{
stanje = PROCITANO_MANJE;
}
break;
case PROCITANO_MANJE:
if(c == ’/’)
{
tip = ZATVORENA;
}
else if(isalpha(c))

155
Milena Vujošević–Janičić 10.4 Stek

{
tip = OTVORENA;
etiketa[i++] = tolower(c);
}
stanje = U_ETIKETI;
break;
case U_ETIKETI:
if(isalpha(c) && i < MAX - 1)
etiketa[i++] = tolower(c);
else {
stanje = VAN_ETIKETE;
etiketa[i]=’\0’;
return tip;
}
break;
}
}
return EOF;
}

/* Test program */
int main(int argc, char **argv)
{

Cvor * vrh = NULL;


char etiketa[MAX];
int tip;
int u_redu = 1;
FILE * f;

/* Ime datoteke zadajemo na komandnoj liniji */


if(argc < 2)
{
fprintf(stderr, "Koriscenje: %s ime_html_datoteke\n", argv[0]);
exit(0);
}

/* Otvaramo datoteku */
if((f = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska!\n");
exit(1);
}

156
Milena Vujošević–Janičić 10.4 Stek

/* Dokle god ima etiketa, uzimamo ih jednu po jednu sa ulaza */


while((tip = uzmi_etiketu(f, etiketa)) != EOF)
{
/* Ako je otvorena etiketa, dodajemo je na stek. Izuzetak su
etikete <br>, <hr> i <meta> koje nemaju sadrzaj, tako da
ih nije potrebno zatvoriti. NAPOMENA: U html-u postoje
jos neke etikete koje koje nemaju sadzaj (npr link).
Pretpostavimo da njih nema u dokumentu, zbog jednostavnosti */
if(tip == OTVORENA)
{
if(strcmp(etiketa, "br") != 0
&& strcmp(etiketa, "hr") != 0
&& strcmp(etiketa, "meta") != 0)
potisni_na_stek(&vrh, etiketa);
}
/* Ako je zatvorena etiketa, tada je uslov dobre uparenosti da je u pitanju
zatvaranje etikete koja je poslednja otvorena, a jos uvek nije zatvorena.
Ova etiketa se mora nalaziti na vrhu steka. Ako je taj uslov ispunjen,
tada je skidamo sa steka, jer je zatvorena. U suprotnom, obavestavamo
korisnika da etikete nisu pravilno uparene. */
else if(tip == ZATVORENA)
{
if(vrh_steka(vrh) != NULL && strcmp(vrh_steka(vrh), etiketa) == 0)
skini_sa_steka(&vrh, NULL);
else
{
printf(vrh_steka(vrh) != NULL ?
"Etikete nisu pravilno uparene\n(nadjena etiketa
</%s> a poslednja otvorena etiketa je <%s>)\n" :
"Etikete nisu pravilno uparene\n(nadjena etiketa
</%s> koja nije otvorena)\n",
etiketa, vrh_steka(vrh));
u_redu = 0;
break;
}
}
}

/* Zatvaramo fajl */
fclose(f);

/* Ako nismo pronasli pogresno uparivanje...*/


if(u_redu)
{

157
Milena Vujošević–Janičić 10.4 Stek

/* Nakon zavrsetka citanja etiketa uslov je da stek mora biti prazan.


Ako nije, tada znaci da postoje jos neke etikete koje su otvorene
ali nisu zatvorene. */
if(vrh_steka(vrh) == NULL)
printf("Etikete su pravilno uparene!\n");
else
printf("Etikete nisu pravilno uparene\n(etiketa <%s> nije zatvorena)\n",
vrh_steka(vrh));
}

/* Oslobadjamo stek */
oslobodi_stek(&vrh);

return 0;
}
Primer 10.10 Program formira celobrojni stek i ispisuje sadržaj steks na standardni
izlaz.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
int broj; /* broj */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;

/* Funkcija kreira novi cvor, upisuje u njega broj


i vraca njegovu adresu */
Cvor * napravi_cvor(int broj)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}
novi->broj = broj;
novi->sledeci = NULL;
return novi;
}

158
Milena Vujošević–Janičić 10.4 Stek

/* Funkcija dodaje broj na stek*/


void potisni_na_stek(Cvor **vrh, int broj)
{
Cvor * novi = napravi_cvor(broj);
novi->sledeci = *vrh;
*vrh = novi;
}

/* Funkcija skida broj sa steka */


int skini_sa_steka(Cvor **vrh, int *broj)
{
Cvor * pomocni;

if(*vrh == NULL)
return 0;

if(broj != NULL)
*broj = (*vrh)->broj);

pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);

return 1;
}

main()
{
Cvor * vrh = NULL;
int i, broj;

/*Formiranje steka*/
for(i=0; i<100; i++)
potisni_na_stek(&vrh, i);

/*Ispis elemenata steka: 99, 98 ... 0*/


while(skini_sa_steka(&pocetak, &kraj, &broj))
printf("Broj skinut sa vrha steka je %d\n", broj);

/*Nema potrebe da se oslobadja memorija jer je memorija koju


je stek zauzimao oslobodjena prilikom ispisa elemenata
steka - nakon ispisa stek je ostao prazan!*/

159
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste

10.5 Dvostruko povezane liste

pocetak dvostruko povezane liste kraj liste

...
NULL A B C ... Z NULL

Slika 10.4: Dvostruko povezana lista

Dvostruko povezana lista je struktura podataka koja se sastoji od sekvence cvorova.


Svaki cvor sadrzi podatak (odred̄enog tipa) i pokazivace na prethodni i sledeci cvor
u sekvenci. Za razliku od obicne liste, u svakom cvoru imamo zapisanu i adresu
prethodnog elementa, pa se kroz listu mozemo kretati i unazad. Poslednji element u
listi nema sledeci element: u tom slucaju se njegov pokazivac na sledeci postavlja na
NULL. Slicno, glava liste nema prethodni element, pa je njen pokazivac na prethodni
postavljen na NULL. Takod̄e, prazna lista se predstavlja NULL pokazivacem.
Prednost dvostruko povezane liste u odnosu na jednostruko povezanu je u tome
sto se mozemo kretati u oba smera kroz listu. Nedostatak je to sto se velicina
memorije potrebne za cuvanje cvora povecava za velicinu jednog pokazivaca.
Primer 10.11 Program demonstrira rad sa dvostruko povezanim listama. Za testi-
ranje narednih funkcija može se koristiti main funkcija iz primera 10.1.
#include <stdio.h>
#include <stdlib.h>

/* Struktura koja predstavlja cvor liste */


typedef struct cvor {
int vrednost; /* podatak koji cvor sadrzi */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
struct cvor *prethodni; /* pokazivac na prethodni */
} Cvor;

/* Pomocna funkcija koja kreira cvor. Funkcija vrednost


novog cvora inicijalizuje na broj, dok pokazivace na
prethodni i sledeci cvor u novom cvoru postavlja na NULL.
Funkcija ispisuje poruku o gresci i prekida program u
slucaju da malloc() funkcija ne uspe da alocira prostor.

160
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste

Funkcija vraca pokazivac na novokreirani cvor */


Cvor* napravi_cvor(int broj)
{
Cvor *novi = NULL;
if((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska!\n");
exit(1);
}

novi->vrednost = broj;
novi->prethodni = NULL;
novi->sledeci = NULL;
return novi;
}

/* Funkcija dodaje novi cvor na pocetak liste. Funkcija


kreira novi cvor koriscenjem funkcije napravi_cvor().
Funkcija vraca pokazivac na novu glavu liste */
Cvor* dodaj_na_pocetak_liste(Cvor *glava, int broj)
{
Cvor *novi = napravi_cvor(broj);
novi->sledeci = glava;
if(glava != NULL) glava->prethodni = novi;

return novi;
}

/* Funkcija dodaje novi cvor na kraj liste. Funkcija


kreira novi cvor koriscenjem funkcije napravi_cvor().
Funkcija vraca pokazivac na glavu liste (koji moze
biti promenjen u slucaju da je lista inicijalno bila
prazna). */
Cvor* dodaj_na_kraj_liste(Cvor *glava, int broj)
{
Cvor *novi = napravi_cvor(broj);
Cvor *tekuci = glava;

/* slucaj prazne liste. U tom slucaju je glava nove liste


upravo novi cvor. */
if(glava == NULL) return novi;

/* Ako lista nije prazna, tada se krecemo duz liste sve dok
ne dodjemo do poslednjeg cvora (tj. do cvora ciji pokazivac

161
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste

na sledeci pokazuje na NULL) */


while(tekuci->sledeci != NULL)
tekuci = tekuci->sledeci;

/* Dodajemo novi element na kraj preusmeravanjem pokazivaca */


tekuci->sledeci = novi;
novi->prethodni = tekuci;

/* Vracamo glavu liste */


return glava;
}

/* Funkcija dodaje novi element u sortiranu listu tako da i nova


lista ostane sortirana. Funkcija kreira novi cvor koriscenjem
funkcije napravi_cvor(). Funkcija vraca pokazivac na glavu liste
(koji moze biti promenjen u slucaju da je novi element dodat na
pocetak liste) */
Cvor* dodaj_sortirano(Cvor *glava, int broj)
{
Cvor *novi = napravi_cvor(broj);
Cvor *tekuci = glava;

/* u slucaju prazne liste glava nove liste je


upravo novi element */
if(glava == NULL) return novi;

/* ako je novi element manji ili jednak od glave,


tada novi element mora da bude nova glava */
if(glava->vrednost >= novi->vrednost)
{
novi->sledeci = glava;
glava->prethodni = novi;
return novi;
}

/* u slucaju da je glava manja od novog elementa, tada se krecemo kroz


listu sve dok se ne dodje do elementa ciji je sledeci element veci ili
jednak od novog elementa, ili dok se ne dodje do poslednjeg elementa. */
while(tekuci->sledeci != NULL && tekuci->sledeci->vrednost < novi->vrednost)
tekuci = tekuci->sledeci;

/* U svakom slucaju novi element dodajemo IZA tekuceg elementa */


novi->sledeci = tekuci->sledeci;
novi->prethodni = tekuci;

162
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste

if(tekuci->sledeci != NULL)
tekuci->sledeci->prethodni = novi;
tekuci->sledeci = novi;

/* vracamo vrednost glave */


return glava;
}

/* Funkcija trazi u listi element cija je vrednost jednaka


datom broju. Funkcija vraca pokazivac na cvor liste u
kome je sadrzan trazeni broj ili NULL u slucaju da takav
element ne postoji u listi */
Cvor* pretrazi_listu(Cvor *glava, int broj)
{
/* Pretrazivanje se vrsi bez pretpostavke o sortiranosti
liste.*/
for(; glava != NULL ; glava = glava->sledeci)
if(glava->vrednost == broj)
return glava;

return NULL;
}

/* Funkcija brise tekuci element liste, tj. element liste


na koji pokazuje pokazivac tekuci. Funkcija vraca pokazivac
na glavu liste, koja moze biti promenjena ako je upravo
glava obrisani cvor */
Cvor* obrisi_tekuci(Cvor * glava, Cvor * tekuci)
{
if(tekuci == NULL)
return glava;

/* Preusmeravamo pokazivace prethodnog i sledeceg


ako oni postoje */
if(tekuci->prethodni != NULL)
tekuci->prethodni->sledeci = tekuci->sledeci;
if(tekuci->sledeci != NULL)
tekuci->sledeci->prethodni = tekuci->prethodni;

/* Ako je cvor koji brisemo glava, tada moramo da


promenimo glavu (sledeci element postaje glava) */
if(tekuci == glava)
glava = tekuci->sledeci;

163
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste

/* Brisemo tekuci cvor */


free(tekuci);
return glava;
}

/* Funkcija brise iz liste sve cvorove koji sadrze dati broj.


Funkcija vraca pokazivac na glavu liste (koji moze biti
promenjen u slucaju da se obrise stara glava) */
Cvor* obrisi_element(Cvor *glava, int broj)
{
Cvor *tekuci = glava;
Cvor *pomocni;

/* Pretrazujemo listu pocev od tekuceg elementa trazeci


datu vrednost. Ako je pronadjemo, brisemo nadjeni cvor
i nastavljamo pretragu od elementa koji sledi nakon
upravo obrisanog */
while((tekuci = pretrazi_listu(tekuci, broj)) != NULL)
{
pomocni = tekuci->sledeci;
glava = obrisi_tekuci(glava, tekuci);
tekuci = pomocni;
}
/* vracamo novu glavu */
return glava;
}

/* Funkcija prikazuje elemente liste pocev


od glave ka kraju liste */
void prikazi_listu(Cvor *glava)
{
putchar(’[’);
for(;glava != NULL; glava = glava->sledeci)
printf("%d ", glava->vrednost);
putchar(’]’);

putchar(’\n’);
}

/* Funkcija prikazuje elemente liste u obrnutom poretku */


void prikazi_listu_obrnuto(Cvor * glava)
{
/* Ako je lista prazna... */
if(glava == NULL)

164
Milena Vujošević–Janičić 10.5 Dvostruko povezane liste

{
printf("[]\n");
return;
}

/* Prolazimo kroz listu dok ne stignemo do poslednjeg


elementa. */
while(glava->sledeci != NULL)
glava = glava->sledeci;

/* Ispisujemo elemente liste iteracijom u suprotnom smeru */


putchar(’[’);
for(;glava != NULL; glava = glava->prethodni)
printf("%d ", glava->vrednost);
putchar(’]’);

putchar(’\n’);
}

/* Funkcija oslobadja dinamicku memoriju zauzetu


od strane liste. Funkcija vraca NULL, tj.
vrednost koju treba dodeliti pokazivackoj
promenljivoj, s obzirom da je sada lista prazna. */
Cvor* oslobodi_listu(Cvor *glava)
{
Cvor *pomocni;

while(glava != NULL)
{
/* moramo najpre zapamtiti adresu sledeceg
elementa, a tek onda osloboditi glavu */
pomocni = glava->sledeci;
free(glava);
glava = pomocni;
}

return NULL;
}

165
Glava 11

Stabla

Binarno stablo1 je skup cvorova koji su povezani na sledeci nacin:


1. Svaki cvor moze imati levog i desnog SINA (pri tom svaki od sinova moze biti
i izostavljen, ili oba). Kazemo da je dati cvor RODITELJ svojim sinovima. Ako
je cvor U roditelj cvoru V, tada pisemo da je U < V . Cvor koji nema ni levog
ni desnog sina naziva se LIST.
2. Postoji jedan jedinstveni cvor takav da nema roditelja. Ovaj cvor nazivamo
KOREN stabla.
3. U stablu nema ciklusa, tj. ne postoji niz cvorova x1,x2,...,xn, takav da je
x1 < x2 < ... < xn < x1.
Inace, niz cvorova x1 < x2 < ... < xn nazivamo put u stablu. Kazemo da je
cvor U predak cvora V ako u stablu postoji put od U do V. Specijalno, svaki cvor
je predak samom sebi. Lako se moze pokazati da je koren predak svih cvorova u
stablu. Rastojanje od korena do nekog cvora naziva se visina cvora (koren je visine
0). Maksimalna visina cvora u stablu naziva se visina stabla.
Stablo koje nema cvorova naziva se prazno stablo.
Za svaki cvor V u stablu mozemo posmatrati stablo koje se sastoji od svih njegovih
potomaka (svih cvorova kojima je on predak). Ovo stablo se naziva podstablo sa
datim korenom V. Podstablo sa njegovim levim sinom kao korenom nazivamo levim
podstablom cvora V, dok podstablo sa njegovim desnim sinom kao korenom nazivamo
desnim podstablom cvora V. Ako je neki od njegovih sinova izostavljen, tada kazemo
da je odgovarajuce podstablo cvora V prazno stablo. Specijalno, ako je V koren, tada
njegovo levo i desno podstablo nazivamo levim i desnim podstablom datog (citavog)
stabla.
Stablo se moze de nisati i rekurzivno na sledeci nacin:
1. Prazno stablo je stablo
2. Ako su data dva stabla t1 i t2, i cvor r, tada je i (t1,r,t2) takodje stablo.
t1 je tada levo podstablo, t2 je desno podstablo dok je cvor r koren tako
formiranog stabla.

166
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

NULL NULL

NULL NULL NULL

NULL NULL

Slika 11.1: Binarno stablo

U programiranju se stabla obicno koriste kao strukture podataka, tako sto svaki
cvor sadrzi po jedan podatak odred̄enog tipa. Nacin raspored̄ivanja podataka u
stablu zavisi od konkretne primene stabla. S obzirom na rekurzivnu prirodu stabla,
uobicajeno je da se u programiranju stabla obrad̄uju rekurzivno.

11.1 Binarno pretraživačko stablo


Posebna vrsta stabla su tzv. binarna pretrazivacka stabla. Ova stabla imaju osobinu
da za svaki cvor vazi sledece: svi cvorovi njegovog levog podstabla sadrze podatke
sa manjom vrednoscu od vrednosti podatka u tom cvoru, dok svi cvorovi njegovog
desnog podstabla sadrze podatke sa vecom vrednoscu od vrednosti podatka u tom
cvoru. Ovakva organizacija omogu ’cava e kasno pretrazivanje.
Primer 11.1 Program demonstrira rad sa binarnim pretrazivackim drvetima čiji su
podaci celi brojevi. Drvo sadrži cele brojeve sortirane po veličini. Za svaki cvor, levo
podstabla sadrzi manje elemente, dok desno podstablo sadrzi vece.
#include <stdlib.h>
1 Tekst preuzet sa sajta http://www.matf.bg.ac.rs/~milan

167
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

17, 12, 21, 15, 5, 14


17

12 21

NULL NULL

5 15

NULL NULL NULL

inf ix : 5, 12, 14, 15, 17, 21


14 pref ix : 17, 12, 5, 15, 14, 21

postf ix : 5, 14, 15, 12, 21, 17


NULL NULL

Slika 11.2: Ured̄eno stablo

#include <stdio.h>

/* Struktura koja predstavlja cvor drveta */


typedef struct _cvor
{
int broj;
struct _cvor *l, *d;
} cvor;

/* Pomocna funkcija za kreiranje cvora. */


cvor* napravi_cvor(int b) {
cvor* novi = (cvor*)malloc(sizeof(cvor));
if (novi == NULL)
{
fprintf(stderr, "Greska prilikom
alokacije memorije");
exit(1);
}

168
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

novi->broj = b;
novi->l = NULL;
novi->d = NULL;
return novi;
}

/* Funkcija umece broj b u drvo ciji je koren dat preko


pokazivaca koren. Funkcija vraca pokazivac na koren
novog drveta */
cvor* ubaci_u_drvo(cvor* koren, int b)
{
if (koren == NULL)
return napravi_cvor(b);

if (b < koren->broj)
koren->l = ubaci_u_drvo(koren->l, b);
else
koren->d = ubaci_u_drvo(koren->d, b);

return koren;
}

/* Funkcija proverava da li dati broj postoji u drvetu */


int pronadji(cvor* koren, int b)
{
if (koren == NULL)
return 0;

if (koren->broj == b)
return 1;

if (b < koren->broj)
return pronadji(koren->l, b);
else
return pronadji(koren->d, b);
}

/* Funkcija ispisuje sve cvorove drveta u infiksnom redosledu */


void ispisi_drvo(cvor* koren) {
if (koren != NULL)
{
ispisi_drvo(koren->l);
printf("%d ", koren->broj);
ispisi_drvo(koren->d);

169
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

}
}

/* Funkcija oslobadja memoriju koju je drvo zauzimalo */


void obrisi_drvo(cvor* koren) {
if (koren != NULL)
{
/* Oslobadja se memorija za levo poddrvo */
obrisi_drvo(koren->l);
/* Oslobadja se memorija za desno poddrvo */
obrisi_drvo(koren->d);
/* Oslobadja se memorija koju zauzima koren */
free(koren);
}
}

/* Funkcija sumira sve vrednosti binarnog stabla */


int suma_cvorova(cvor* koren)
{
if (koren == NULL)
return 0;
return suma_cvorova(koren->l) +
koren->broj +
suma_cvorova(koren->d);
}

/* Funkcija prebrojava broj cvorova binarnog stabla */


int broj_cvorova(cvor* koren)
{
if (koren == NULL)
return 0;
return broj_cvorova(koren->l) +
1 +
broj_cvorova(koren->d);
}

/* Funkcija prebrojava broj listova binarnog stabla */


int broj_listova(cvor* koren)
{
if (koren == NULL)
return 0;
if (koren->l == NULL && koren->d == NULL)
return 1;
return broj_listova(koren->l) +

170
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

broj_listova(koren->d);
}

/* Funkcija izracunava sumu listova binarnog stabla */


int suma_listova(cvor* koren)
{
if (koren == NULL)
return 0;

if (koren->l == NULL && koren->d == NULL)


return koren->broj;

return suma_listova(koren->l) +
suma_listova(koren->d);
}

/* Funkcija ispisuje sadrzaj listova binarnog stabla */


void ispisi_listove(cvor* koren)
{
if (koren == NULL)
return;

ispisi_listove(koren->l);

if (koren->l == NULL && koren->d == NULL)


printf("%d ", koren->broj);

ispisi_listove(koren->d);
}

/* Funkcija pronalazi maksimalnu vrednost u drvetu


Koristi se cinjenica da je ova vrednost
smestena u najdesnjem listu */
int max_vrednost(cvor* koren)
{
if (koren==NULL)
return 0;

if (koren->d==NULL)
return koren->broj;

return max_vrednost(koren->d);
}

171
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Iterativna funkcija za pronalazenje maksimalne vrednosti. */


int max_vrednost_nerekurzivno(cvor* koren)
{
if (koren==NULL)
return 0;
else
{
cvor* tekuci;
for (tekuci=koren; tekuci->d!=NULL; tekuci=tekuci->d)
;
return tekuci->broj;
}
}

#define max(a,b) (((a)>(b))?(a):(b))

/* Funkcija racuna "dubinu" binarnog stabla */


int dubina(cvor* koren)
{
if (koren==NULL)
return 0;
else
{ int dl=dubina(koren->l);
int dd=dubina(koren->d);
return 1+max(dl,dd);
}
}

/* Program koji testira rad prethodnih funkcija */


main()
{
cvor* koren = NULL;
koren = ubaci_u_drvo(koren, 1);
koren = ubaci_u_drvo(koren, 8);
koren = ubaci_u_drvo(koren, 5);
koren = ubaci_u_drvo(koren, 3);
koren = ubaci_u_drvo(koren, 7);
koren = ubaci_u_drvo(koren, 6);
koren = ubaci_u_drvo(koren, 9);

if (pronadji(koren, 3))
printf("Pronadjeno 3\n");
if (pronadji(koren, 2))

172
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

printf("Pronadjeno 2\n");
if (pronadji(koren, 7))
printf("Pronadjeno 7\n");

ispisi_drvo(koren);

putchar(’\n’);
printf("Suma cvorova : %d\n", suma_cvorova(koren));
printf("Broj cvorova : %d\n", broj_cvorova(koren));
printf("Broj listova : %d\n", broj_listova(koren));
printf("Suma listova : %d\n", suma_listova(koren));
printf("Dubina drveta : %d\n", dubina(koren));
printf("Maximalna vrednost : %d\n", max_vrednost(koren));

ispisi_listove(koren);

obrisi_drvo(koren);
}

/*
Pronadjeno 3
Pronadjeno 7
1 3 5 6 7 8 9
Suma cvorova : 39
Broj cvorova : 7
Broj listova : 3
Suma listova : 18
Dubina drveta : 5
Maximalna vrednost : 9
3 6 9
*/
Primer 11.2 Binarno pretraživačko drvo - funkcije za izračunavanje kopije, unije,
preseka i razlike dva drveta, funkcija za izbacivanje čvora iz drveta.
/* Struktura koja predstavlja cvor drveta */
typedef struct cvor {

int vrednost; /* Vrednost koja se cuva */


struct cvor * levi; /* Pokazivac na levo podstablo */
struct cvor * desni; /* Pokazivac na desno podstablo */

} Cvor;

/* NAPOMENA: Prazno stablo se predstavlja NULL pokazivacem. */

173
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Pomocna funkcija za kreiranje cvora. Cvor se kreira


dinamicki, funkcijom malloc(). U slucaju greske program
se prekida i ispisuje se poruka o gresci. U slucaju
uspeha inicijalizuje se vrednost datim brojem, a pokazivaci
na podstabla se inicijalizuju na NULL. Funkcija vraca
adresu novokreiranog cvora */
Cvor * napravi_cvor (int broj)
{

/* dinamicki kreiramo cvor */


Cvor * novi = (Cvor *) malloc (sizeof(Cvor));

/* u slucaju greske ... */


if (novi == NULL)
{
fprintf (stderr,"malloc() greska\n");
exit (1);
}

/* inicijalizacija */
novi->vrednost = broj;
novi->levi = NULL;
novi->desni = NULL;

/* vracamo adresu novog cvora */


return novi;
}

/* Funkcija dodaje novi cvor u stablo sa datim korenom.


Ukoliko broj vec postoji u stablu, ne radi nista.
Cvor se kreira funkcijom napravi_cvor(). Funkcija
vraca koren stabla nakon ubacivanja novog cvora. */
Cvor * dodaj_u_stablo (Cvor *koren, int broj)
{

/* izlaz iz rekurzije: ako je stablo bilo prazno,


novi koren je upravo novi cvor */
if (koren == NULL)
return napravi_cvor (broj);

/* Ako je stablo neprazno, i koren sadrzi manju vrednost


od datog broja, broj se umece u desno podstablo,
rekurzivnim pozivom */

174
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

if (koren->vrednost < broj)


koren->desni = dodaj_u_stablo (koren->desni, broj);
/* Ako je stablo neprazno, i koren sadrzi vecu vrednost
od datog broja, broj se umece u levo podstablo,
rekurzivnim pozivom */
else if (koren->vrednost > broj)
koren->levi = dodaj_u_stablo (koren->levi, broj);

/* U slucaju da je koren jednak datom broju, tada


broj vec postoji u stablu, i ne radimo nista */

/* Vracamo koren stabla */


return koren;

/* Funkcija pretrazuje binarno stablo. Ukoliko


pronadje cvor sa vrednoscu koja je jednaka
datom broju, vraca adresu tog cvora. U
suprotnom vraca NULL */
Cvor * pretrazi_stablo (Cvor * koren, int broj)
{

/* Izlaz iz rekurzije: ako je stablo prazno,


tada trazeni broj nije u stablu */
if (koren == NULL)
return NULL;

/* Ako je stablo neprazno, tada se pretrazivanje


nastavlja u levom ili desnom podstablu, u
zavisnosti od toga da li je trazeni broj
respektivno manji ili veci od vrednosti
korena. Ukoliko je pak trazeni broj jednak
korenu, tada se vraca adresa korena. */
if (koren->vrednost < broj)
return pretrazi_stablo (koren->desni, broj);
else if (koren->vrednost > broj)
return pretrazi_stablo (koren->levi, broj);
else
return koren;
}

/* Funkcija vraca adresu cvora sa najmanjom vrednoscu


u stablu, ili NULL ako je stablo prazno */

175
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

Cvor * pronadji_najmanji (Cvor * koren)


{

/* Slucaj praznog stabla */


if (koren == NULL)
return NULL;

/* Izlaz iz rekurzije: ako koren nema levog sina,


tada je upravo koren po vrednosti najmanji cvor.*/
if (koren->levi == NULL)
return koren;
/* U suprotnom je najmanja vrednost u stablu upravo
najmanja vrednost u levom podstablu, pa se pretraga
nastavlja rekurzivno u levom podstablu. */
else
return pronadji_najmanji (koren->levi);
}

/* Funkcija vraca adresu cvora sa najvecom vrednoscu


u stablu, ili NULL ako je stablo prazno */
Cvor * pronadji_najveci (Cvor * koren)
{

/* Slucaj praznog stabla */


if (koren == NULL)
return NULL;

/* Izlaz iz rekurzije: ako koren nema desnog sina,


tada je upravo koren po vrednosti najveci cvor. */
if (koren->desni == NULL)
return koren;
/* U suprotnom je najveca vrednost u stablu upravo
najveca vrednost u desnom podstablu, pa se pretraga
nastavlja rekurzivno u desnom podstablu. */
else
return pronadji_najveci (koren->desni);

/* Funkcija brise cvor sa datom vrednoscu iz stabla,


ukoliko postoji. U suprotnom ne radi nista. Funkcija
vraca koren stabla (koji moze biti promenjen nakon
brisanja) */
Cvor * obrisi_element (Cvor * koren, int broj)

176
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

Cvor * pomocni=NULL;

/* Izlaz iz rekurzije: ako je stablo prazno, ono ostaje


prazno i nakon brisanja */
if (koren == NULL)
return NULL;

/* Ako je vrednost broja veca od vrednosti korena,


tada se broj eventualno nalazi u desnom podstablu,
pa treba rekurzivno primeniti postupak na desno
podstablo. Koren ovako modifikovanog stabla je
nepromenjen, pa vracamo stari koren */
if (koren->vrednost < broj)
{
koren->desni = obrisi_element (koren->desni, broj);
return koren;
}

/* Ako je vrednost broja manja od vrednosti korena,


tada se broj eventualno nalazi u levom podstablu,
pa treba rekurzivno primeniti postupak na levo
podstablo. Koren ovako modifikovanog stabla je
nepromenjen, pa vracamo stari koren */
if (koren->vrednost > broj)
{
koren->levi = obrisi_element (koren->levi, broj);
return koren;
}

/* Slede podslucajevi vezani za slucaj kada je vrednost


korena jednaka broju koji se brise (tj. slucaj kada
treba obrisati koren) */

/* Ako koren nema sinova, tada se on prosto brise, i


rezultat je prazno stablo (vracamo NULL) */
if (koren->levi == NULL && koren->desni == NULL)
{
free (koren);
return NULL;
}

/* Ako koren ima samo levog sina, tada se brisanje

177
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

vrsi tako sto obrisemo koren, a novi koren postaje


levi sin */
if (koren->levi != NULL && koren->desni == NULL)
{
pomocni = koren->levi;
free (koren);
return pomocni;
}

/* Ako koren ima samo desnog sina, tada se brisanje


vrsi tako sto obrisemo koren, a novi koren postaje
desni sin */
if (koren->desni != NULL && koren->levi == NULL)
{
pomocni = koren->desni;
free (koren);
return pomocni;
}

/* Slucaj kada koren ima oba sina. U tom slucaju se


brisanje vrsi na sledeci nacin: najpre se potrazi
sledbenik korena (u smislu poretka) u stablu. To
je upravo po vrednosti najmanji cvor u desnom podstablu.
On se moze pronaci npr. funkcijom pronadji_najmanji().
Nakon toga se u koren smesti vrednost tog cvora, a u taj
cvor se smesti vrednost korena (tj. broj koji se brise).
Onda se prosto rekurzivno pozove funkcija za brisanje
na desno podstablo. S obzirom da u njemu treba obrisati
najmanji element, a on definitivno ima najvise jednog
potomka, jasno je da ce to brisanje biti obavljeno na
jedan od nacina koji je gore opisan. */
pomocni = pronadji_najmanji (koren->desni);
koren->vrednost = pomocni->vrednost;
pomocni->vrednost = broj;
koren->desni = obrisi_element (koren->desni, broj);
return koren;
}

/* Funkcija prikazuje stablo s leva u desno (tj.


prikazuje elemente u rastucem poretku) */
void prikazi_stablo (Cvor * koren)
{
/* izlaz iz rekurzije */

178
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

if(koren == NULL)
return;

prikazi_stablo (koren->levi);
printf("%d ", koren->vrednost);
prikazi_stablo (koren->desni);
}

/* Funkcija oslobadja prostor koji je alociran za


cvorove stabla. Funkcija vraca NULL, zato sto je
nakon oslobadjanja stablo prazno. */
Cvor * oslobodi_stablo (Cvor *koren)
{

/* Izlaz iz rekurzije */
if(koren == NULL)
return NULL;

koren->levi = oslobodi_stablo (koren->levi);


koren->desni = oslobodi_stablo (koren->desni);
free(koren);

return NULL;
}

/* Funkcija kreira novo stablo identicno stablu koje je


dato korenom. Funkcija vraca pokazivac na koren
novog stabla. */
Cvor * kopiraj_stablo (Cvor * koren)
{
Cvor * duplikat = NULL;

/* Izlaz iz rekurzije: ako je stablo prazno,


vracamo NULL */
if(koren == NULL)
return NULL;

/* Dupliramo koren stabla i postavljamo ga


da bude koren novog stabla */
duplikat = napravi_cvor (koren->vrednost);

/* Rekurzivno dupliramo levo podstablo i njegovu


adresu cuvamo u pokazivacu na levo podstablo
korena duplikata. */

179
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

duplikat->levi = kopiraj_stablo (koren->levi);

/* Rekurzivno dupliramo desno podstablo i njegovu


adresu cuvamo u pokazivacu na desno podstablo
korena duplikata. */
duplikat->desni = kopiraj_stablo (koren->desni);

/* Vracamo adresu korena duplikata */


return duplikat;

/* Funkcija modifikuje stablo dato korenom koren_1


tako da sadrzi i sve elemente drugog stabla datog
korenom koren_2 (drugim recima funkcija kreira uniju
dva stabla, i rezultat se smesta u prvo stablo).
Funkcija vraca pokazivac na koren tako modifikovanog
prvog stabla. */
Cvor * kreiraj_uniju (Cvor * koren_1, Cvor * koren_2)
{

/* Ako je drugo stablo neprazno */


if(koren_2 != NULL)
{
/* dodajemo koren drugog stabla u prvo stablo */
koren_1 = dodaj_u_stablo (koren_1, koren_2->vrednost);

/* rekurzivno racunamo uniju levog i desnog podstabla


drugog stabla sa prvim stablom */
koren_1 = kreiraj_uniju (koren_1, koren_2->levi);
koren_1 = kreiraj_uniju (koren_1, koren_2->desni);
}

/* vracamo pokazivac na modifikovano prvo stablo */


return koren_1;
}

/* Funkcija modifikuje stablo dato korenom koren_1


tako da sadrzi samo one elemente koji su i elementi
stabla datog korenom koren_2 (drugim recima funkcija
kreira presek dva stabla, i rezultat se smesta u prvo
stablo). Funkcija vraca pokazivac na koren tako
modifikovanog prvog stabla. */
Cvor * kreiraj_presek (Cvor * koren_1, Cvor * koren_2)

180
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Ako je prvo stablo prazno, tada je i rezultat prazno


stablo */
if(koren_1 == NULL)
return NULL;

/* Kreiramo presek levog i desnog podstabla sa drugim


stablom, tj. iz levog i desnog podstabla prvog stabla
brisemo sve one elemente koji ne postoje u drugom
stablu */
koren_1->levi = kreiraj_presek (koren_1->levi, koren_2);
koren_1->desni = kreiraj_presek (koren_1->desni, koren_2);

/* Ako se koren prvog stabla ne nalazi u drugom stablu


tada ga uklanjamo iz prvog stabla */
if(pretrazi_stablo (koren_2, koren_1->vrednost) == NULL)
koren_1 = obrisi_element (koren_1, koren_1->vrednost);

/* Vracamo koren tako modifikovanog prvog stabla */


return koren_1;

/* Funkcija modifikuje stablo dato korenom koren_1


tako da sadrzi samo one elemente koji nisu i elementi
stabla datog korenom koren_2 (drugim recima funkcija
kreira razliku dva stabla, i rezultat se smesta u prvo
stablo). Funkcija vraca pokazivac na koren tako
modifikovanog prvog stabla. */
Cvor * kreiraj_razliku (Cvor * koren_1, Cvor * koren_2)
{

/* Ako je prvo stablo prazno, tada je i rezultat prazno


stablo */
if(koren_1 == NULL)
return NULL;

/* Kreiramo razliku levog i desnog podstabla sa drugim


stablom, tj. iz levog i desnog podstabla prvog stabla
brisemo sve one elemente koji postoje i u drugom
stablu */
koren_1->levi = kreiraj_razliku (koren_1->levi, koren_2);
koren_1->desni = kreiraj_razliku (koren_1->desni, koren_2);

181
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Ako se koren prvog stabla nalazi i u drugom stablu


tada ga uklanjamo iz prvog stabla */
if(pretrazi_stablo (koren_2, koren_1->vrednost) != NULL)
koren_1 = obrisi_element (koren_1, koren_1->vrednost);

/* Vracamo koren tako modifikovanog prvog stabla */


return koren_1;

/* test program */
int main()
{

Cvor * koren = NULL, * koren_2 = NULL;


Cvor * pomocni = NULL;
int broj;

/* Testiranje dodavanja u stablo */


printf("-------------------------------------------------------\n");
printf("---------- Testiranje dodavanja u stablo --------------\n");
do {
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja stabla:\n");
prikazi_stablo (koren);
putchar(’\n’);
printf("-------------------------------------------------------\n");
printf("Dodati element u stablo (ctrl-D za kraj unosa):\n");
} while(scanf("%d", &broj) > 0 &&
(koren = dodaj_u_stablo (koren, broj)) );

printf("-------------------------------------------------------\n");
putchar(’\n’);

/* Testiranje pretrage elementa */


printf("-------------------------------------------------------\n");
printf("---------------- Testiranje pretrage ------------------\n");
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja stabla:\n");
prikazi_stablo (koren);
putchar(’\n’);
printf("-------------------------------------------------------\n");

182
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

printf("Uneti broj koji se trazi: ");


scanf("%d", &broj);

if((pomocni = pretrazi_stablo (koren, broj)) == NULL)


printf("Trazeni broj nije u stablu\n");
else
printf("Trazeni element %d je u stablu\n", pomocni->vrednost);
printf("-------------------------------------------------------\n");
putchar(’\n’);

/* Testiranje brisanja elemenata */


printf("-------------------------------------------------------\n");
printf("--------------- Testiranje brisanja -------------------\n");
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja stabla:\n");
prikazi_stablo (koren);
putchar(’\n’);
printf("-------------------------------------------------------\n");
printf("Uneti broj koji se brise: ");
scanf("%d", &broj);

koren = obrisi_element (koren, broj);


printf("-------------------------------------------------------\n");
printf("Stablo nakon izbacivanja:\n");
prikazi_stablo (koren);
putchar(’\n’);
printf("-------------------------------------------------------\n");
putchar(’\n’);

/* Testiranje dupliranja, unije, preseka i razlike */


printf("-------------------------------------------------------\n");
printf("----- Testiranje dupliranja i skupovnih operacija -----\n");
do {
printf("-------------------------------------------------------\n");
printf("Prikaz trenutnog sadrzaja 2. stabla:\n");
prikazi_stablo (koren_2);
putchar(’\n’);
printf("-------------------------------------------------------\n");
printf("Dodati element u 2. stablo (ctrl-D za kraj unosa):\n");
} while(scanf("%d", &broj) > 0 &&
(koren_2 = dodaj_u_stablo (koren_2, broj)) );

183
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

printf("-------------------------------------------------------\n");
putchar(’\n’);

pomocni = kopiraj_stablo(koren);
pomocni = kreiraj_uniju(pomocni, koren_2);

printf("-------------------------------------------------------\n");
printf("Prikaz 1. stabla:\n");
prikazi_stablo (koren);
putchar(’\n’);
printf("-------------------------------------------------------\n");
printf("Prikaz 2. stabla:\n");
prikazi_stablo (koren_2);
putchar(’\n’);
printf("-------------------------------------------------------\n");
printf("Unija ova dva stabla:\n");
prikazi_stablo (pomocni);
putchar(’\n’);
printf("-------------------------------------------------------\n");

pomocni = oslobodi_stablo(pomocni);

pomocni = kopiraj_stablo(koren);
pomocni = kreiraj_presek(pomocni, koren_2);

printf("Presek ova dva stabla:\n");


prikazi_stablo (pomocni);
putchar(’\n’);
printf("-------------------------------------------------------\n");

pomocni = oslobodi_stablo(pomocni);

pomocni = kopiraj_stablo(koren);
pomocni = kreiraj_razliku(pomocni, koren_2);

printf("Razlika ova dva stabla:\n");


prikazi_stablo (pomocni);
putchar(’\n’);
printf("-------------------------------------------------------\n");

pomocni = oslobodi_stablo (pomocni);


koren_2 = oslobodi_stablo (koren_2);
koren = oslobodi_stablo (koren);

184
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

return 0;

}
Primer 11.3 Primer demonstrira sortiranje niza pomoću binarnog stabla. Elementi
niza se redom prvo smeste u binarno stablo pretrage, a zatim se elementi ”pokupe”
iz stabla obilazeći ga sa leva u desno (tj. u rastućem poretku). Vremenska složenost
ovakvog algoritma je u ekvivalentna quick_sort()-u. Prostorna slozenost je nesto
veća, jer sortiranje nije ”u mestu”, već se koristi pomoćna struktura – binarno
stablo.
#include <stdio.h>
#include <stdlib.h>

#define MAX 1000

/* Struktura koja predstavlja cvor stabla */


typedef struct cvor {

int vrednost;
struct cvor * levi;
struct cvor * desni;

} Cvor;

/* Funkcija kreira novi cvor */


Cvor * napravi_cvor (int broj)
{

Cvor * novi = (Cvor *) malloc (sizeof(Cvor));

if (novi == NULL)
{
fprintf (stderr,"malloc() greska\n");
exit (1);
}

novi->vrednost = broj;
novi->levi = NULL;
novi->desni = NULL;

return novi;

185
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Funkcija dodaje novu vrednost u stablo. Dozvoljava


ponavljanje vrednosti u stablu -- levo se dodaju
manje vrednosti, a desno vece ili jednake. */
Cvor * dodaj_u_stablo (Cvor * koren, int broj)
{

if (koren == NULL)
return napravi_cvor (broj);

if (koren->vrednost <= broj)


koren->desni = dodaj_u_stablo (koren->desni, broj);

else if (koren->vrednost > broj)


koren->levi = dodaj_u_stablo (koren->levi, broj);

return koren;

/* Funkcija oslobadja stablo */


void oslobodi_stablo (Cvor *koren)
{

if(koren == NULL)
return;

oslobodi_stablo (koren->levi);
oslobodi_stablo (koren->desni);
free(koren);

/* Funkcija obilazi stablo sa leva u desno i


vrednosti cvorova smesta u niz. Funkcija
vraca broj vrednosti koje su smestene u niz. */
int kreiraj_niz(Cvor * koren, int a[])
{
int r, s;

if(koren == NULL)
return 0;

r = kreiraj_niz(koren->levi, a);

186
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

a[r] = koren->vrednost;

s = kreiraj_niz(koren->desni, a + r + 1);

return r + s + 1;

/* Funkcija sortira niz tako sto najpre elemente


niza smesti u stablo, a zatim kreira novi niz
prolazeci kroz stablo sa leva u desno. */
void sortiraj(int a[], int n)
{
int i;
Cvor * koren = NULL;

for(i = 0; i < n; i++)


koren = dodaj_u_stablo(koren, a[i]);

kreiraj_niz(koren, a);

oslobodi_stablo(koren);

/* Test program */
int main()
{
int a[MAX];
int n, i;

printf("Uneti dimenziju niza manju od %d: ", MAX);


scanf("%d", &n);

printf("Uneti elemente niza: ");


for(i = 0; i < n; i++)
scanf("%d", &a[i]);

printf("Niz pre sortiranja:\n");


for(i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");

187
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

sortiraj(a, n);

printf("Niz nakon sortiranja:\n");


for(i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");

return 0;
}
Primer 11.4 Program sa ulaza čita tekst i ispisuje broj pojavljivanja svake od reči
koje su se javljale u tekstu. Radi poboljšanja efikasnosti, prilikom brojanja reči koristi
se struktura podataka pogodna za leksikografsku pretragu — u ovom slučaju binarno
pretraživačko drvo.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX 1024

typedef struct cvor {


char rec[MAX]; /* rec */
int brojac; /* broj pojavljivanja reci */
struct cvor * levi;
struct cvor * desni;
} Cvor;

/* Pomocna funkcija za kreiranje cvora. Funkcija vraca


adresu novokreiranog cvora */
Cvor * napravi_cvor (char * rec)
{

/* dinamicki kreiramo cvor */


Cvor * novi = (Cvor *) malloc (sizeof(Cvor));

/* u slucaju greske ... */


if (novi == NULL)
{
fprintf (stderr,"malloc() greska\n");
exit (1);
}

/* inicijalizacija */

188
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

strcpy(novi->rec, rec);
novi->brojac = 1;
novi->levi = NULL;
novi->desni = NULL;

/* vracamo adresu novog cvora */


return novi;
}

/* Funkcija dodaje novi cvor u stablo sa datim korenom.


Ukoliko rec vec postoji u stablu, uvecava dati brojac.
Cvor se kreira funkcijom napravi_cvor(). Funkcija
vraca koren stabla nakon ubacivanja novog cvora. */
Cvor * dodaj_u_stablo (Cvor * koren, char *rec)
{

/* izlaz iz rekurzije: ako je stablo bilo prazno,


novi koren je upravo novi cvor */
if (koren == NULL)
return napravi_cvor (rec);

/* Ako je stablo neprazno, i koren sadrzi leksikografski


manju rec od date reci, broj se umece u desno podstablo,
rekurzivnim pozivom */
if (strcmp(koren->rec, rec) < 0)
koren->desni = dodaj_u_stablo (koren->desni, rec);
/* Ako je stablo neprazno, i koren sadrzi vecu vrednost
od datog broja, broj se umece u levo podstablo,
rekurzivnim pozivom */
else if (strcmp(koren->rec, rec) > 0)
koren->levi = dodaj_u_stablo (koren->levi, rec);
else
/* Ako je data rec vec u stablu, samo uvecavamo brojac. */
koren->brojac++;

/* Vracamo koren stabla */


return koren;

/* Funkcija pronalazi najfrekventniju rec, tj. cvor ciji


brojac ima najvecu vrednost. Funkcija vraca NULL, ako
je stablo prazno, odnosno adresu cvora koji sadrzi
najfrekventniju rec u suprotnom. */

189
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

Cvor * nadji_najfrekventniju (Cvor * koren)


{
Cvor *max, *max_levi, *max_desni;

/* Izlaz iz rekurzije */
if (koren == NULL)
return NULL;

/* Odredjujemo najfrekventnije reci u levom i desnom podstablu */


max_levi = nadji_najfrekventniju(koren->levi);
max_desni = nadji_najfrekventniju(koren->desni);

/* Odredjujemo MAX(koren, max_levi, max_desni) */


max = koren;
if(max_levi != NULL && max_levi->brojac > max->brojac)
max = max_levi;
if(max_desni != NULL && max_desni->brojac > max->brojac)
max = max_desni;

/* Vracamo adresu cvora sa najvecim brojacem */


return max;

/* Prikazuje reci u leksikografskom poretku, kao i broj pojava svake


od reci */
void prikazi_stablo(Cvor *koren)
{
if(koren == NULL)
return;

prikazi_stablo(koren->levi);
printf("%s: %d\n", koren->rec, koren->brojac);
prikazi_stablo(koren->desni);

/* Funkcija oslobadja prostor koji je alociran za


cvorove stabla. Funkcija vraca NULL, zato sto je
nakon oslobadjanja stablo prazno. */
void oslobodi_stablo (Cvor *koren)
{
/* Izlaz iz rekurzije */

190
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

if(koren == NULL)
return;

oslobodi_stablo (koren->levi);
oslobodi_stablo (koren->desni);
free(koren);

/* Funkcija ucitava sledecu rec iz fajla i upisuje je


u niz na koji pokazuje rec, maksimalne duzine max.
Funkcija vraca EOF ako nema vise reci, 0 u suprotnom.
Rec je niz alfabetskih karaktera.*/
int sledeca_rec(FILE *f, char * rec, int max)
{
int c;
int i = 0;

/* Dokle god ima mesta za jos jedan karakter u stringu,


i dokle god nismo stigli do kraja fajla... */
while(i < max - 1 && (c = fgetc(f)) != EOF)
{
/* Ako je slovo, ubacujemo ga u rec */
if(isalpha(c))
rec[i++] = tolower(c);
/* U suprotnom, ako smo procitali bar jedno slovo
prethodno, onda imamo rec. Inace idemo na sledecu
iteraciju */
else if(i > 0)
break;
}

/* Zatvaramo string */
rec[i] = ’\0’;

/* Vracamo 0 ako imamo rec, EOF u suprotnom */


return i > 0 ? 0 : EOF;
}

/* test program */
int main(int argc, char **argv)
{

191
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

Cvor *koren = NULL, *max;


FILE *f;
char rec[MAX];

/* Proveravamo da li je navedeno ime datoteke */


if(argc < 2)
{
fprintf(stderr, "Morate uneti ime datoteke sa tekstom!\n");
exit(0);
}

/* Otvaramo datoteku */
if((f = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska\n");
exit(1);
}

/* Ucitavamo reci iz datoteke. Rec je niz alfabetskih karaktera. */


while(sledeca_rec(f, rec, MAX) != EOF)
{
koren = dodaj_u_stablo(koren, rec);
}
/* Zatvaramo datoteku */
fclose(f);

/* Prikazujemo sve reci i brojeve njihovih pojavljivanja */


prikazi_stablo(koren);

/* Pronalazimo najfrekventniju rec */


if((max = nadji_najfrekventniju(koren)) == NULL)
printf("U tekstu nema reci!\n");
else
printf("Najcesca rec %s (pojavljuje se %d puta)\n", max->rec, max->brojac);

/* Oslobadjamo stablo */
oslobodi_stablo(koren);

return 0;
}
Primer 11.5 Mapa je apstraktna struktura podataka koja u sebi sadrzi parove oblika
(kljuc, vrednost). Pri tom su i ključ i vrednost unapred odred̄enog (ne obavezno
istog) tipa (na primer, ključ nam može biti string koji predstavlja ime studenta, a
vrednost je npr. broj koji predstavlja njegov prosek). Operacije koje mapa mora

192
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

efikasno da podržava su:


 dodavanje para (kljuc, vrednost) u mapu
 brisanje para (kljuc, vrednost) iz mape
 pronalazenje vrednosti za dati ključ
 promena vrednosti za dati ključ
Jedan od najčešćih načina implementacije mape je preko binarnog stabla pretrage.
Svaki čvor ovog stabla sadržaće odgovarajući par (kljuc, vrednost), tj. svaki čvor
ce sadržati dva podatka. Pri tom će poredak u stablu biti odred̄en poretkom koji je
definisan nad ključevima. Ovim se postiže da se pretraga po ključu može obaviti na
uobičajen način, kao i sve ostale navedene operacije.
Jasno je da ovako implementirana mapa neće efikasno podržavati operaciju pre-
trage po vrednosti (npr. naći sve ključeve koji imaju datu vrednost), zato što poredak
u stablu nije ni na koji način u vezi sa poretkom med̄u vrednostima. Med̄utim, u
mapi se najčešće i ne zahteva takva operacija.
Sledi primer koji demonstrira implementaciju mapa pomoću binarnog stabla.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 1024

/* Struktura koja predstavlja cvor stabla */


typedef struct cvor {
char naziv[MAX];
int cena;
struct cvor * levi;
struct cvor * desni;
} Cvor;

/* Funkcija kreira novi cvor i vraca njegovu adresu */


Cvor * napravi_cvor (char * naziv, int cena)
{

/* dinamicki kreiramo cvor */


Cvor * novi = (Cvor *) malloc (sizeof(Cvor));

/* u slucaju greske ... */


if (novi == NULL)
{
fprintf (stderr,"malloc() greska\n");
exit (1);
}

193
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* inicijalizacija */
strcpy(novi->naziv, naziv);
novi->cena = cena;
novi->levi = NULL;
novi->desni = NULL;

/* vracamo adresu novog cvora */


return novi;

/* Funkcija dodaje novi cvor u stablo sa datim korenom.


U cvor se upisuje vrednost (naziv, cena). Ukoliko naziv
vec postoji u stablu, tada se azurira njegova cena.
Cvor se kreira funkcijom napravi_cvor(). Funkcija
vraca koren stabla nakon ubacivanja novog cvora. */
Cvor * dodaj_u_stablo (Cvor * koren, char * naziv, int cena)
{

/* izlaz iz rekurzije: ako je stablo bilo prazno,


novi koren je upravo novi cvor */
if (koren == NULL)
return napravi_cvor (naziv, cena);

/* Ako je stablo neprazno, i koren sadrzi naziv koji je


leksikografski manji od datog naziva, vrednost se umece
u desno podstablo, rekurzivnim pozivom */
if (strcmp(koren->naziv, naziv) < 0)
koren->desni = dodaj_u_stablo (koren->desni, naziv, cena);
/* Ako je stablo neprazno, i koren sadrzi naziv koji je
leksikografski veci od datog naziva, vrednost se umece
u levo podstablo, rekurzivnim pozivom */
else if (strcmp(koren->naziv, naziv) > 0)
koren->levi = dodaj_u_stablo (koren->levi, naziv, cena);
/* Ako je naziv korena jednak nazivu koja se umece, tada se samo
azurira cena. */
else
koren->cena = cena;

/* Vracamo koren stabla */


return koren;

194
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Funkcija pretrazuje binarno stablo. Ukoliko


pronadje cvor sa vrednoscu naziva koja je jednaka
datom nazivu, vraca adresu tog cvora. U
suprotnom vraca NULL */
Cvor * pretrazi_stablo (Cvor * koren, char * naziv)
{

/* Izlaz iz rekurzije: ako je stablo prazno,


tada trazeni broj nije u stablu */
if (koren == NULL)
return NULL;

/* Ako je stablo neprazno, tada se pretrazivanje


nastavlja u levom ili desnom podstablu, u
zavisnosti od toga da li je trazeni naziv
respektivno manji ili veci od vrednosti naziva
korena. Ukoliko je pak trazeni naziv jednak
nazivu korena, tada se vraca adresa korena. */
if (strcmp(koren->naziv, naziv) < 0)
return pretrazi_stablo (koren->desni, naziv);
else if (strcmp(koren->naziv, naziv) > 0)
return pretrazi_stablo (koren->levi, naziv);
else
return koren;

/* cvor liste */
typedef struct cvor_liste {
char naziv[MAX];
int cena;
struct cvor_liste * sledeci;
} Cvor_liste;

/* Pomocna funkcija koja kreira cvor liste */


Cvor_liste * napravi_cvor_liste(char * naziv, int cena)
{
Cvor_liste * novi;

if((novi = malloc(sizeof(Cvor_liste))) == NULL)


{
fprintf(stderr, "malloc() greska\n");
exit(1);

195
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

strcpy(novi->naziv, naziv);
novi->cena = cena;
novi->sledeci = NULL;
return novi;
}

/* Funkcija pronalazi sve nazive cija je cena manja ili jednaka od date,
i formira listu koja sadrzi nadjene parove (naziv, cena) u leksikogra-
fskom poretku po nazivima. Prilikom pocetnog poziva, treci argument
treba da bude NULL. Funkcija obilazi stablo sa desna u levo, kako bi
se prilikom dodavanja na pocetak liste poslednji dodao onaj koji je
leksikografski najmanji (tj. on ce biti na pocetku). */
Cvor_liste * pronadji_manje (Cvor * koren, int cena, Cvor_liste * glava)
{
if(koren == NULL)
return glava;

/* Dodajemo na pocetak liste sve cvorove desnog podstabla cija je cena


manja od date. */
glava = pronadji_manje(koren->desni, cena, glava);

/* Dodajemo koren u listu, ako mu je cena manja od date */


if(koren->cena <= cena)
{
Cvor_liste * novi = napravi_cvor_liste(koren->naziv, koren->cena);
novi->sledeci = glava;
glava = novi;
}

/* Dodajemo na pocetak liste sve cvorove levog podstabla cija je cena


manja od date */
glava = pronadji_manje(koren->levi, cena, glava);

/* Vracamo glavu liste nakon svih modifikacija */


return glava;

/* Funkcija prikazuje listu */


void prikazi_listu(Cvor_liste * glava)
{
if(glava == NULL)

196
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

return;

printf("%s = %d\n", glava->naziv, glava->cena);


prikazi_listu(glava->sledeci);
}

/* Funkcija oslobadja listu */


Cvor_liste * oslobodi_listu(Cvor_liste * glava)
{
if(glava == NULL)
return NULL;

glava->sledeci = oslobodi_listu(glava->sledeci);
free(glava);

return NULL;
}

/* Funkcija oslobadja stablo. */


Cvor * oslobodi_stablo (Cvor *koren)
{

if(koren == NULL)
return NULL;

koren->levi = oslobodi_stablo (koren->levi);


koren->desni = oslobodi_stablo (koren->desni);
free(koren);

return NULL;

/* test program */
int main(int argc, char ** argv)
{
Cvor * koren = NULL, * pomocni;
Cvor_liste * glava = NULL;
FILE *f;
char naziv[MAX];
int cena;

/* Proveravamo da li je navedeno ime datoteke */

197
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

if(argc < 2)
{
fprintf(stderr, "Morate navesti ime datoteke!\n");
exit(0);
}

/* Otvaramo datoteku */
if((f = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska\n");
exit(1);
}

/* Ubacujemo proizvode u stablo */


while(fscanf(f, "%s%d", naziv, &cena) == 2)
{
koren = dodaj_u_stablo(koren, naziv, cena);
}
fclose(f);

/* Testiranje pretrage po nazivu (efikasna operacija) */


printf("Uneti naziv proizvoda koji vas zanima: ");
scanf("%s", naziv);

if((pomocni = pretrazi_stablo(koren, naziv)) == NULL)


printf("Trazeni proizvod ne postoji\n");
else
printf("Cena trazenog proizvoda je: %d\n", pomocni->cena);

/* Testiranje pretrage po ceni (neefikasno) */


printf("Unesite maksimalnu cenu: ");
scanf("%d", &cena);
glava = pronadji_manje(koren, cena, NULL);
prikazi_listu(glava);

/* Oslobadjanje memorije */
glava = oslobodi_listu(glava);
koren = oslobodi_stablo(koren);

return 0;
}

Primer 11.6 Program broji pojavljivanje svake etikete u tekstu i ispisuje etikete i
njihove frekvencije u opadajućem poretku po frekvencijama.
Radi poboljšanja efikasnosti, prilikom brojanja pojavljivanja etiketa koristi se

198
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

struktura podataka pogodna za leksikografsku pretragu - u ovom slučaju binarno pre-


traživačko drvo.
Na kraju rada, čvorovi drveta se ”presortiraju” na osnovu broja pojavljivanja.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

/* Makimalna duzina imena etikete */


#define MAX_ETIKETA 32

/* Definisemo stanja prilikom citanja html datoteke */


#define VAN_ETIKETE 1
#define U_ETIKETI 2

/* Struktura koja predstavlja cvor stabla */


typedef struct cvor {
char etiketa[MAX_ETIKETA]; /* Ime etikete */
int brojac; /* Brojac pojavljivanja etkete u tekstu */
struct cvor *levi; /* Pokazivaci na levo */
struct cvor *desni; /* i desno podstablo */
} Cvor;

/* Funkcija dodaje ime html etikete u binarno stablo,


u rastucem leksikografskom poretku. Funkcija vraca
koren stabla nakon modifikacije. U slucaju da je
etiketa sa istim imenom vec u stablu, uvecava se
brojac pojavljivanja. */
Cvor * dodaj_leksikografski(Cvor *koren, char *etiketa)
{
int cmp;

/* Izlaz iz rekurzije */
if(koren == NULL)
{
if((koren = malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska\n");
exit(1);
}

/* Ime etikete se kopira u novi cvor, a brojac


se inicijalizuje na 1 (prvo pojavljivanje) */

199
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

strcpy(koren->etiketa, etiketa);
koren->brojac = 1;
koren->levi = NULL;
koren->desni = NULL;
return koren;
}

/* Rekurzivni pozivi */
if((cmp = strcmp(koren->etiketa,etiketa)) < 0)
koren->desni = dodaj_leksikografski(koren->desni, etiketa);
else if(cmp > 0)
koren->levi = dodaj_leksikografski(koren->levi, etiketa);
else
koren->brojac++; /* uvecanje brojaca za vec prisutne etikete */

return koren;
}

/* Funkcija cita ulazni fajl i iz njega izdvaja sve


otvorene html etikete (npr. <html>, <br> itd, ali ne
i </html>, </body> itd.) i njihova imena (bez znakova
(< i > kao i bez eventualnih atributa) ubacuje u stablo
u leksikografskom poretku. Tom prilikom ce se prebrojati
i pojavljivanja svake od etiketa. Funkcija vraca pokazivac
na koren kreiranog stabla. */
Cvor * ucitaj(FILE *f)
{
Cvor * koren = NULL;
int c;
int stanje = VAN_ETIKETE;
int i;
char etiketa[MAX_ETIKETA];

/* NAPOMENA: prilikom izdvajanja etiketa pretpostavlja se da je


html datoteka sintaksno ispravna, kao i da nakon znaka ’<’
nema belina. Zato se otvorene etikete mogu lako prepoznati
tako sto pronadjemo znak ’<’ i nakon toga izdvojimo sva
slova koja slede. Ako postoji neprazan niz slova nakon znaka
’<’, tada je to upravo ime etikete. Ako ne, tada je verovatno
u pitanju zatvorena etiketa, npr. </html>, pa je ignorisemo. */

while((c = fgetc(f)) != EOF)


{
switch(stanje)

200
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

{
/* u ovom stanju trazimo prvu sledecu pojavu znaka ’<’ */
case VAN_ETIKETE:
if(c == ’<’)
{
stanje = U_ETIKETI; /* sada smo u etiketi */
i = 0;
}
break;
/* u ovom stanju citamo slova koja slede, i nakon toga
ubacujemo procitanu etiketu u stablo */
case U_ETIKETI:
/* Ako je slovo, i nismo prekoracili duzinu niza
dodajemo slovo u niz */
if(isalpha(c) && i < MAX_ETIKETA - 1)
etiketa[i++] = c;
/* u suprotnom se vracamo u stanje VAN_ETIKETE */
else {
stanje = VAN_ETIKETE;
/* Ako je niz slova nakon ’<’ bio neprazan... */
if(i > 0)
{
etiketa[i]=’\0’;
/* ubacujemo procitanu etiketu u stablo */
koren = dodaj_leksikografski(koren, etiketa);
}
}
break;
}

return koren;

/* Funkcija dodaje u stablo etiketu ciji je broj pojavljivanja


poznat (broj), i to u opadajucem poretku po broju pojavljivanja.
Funkcija vraca pokazivac na koren tako modifikovanog stabla */
Cvor * dodaj_po_broju(Cvor * koren, char * etiketa, int broj)
{

/* Izlaz iz rekurzije */
if(koren == NULL)

201
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

{
if((koren = malloc(sizeof(Cvor))) == NULL)
{
fprintf(stderr,"malloc() greska\n");
exit(1);
}

/* Kopiramo u novi cvor ime i broj pojavljivanja etikete */


strcpy(koren->etiketa, etiketa);
koren->brojac = broj;
koren->levi = NULL;
koren->desni = NULL;
return koren;
}

/* NAPOMENA: s obzirom da dve ili vise etiketa mogu imati isti broj
pojavljivanja, etiketa se mora dodavati u stablo, cak i ako ima
isti broj pojavljivanja sa korenom. Zato cemo u levo podstablo
dodavati etikete koje imaju veci broj pojavljivanja od korena,
dok cemo u desno podstablo dodavati etikete koje imaju manji
ili jednak broj pojavljivanja od korena. */

/* Rekurzivni pozivi */
if(koren->brojac >= broj)
koren->desni = dodaj_po_broju(koren->desni, etiketa, broj);
else if(koren->brojac < broj)
koren->levi = dodaj_po_broju(koren->levi, etiketa, broj);

return koren;

/* Funkcija pretpostavlja da je novo stablo ili prazno, ili


uredjeno prema opadajucem poretku broja pojavljavanja
etiketa. Funkcija u takvo stablo rekurzivno dodaje sve
etikete iz starog stabla, i vraca koren na tako modifikovano
novo stablo. */
Cvor * resortiraj_stablo(Cvor * staro, Cvor * novo)
{

/* Izlaz iz rekurzije - nemamo sta da dodamo u novo stablo */


if(staro == NULL)
return novo;

202
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Dodajemo etiketu iz korena starog stabla u novo stablo,


sortirano opadajuce prema broju pojavljivanja */
novo = dodaj_po_broju(novo, staro->etiketa, staro->brojac);

/* Rekurzivno dodajemo u novo stablo sve cvorove iz levog


i desnog podstabla starog stabla. */
novo = resortiraj_stablo(staro->levi, novo);
novo = resortiraj_stablo(staro->desni, novo);

return novo;
}

/* Ispis stabla - s leva na desno */


void ispisi_stablo(Cvor * koren)
{
if(koren == NULL)
return;

ispisi_stablo(koren->levi);
printf("%s: %d\n", koren->etiketa, koren->brojac);
ispisi_stablo(koren->desni);

/* Oslobadjanje dinamicki alociranog prostora */


void oslobodi_stablo(Cvor *koren)
{
if(koren == NULL)
return;

oslobodi_stablo(koren->levi);
oslobodi_stablo(koren->desni);
free(koren);
}

/* glavni program */
int main(int argc, char **argv)
{

FILE *in = NULL; /* Ulazni fajl */


Cvor * koren = NULL; /* Stablo u leksikografskom poretku */
Cvor * resortirano = NULL; /* stablo u poretku po broju pojavljivanja */

203
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Mora se zadati makar ime ulaznog fajla na komandnoj liniji.


Opciono se kao drugi argument moze zadati opcija "-b"
sto dovodi do ispisa po broju pojavljivanja (umesto leksikografski) */
if(argc < 2)
{
fprintf(stderr, "koriscenje: %s ime_fajla [-b]\n", argv[0]);
exit(1);
}

/* Otvaramo fajl */
if((in = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "fopen() greska\n");
exit(1);
}

/* Formiramo leksikografsko stablo etiketa */


koren = ucitaj(in);

/* Ako je korisnok zadao "-b" kao drugi argument, tada


se vrsi resortiranje, i ispisuje izvestaj sortiran
opadajuce po broju pojavljivanja */
if(argc == 3 && strcmp(argv[2], "-b") == 0)
{
resortirano = resortiraj_stablo(koren, resortirano);
ispisi_stablo(resortirano);
}
/* U suprotnom se samo ispisuje izvestaj u leksikografskom poretku */
else
ispisi_stablo(koren);

/* Oslobadjamo stabla */
oslobodi_stablo(koren);
oslobodi_stablo(resortirano);

return 0;
}
Primer 11.7 Efikasnije sortiranje čorova stabla — formira se niz pokazivača na
čvorove stabla koji se u skladu sa funkcijom pored̄enja sortiraju pomoću bibliotečke
qsort funkcije.
#include <stdlib.h>
#include <stdio.h>

204
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Cvor drveta sadrzi ime reci i


broj njenih pojavljivanja */
typedef struct _cvor {
char ime[80];
int br_pojavljivanja;
struct _cvor* levo, *desno;
} cvor;

/* Gradimo niz pokazivaca na cvorove drveta koji ce


nam sluziti da po prihvatanju svih reci izvrsimo
sortiranje po broju pojavljivanja */

#define MAX_BROJ_RAZLICITIH_RECI 1000

cvor* razlicite_reci[MAX_BROJ_RAZLICITIH_RECI];

/* Tekuci broj cvorova drveta */


int broj_razlicitih_reci=0;

/* Funkcija uklanja binarno drvo iz memorije */


void obrisi_drvo(cvor* drvo)
{
if (drvo!=NULL)
{ obrisi_drvo(drvo->levo);
obrisi_drvo(drvo->desno);
free(drvo);
}
}

cvor* napravi_cvor(char rec[])


{
cvor* novi_cvor=(cvor*)malloc(sizeof(cvor));
if (novi_cvor==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
strcpy(novi_cvor->ime, rec);
novi_cvor->br_pojavljivanja=1;

return novi_cvor;
}

205
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

/* Funkcija ubacuje datu rec u dato drvo i vraca pokazivac na


koren drveta */
cvor* ubaci(cvor* drvo, char rec[])
{
/* Ukoliko je drvo prazno gradimo novi cvor */
if (drvo==NULL)
{
cvor* novi_cvor = napravi_cvor(rec);

/* pokazivac na novo napravljeni cvor smestamo u niz


pokazivaca na sve cvorove drveta */
razlicite_reci[broj_razlicitih_reci++] = novi_cvor;

return novi_cvor;
}

int cmp = strcmp(rec, drvo->ime);

/* Ukoliko rec vec postoji u drvetu


uvecavamo njen broj pojavljivanja */
if (cmp==0)
{ drvo->br_pojavljivanja++;
return drvo;
}

/* Ukoliko je rec koju ubacujemo leksikografski ispred


reci koja je u korenu drveta, rec ubacujemo
u levo podstablo */
if (cmp<0)
{ drvo->levo=ubaci(drvo->levo, rec);
return drvo;
}

/* Ukoliko je rec koju ubacujemo


leksikografski iza reci koja je u
korenu drveta, rec ubacujemo
u desno podstablo */
if (cmp>0)
{ drvo->desno=ubaci(drvo->desno, rec);
return drvo;
}
}

/* Pomocna funkcija koja cita rec iz date datoteke i vraca

206
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

njenu duzinu, odnosno -1 ukoliko se naidje na EOF */


int getword(char word[], int lim, FILE* ulaz)
{
int c, i=0;
/* Umesto funkcije getchar koristimo fgetc
za rad sa datotekama */
while (!isalpha(c=fgetc(ulaz)) && c!=EOF)
;
if (c==EOF)
return -1;
do
{ word[i++]=c;
}while (i<lim-1 && isalpha(c=fgetc(ulaz)));

word[i]=’\0’;
return i;
}

/* Funkcija poredjenja za funkciju qsort. */


int poredi_br_pojavljivanja(const void* a, const void* b)
{
return
/* Konverzija pokazivaca b iz pokazivaca
na tip void u pokazivac na cvor jer
nam je svaki element niza koji sortiramo
tipa pokazivaca na cvor */
(*(cvor**)b)->br_pojavljivanja
-
(*(cvor**)a)->br_pojavljivanja;
}

main(int argc, char* argv[])


{
int i;

/* Drvo je na pocetku prazno */


cvor* drvo=NULL;
char procitana_rec[80];
FILE* ulaz;

if (argc!=2)
{ fprintf(stderr,"Greska :
Ocekivano ime datoteke\n");

207
Milena Vujošević–Janičić 11.1 Binarno pretraživačko stablo

exit(1);
}

if ((ulaz=fopen(argv[1],"r"))==NULL)
{
fprintf(stderr,"Greska : nisam uspeo da otvorim datoteku %s\n");
exit(1);
}

/* Citamo rec po rec dok ne naidjemo na kraj datoteke i


ubacujemo ih u drvo */
while(getword(procitana_rec,80,ulaz)!=-1)
drvo=ubaci(drvo,procitana_rec);

/* Sortiramo niz pokazivaca na cvorove


drveta po broju pojavljivanja */
qsort(razlicite_reci,
broj_razlicitih_reci,
sizeof(cvor*),
poredi_br_pojavljivanja);

/* Ispisujemo prvih 10 (ukoliko ih ima)


reci i njihov broj pojavljivanja */
for (i=0; i<10 && i<broj_razlicitih_reci; i++)
printf("%s - %d\n",razlicite_reci[i]->ime,
razlicite_reci[i]->br_pojavljivanja);

/* Uklanjamo drvo iz memorije */


obrisi_drvo(drvo);

fclose(ulaz);
}

208
Glava 12

Grafovi

Graf1 G=(V,E) sastoji se od skupa V cvorova i skupa E grana. Grane predstavljaju


relacije izmed̄u cvorova i odgovara paru cvorova. Graf moze biti usmeren (orijen-
tisan), ako su mu grane ured̄eni parovi i neusmeren (neorjentisan) ako su grane
neured̄eni parovi.
Put u grafu je niz cvorova v1,v2,...,vn, pri cemu u grafu postoje grane (v1,v2),
(v2,v3), ..., (vn-1, vn). Ako jos vazi da je v1 = vn, tada se ovakav put naziva ciklus.
Iako su liste i stabla specijalni oblici grafova, u programiranju postoji bitna raz-
lika: liste i stabala se prevashodno koriste kao kontejneri za podatke (u svaki cvor
se smesta neki podatak odred̄enog tipa), grafovi se pre svega koriste za modeliranje
nekih problema iz prakse, kako bi se ti problemi predstavili na apstraktan nacin
i resili primenom algoritama nad odgovarajucim grafom. Na primer, cvorovima u
grafu se mogu predstaviti raskrsnice u gradu, a granama ulice koji ih povezuju. Tada
se zadatak nalazenja najkraceg puta od tacke A do tacke B u gradu moze svesti na
nalazenje najkraceg puta od cvora u do cvora v u grafu. Slicno se mogu resavati
problemi sa racunarskim mrezama (racunari se predstave cvorovima, a veze med̄u
njima granama), itd.
Grafovi se mogu predstavljati na vise nacina. Uobicajena su dva nacina pred-
stavljanja grafova. To su matrica povezanosti grafa i lista povezanosti.
Matrica povezanosti je kvadratna matrica dimenzije n, pri cemu je n broj cvorova
u grafu, takva da je element na preseku i-te vrste i j-te kolone jednak jedinici uko-
liko postoji grana u grafu od i-tog do j-tog cvora, inace je nula. Jasno je da
ce neusmerenim grafovima odgovarati simetricne matrice. Prednost ovakvog pred-
stavljanja je jednostavnost. Nedostatak ovakvog pristupa je neracionalno koriscenje
memorije u slucaju ”retkih” grafova (grafova sa malo grana), gde ce najveci broj
elemenata matrice biti 0.
Umesto da se i sve nepostojece grane eksplicitno predstavljaju u matrici povezanosti,
mogu se formirati povezane liste od jedinica iz i-te vrste za i=1,2,...,n. To je
lista povezanosti. Svakom cvoru se pridruzuje povezana lista, koja sadrzi sve grane
susedne tom cvoru. Graf je predstavljen vektorom lista. Svaki elemenat vektora
1 Tekst i primeri preuzeti od Jelene Tomasevic, www.matf.bg.ac.yu/~jtomasevic, i Milana
Bankovica www.matf.bg.ac.yu/~milan zasnovano na materijalu Algoritmi, Miodrag Zivkovic i
http://www.matf.bg.ac.yu/~filip

209
Milena Vujošević–Janičić Grafovi

sadrzi ime (indeks) cvora i pokazivac na njegovu listu cvorova. Ovakav pristup stedi
memoriju, a omogucava i e kasno dodavanje novih cvorova i grana.
Osnovni problem koji se javlja kod grafova jeste kako polazeci od nekog cvora, kre-
tanjem kroz puteva grafa posetiti sve cvorove. Ovakav postupak se naziva obilazak
grafa. Postoje dva osnovna algoritma za obilazak grafa: pretraga u dubinu (DFS,
skracenica od depth- rst-search) i pretraga u sirinu (BFS, skracenica od breadth-
rst-search).
Kod DFS algoritma, obilazak zapocinje iz proizvoljnog zadatog cvora r koji se
naziva koren pretrage u dubinu. Koren se oznacava kao posecen. Zatim se bira
proizvoljan neoznacen cvor r1, susedan sa r, pa se iz cvora r1 rekurzivno startuje
pretraga u dubinu. Iz nekog nivoa rekurzije izlazi se kad se naid̄e na cvor v kome su
svi susedi vec oznaceni.
Primer 12.1 Primer reprezentovanja grafa preko matrice povezanosti. U programu
se unosi neorijentisan graf i DFS algoritmom se utvrd̄uju čvrovi koji su dostižni iz
čvora 0.
#include <stdlib.h>
#include <stdio.h>

int** alociraj_matricu(int n)
{ int **matrica;
int i;
matrica=malloc(n*sizeof(int*));
if (matrica==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}

for (i=0; i<n; i++)


{
/* Funkcija calloc popunjava rezervisan
prostor u memoriji nulama. */
matrica[i]=calloc(n,sizeof(int));
if (matrica[i]==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
}
return matrica;
}

void oslobodi_matricu(int** matrica, int n)


{ int i;

210
Milena Vujošević–Janičić Grafovi

for (i=0; i<n; i++)


free(matrica[i]);
free(matrica);
}

int* alociraj_niz(int n)
{ int* niz;
niz=calloc(n,sizeof(int));
if (niz==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
return niz;
}

void oslobodi_niz(int* niz)


{ free(niz);
}

void unesi_graf(int** graf, int n)


{ int i,j;
for (i=0; i<n; i++)
for (j=i; j<n; j++)
{ printf("Da li su element %d i %d povezani : ",i,j);
do
{ scanf("%d",&graf[i][j]);
/* Radimo sa neusmerenim grafom */
graf[j][i]=graf[i][j];
} /* Obezbedjujemo ispravan unos */
while (graf[i][j]!=0 && graf[i][j]!=1);
}
}

void ispisi_graf(int** graf, int n)


{ int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
printf("%d",graf[i][j]);
printf("\n");
}
}

211
Milena Vujošević–Janičić Grafovi

/* Rekurzivna implementacija DFS algoritma */


void poseti(int i, int** graf, int n, int* posecen)
{ int j;
posecen[i]=1;
printf("Posecujem cvor %d\n",i);
for (j=0; j<n; j++)
if (graf[i][j] && !posecen[j])
poseti(j);
}

main()
{

/* Broj cvorova grafa (dimenzija matrice) */


int n;
/* Matrica povezanosti */
int **graf;

/* Pomocni vektor koji govori o tome koji su cvorovi posecivani


tokom DFS obilaska */
int *posecen;

int i, j;
printf("Unesi broj cvorova : ");
scanf("%d",&n);

graf=alociraj_matricu(n);
unesi_graf(graf,n);
ispisi_graf(graf,n);

posecen=alociraj_niz(n);
poseti(0, graf, n);

oslobodi_niz(posecen);
oslobodi_matricu(graf,n);
}
Primer 12.2 Primer demonstrira osnovne algoritme nad grafovima. U ovom primer
grafovi se predstavljaju matricama povezanosti. Zbog jednostavnosti, pretpostavlja se
da je broj cvorova ogranicen nekom fiksiranom konstantom, tako da se odgovarajuce
matrice alociraju staticki. Takod̄e, da bi se pojednostavile liste argumenata pojedinih
funkcija, većina promenljivih u ovom primeru se deklarišu kao globalne, kako bi kao
takve bile dostupne svim funkcijama.
#include <stdio.h>
#include <stdlib.h>

212
Milena Vujošević–Janičić Grafovi

#define MAX_CVOROVA 100

/* Matrica povezanosti grafa. Pretpostavka je da broj


cvorova grafa nece biti veca od MAX_CVOROVA */
int graf[MAX_CVOROVA][MAX_CVOROVA];
int broj_cvorova;

/* Niz 0/1 vrednosti kojim se obelezavaju poseceni cvorovi */


int posecen[MAX_CVOROVA];

/* Pomocna funkcija koja utvrdjuje da li postoji neposecen cvor.


Funkcija vraca indeks prvog takvog cvora, ili -1 u slucaju da
su svi cvorovi vec poseceni */
int postoji_neposecen()
{
int i;

for(i = 0; i < broj_cvorova; i++)


if(!posecen[i]) return i;

return -1;

/* Pomocna funkcija koja sluzi za inicijalizaciju raznih nizova


(poput posecen[], dolazna_numeracija[] itd.) Za sve nizove
se pretpostavlja da su duzine broj_cvorova. */
void inicijalizuj(int niz[])
{
int i;

for(i = 0 ; i < broj_cvorova ; i++)


niz[i] = 0;

/* NAPOMENA: za potrebu demonstracije obilaska grafa, obrada koja


se prilikom obilaska vrsi bice numerisanje cvorova grafa u
poretku posecivanja. */

/* Staticki podaci koji se koriste za smestanje rezultata


prilikom numeracije cvorova (i za DFS i za BFS). */
int dolazna_numeracija[MAX_CVOROVA];

213
Milena Vujošević–Janičić Grafovi

int odlazna_numeracija[MAX_CVOROVA];

/* Donji brojaci treba da se postave na nulu pre pozivanja


funkcija za numeraciju */
int brojac_dolazna=0;
int brojac_odlazna=0;

/* Funkcija obilazi graf DFS algoritmom, i tom prilikom


vrsi dolaznu i odlaznu numeraciju cvorova. Pre poziva
ove funkcije obavezno je postaviti brojace dolazne i
odlazne numeracije na 0 */
void DFS_numeracija(int polazni_cvor)
{
int i;

/* Obelezavanje */
posecen[polazni_cvor] = 1;

/* Ulazna obrada */
dolazna_numeracija[polazni_cvor] = ++brojac_dolazna;

/* Rekurzija (za sve cvorove ka kojima postoji grana


i koji jos nisu obelezeni) */
for(i = 0 ; i < broj_cvorova; i++)
if(graf[polazni_cvor][i] && !posecen[i])
DFS_numeracija(i);

/* Izlazna obrada */
odlazna_numeracija[polazni_cvor] = ++brojac_odlazna;
}

/* Funkcija vrsi BFS obilazak i numerise cvorove u poretku


obilaska. Pre poziva ove funkcije treba inicijalizovati
posecen[] i brojac_dolazna */
void BFS_numeracija(int polazni_cvor)
{

/* Improvizovani red koji koristimo za smestanje


cvorova koji cekaju da budu obradjeni. Cvorovi
se smestaju na kraj reda (kraj niza), a uzimaju
sa pocetka reda (niza). Zato imamo dva indeksa
koji pokazuju na pocetak i kraj reda. Duzina
ovog reda je MAX_CVOROVA sto je dovoljno jer
ce svaki cvor na red biti postavljen tacno jednom */

214
Milena Vujošević–Janičić Grafovi

int red[MAX_CVOROVA];
int sledeci_na_redu = 0;
int poslednji_na_redu = -1;
int i;

/* Inicijalno se na redu nalazi samo polazni cvor */


posecen[polazni_cvor] = 1;
red[++poslednji_na_redu] = polazni_cvor;

/* Dokle god imamo cvorove u redu...*/


while(sledeci_na_redu <= poslednji_na_redu)
{
/* Vrsimo obradu cvora (numeracija) */
dolazna_numeracija[red[sledeci_na_redu]] = ++brojac_dolazna;

/* Za sve cvorove ka kojima postoji grana i koji nisu


poseceni vrsimo obelezavanje i dodavanje u red */
for(i = 0; i < broj_cvorova; i++)
if(graf[red[sledeci_na_redu]][i] && !posecen[i])
{
red[++poslednji_na_redu] = i;
posecen[i] = 1;
}
/* Prelazimo na sledeci u redu */
sledeci_na_redu++;
}
}

/* Test program */
int main()
{
int i,j;
int aciklican;

/* Unos matrice povezanosti grafa */


printf("Unesite broj cvorova grafa (<=%d): ", MAX_CVOROVA);
scanf("%d",&broj_cvorova);

for(i = 0; i < broj_cvorova; i++)


for(j = 0; j < broj_cvorova; j++)
{
if(i == j) continue;

printf("Da li postoji grana (%d,%d) (0/1): ", i, j);

215
Milena Vujošević–Janičić Grafovi

scanf("%d", &graf[i][j]);
}

/* Testiramo DFS numeraciju */


inicijalizuj(posecen);

brojac_dolazna = 0;
brojac_odlazna = 0;

while((i = postoji_neposecen()) >= 0)


DFS_numeracija(i);

printf("Dolazna DFS numeracija: ");


for(i = 0; i < broj_cvorova; i++)
printf("%d ",dolazna_numeracija[i]);

putchar(’\n’);
printf("Odlazna DFS numeracija: ");
for(i = 0; i < broj_cvorova; i++)
printf("%d ", odlazna_numeracija[i]);
putchar(’\n’);

/* Testiramo BFS numeraciju */


inicijalizuj(posecen);
brojac_dolazna = 0;

while((i = postoji_neposecen()) >= 0)


BFS_numeracija(i);

printf("Dolazna BFS numeracija: ");


for(i = 0; i < broj_cvorova; i++)
printf("%d ",dolazna_numeracija[i]);
putchar(’\n’);

return 0;
}
Primer 12.3 Primer predstavljanja grafa preko niza listi suseda svakog od čvorova
grafa. U programu se unosi graf i DFS algoritmom se utvrdjuje koji su čvorovi
dostižni iz cvora 0.
#include <stdlib.h>
#include <stdio.h>

/* Cvor liste suseda */

216
Milena Vujošević–Janičić Grafovi

typedef struct _cvor_liste


{ int broj; /* Indeks suseda */
struct _cvor_liste* sledeci;
} cvor_liste;

/* Ubacivanje na pocetak liste */


cvor_liste* ubaci_u_listu(cvor_liste* lista, int broj)
{ cvor_liste* novi=malloc(sizeof(cvor_liste));
if (novi==NULL)
{
printf("Greska prilikom alokacije memorije\n");
exit(1);
}
novi->broj=broj;
novi->sledeci=lista;
return novi;
}

/* Rekurzivno brisanje liste */


void obrisi_listu(cvor_liste* lista)
{ if (lista)
{ obrisi_listu(lista->sledeci);
free(lista);
}
}

/* Ispis liste */
void ispisi_listu(cvor_liste* lista)
{ if (lista)
{ printf("%d ",lista->broj);
ispisi_listu(lista->sledeci);
}
}

#define MAX_BROJ_CVOROVA 100

/* Graf predstavlja niz pokazivaca na pocetke listi suseda */


cvor_liste* graf[MAX_BROJ_CVOROVA];
int broj_cvorova;

int posecen[MAX_BROJ_CVOROVA];

/* Rekurzivna implementacija DFS algoritma */


void poseti(int i)

217
Milena Vujošević–Janičić Grafovi

{ cvor_liste* sused;
printf("Posecujem cvor %d\n",i);
posecen[i]=1;
for( sused=graf[i]; sused!=NULL; sused=sused->sledeci)
if (!posecen[sused->broj])
poseti(sused->broj);
}

void oslobodi_graf(cvor_liste* graf[], int broj_cvorova)


{
int i;
for(i=0; i<broj_cvorova; i++)
obrisi_listu(graf[i]);
}

main()
{
int i;
printf("Unesi broj cvorova grafa : ");
scanf("%d",&broj_cvorova);
/*Unos grafa*/
for (i=0; i<broj_cvorova; i++)
{ int br_suseda,j;

graf[i]=NULL;

printf("Koliko cvor %d ima suseda : ",i);


scanf("%d",&br_suseda);
for (j=0; j<br_suseda; j++)
{ int sused;
do
{
printf("Unesi broj %d.-tog suseda cvora %d : ",j,i);
scanf("%d",&sused);
} while (sused<1 && sused>broj_cvorova);
graf[i]=ubaci_u_listu(graf[i],sused-1);
}
}

/*Ispis grafa*/
for (i=0; i<broj_cvorova; i++)
{ printf("%d - ",i);
ispisi_listu(graf[i]);
printf("\n");

218
Milena Vujošević–Janičić Grafovi

}
/*Koji su sve cvorovi dostupni iz cvora 0*/
poseti(0);

/*Oslobadjanje memorije*/
oslobodi_graf(graf, broj_cvorova);
}
Primer 12.4 MINESWEEPER - primer jednostavne igrice.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

/* Dimenzija table */
int n;

/* Tabla koja sadrzi 0 i 1 u zavisnosti


od toga da li na polju postoji bomba */
int** bombe;

#define PRAZNO (-1)


#define ZATVORENO 0
#define ZASTAVICA 9

/* Tabla koja opisuje tekuce stanje igre.


Moze da sadrzi sledece vrednosti :
ZATVORENO - opisuje polje
koje jos nije bilo otvarano
PRAZNO - polje na kome ne
postoji ni jedna bomba
BROJ od 1-8 - polje koje je
otvoreno i na kome pise
koliko bombi postoji u okolini
ZASTAVICA - polje koje je korisnik
oznacio zastavicom
*/
int** stanje;

/* Ukupan broj bombi */


int broj_bombi;

/* Ukupan broj postavljenih zastavica */


int broj_zastavica = 0;

/* Pomocne funkcije za rad sa matricama */

219
Milena Vujošević–Janičić Grafovi

int** alociraj(int n)
{
int i;
int** m=(int**)malloc(n*sizeof(int*));
if(m==NULL) {printf("Greska prilikom alokacije memorije\n"); exit(1);}
for (i=0; i<n; i++)
{
m[i]=(int *)calloc(n,sizeof(int));
if(m[i]==NULL)
{printf("Greska prilikom alokacije memorije\n"); exit(1);}
}
return m;
}

void obrisi(int** m, int n)


{ int i;
for (i=0; i<n; i++)
free(m[i]);

free(m);
}

/* Funkcija postavlja bombe */


void postavi_bombe()
{
broj_bombi=(n*n)/6;
int kolona;
int vrsta;
int i;

/* Inicijalizujemo generator slucajnih brojeva */


srand(time(NULL));

for (i=0; i<broj_bombi; i++)


{ /* Racunamo slucajni polozaj bombe */
kolona=rand()%n;
vrsta=rand()%n;

/* Ukoliko bomba vec postoji tu,


opet idemo u istu iteraciju */
if (bombe[vrsta][kolona]==1)
{ i--;
continue;

220
Milena Vujošević–Janičić Grafovi

/* Postavljamo bombu */
bombe[vrsta][kolona]=1;
}
}

/* Funkcija ispisuje tablu sa bombama */


void ispisi_bombe()
{
int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
printf("%d",bombe[i][j]);
printf("\n");
}
}

/* Funkcija ispisuje tekuce stanje */


void ispisi_stanje()
{ int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++)
{ if (stanje[i][j]==ZATVORENO)
printf(".");
else if (stanje[i][j]==PRAZNO)
printf(" ");
else if (stanje[i][j]==ZASTAVICA)
printf("*");
else
printf("%d",stanje[i][j]);
}
printf("\n");
}
}

/* Funkcija postavlja zastavicu na


dato polje ili je uklanja
ukoliko vec postoji */
void postavi_zastavicu(int i, int j)
{
if (stanje[i][j]==ZATVORENO)
{ stanje[i][j]=ZASTAVICA;
broj_zastavica++;

221
Milena Vujošević–Janičić Grafovi

}
else if (stanje[i][j]==ZASTAVICA)
{ stanje[i][j]=ZATVORENO;
broj_zastavica--;
}
}

/* Funkcija izracunava koliko bombi


postoji u okolini date bombe */
int broj_bombi_u_okolini(int v, int k)
{ int i, j;
int br=0;
/* Prolazimo kroz sva okolna polja */
for (i=-1; i<=1; i++)
for(j=-1; j<=1; j++)
{ /* preskacemo centralno polje */
if (i==0 && j==0)
continue;
/* preskacemo polja "van table" */
if (v+i<0 || k+j<0 || v+i>=n || k+j>=n)
continue;
if (bombe[v+i][k+j]==1)
br++;
}

return br;
}

/* Centralna funkcija koja vrsi otvaranje


polja i pritom se otvaranje "siri"
i na polja koja su oko datog */
void otvori_polje(int v, int k) {
/* Ukoliko smo "nagazili" bombu
zavrsavamo program */
if (bombe[v][k]==1)
{ printf("BOOOOOOOOOOOOOOOOM!!!!\n");
ispisi_bombe();
exit(1);
}
else
{
/* Brojimo bombe u okolini */
int br=broj_bombi_u_okolini(v,k);

222
Milena Vujošević–Janičić Grafovi

/* Azuriramo stanje ovog polja */


stanje[v][k]=(br==0)?PRAZNO:br;

/* Ukoliko u okolini nema bombi,


rekurzivno otvaramo
sva polja u okolini koja su zatvorena */
if (br==0)
{
/* Petlje indeksiraju sva okolna polja */
int i,j;
for (i=-1; i<=1; i++)
for (j=-1; j<=1; j++)
{
/* Preskacemo centralno polje */
/* if (i==0 && j==0)
continue; */
/* Preskacemo polja van table */
if (v+i<0 || v+i>=n || k+j<0 || k+j>=n)
continue;
/* Ukoliko je okolno polje
zatvoreno, otvaramo ga */
if (stanje[v+i][k+j]==ZATVORENO)
otvori_polje(v+i, k+j);
}
}
}
}

/* Funkcija utrdjuje da li je partija gotova


Partija je gotova u trenutku kada su sve
bombe pokrivene zastavicama i
kada nijedno drugo polje nije
pokriveno zastavicom */
int gotova_partija()
{ int i,j;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{ /* Ukoliko postoji nepokrivena bomba,
partija nije zavrsena */
if (bombe[i][j]==1 && stanje[i][j]!=ZASTAVICA)
return 0;
}

/* Partija je zavrsena samo ukoliko je

223
Milena Vujošević–Janičić Grafovi

broj zastavica jednak broj bombi */


return broj_zastavica==broj_bombi;
}

main() {

/* Unosimo dimenziju table */


printf("Unesite dimenziju table : ");
scanf("%d",&n);

/* Alociramo table */
bombe=alociraj(n);
stanje=alociraj(n);

/* Postavljamo bombe */
postavi_bombe();

/* Sve dok partija nije gotova */


while(!gotova_partija())
{ int v,k;
char akcija;

/* Ispisujemo tekuce stanje */


ispisi_stanje();

/* Sve dok korisnik ne unese o ili z


trazimo od njega da upise
odgovarajucu akciju */
do
{
getchar();
printf("Unesi akciju (o - otvaranje polja,
z - postavljanje zastavice) : ");
scanf("%c",&akcija);
} while (akcija!=’o’ && akcija!=’z’);

/* Trazimo od korisnika da unese koordinate


polja sve dok ih ne unese ispravno
Korisnicke koordinate krecu od 1,
a interne od 0 */
do
{
printf("Unesi koordinate polja : ");
scanf("%d",&v);

224
Milena Vujošević–Janičić Grafovi

scanf("%d",&k);
} while(v<1 || v>n || k<1 || k>n);

/* Reagujemo na akciju */
switch(akcija)
{ case ’o’:
otvori_polje(v-1,k-1);
break;
case ’z’:
postavi_zastavicu(v-1,k-1);
}
}

/* Konstatujemo pobedu */
ispisi_stanje();
printf ("Cestitam! Pobedili ste\n");
obrisi(stanje,n);
obrisi(bombe,n);
}

225
Ivan P. Stanimirović Uvod u programiranje

0. ELEMENTI TEORIJE ALGORITAMA .............................................................. 5

0. 1. INTUITIVNA DEFINICIJA ALGORITMA ............................................................................................ 5

0. 2. OSOBINE ALGORITAMA ...................................................................................................................... 6

0.3. ZAPIS (OPIS) ALGORITMA...................................................................................................................... 8


0.3.1. Zapis algoritama skupom pravila ........................................................................................................... 8
0.3.2. Zapis algoritama dijagramom toka ......................................................................................................... 9

0.4. BEKUSOVA NORMALNA FORMA (BNF) ........................................................................................... 10


0. 4. 1. SINTAKSNI DIJAGRAMI ................................................................................................................ 13

1. OSNOVNI ELEMENTI PROGRAMSKIH JEZIKA ................................................ 13

1.1. Pseudojezik kao opšti model viših programskih jezika ............................................................................ 13

1.2. Azbuka jezika ............................................................................................................................................... 15

1.3. Identifikatori i rezervisane reči ................................................................................................................... 15

1.4. Konstante ..................................................................................................................................................... 16

1.5. Promenljive ................................................................................................................................................... 17

1.6. Komentari ..................................................................................................................................................... 17

1.7. Struktura programa .................................................................................................................................... 18


1.7.1. Struktura programa u C .......................................................................................................................... 18

2. TIPOVI PODATAKA............................................................................................. 18
Statička i dinamička tipizacija ..................................................................................................................... 20

2.1. Koncept jakih tipova podataka ................................................................................................................... 21

2.2. Koncept slabih tipova ................................................................................................................................. 21

2.3. Ekvivalentnost tipova................................................................................................................................... 22

2.4. Elementarni tipovi podataka ..................................................................................................................... 22


2.4.1. Celobrojni tipovi (Integer ili int) ............................................................................................................ 22
2.4.2. Realni tip (float ili real) .......................................................................................................................... 23
2.4.3. Logički tip podataka ............................................................................................................................... 23
2.4.4. Znakovni tipovi ...................................................................................................................................... 23

2.5. Tipovi podataka u jeziku C ......................................................................................................................... 24


Celobrojni tipovi u C ................................................................................................................................... 25
Realni tipovi podataka u C .......................................................................................................................... 26
Tip char........................................................................................................................................................ 27
Konverzija tipova podataka i kast................................................................................................................ 28
Vrste konverzije tipova ................................................................................................................................ 29
Konstante ..................................................................................................................................................... 29
Sizeof operator............................................................................................................................................. 30
Osnovne aritmetičke operacije .................................................................................................................... 30
Operacije poređenja i logičke operacije....................................................................................................... 33

1
Ivan P. Stanimirović Uvod u programiranje

2.6. Diskretni tipovi podataka u programskim jezicima ................................................................................. 34


2.6.1. Nabrojivi tipovi u programskim jezicima ............................................................................................... 34

2.8. Upotreba typedef iskaza u C ....................................................................................................................... 34

3. ULAZ I IZLAZ PODATAKA.................................................................................. 35

3.1. Ulaz i izlaz podataka u jeziku C .................................................................................................................. 35


3.1.1. Funkcije printf() i scanf() ....................................................................................................................... 35
3.1.2. Direktive pretprocesora u C.................................................................................................................... 38

4. OSNOVNE UPRAVLJAČKE STRUKTURE ........................................................ 40

4.1. načini predstavljanja algoritama ................................................................................................................ 41

4.2. Sekvenca naredbi i blok ............................................................................................................................... 47


4.2.1. Globalne i lokalne promenljive .............................................................................................................. 47

4.3. Struktura selekcije ....................................................................................................................................... 49


4.3.1. If-then struktura ...................................................................................................................................... 49
4.3.2. If-then-else struktura .............................................................................................................................. 50
4.3.3. Operator uslovnog prelaza u C ............................................................................................................... 56

4.4. Struktura višestruke selekcije ..................................................................................................................... 56


4.4.1. Višestruka selekcija u C ......................................................................................................................... 57

4.5. Programske petlje ........................................................................................................................................ 60


4.5.1. Programske petlje u C ............................................................................................................................ 61
While naredba u C ....................................................................................................................................... 61
Primena while ciklusa u obradi teksta u C .................................................................................................. 65
Do-while naredba u C .................................................................................................................................. 65
For naredba u C ........................................................................................................................................... 66

4.6. Formalizacija repetitivnih iskaza ............................................................................................................... 69

4.7. Nasilni prekidi ciklusa ................................................................................................................................. 71

4.8. Naredbe za bezuslovno grananje ................................................................................................................ 72


4.8.1. Oznake (labele) ...................................................................................................................................... 72

5. POTPROGRAMI ................................................................................................. 76

5.1. Funkcije ........................................................................................................................................................ 77


5.1.1. Poziv i definicija funkcija u C ................................................................................................................ 77
Return naredba............................................................................................................................................. 78
Prototip funkcije .......................................................................................................................................... 79
5.1.2. Makroi u jeziku C ................................................................................................................................... 84

5.2. Procedure ...................................................................................................................................................... 84

5.3. Prenos argumenata ...................................................................................................................................... 85


5.3.1. Prenos po vrednosti (Call by Value) ...................................................................................................... 85
Prenos parametara po vrednosti u C ............................................................................................................ 86
5.3.2. Prenos po rezultatu (Call by Result) ....................................................................................................... 87
5.3.3. Prenos po vrednosti i rezultatu (Call by Value-Result) .......................................................................... 87
5.3.4. Prenos po referenci (Call by Reference)................................................................................................. 87
Poziv po adresi pomoću pokazivača u C ..................................................................................................... 89
Prenos po referenci koristeći reference u C++............................................................................................. 93

2
Ivan P. Stanimirović Uvod u programiranje

Vraćanje višestrukih vrednosti .................................................................................................................... 95


Vraćanje višestrukih vrednosti po referenci ................................................................................................ 97
Predavanje po referenci, zbog efikasnosti ................................................................................................... 98

5.4. Globalne promenljive kao parametri potprograma ................................................................................ 105


Primeri ....................................................................................................................................................... 107

5.5. Rekurzivni potprogrami ............................................................................................................................ 110


5.5.1. Primeri rekurzivnih funkcija u C .......................................................................................................... 112

5.6. Implementacija potprograma ................................................................................................................... 115

5.7. Scope rules (domen važenja) ..................................................................................................................... 118

5.8. Memorijske klase u C ................................................................................................................................ 119


5.8.1. Životni vek objekata ........................................................................................................................ 121
5.8.2. Vrste objekata po životnom veku .................................................................................................... 121
Statički i automatski objekti ...................................................................................................................... 121

6. STRUKTURNI TIPOVI PODATAKA .................................................................. 122

6.1. Polja u programskim jezicima .................................................................................................................. 122

6.2. Jednodimenzionalni nizovi u C ................................................................................................................. 123

6.3. Veza između nizova i pointera u C ........................................................................................................... 133


6.3.1. Pointerska aritmetika ............................................................................................................................ 135

6.4. Nizovi i dinamička alokacija memorije u C ............................................................................................. 136

6.5. Višedimenzionalna polja ............................................................................................................................ 142


6.5.1. Višedimenzionalni nizovi u C .............................................................................................................. 143
6.5.2. Pokazivači i višedimenzionalni nizovi u C ........................................................................................... 143
6.5.3. Matrice i dinamička alokacija memorije .............................................................................................. 170

6.6. STRINGOVI ............................................................................................................................................... 173


6.6.1. Stringovi u C ........................................................................................................................................ 173
Inicijalizacija i obrada stringova ................................................................................................................ 173
Testiranje i konverzija znakova ................................................................................................................. 175
Učitavanje i ispis stringova........................................................................................................................ 176
Standardne funkcije za rad sa stringovima u C .......................................................................................... 181

6.7. Strukture i nabrojivi tipovi u c ................................................................................................................. 184


6.7.1. Članovi strukture .................................................................................................................................. 184
6.7.2 Strukturni tipovi i pokazivači u C ......................................................................................................... 189
6.7.3. Definicija strukturnih tipova pomoću typedef ...................................................................................... 193
6.7.4. Unije ..................................................................................................................................................... 165

6.8. Nabrojivi tip podataka u c ......................................................................................................................... 168

6.9. Dinamičke matrice i strukture .................................................................................................................. 170

6.10. Datoteke .................................................................................................................................................... 172


6.10.1. Pristup datotekama u C....................................................................................................................... 172
Otvaranje i zatvaranje datoteka ................................................................................................................. 173
Funkcije fgetc() i fputc()............................................................................................................................ 175
fputc ........................................................................................................................................................... 175
Funkcije fprintf() i fscanf() ........................................................................................................................ 176
Funkcija feof() ........................................................................................................................................... 178

3
Ivan P. Stanimirović Uvod u programiranje

fclose, _fcloseall ........................................................................................................................................ 180


feof ............................................................................................................................................................ 180
6.10.2. Binarne datoteke ................................................................................................................................. 181
Direktni pristup datotekama ...................................................................................................................... 182

Literatura........................................................................................................................................................... 183

4
Ivan P. Stanimirović Uvod u programiranje

0. ELEMENTI TEORIJE ALGORITAMA

0. 1. INTUITIVNA DEFINICIJA ALGORITMA


Algoritam jeste jedan od osnovnih pojmova matematike i računarstva. Prve algoritme srećemo
kod starih Grka. Svima su poznati Euklidov algoritam i Eratostenovo sito (250. g. p. n.e.) Algoritam
predstavlja uputstvo za rešavanje nekog zadatka u cilju dobijanja rešenja (posle konačno mnogo
vremena).
Pri rešavanju nekog složenog zadatka (problema) korsitimo rastavljanje (dekompoziciju) zadatka
na prostije podzadatke (podprobleme). Postupak možemo nastaviti sve dok se ne dobije jedan konačan
skup relativno jednostavnih podzadataka. Takve podzadatke nazvaćemo elementarnim koracima ili
elementarnim operacijama. Svaki takav korak definiše koju operaciju i kojim redosledom se takva
obrada izvršava u cilju dobijanja rešenja datog problema. Ukoliko je elementarni korak relativno
složen tada se on može zadati u vidu uputstva (pravila) za rešavanje takvog podproblema. Zato
elementarne korake nazivamo i (elementarnim) pravilima.
Opis toka odvijanja elementarnih operacija (koraka) u cilju rešavanja nekog zadatka (problema)
naziva se procedura. Procedura se sastoji od konačno mnogo elementarnih koraka koji se mogu
mehanički izvršavati u određenom strogo definisanom redosledu i to za konačno vreme.
Primena procedure može dovesti do sledeća tri slučaja:
1) Primena procedure predstavlja beskonačan proces. Rešenje zadatka se u tom slučaju ne može
dobiti posle konačno mnogo koraka, odnosno, posle koančno mnogo vremena. Procedura ne
daje rezultat.
2) Primena procedure se prekida posle konačno mnogo koraka i ne dobija se rezultat. Proces
računanja se ne može nastaviti jer se ne zna korak na koji se prenosi izvršenje. Uzrok ove
situacije mogu biti pogrešni ulazni podaci (ili pogrešno definisana procedura). U prethodna dva
slučaja kažemo da imamo nerezultativnu proceduru.
3) Proces primene procedure se prekida posle konačno mnogo koraka sa dobijanjem rezultata.
Rešenje zadatka postoji i može se dobiti primenom procedure (rezultativne).
Samo u trećem slučaju kažemo da procedura predstavlja algoritam koji se može primeniti za rešavanje
datog zadatka. Na sličan način uvedene su i stroge matematičke definicije algoritama.
Na osnovu prethodnog možemo dati intuitivnu definiciju algoritma, gde umesto pojma
elementarni korak koristimo naziv algoritamski korak (pravilo).
Def. 1: Algoritam je konačan (uređen) skup strogo definisanih algoritamskih koraka
(pravila) čijom primenom na ulazne podatke (i međurezultate) dobijamo rešenje zadatka posle
konačno mnogo vremena.
Iz definicije uočavamo da svaki algoritam ima konačno mnogo algoritamskih koraka (koij je
najčešće uređen). Svaki algoritamski korak mora biti strogo (nedvosmisleno) definisan (kao i ceo
algoritam) tako da se može na isti način razumeti i izvršiti od strane bilo kog izvršioca.
Primena algoritma se završava posle konačno mnogo vremena a to znači da svaki algoritamski
korak mora biti izvršiv i da se mora primeniti konačno mnogo puta.
Algoritam definiše preslikavanje (funkciju) koje svakom izboru vrednosti ulaznih veličina
algoritma (zadatka) pridružuje odgovarajući rezultat. Kažemo da svaki algoritam ima svoju oblast

5
Ivan P. Stanimirović Uvod u programiranje

primenljivosti (ulaz).

0. 2. OSOBINE ALGORITAMA
Intuitivna definicija algoritma je nestroga definicija. Zato navodimo neke osobine koje
karakterišu svaki algoritam. Na taj način dodatno preciziramo ovaj pojam tako da je ekvivalentan sa
strogim matematičkim definicijama algoritma.

1. Diskretnost. Svaki algoritam predstavlja konačan uređen skup algoritamskih koraka. To je


rezultat dekompozicije (diskretizacije) problema koji se rešava od strane čoveka. Pri tome,
algoritam nije skup algoritamskih koraka, već uređen skup ili niz, jer je bitan redosled
algoritamskih koraka u zapisu algoritma. Takođe kažmo da je proces izvršenja algoritma
diskretan u vremenu. To znači da se u svakom vremenskom trenutku (intervalu) izvršava samo
jedan algoritamski korak. Proces izvršavanja algoritma jeste konačan niz algoritamskih koraka
koji se po strogo definisanom redosledu izvršavaju. To je slučaj kada imamo jednog izvršioca
algoritma (jedan procesor). Postoje i paralelni algoritmi, koji omogućuju da se dva ili više
algoritamskih koraka izvršavaju istovremeno.
2. Determinisanost (određenost). Svaki algoritamski korak treba da je definisan jasno, strogo
(tačno) i nedvosmisleno. Tumačenje i izvršavanje pravila algoritma ne sme zavisiti od volje
čoveka ili mašine. Posle izvršenja nekog algoritamskog koraka strogo je definisan prelaz na
sledeći algoritamski korak. To znači da je izvršenje algoritma deterministički proces i da se
može automatski izvršavati. Opis algoritma na prirodnom jeziku može dovesti do
dvosmislenosti.
3. Izvršivost. Uspešnu definiciju izvršivosti dao je D. Knut. On kaže da je algoritamski korak
izvršiv ako je čovek u stanju da ga izvrši za konačno vreme (pomoću olovke i papira). Kod
algoritamski rešivih zadataka nema neizvršivih koraka. Međutim, moguće je lako formulisati
pravilo koje nije izvršivo. Na primer: Ako razvoj broja  sadrži 7 uzastopnih devetki tada
sabrati sve preostale cifre.
4. Konačnost. Osobina konačnosti algoritma jeste zahtev da se izvršenje svakog algoritma završi
posle konačno mnogo vremena. Drugim rečima,izvršenje svakog algoritma je postignuto posle
konačno mnogo primena algoritamskih koraka. Zbog osobina 1. i 3. to znači da svaki
algoritamski korak ma kog algoritma mora da se izvrši konačno mnogo puta. U suprotnom,
nemamo algoritam. Takav je sledeći primer procedure koja se nikad ne završava :
Korak 1 : Neka je i = 0 ;
Korak 2 : Neka i dobije vrednost i +1 ;
Korak 3 : Pređi na korak 2 .
Iako imamo konačno mnogo algoritamskih koraka, pri čemu je svaki od njih strogo definisan i
izvršiv, ovo nije algoritam. Kod složenijih algoritama (zadataka)

javlja se potreba formalnog dokaza konačnosti algoritma.


5. Ulaz i izlaz algoritma. Svaki algoritam ima dva posebno izdvojena (konačna) skupa podataka
(veličina). Prva jeste skup ulaznih a druga skup izlaznih veličina. Broj veličina u ovim
skupovima može biti i nula. Skup ulaznih veličina algoritma predstavlja polazne veličine
(podatke) zadatka koji se rešava. Skup izlaznih veličina jeste traženo rešenje (rezultat)
postavljenog zadatka. Ukratko, ove skupove nazivamo ulaz i izlaz algoritma. (Za podatke koji
na pripadaju skupu ulaznih podataka algoritma kažemo da algoritam nije primenljiv).
6. Masovnost (Univerzalnost). Univerzalnost je osobina algoritma da se može primeniti na što
širu klasu problema. To upravo znači da ulazne veličine algoritma mogu uzimati početne
vrednosti iz što obilnijih (masovnijih) skupova podataka. Algoritam jeste opšte uputstvo koje
se može primeniti na ma koji izbor vrednosti ulaznih veličina. Zbog ove osobine,možemo reći
da je algoritam bolji ukoliko je univerzalniji (termin masovnost manje odgovara ovoj osobini).

6
Ivan P. Stanimirović Uvod u programiranje

7. Elementarnost algoritamskih koraka. Algoritam treba da sadrži algoritamske korake koji


predstavljaju elementarne operacije koje korisnik algoritma može da razume ili izvršilac
algoritma da izvrši. Za potrebe čoveka, algoritamski koraci mogu biti kompleksnije
fundamentalne ili logičke celine u složenom algoritmu. Međutim, za potrebe pisanja programa,
algoritam sadrži elementarne algoritamske korake koji odgovaraju naredbama ili pozivima
potprograma, algoritam sadži elementarne algoritamske korake koji odgovaraju naredbama ili
pozivima potprograma programskog jezika.
8. Rezultativnost (usmerenost). Algoritam je tako definisan da polazeći od proizvoljnih
vrednosti ulaznih veličina primena algoritamskih koraka vodi (usmerava) strogo ka dobijanju
traženog rezultata.
Analizom izvršenja algoritma mogu se uočiti tri načina izvršavanja algoritamskih koraka:
sukcesivno (sekvencijalno), sa granicom i cikličko.
a) Sukcesivno izvršavanje algoritamskih koraka jeste takvo da se koraci izvršavaju jedanput i u
redosledu kako su napisani. Takvi algoritamski koraci čine prostu linijsku algoritamsku
strukturu ili sekvencu (nisku) algoritamskih koraka.
b) Izvršavanje algoritamskih koraka tako da se neki izvrše jedanput a neki nijednom predstavlja
primer izvršavanja sa grananjem (ili prelazom). Takvu algoritamsku strukturu nazivamo
razgranatom linijskom algoritamskom strukturom.
c) Cikličko izvršavanje se javlja kada se grupa algoritamskih koraka izvršava više puta. Takvu
grupu naredbi nazivamo cikličkom algoritamskom strukturom ili ciklusom.
Korišćenjem (komponovanjem) ovakve tri algoritamske strukture možemo rešiti ma koji zadatak.
Paralelnost (jednovremenost). Algoritam definišemo kao konačan skup algoritamskih koraka.
Taj skup je uređen jer se njime definiše prirodan redosled izvršavanja koraka sa mogućnošću grananja
ili ponovnog izvršavanja. Za izvršenje algoritma kažemo da je niz primena algoritamskih koraka.
Postavlja se pitanje šta je pravilnije reći : skup ili niz. Prednost dajemo prvom terminu jer postoje
algoritmi u kojima se može promeniti redosled nekih algoritamskih koraka a da se rešenje ne
menja. Takve algoritamske korake možemo izvršavati istovremeno (paralelno), pomoću više
izvršioca (procesora). Algoritmi koji definišu paralelno izvršavanje algoritamskih koraka jesu
paralelni algoritmi, a paralelni procesori izvršavaju takve algoritme.
Efikasnost (efektivnost). Dva različita algoritma koji rešavaju jedan isti zadatak možemo
upoređivati u odnosu na neki izbrani kriterijum. Rezultat upoređivanja može biti da je jedan algoritam
bolji ili efikasniji od drugog. Izbor kriterijuma može biti različit. Najčešće se pravi kompromis
između različitih kriterijuma (vreme – memorija, jednostavnost – brzina ). Često puta neki
efikasni algoritmi zavise od izbora ulaznih podataka algoritma. Tako imamo efikasne algoritme
sortiranja podataka za slučajno izabrane (neuređene) podatke ili pak za delimično uređene.
Elegantnost. Elegantnost može biti subjektivan kriterijum za izbor algoritma, ali se često koristi.
Elegantno rešenje zadatka jeste ono koje je prosto (jednostavno) i originalno. Jednostavnost
rešenja je uvek poželjno ali je pitanje da li su uvek moguća originalna rešenja. Pod originalnošću
rešenja podrazumeva se njegova neočiglednost.
Originalno rešenje za izmenu mesta (vrednosti) dveju promenljivih a i b može biti sledeći
algoritam :
Korak 1 : Neka je a = a+b ;
Korak 2 : Neka je b = a-b ;
Korak 3 : Neka je a = ab .
Međutim,ovo nije elegantno rešenje jer nije jednostavno, a takođe nije efikasno niti univerzalno (ne
važi za sve moguće vrednosti a i b). Univerzalno rešenje koristi pomoćnu promenljivu :
1) p = a ;
2) a = b ;
3) b = p .
Rekurzija. Nasuprot iteraciji, koja se najčešće koristi za rešavanje zadataka cikličke prirode,

7
Ivan P. Stanimirović Uvod u programiranje

rekurzija je razrađena od strane specijalista funadamentalne matematike kao način definisanja


funkcija. Ona se koristi i u (računarstvu i) programiranju za rekurzivne definicije tipova i struktura
podataka, kao i za rekurzivne potprograme (funkcije i procedure). Rekurzivne definicije se karakterišu
time što objekat koji se definiše figuriše u samoj definiciji. Rekurzivna definicija funkcije f, koja
zavisi od prirodnog broja n, sadrži dva dela. Najpre se definiše veza između funkcije f(n) i funkcije
f(n1). U drugom delu se definiše vrednost funkcije f za posebnu vrednost argumenta n. Na sličan
način se iskazuju različite rekurzivne definicije. Navedimo sledeće rekurzivne definicije funkcija :
n  (n1)! ,n>1
1) n-faktorijel : n! =
1 , n = 0, 1

a  an1 , n>0
2) stepen : an =
1, n=0

f(n1)+f(n2) , n >1
3) Fibonačijev niz : f(n) =
1 ,n=0

4) najveći zajednički delilac :


n, m=n
NZD(m,n) = NZD(nm, m), n > m
NZD(mn, n) , m > n

0.3. ZAPIS (OPIS) ALGORITMA


Opis algoritma ima dva osnovna cilja :
1) da je (algoritam) razumljiv raznim korisnicima (ljudima) tako da se može koristiti ili prenositi;
2) da se na osnovu njega može pisati program na nekom (algoritamskom) programskom jeziku u
cilju izvršavanja na računaru.
U tom cilju razvijeni su različiti sistemi (dogovori) za zapis (opis, zadavanje, predstavljanje)
algoritama. Ovakvi sistemi zapisivanja algoritama treba da budu jednostavni ali (dovoljno) precizni
tako da ih čovek može lako da razume. Takvi opisi algoritama predstavljaju ‘univerzalne’ jezike, koji
su nezavisni od računara. Postoji nekoliko najčešće korišćenih načina za zapis algoritama,a to su :
a) skup pravila (pomoću prirodnog jezika);
b) dijagram toka (pomoću grafičkih tabela);
c) pseudokod.
Za tačan zapis algoritama tako da se može izvršiti na računaru koristimo algoritamske programske
jezike. Ekvivalentan zapis algoritma na programskom jeziku jeste program. Program predstavlja zapis
algoritma pomoću naredbi koje su ekvivalentne odgovarajućim algoritamskim koracima.

0.3.1. Zapis algoritama skupom pravila


Najprirodniji način zapisa algoritama jeste pomoću prirodnog jezika kojim komuniciraju ljudi.
Tako se algoritam može saopštiti govorom ili tekstualno. Primeri za to su razni kulinarski recepti,
uputstva za rukovanje mašinama, koja jesu neka vrsta algoritama. Takvi opisi mogu biti neprecizni, pa
čak i dvosmisleni zbog složenosti prirodnog jezika.
Međutim, zapis algoritama pomoću skupa pravila ima zadatak da pregledno, jasno i tačno opiše
algoritamske korake pomoću reči, simbola i rečenica prirodnog jezika. Oblik pravila algoritma je na
određen način precizan tako da su ona jasna i razumljiva svakome. U zapisu algoritama skupom

8
Ivan P. Stanimirović Uvod u programiranje

pravila može se uvesti ime algoritma. Pored toga algoritamska pravila se najčešće označavaju rednim
brojevima (0,1,2,. . . ), sa dodatnom simboličkom oznakom u vidu slova ili reči. Izvršenje algoritma
počinje od pravila sa rednim brojem 0 ili 1. Zatim se pravila algoritma izvršavaju prirodnim
redosledom (redno) dok se ne dođe do pravila za grananje,prelaz ili pravila za cikličko izvršavanje
algoritamskih koraka.
Navodimo neka najčešće upotrebljavana pravila za zapis algoritma :
1. Pravilo dodeljivanja : <promenljiva> := <izraz>
Izračunata vrednost izraza dodeljuje se promenljivoj sa leve strane simbola dodeljivanja := .
Alternativni simboli mogu biti = ,  , .
2. Pravilo uslovnog grananja : if <uslov> then <pravilo>
Ako je <uslov> ispunjen tada se izvršava <pravilo>,a u suprotnom prelazi se na sledeće pravilo.
3. Pravilo grananja : if <uslov> then <pravilo1>
else <pravilo2>
Ako je <uslov> ispunjen izvršava se <pravilo1>,a u suprotnom <pravilo2>.
4. Pravilo bezuslovnog grananja (skoka) : go to <oznaka pravila>
Ovo pravilo ukazuje da se prekida prirodni redosled izvršenja pravila algoritma i zahteva prelaz na
pravilo označeno sa <oznaka pravila>.
5. Pravilo za prekid izvršenja algoritma : Kraj (Stop)
Posle izvršenja ovog pravila prekida se izvršenje algoritma.
6. Pravilo za ulaz podataka : Ulaz (<lista ulaznih veličina>)
7. Pravilo za izlaz podataka : Izlaz (<lista izlaznih veličina>)
8. Pravilo ciklusa : Ponavljaj
<pravilo 1>
<pravilo 2>
. . .
<pravilo n>
Sve dok se <uslov> ne ispuni
Ovo pravilo definiše ponovljeno izvršavanje niza pravila <pravilo 1>,. . . ,<pravilo n> sve dok
<uslov> nije ispunjen. Kada se <uslov> ispuni prelazi se na sledeće pravilo.
Navedimo primer Euklidovog algoritma za nalaženje najvećeg zajedničkog delioca.
E0. Euklid
E1. Ulaz (m,n)
E2. r:= m MOD n ostatak deljenja
E3. Ako r=0 tada pređi na E7
E4. m:=n
E5. n:=r
E6. Pređi na E2
E7. nzd:=n
E8. Izlaz (nzd)
E9. Kraj
Slična algoritamska pravila imamo kod opisa algoritama pomoću pseudo koda. Pseudo kod koristi
pravila bliska naredbama programskog jezika. Pravila su jednostavna, čitljiva i nedvosmislena.

0.3.2. Zapis algoritama dijagramom toka


Jedan od najjednostavnijih i često korišćenih načina zapisa algoritama jeste dijagram toka (ili
blok šema) algoritma (tokovnik). Dijagram toka predstavlja jednu varijantu grafičkog opisa algoritma.

9
Ivan P. Stanimirović Uvod u programiranje

Svaki algoritamski korak predstavljen je grafičkim simbolom (blokom). Svi blokovi su povezani
linijama sa mogućim strelicama. Na taj način se zadaje struktura algoritma i redosled izvršavanja
algoritamskih koraka. Oblik grafičkog simbola ukazuje na vrstu algoritamskog koraka,odnosno
njegovu funkciju u algoritmu. U tabeli su dati najčešće korišćeni grafički simboli i njihova funkcija.
Grafički simbol algoritamskog koraka Funkcija algoritamskog koraka
(Definiše) početak algoritma

Ulazne veličine algoritma


(blok ulaza)
Obrada podataka
(blok obrade)
Uslovni algoritamski korak
(blok odluke)
Izlazne veličine algoritma
(blok izlaza)
Kraj algoritma

Proizvoljna algoritamska šema se u opštem slučaju može razložiti na elementarne šeme (ili
elementarne algoritamske strukture). Postoje tri vrste elementarnih šema:
1) linijska (sekvenca)
2) razgranata (grananje)
3) ciklička (ciklus)
Pokazuje se da je dovoljno imati na raspolaganju jednu linijsku,jednu razgranatu i jednu cikličku
elementarnu šemu da bi se realizovala proizvoljna algoritamska struktura. U praksi se često koriste
različiti oblici razgranatih i cikličkih elementarnih šema.
Može se primetiti da svaka od ovih elementarnih šema ima jedinstven ulaz u šemu i jedinstven
izlaz iz nje. To omogućuje lako komponovanje složenih algoritamskih šema pomoću elementarnih.
Takve šeme zovemo dobro strukturiranim. Ukoliko se na izlaz jedne elementarne šeme poveže ulaz
druge elementarne šeme i tako postupak nastavi dobijamo linijsku kompoziciju elementarnih šema.
Međutim,ako na izlaz nekog algoritamskog koraka u okviru cikličke šeme nadovežemo ulaz
elementarne cikličke šeme dobijamo koncentričnu kompoziciju cikličkih šema.
Višestruko grananje možemo realizovati kada (na izlaz nekog algoritamskog koraka) u okviru
jedne od grana umetnemo novu razgranatu šemu.

0.4. BEKUSOVA NORMALNA FORMA (BNF)


Ovaj metajezik prvi je predložio Homski 56 za opis prirodnih jezika. Sistem zapisa koji
opisujemo i koristimo pripada Bekusu, po kome je ovaj metajezik dobio naziv. Često se koristi termin
Bekusova notacija (ili Bekus-Naurova forma što je donekle nepravilno). Ovim metajezikom opisana je
nepotpuno sintaksa jezika ALGOL 60. Prema mišljenju Homskog, ovaj metajezik je pogodan za opis
jednostavnijih (kontekstno-nezavisnih) jezika. Zato su lingvisti pristupili definisanju i korišćenju
moćnijih metajezika.
Bekusova notacija je jednostavan metajezik. Osnovni pojmovi (konstrukcije) u ovom jeziku jesu:
metaformula, metaizraz, metaoperacije, metapromenljiva i metakonstanta. Pomoću metaformula
opisujemo sve sintaksne konstrukcije (pojmove) u izvornom (programskom) jeziku. Opišimo sve ove
pojmove Bekusove notacije (polazeći od najjednostavnijih).
Metakonstanta (terminal, terminalni simbol) jeste jedan simbol ili niska simbola azbuke jezika
koji opisujemo. Dakle, metakonstanta se na jedinstven način zapisuje u metajeziku preuzimanjem iz
izvornog jezika. Da bi se to naglasilo (i ako ima potrebe) metakonstanta se može uokviriti znacima
navoda (“) ili apostrofom (‘).

10
Ivan P. Stanimirović Uvod u programiranje

Metapromenljiva (neterminal, neterminalni simbol) u Bekusovoj notaciji jeste pojam (sintaksna


jedinica) izvornog jezika. Metapromenljiva se mora definisati pomoću metaformule, jer se ne može
preuzeti iz izvornog jezika na jedan jedini način kao metakonstanta. Metapromenljiva se zapisuje kao
fraza prirodnog stavljena između ugalstih zagrada ( < , > ). Time se u Bekusovoj notaciji imenuje
pojam iz izvornog jezika (Npr. <program>,<naredba>,<izraz>,<slovo>).
Metaizraz je:
1. metakonstanta ,
2. metapromenljiva ili
3. konačan niz metakonstanti i/ili metapromenljivih koje su međusobno razdvojene
metaoperacijama.
Metaoperacija može biti operacija spajanja (nadovezivanja, katenacije) ili razdvajanja (izbora,
alternacije).
Operacija spajanja (nadovezivanja) piše se u obliku  i čita se “ za kojim sledi ” , gde su  i
 metakonstante ili metapromenljive (ili metaizrazi u opštem slučaju sa zagradama ).
Operacija razdvajanja (izbora,alternacije) piše se u obliku  i čita “ ili ”. Simbol operacije
razdvajanja “” je simbol metajezika. Operacija nadovezivanja ima viši prioritet od operacije
razdvajanja. Tako zapis  predstavlja izbor od dve mogućnosti ili , što znači da se najpre
realizuje spajanje.
Metaformula (definiciona jednačina, gramatičko pravilo, (pravilo) produkcija(e), pravilo
redukcije, pravilo zamene, itd.) jeste uređeni par (,) , koji se zapisuje u obliku
 ::=  ,
i čita “ po definiciji je ” (ili “ to je ”),gde je  metapromenljiva ,  metaizraz a metasimbol ::=
jeste simbol (operacije) definisanja.
Alternativni simboli definisanja mogu biti :  ,  , = , := .
Metapromenljiva  na levoj strani metaformule predstavlja pojam (konstrukciju) u izvornom
jeziku koji se definiše. Metaizraz  definiše postupak generisanja ispravne konstrukcije na osnovu
jednostavnijih pojmova (metaoperanada) primenjujući operacije izbora i nadovezivanja. Rezultujuća
vrednost metaizraza jeste metakonstanta (niska terminalnih simbola) koja se može dodeliti (upotrbiti)
matapromenljivoj  sa leve strane metaformule.
Metaizraz se može upotrebiti za generisanje svih mogućih sintaksno korektnih terminalnih niski
koje predstavlja pojam .
Metaformule se mogu,dakle,upotrebiti kao gramatička pravila za građenje ispravnih konstrukcija
u izvornom jeziku (potreba programera). Druga njihova uloga je da se mogu koristiti za proveru
sintaksne korektnosti prethodno napisanih terminalnih niski (potreba prevodilaca).
Primer 1. Opisati pojam celog broja u programskom jeziku.
1. <ceo broj> ::= <znak broja> <ceo broj bez znaka>  <ceo broj bez znaka>
2. <znak broja> ::= +  
3. <ceo broj bez znaka> ::= <cifra> <ceo broj bez znaka>  <cifra>
4. <cifra> ::= 0  1  2  3  4  5  6  7  8  9 .
Proširena Bekusova Normalna Forma (PBNF)
U literaturi se za opis sintakse različitih jezika koriste i neki drugi načini zapisa (varijante
Bekusove notacije). Ukazaćemo na neka korisna proširenja koja olakšavaju i skraćuju zapis
(metaformula). Ovakve nove mogućnosti imaju istu moć kao i Bekusova normalna forma,ali su
pogodnije za korišćenje. Proširenja uvode ( male , srednje i velike ) zagrade kao i neke druge
mogućnosti.
1. Male zagrade
Ukazali smo da operacija spajanja (nadovezivanja) ima viši prioritet od operacije razdvajanja. Ukoliko

11
Ivan P. Stanimirović Uvod u programiranje

želimo da promenimo ovaj prioritet tada možemo upotrebiti male zagrade kao u aritmetičkom izrazu.
Tako izraz  (    ) znači izbor  ili  , ( za razliku od zapisa    ). Na taj način možemo reći da
je operacija spajanja distributivna u odnosu na operaciju razdvajanja. Obrnuto ne važi jer je ()   =
   zbog uvedenog prioriteta.
Male zagrade možemo upotrebiti kao metasimbole u cilju skraćivanja zapisa (faktorizacije) u
sledećem slučaju.
Metaformulu
 ::= xy  xz  . . .  xt
možemo zapisati u obliku
::= x ( y  z  . . .  t )
što je mnogo preglednije. I ovo je primena distribucije prema razdvajanju.
Zagrade se mogu i dalje umetati,na sličan način kao kod aritmetičkih izraza. Na primer, ako je y
= f y1, z = f z1 , tada možemo zapisati
 ::= x ( f ( y1  z1 )  . . .  t ).
2. Srednje zagrade
Srednje zagrade koristimo kada želimo da ukažemo na opcionu (fakultativnu) nisku (konstrukciju). To
znači da se takva niska može ali ne mora upotrebiti. Tako u opisu celog broja znak broja je opciona
konstrukcija pa možemo pisati:
< ceo broj > ::=  < znak > < ceo broj bez znaka > .
U opštem slučaju možemo pisati :
   =  .
3. Velike zagrade
Pomoću rekurzije (rekurzivnih pravila) u Bekusovoj normalnoj formi možemo definisati (opisati) listu
(spisak,niz) proizvoljno mnogo elemenata. Tako možemo pisati
( 1 ) < ceo broj bez znaka > ::= < cifra > < ceo broj bez znaka >  < cifra >
( 2 ) <spisak imena> ::= < ime >  < ime > , < spisak imena > .
Velike zagrade možemo upotrebiti kao metasimbole da bi ukazali da se niska uokvirena velikim
zagradama može ponoviti proizvoljan broj puta i da se može izostaviti. U tom slučaju gornja pravila
možemo napisati na sledeći način:
( 1’ ) < ceo broj bez znaka > ::= < cifra >  < cifra > 
( 2’ ) < spisak imena > ::= < ime >  , < ime >  .
Za proizvoljnu konstrukciju (nisku)  možemo pisati
 =   . . .
To znači da zapis  predstavlja drugi način zapisa za iteraciju *= A* jednoelementnog skupa
A=, i pišemo
*=  . . .
=  . . . .
Zato umesto  možemo pisati i *. Takođe zapis  za proizvoljnu iteraciju možemo upotrebiti
umesto . . . .
Pomoću gornjuh i donjih indeksa možemo zadati maksimalni i minimalni broj ponavljanja neke
konstrukcije.
Sreću se i sledeći zapisi za konačne liste elemenata koji se ponavljaju pomoću tri tačke:
e1 , e2 , . . . , en

12
Ivan P. Stanimirović Uvod u programiranje

0. 4. 1. SINTAKSNI DIJAGRAMI
Sintaksni dijagrami su jedna vrsta grafičkog metajezika jer koriste grafičke simbole za opis
sintakse jezika. Zato su oni pregledniji i čitljiviji od Bekusove notacije. Ovaj jedinstven metajezik je
ekvivalentan sa Bekusovom normalnom formom. I proširene Bekusove normalne forme se lako
realizuju pomoću sintaksnih dijagrama.
Sintaksni dijagram je imenovani orijentisani graf sa jednim ulazom i jednim izlazom sa
čvorovima grafa koji predstavljaju terminalne ili neterminalne simbole. Svaki prolaz kroz sintaksni
dijagram od ulaza prema izlazu generiše jednu sintaksno pravilnu konstrukciju jezika. Linije (sa
strelicama) koje spajaju čvorove grafa realizuju metaoperacije nadovezivanja i razdvajanja (izbora) na
prirodan način.
Za terminalni simbol t koristimo grafički simbol kružnog ili elipsoidnog oblika. Za neterminalne
simbole predviđen je pravougaoni simbol..
Metaoperacija iz Bekusove notacije i proširenja (upotreba zagrada) se realizuju na jedostavan
način. U nastavku navodimo ekvivalentne realizacije operacija u oba metajezika.
1. Spajanje (nadovezivanje) :
12. . . n  12. . . n

1 2 n

2. Razdvajanje (izbor) :
1  2  . . .  n  1

2

n
3. Iteracija (pozitivna iteracija) :
* =  . . .
   . . .
4. Opciona konstrukcija :
= 
5. Ograničeno ponavljanje :
   =  . . .  . . . 
   = . . .  . . . 

1. Osnovni elementi programskih jezika

1.1. Pseudojezik kao opšti model viših programskih jezika


Za definiciju pseudojezika kao opšteg modela viših programskih jezika neophodno je obuhvatiti
sledeće četiri fundamentalne komponente:

13
Ivan P. Stanimirović Uvod u programiranje

(1) Tipovi i strukture podataka koje pseudojezik podržava:


- statički skalarni tipovi,
- statički strukturirani tipovi,
- dinamički tipovi sa promenljivom veličinom,
- dinamički tipovi sa promenljivom strukturom.
(2) Osnovne kontrolne strukture koje se primenjuju u pseudojeziku:
- sekvenca,
- selekcije,
- ciklusi,
- skokovi.
(3) Operacije ulaza i izlaza podataka:
- ulaz/izlaz podataka za ulazno-izlazne uređaje i datoteke,
- konverzija tekstualnog i binarnog formata podataka.
(4) Tehnike modularizacije programa:
- nezavisne funkcije i procedure,
- interne funkcije i procedure,
- rekurzivne funkcije i procedure.
Razni tipovi podataka neophodni su u programskim jezicima da bi podražavali razne tipove
objekata koje srećemo u matematičkim modelima. Podaci mogu biti skalarni ili strukturirani. Podatak
je strukturiran ukoliko se sastoji od više komponenti koje se nalaze u precizno definisanom odnosu.
Primer strukturiranog objekta je pravougaona matrica realnih brojeva kod koje svaki element
predstavlja komponentu koja se nalazi u određenom odnosu sa ostalim komponentama. Podatak je
skalaran ukoliko se ne sastoji od jednostavnijih komponenti. Jedan od skalarnih tipova podataka na
svim programskim jezicima je celobrojni tip podataka. Lako je uočiti da za svaki tip podataka postoje
operacije koje za njih važe, a ne važe za druge tipove podataka. Tako je na primer inverzija matrice
operacija koja se ne primenjuje na celobrojne skalare, na isti način kao što se operacija celobrojnog
deljenja dva skalara ne može primeniti na matrice.
Osnovne kontrolne strukture su izuzetno važna komponenta svakog programskog jezika. Pomoću
njih se određuje redosled izvršavanja operacija koje računar obavlja. Osnovni tipovi kontrolnih
struktura su sekvenca kod koje se instrukcije obavljaju onim redosledom kojim su napisane u
programu, i strukture sa grananjima, ciklusima i skokovima. Grananja se koriste za izbor jednog od
više paralelnih programskih segmenata, ciklusi realizuju ponavljanje nekog niza instrukcija, a skokovi
služe za kontrolisani izlaz iz petlji, iz programa (kraj rada) i za realizaciju pojedinih osnovnih
kontrolnih struktura.
Da bi se omogućilo komuniciranje računara sa spoljnim okruženjem potrebne su instrukcije ulaza i
izlaza podataka. Pri tome podaci mogu da se učitavaju sa tastature ili iz datoteka i da se prenose na
ekran, štampač, ili u datoteke.
Pod datotekom (file) podrazumevamo osnovnu organizaciju podataka koja obuhvata proizvoljan
broj manjih jednoobrazno strukturiranih celina koje se nazivaju zapisi. Svaki zapis sadrži podatke o
jednoj jedinici posmatranja. Na primer, zapis može sadržati strukturirane podatke o motornom vozilu
(tip, godina proizvodnje, snaga motora, vlasnik, itd.), dok skup većeg broja ovakvih zapisa predstavlja
datoteku motornih vozila. Alfanumerički podaci (slova, cifre i specijalni znaci) se čuvaju u tekst
datotekama, a numerički podaci mogu da se čuvaju bilo u tekstualnoj bilo u kompaktnoj binarnoj
formi. Za sve podatke postoji format kojim se određuje njihova struktura, a pri nekim prenosima
podataka može se automatski vršiti i konverzija formata.
Ako bi programi bili formirani kao neprekidni nizovi instrukcija, onda bi kod velikih programa bilo
nemoguće razumevanje načina rada celine, i na taj naćin bilo bl znatno otežano održavanje programa.
Zbog toga su mehanizmi modularizacije programa od vitalnog značaja za uspeh nekog programskog
jezika. Pod modularizacijom programa podrazumevamo razbijanje programa na manje (najčešće
nezavisne) celine kod kojih su precizno definisani ulazni i izlazni podaci, kao i postupak kojim se na

14
Ivan P. Stanimirović Uvod u programiranje

osnovu ulaznih podataka dobijaju izlazni podaci. U ovu grupu spadaju nerekurzivne i rekurzivne
funkcije i procedure.

Prilikom definicije jezika polazi se od osnovnog skupa znakova, azbuke jezika koja sadrži sve
završne simbole (terminalne simbole) jezika. Nad azbukom jezika definišu se ostali elementi jezika,
konstante, rezervisane reči, identifikatori od kojih se dalje grade druge složene sintaksne kategorije
kao što su na primer opisi, upravljačke naredbe i slično.

1.2. Azbuka jezika


Azbuka jezika predstavlja osnovni skup simbola (znakova) od kojih se grade sve sintaksne
kategorije jezika. Broj znakova azbuke se obično razlikuje od jezika do jezika i kreće se od najmanje
48 do 90 znakova. Azbuka programskog jezika obično obuhvata skup velikih i malih slova engleske
abecede, skup dekadnih cifara i određeni skup specijalnih znakova. Dok je kod starijih programskih
jezika bilo uobičajeno da se koriste samo velika slova (na primer FORTRAN IV), danas se skoro
redovno dozvoljava i ravnopravno korišćenje malih slova abecede. Azbuke programskih jezika se
najviše razlikuju po skupu specijalnih znakova koje obuhvataju. Narednih nekoliko primera azbuka
programskih jezika to ilustruje.
Azbuka jezika C
velika slova: A | B| C | D| E| F|G|H|I|J|K|L|M|N|0| P|Q| R|S|T|U|V|W|X|Y|Z
cifre: 0 |1 |2|3|4|5|6|7|8|9
specijalni znaci: + | - | * | / |= | ( | ) | { \ } \ [ | ] \ < | > | ' | " | ! | # | \ | % | & | | | | _ | ^ | ¸ | ~ \ , \ ; | : | ?
znak blanko
mala slova: a | b | c | d | e| f|g|h| i| j| k|l|m|n|o|p|q|r|s| t|u| v|w|x|y|z

Danas se obično skup specijalnih znakova azbuke programskog jezika standardizuje i svodi na skup
znakova međunarodnog standardnog koda ISO7 (ASCII kod).
b | ! | " | $ | % | & | ' | ( | ) | * | + | , | - | . | / | : | ; | < | = | > | ? | @ | [ | ] | \ | ^ ili _ | ` | { | } | ~
Češto se pored osnovnog skupa specijalnih znakova koriste i složeni simboli, obično dvoznaci,
kao na primer:
| ** | >= | <= | => | =< | << | <> | >< | := | -> | /* | */ |
U nekim programskim jezicima (FORTRAN), zbog nedovoljnog broja odgovarajućih znakova
umesto specijalnih znakova koriste se posebne simboličke oznake .EQ., .NE., .GT., .GE., .LT., .LE.,
kojima se označavaju relacije jednako, različiti, veće, veće ili jednako, manje i manje ili jednako,
redom.

1.3. Identifikatori i rezervisane reči


Identifikatori su uvedene reči kojima se imenuju konstante, promenljive, potprogrami, programski
moduli, klase, tipovi podataka i slično.
U svim programskim jezicima postoji slična konvencija za pisanje identifikatora. Identifikatori su
nizovi koji se obično sastoje od slova i cifara i obavezno započinju slovom. Ovo ograničenje
omogućava jednostavniju implementaciju leksičkog analizatora i razdvajanje identifikatora od drugih
sintaksnih kategorija (numeričkih i znakovnih konstanti na primer). U nekim jezicima dozvoljeno je da
se i neki specijalni znaci pojave u okviru identifikatora. Najčešće je to crtica za povezivanje "_" kojom
se postiže povezivanje više reči u jedan identifikator. Na primer, u jeziku C crtica za povezivanje se
može koristiti na isti način kao i slova, što znači da identifikator može da započne ovim znakom. Slede
primeri nekih identifikatora:
ALFA A B1223 Max_vrednost PrimerPrograma
U jeziku C velika i mala slova se razlikuju. Programski jezik PASCAL ne razlikuje velika i mala
slova.

15
Ivan P. Stanimirović Uvod u programiranje

Dobra je programerska praksa da identfikatori predstavljaju mnemoničke skraćenice.


Nizovi znakova azbuke koji u programu imaju određeni smisao nazivaju se lekseme. Leksema
može da bude i samo jedan znak.
Reč jezika čije je značenje utvrđeno pravilima tog jezika naziva se rezervisana reč.
Rezervisane reči mogu da budu zabranjene, kada se ne mogu koristiti kao identifikatori u
programu. Takav je slučaj u programskom jeziku C. Međutim, i u jezicima u kojima je to dozvoljeno
ne preporučuje se korišćenje ključnih reči kao identifikatora jer može da smanji preglednost programa,
a u nekim slučajevima da dovede i do ozbiljnih grešaka u programu. Poznat je, na primer, slučaj
greške sa DO naredbom koji je doveo do pada letilice iz satelitskog programa Geminy 19. U programu
za upravljanje letilicom stajala je DO naredba napisana kao:
DO 10 I = 1.10
umesto ispravnog koda
DO 10 I = 1,10.
Greška pri prevođenju međutim nije otkrivena jer je leksički analizator ovu liniju kôda protumačio kao
naredbu dodeljivanja
DO10I = 1.10
u kojoj se promenljivoj D010I dodeljuje vrednost 1.10. Greška je otkrivena tek u fazi izvršavanja
programa kada je prouzrokovala pad letilice.
Rezervisane reči jezika C:
auto, break, case, char, const, continue, default, do, double, else, enum, extern, float, for, goto, if, int, long,
register, return, short, signed, sizeof, static, struct, switch, typedef, union, unsigned, void, voatile, while.
U poređenju sa ostalim programskim jezicima, C poseduje mali broj službenih reči.

1.4. Konstante
Bilo koji niz znakova u programu, posmatran nezavisno od njegovog logičkog značenja, nad
kojim se mogu izvršavati određena dejstva (operacije) naziva se podatak. Deo podatka nad kojim se
mogu izvršavati elementarne operacije naziva se element podatka. Elementu podatka u matematici
približno odgovara pojam skalarne veličine. Podatak je uređeni niz znakova kojim se izražava
vrednost određene veličine.
Veličina koja u toku izvršavanja programa uvek ima samo jednu vrednost, koja se ne može
menjati, naziva se konstanta. Kao oznaka konstante koristi se ona sama.
U nekim programskim jezicima (Pascal, Ada, C) postoji mogućnost imenovanja konstante.
Konstantama se dodeljuju imena koja se u programu koriste umesto njih. Na taj način nastaju
simboličke konstante.
Tipovi konstanti koje se mogu koristiti u određenom programskom jeziku određeni su tipovima
podataka koje taj jezik predviđa.
U jeziku C se koristi više vrsta konstanti i to su:
- celobrojne konstante; 2, 3, +5, -123
- karakteri: 'a', 'b', ... ;
- stringovi: sekvence karaktera između navodnika.
Slede neki primeri različitih vrsta konstanti:
Celobrojne dekadne konstante: 1; 50; 153; +55; -55
Realne konstante u fiksnom zarezu: 3.14; 3.0; -0.314; -.314; +.314
Realne konstante u pokretnom zarezu:
3.14E0; -0.314E1; -.314E+0; +.314E-2 (FORTRAN, Pascal, Ada, C)
Realne konstante dvostruke tačnosti:

16
Ivan P. Stanimirović Uvod u programiranje

Oktalne konstante (C): 0567; 0753; 0104


Heksadecimalne konstante (C): 0X1F; 0XAA; 0X11
Long konstante (C): 123L; 527L;321L;+147L
Logičke konstante: true; false (Pascal, Ada)
.TRUE.; .FALSE. (FORTRAN)
Znakovne konstante: 'A'; 'B' (Pascal, Ada, C)
String konstante: "Beograd"; "Alfa 1" (C)
String konstante: ‘Beograd’; ‘Alfa 1’ (Pascal)
Simboličke konstante: ZERO; ZEROS; SPACE (COBOL)
Pi, E (MATHEMATICA)
Racionalni brojevi: 2/3; -4/5 (MATHEMATICA)

1.5. Promenljive
Veličine čije se vrednosti menjaju u toku izvršavanja programa nazivaju se promenljive.
Promenljivoj se u programu dodeljuje ime, i u svakom trenutku ona je definisana svojom vrednošću.
Kažemo da je svaka promenljiva u programu povezana sa tri pojma:
imenom - identifikatorom promenljive.
referencom - pokazivačem koji određuje mesto promenljive u memoriji i
vrednošću - podatkom nad kojim se izvršavaju operacije.
Veza između imena, reference i vrednosti promenljive može se predstaviti sledećim dijagramom:

ime referenca vrednost


Ovaj dijagram u slučaju imenovane konstante dobija oblik:

ime vrednost
Na primer naredbu dodeljivanja X:=3.141592 čitamo: X dobija vrednost 3.141592, pri čemu
imamo u vidu da je X simboličko ime memorijske lokacije gde se u toku izvršavanja programa pamti
vrednost 3.141592. Pri tome je potrebno imati na umu sledeće pojmove:
• vrednost 3.141592, koja predstavlja vrednost promenljive X,
• adresu memorijske lokacije u kojoj se pamti vrednost 3.141592,
• ime promenljive X, identifikator koji se u datom programu koristi kao ime promenljive koja
ima datu brojnu vrednost.

1.6. Komentari
U svim programskim jezicima postoji mogućnost proširenja izvršnog koda programa komentarima
kojima se kod dodatno pojašnjava. Ovi komentari se u toku prevođenja programa ignoršu od strane
kompilatora i ne ulaze u sastav izvršnog koda koji se generiše prevođenjem programa. Međutim
komentari su veoma važan deo programa kojim se podešava njegova dokumentarnost, i bitno utiču na
efikasnost analize programa. Konvencija za zapisivanje komentara se razlikuje od jezika od jezika.
Slede primeri komentara u nekim programskim jezicima:
/* Ovo je primer komentara u jeziku C */
// Kratak C++ komentar u okviru jednog reda

17
Ivan P. Stanimirović Uvod u programiranje

1.7. Struktura programa


Globalna struktura programa zavisi od toga da li jezik zahteva deklaraciju tipova promenljivih kao i
da li su u jeziku zastupljeni stariji koncepti sa implicitnim definicijama tipova promenljivih ili je
zastupljen noviji koncept sa eksplicitnim definicijama.

1.7.1. Struktura programa u C


Programi pisani u C jeziku imaju strukturu bloka, ali se za ograničavanje bloka koriste vitičaste
zagrade umesto zagrada begin i end. Zastupljen je takođe stariji koncept bloka, poznat iz jezika Algol
60 i PL/1, gde se opisi elemenata koji pripadaju jednom bloku nalaze unutar zagrada { i }, za razliku
od novijeg koncepta koji se koristi u jeziku Pascal, kod kojih opisi elemenata bloka prethode zagradi
begin kojom se otvara blok. Svaki blok u C-u takođe može da sadrži opise promenljivih i funkcija.
C program se može nalaziti u jednom ili više fajlova. Samo jedan od tih fajlova (glavni programski
modul) sadrži funkciju main kojom započinje izvršenje programa. U programu se mogu koristiti
funkcije iz standardne biblioteke. U tom slučaju se može navesti direktiva pretprocesora oblika
#include <ime>.
česta je direktiva oblika #include<stdio.h> kojom se uključuju funkcije iz fajla stdio.h (standard
input/output header).
Glavni program, main(), takođe predstavlja jednu od funkcija. Opis svake funkcije se sastoji iz
zaglavlja i tela funkcije. U ovom slučaju, zaglavlje funkcije je najjednostavnije, i sadrži samo ime
funkcije i zagrade (). Iza zaglavlja se navodi telo funkcije koje se nalazi između zagrada { i }. Između
ovih zagrada se nalaze operatori koji obrazuju telo funkcije. Svaki prost operator se završava znakom
';' a složeni operator se piše između zagrada { i }.
U jeziku C sve promenljive moraju da se deklarišu. Opšti oblik jednostavnog programa je:
void main()
{
<deklaracije>
<naredbe>
}

2. TIPOVI PODATAKA

Jedan od najznačajnijih pojmova u okviru programskih jezika je pojam tipa podataka. Atribut tipa
određuje skup vrednosti koje se mogu dodeljivati promenljivima, format predstavljanja ovih vrednosti
u memoriji računara, skup osnovnih operacija koje se nad njima mogu izvršavati i veze sa drugim
tipovima podataka. Na primer, promenljivoj koja pripada celobrojnom tipu mogu se kao vrednosti
dodeljivati samo celi brojevi iz određenog skupa. Nad tako definisanim podacima mogu se izvršavati
osnovne aritmetičke operacije sabiranja, oduzimanja, mnozenja, deljenja, stepenovanja, kao i neke
specifične operacije kao što je određivanje vrednosti jednog broja po modulu drugog.
Koncept tipova podataka prisutan je, na neki način, već kod simboličkih asemblerskih jezika gde se
za definiciju tipa koriste implicitne definicije preko skupa specijalnih znakova kojima se određuju
podaci različitog tipa.
Neka je zadat skup T sačinjen od n proizvoljnih apstraktnih objekata: T:={v1,...,vn}, n>1. Ukoliko
su svi objekti istorodni, u smislu da se u okviru nekog programskog jezika na njih može primenjivati
jedan određeni skup operatora, onda se T naziva tip podataka, Ako za promenljive x i y uvek važi xT
i yT onda su one tipa T. To u okviru programa formalno definišemo iskazom

18
Ivan P. Stanimirović Uvod u programiranje

DEFINE x, y : T.
Vrednost je bilo koji entitet kojim se može manipulisati u programu. Vrednosti se mogu
evaluirati, zapamtiti u memoriji, uzimati kao argumenti, vraćati kao rezultati funkcija, i tako dalje.
Različiti programski jezici podržavaju različite tipove vrednosti.
Jedna od klasifikacija osnovnih tipova podataka prikazana je na slici.

Tipovi podataka su podeljeni u dve osnovne grupe: statički tipovi i dinamički tipovi. Pod
statičkim tipovima (ili tipovima sa statičkom strukturom podrazumevamo tipove podataka kod kojih je
unapred i fiksno definisana unutrašnja struktura svakog podataka, a veličina (t.j. memorijska
zapremina) fiksno se definiše pre (ili u vreme) izvršavanja programa koji koristi podatke statičkog
tipa.
Statički tipovi podataka obuhvataju skalarne i strukturirane podatke. Pod skalarnim tipovima
podrazumevamo najprostije tipove podataka čije su vrednosti skalari, odnosno takve veličine koje se
tretiraju kao elementarne celine i za koje nema potrebe da se dalje razlažu na komponente. U tom
smislu realne i kompleksne brojeve tretiramo kao skalare u svim programskim jezicima koji ih
tretiraju kao elementarne celine (neki jezici nemaju tu mogućnost pa se tada kompleksni brojevi
tretiraju kao struktura koja se razlaže na realni i imaginarni deo; na sličan način mogao bi se realni
broj razložiti na normalizovanu mantisu i eksponent). Pod strukturiranim tipovima podataka
podrazumevamo sve složene tipove podataka koji se realizuju povezivanjem nekih elementarnih
podataka u precizno definisanu strukturu. U ulozi elementarnih podataka obično se pojavljuju skalari
ili neke jednostavnije strukture. Kompozitna vrednost ili struktura podataka (data structure) jeste
vrednost koja je komponovana iz jednostavnijih vrednosti. Kompozitni tip jeste tip čije su vrednosti
kompozitne. Programski jezici podržavaju mnoštvo kompozitnih vrednosti: strukture, slogove, nizove,
algebarske tipove, objekte, unije, stringove, liste, stabla, sekvuencijalni fajlovi, direktni fajlovi,
relacije, itd.
Skalarni tipovi podataka mogu biti linearno uređeni ili linearno neuređeni. Linearno uređeni
tipovi podataka su tipovi kod kojih se vrednosti osnovnog skupa T preslikavaju na jedan interval iz
niza celih brojeva, t.j. za svaki podatak xT zna se redni broj podatka. Stoga svaki podatak izuzev
početnog ima svog prethodnika u nizu, i slično tome, svaki podatak izuzev krajnjeg ima svog
sledbenika u nizu.

19
Ivan P. Stanimirović Uvod u programiranje

Pod dinamičkim tipovima podataka podrazumevamo tipove podataka kod kojih se veličina i/ili
struktura podataka slobodno menja u toku obrade. Kod dinamičkih tipova sa promenljivom veličinom
podrazumevamo da je struktura podataka fiksna, ali se njihova veličina dinamićki menja tokom obrade
tako da se saglasno tome dinamički menjaju i memorijski zahtevi. Na primer, dopisivanjem novih
zapisa u sekvencijalnu datoteku veličina datoteke raste uz neizmenjenu strukturu. Kod dinamičkih
tipova sa promenljivom strukturom unapred je fiksno definisan jedino princip po kome se formira
struktura podataka dok se sama konkretna struktura i količina podataka u memoriji slobodno
dinamički menjaju.
Statička i dinamička tipizacija
Pre izvršenja bilo koje operacije, moraju se proveriti tipovi operanada da bi se sprečila greška u tipu
podataka. Na primer, pre izvršenja operacije množenja dva cela broja, oba operanda moraju biti
proverena da bi se osiguralo da oni budu celi brojevi. Slično, pre izvršenja neke and ili or operacije,
oba operanda moraju biti proverena da bi se osiguralo da oni budu tipa boolean. Pre izvršenja neke
operacije indeksiranja niza, tip operanda mora da bude array (a ne neka prosta vrednost ili slog).
Ovakva provera se naziva proverom tipa (type checks). Provera tipa mora da bude izvršena pre
izvršenja operacije.
Međutim, postoji izvestan stepen slobode u vremenu provere: provera tipa se može izvršiti ili u
vremenu kompilacije (compile-time) ili u vremenu izvršenja programa (at run-time). Ova mogućnost
leži u osnovi važne klasifikacije programskih jezika na statički tipizirane (statically typed) i
dinamički tipizirane (dynamically typed). U nekom statički tipiziranom jeziku, svaka varijabla i
svaki izraz imaju fiksni tip (koji je ili eksplicitno postavljen od strane programera ili izveden od strane
kompajlera). Svi operandi moraju biti proverenog tipa (type-checked) u vremenu kompilovanja
programa (at compile-time). U dinamički tipiziranim jezicima, vrednosti imaju fiksne tipove, ali
varijable i izrazi nemaju fiksne tipove. Svaki put kada se neki operand izračunava, on može da
proizvede vrednost različitog tipa. Prema tome, operandi moraju imati proveren tip posle njihovog
izračunavanja, ali pre izvršenja neke operacije, u vremenu izvršenja programa (at run-time). Mnogi
jezici visokog nivoa su statički tipizirani. SMALLTALK, LISP, PROLOG, PERL, i PYTHON jesu
primeri dinamički tipiziranih jezika.
S druge strane, moderni funkcionalni jezici (kao ML, HASKELL, MATHEMATICA)
omogućavaju da sve vrednosti, uključujući i funkcije, imaju sličnu obradu.
Izbor između statičke i dinamičke tipizacije je pragmatičan:
• Statička tipizacija je efikasnija. Dinamička tipizacija zahteva (verovatno ponovljenu) proveru tipova
u vremenu izvršenja programa (run-time type checks), što usporava izvršenje programa. Statička
tipizacija zahteva jedino proveru tipa u vremenu kompilacije programa (compile-time type checks),
čija je cena minimalna (i izvršava se jedanput). Osim toga, dinamička tipizacija primorava sve
vrednosti da budu etiketirane (tagged) (da bi se omogućila provera u vreme izvršenja), a ovakvo
označavanje povećava upotrebu memorijskog prostora. Statička tipizacija ne zahteva ovakvo
označavanje.
• Statička tipizacija je sigurnija: kompajler može da proveri kada program sadrži greške u tipovima.
Dinamička tipizacija ne omogućava ovakvu sigurnost.
• Dinamička tipizacija obezbeđuje veliku fleksibilnost, što je neophodno za neke aplikacije u kojima
tipovi podataka nisu unapred poznati.
U praksi veća sigurnost i efikasnost statičke tipizacije imaju prevagu nad većom fleksibilnošću
dinamičke tipizacije u velikoj većini aplikacija. Većina programskih jezika je statički tipizirana.
Na osnovu toga kako je postavljen koncept tipova podataka, programski jezici mogu da se svrstaju
u dve grupe: na programske jezike sa slabim tipovima podataka i na jezike sa jakim tipovima
podataka.

20
Ivan P. Stanimirović Uvod u programiranje

2.1. Koncept jakih tipova podataka


Koncept jakih tipova podataka obuhvata nekoliko osnovnih principa:
• Tip podataka određuju sledeći elementi:
- skup vrednosti,
- format registrovanja podataka,
- skup operacija koje se nad podacima mogu izvršavati,
- skup funkcija za uspostavljanje veza sa drugim tipovima podataka.
• Sve definicije tipa moraju da budu javne, eksplicitne. Nisu dozvoljene implicitne definicije
tipova.
• Objektu se dodeljuje samo jedan tip.
• Dozvoljeno je dodeljivanje vrednosti samo odgovarajućeg tipa.
• Dozvoljene su samo operacije obuhvaćene tipom.
• Tip je zatvoren u odnosu na skup operacija koji obuhvata. Ove operacije se mogu primenjivati
samo nad operandima istog tipa. Mešoviti izrazi nisu dozvoljeni.
• Dodeljivanje vrednosti raznorodnih tipova moguće je samo uz javnu upotrebu funkcija za
transformaciju tipa.
Koncept jakih tipova povećava pouzdanost, dokumentarnost i jasnoću programa. Kako se zahteva
eksplicitna upotreba operacija za transformaciju tipa, onda je nedvosmisleno jasno da je određena
transformacija na nekom mestu namerna i potrebna. Ovaj koncept omogućava da se informacija o tipu
može koristiti u fazi kompilovanja programa i na taj način postaje faktor pouzdanosti programa.

2.2. Koncept slabih tipova


U slučaju jezika sa slabim tipovima podataka informacija o tipu promenljive koristi se, i korektna je
samo na mašinskom nivou, u fazi izvršenja programa. Ovako postavljen koncept podrazumeva sledeće
mogućnosti:
(1) Operacija koja se od strane kompilatora prihvati kao korektna, na nivou izvornog koda
programa, može da bude potpuno nekorektna. Razmotrimo sledeći primer:
char c;
c = 4;
Promenljiva c definisana je da pripada tipu char, što podrazumeva da joj se kao vrednosti dodeljuju
znaci kao podaci. Međutim umesto korektnog dodeljivanja c = '4', promenljivoj c je dodeljena
vrednost broja 4 kao konstante celobrojnog tipa. Kod jezika sa slabim tipovima podataka kompilator
ne otkriva ovu grešku i informaciju o tipu koristi samo na mašinskom nivou kada promenljivoj c
dodeljuje vrednost jednog bajta memorijske lokacije u kojoj je zapisana konstanta 4. Očigledno je da
ovako postavljen koncept tipova može da dovede do veoma ozbiljnih grešaka u izvršavanju programa
koje se ne otkrivaju u fazi kompilovanja programa.
(2) Koncept slabih tipova podrazumeva određeni automatizam u transformaciji tipova podataka u
slučaju kada se elementi različitih tipova nalaze u jednom izrazu čija se vrednost dodeljuje
promenljivoj određenog tipa. Razmotrimo sledeći primer:
float x, y;
int i, j, k;
i = x;
k = x-j ;
Promenljive x i y su realne (tipa float), a i, j i k celobrojne (tipa int). Naredbom i=x; vrši se
dodeljivanje vrednosti tipa float promenljivoj celobrojnog tipa. Kod jezika sa slabim tipovima ovo
dodeljivanje je dozvoljeno iako se pri tome x svodi na drugi format i pravi greška u predstavljanju
njegove vrednosti. Kod ovako postavljenog koncepta tipova, da bi se napisao korektan program

21
Ivan P. Stanimirović Uvod u programiranje

potrebno je tačno poznavati mehanizme transformacije tipova. U drugoj naredbi iz primera (k = x-j;)
od broja x koji je tipa float treba oduzeti broj j, tipa int i rezultat operacije dodeliti promenljivoj tipa
int. Da bi smo bili sigurni u korektnost rezultata potrebno je da znamo redosled transformacija koje se
pri tome izvršavaju, odnosno da li se prvo x prevodi u int i onda izvršava oduzimanje u skupu celih
brojeva i vrednost rezultata dodeljuje promenljivoj tipa int ili se j prevodi u tip float, izvršava
oduzimanje u skupu realnih brojeva, a zatim rezultat prevođi u tip int i dodeljuje promenljivoj k.
Koncept slabih tipova podataka dopušta puno slobode kod zapisivanja izraza u naredbama
dodeljivanja; međutim cena te slobode je nejasan program sa skrivenim transformacijama, bez
mogućnosti kontrole i korišćenja informacije o tipu u fazi kompilovanja programa.

2.3. Ekvivalentnost tipova


Šta ekvivalentnost tipova označava zavisi od programskog jezika. (Sledeća diskusija podrazumeva
da je jezik statički tipiziran.) Jedna moguća definicija ekvivalentnosti tipova jeste strukturna
ekvivalentnost (structural equivalence): T1 ≡ T2 ako i samo ako T1 i T2 imaju isti skup vrednosti.
Strukturna ekvivalentnost se tako naziva zato što se ona može proveriti poređenjem struktura tipova
T1 i T2. (Nepotrebno je, a u opštem slučaju i nemoguće, da se prebroje sve vrednosti ovih tipova.)
Kada kompilator jezika sa jakim tipovima podataka treba da obradi naredbu dodeljivanja oblika
x := izraz
on vrši dodeljivanje samo u slučaju ekvivalentnosti tipa promenljive sa leve strane dodeljivanja i
rezultata izraza na desnoj strani naredbe, osim u slučaju kada je na desnoj strani celobrojni izraz a na
levoj strani promenljiva nekog realnog tipa.
Eksplicitnom ekvivalentnošću tipova postiže se veća pouzdanost jezika. U ovom slučaju nisu
potrebne posebne procedure po kojima bi se ispitivala strukturna ekvivalentnost. Međutim, kada je
potrebno vrednost promenljive ili izraza dodeliti promenljivoj koja mu ne odgovara po tipu ovaj
koncept zahteva korišćenje funkcija za transformisanje tipova.

2.4. Elementarni tipovi podataka


U okviru svakog programskog jezika, sistem tipova podataka zasniva se na skupu osnovnih tipova
podataka nad kojima se dalje definišu izvedeni tipovi, podtipovi, strukturni tipovi i specifični
apstraktni tipovi podataka. Skup osnovnih tipova podataka se obično svodi na tipove podataka za rad
sa elementarnim numeričkim podacima (celi i realni brojevi), znakovnim podacima (pojedinačni znaci
ASCII koda) i logičkim vrednostima (true i false).

2.4.1. Celobrojni tipovi (Integer ili int)

Celobrojni tip podataka (tip INTEGER)


Podaci celobrojnog tipa pripadaju jednom lntervalu celih brojeva koji obuhvata pozitivne i
negativne brojeve i koji se obično označava na sledeći način:
T := {minint, minint+1, ... , -1, 0, 1, ,.. , maxint-1, maxint } .
Ovde je najmanji broj označen sa minint, a najveći sa maxint (od engl. maximum integer i
minimum integer) pri čemu ove veličine nisu fiksne već zavise od implementacije i prema tome
variraju od računara do računara.
Od nekoliko načina binarnog kodiranja celih brojeva izdvojićemo metod potpunog komplementa
koji se najčešće sreće u praksi. Kod ovog postupka brojevi se binarno predstavljaju pomoću sledeće n-
bitne reči:
n-1 3 2 1 0
S

22
Ivan P. Stanimirović Uvod u programiranje

Bit najstarijeg razreda označen sa S (sign) predstavlja predznak broja. Ako je S=0 onda je je broj
nenegativan, a ako je S=1 onda je broj negativan. Nula se označava sa nulama u svim bitovima:
0000 0000 0000 0000
Obično postoji osnovni (standardni) tip INTEGER ili int, koji se zavisno od realizacije odnosi na
određeni opseg celih brojeva. Nekad je to opseg koji odgovara formatu jedne polureči ili formatu
jedne reči. U odnosu na ovaj osnovni celobrojni tip češto postoji mogućnost definisanja i drugih
celobrojnih tipova koji se odnose na neki kraći ili prošireni format.

2.4.2. Realni tip (float ili real)


Promenljive ovih tipova uzimaju za svoje vrednosti podskupove skupa realnih brojeva. U
programskim jezicima postoji više vrsta podataka realnog tipa, koji se razlikuju po tačnosti
predstavljanja podataka.
Realni tip podataka obuhvata jedan konačan podskup racionalnih brojeva ograničene veličine i
tačnosti. Naravno, može se odmah postaviti pitanje zbog čega se koriste nazivi "realni tip" i "realni
broj" za nešto što u opštem slučaju nije u stanju da obuhvati ni iracionalne brojeve ni beskonačne
periodične racionalne brojeve. Ipak, to je terminologija koja je prihvaćena u praksi i opravdava se time
što je (float ili REAL) tip podataka koji se najbliže približava pojmu realnog broja. Sa druge strane,
lako je razumeti da su sve memorijske lokacije konačne dužine, pa stoga i brojni podaci koji se u njih
smeštaju moraju biti konačne dužine i tako po prirodi stvari otpadaju iracionalni brojevi. Potrebe
prakse nisu na ovaj način ni malo ugrožene jer se dovoljna tačnost rezultata može postići i sa
veličinama konačne dužine. Tip float najčešće obuhvata brojne vrednosti iz sledećih podintervala
brojne ose:

-maxreal -minreal 0 minreal maxreal


Ovde minreal označava najmanju apsolutnu vrednost veću od nule, koja se može predstaviti na
raćunaru, a maxreal predstavlja najveću apsolutnu vrednost koja se može predstaviti na raćunaru.
Realni brojevi iz intervala (-minreal, minreal) se zaokružuju i prikazuju kao 0, realni brojevi iz
intervala (-, -maxreal) i (maxreal, +) ne mogu se predstaviti u memoriji računara, a - i + se
kodiraju specijalnim kodovima.

2.4.3. Logički tip podataka


Logički tipovi podataka postoje kao osnovni tipovi podataka u svim novijim jezicima. Obično nose
naziv LOGICAL (FORTRAN) ili BOOLEAN (Pascal, Ada). Obuhvataju samo dve vrednosti true i
false, nad kojima su definisane osnovne logičke operaclje not, and, or i xor.
Takođe, važi i uređenost skupa vrednosti ovog tipa tako da je false < true.
Izrazi u kojima se primenjuju logičke promenljive i konstante nazivaju se logički izrazi. Ako se
logičke konstante označavaju sa false i true onda podrazumevamo da svi izrazi moraju biti sačinjeni
striktno od logičkih veličina. Ha primer, izraz z := (x>0) and ( (y=1) or (y<0) ) je korektan pri čemu se
podrazumeva da su x i y celobrojne ili realne veličine, a z je velićina logičkog tipa. Podrazumeva se i
da su neispravni mešoviti izrazi u kojima se koriste veličine true i false pomešane sa numeričkim
konstantama i aritmetičkim operacijama. Na primer, nije definisan izraz 4*fa1se + 2*true + true, ali
izraz 4*(x>0) + 2*(y>0) + (z>0) , koji je takođe besmislen kod logičkih konstanti false i true, u slučaju
numeričkog kodiranja T={0,1} redovno ima i smisla i upotrebnu vrednost kao generator veličina
0,1,2,3,4,5,6,7.

2.4.4. Znakovni tipovi


Korisnik računara komunicira sa računarom preko ulaznih i izlaznih uređaja i tu je bitno da se
pojavljuju podaci u formi koja je čitljiva za čoveka. To znači da se komuniciranje obavlja pomoću

23
Ivan P. Stanimirović Uvod u programiranje

znakova iz određene azbuke koja redovno obuhvata abecedno poređana velika i mala slova, cifre,
specijalne znake i kontrolne znake. Pod specijalnim znacima se podrazumevaju svi oni znaci koji se
javljaju na tastaturama i mogu odštampati, ali nisu ni slova ni cifre (na tastaturi sa kojom je pisan ovaj
tekst specijalni znaci su ! # S % & *()_-+=:"; '<>?,/.). Pod kontrolnim znacima podrazumevaju se
znaci koji se ne mogu odštampati (ili prikazati na ekranu terminala), već služe za upravljanje radom
ulazno/izlaznog uređaja (na primer štampača). U ovu grupu spadaju specijalni znaci za pomeranje
papira, znak koji izaziva zvučni signal na terminalu i drugi).
Da bi se znaci razlikovali od simboličkih naziva promenljivih obično se umeću između apostrofa
(na nekim programskim jezicima umesto apostrofa se koriste znaci navoda). Tako se, na primer,
podrazumeva da A predstavlja simbolički naziv promenljive, dok 'A' predstavlja binarno kodirano prvo
slovo abecede.
U praksi se primenjuje nekoliko metoda za binarno kodiranje znakova. Najpoznatiji metod je
američki standard ASCII (American Standard Code for Information Interchange). Ovim smenama su
neki manje važni znaci iz skupa ASCII znakova zamenjeni sa specifičnim jugoslovenskim znacima
(na pr., umesto ASCII znakova \ | { } [ ] ~ @ i ^ u srpskoj varijanti se pojavljuju znaci Đ đ š ć š Ć č ž
Ž i Č). Neki terminali imaju mogućnost podesivog izbora skupa znakova tako da korisnik može po
potrebi izabratl američku ili jugoslovensku varijantu skupa ASCII znakova.
Prva 32 znaka u ASCII skupu su kontrolni znaci. Nekl od njlh imaju jedinstvenu interpretaciju kod
svih uređaja, a kod nekih interpretacija se razlikuje od uređaja do uređaja. Ovde pominjemo sledeće:
BEL (Bell) = zvučni signal
LF (Line Feed) = prelazak u naredni red
FF (Form Feed) = prelazak na narednu stranu
CR (Carriage /Return) = povratak na početak reda
ESC (Escape) = prelazak u komandni režim
Skup ASCII znakova je baziran na sedmobitnim znacima, pa prema tome obuhvata ukupno 128
znakova. Kako se radi o linearno uređenom skupu svaki znak ima svoj redni broj i ti brojevi su u
opsegu od 0 do 127. Funkcija koja za svaki znak daje njegov redni broj (ordinal number) označava se
sa ord. Argument ove funkcije je tipa CHARACTER, a vrednost funkcije je tipa CARDINAL. Za
slučaj ASCII skupa imamo da važi sledeće:
ord('0') = 48, ord('A') = 65. ord('a')=97.
Inverzna funkcija funkciji ord, koja od rednog broja znaka formira znak, (character) je funkcija chr:
chr(48) = '0', chr(65) = 'A', chr(97) = 'a' .
Ako je c promenljiva tipa CHARACTER, a n promenljiva tipa CARDINAL onda važi
chr(ord(c) ) = c , ord(chr(n) ) = n .

2.5. Tipovi podataka u jeziku C


Programski jezik C se svrstava u jezike sa slabim tipovima podataka iako su eksplicitne definicije
tipa obavezne. Mogu se koristiti samo unapred definisani tipovi podataka uz mogućnost da im se daju
pogodna korisnička imena i na taj način poveća dokumentarnost programa.
Mehanizam tipa je opšti i odnosi se i na funkcije i na promenljive. Tipovi podataka u jeziku C
mogu se globalno podeliti na osnovne i složene (struktuirane). Osnovni tipovi podataka su celobrojni
(int), realni (float), znakovni (char), nabrojivi (enumerated) i prazan (void). Ovi tipovi podataka se
koriste u građenju složenih tipova (nizova, struktura, unija, itd.).
U sledećoj tabeli su prikazani osnovni tipovi podataka ovog jezika sa napomenom o njihovoj
uobičajenoj primeni.
Tip Memorija u
Opseg Namena
bajtovima
char 1 0 do 255 ASCII skup znakova i mali brojevi

24
Ivan P. Stanimirović Uvod u programiranje

signed char 1 -128 do 127 ASCII skup znakova i veoma mali brojevi
enum 2 -32.768 do 32.767 Uređeni skup vrednosti
int 4 -2.147.483.648 do 2.147.483.647 Mali brojevi, kontrola petlji
unsigned int 4 0 do 4.294.967.295 Veliki brojevi i petlje
short int 2 -32.768 do 32.767 Mali brojevi, kontrola petlji
long 4 -2.147.483.648 do 2.147.483.647 Veliki brojevi
unsigned long 4 0 do 4.294.967.295 Astronomska rastojanja
-38 38
float 4 3,4*10 do 3,4*10 Naučne aplikačije (tačnost na 6 decimala)
-308 308
double 8 1,7*10 do 1,7*10 Naučne aplikačije (tačnost na 16 decimala)
-4932 4932
long double 10 3,4*10 do 3,4*10 Naučne aplikačije (tačnost na 19 decimala)

U C-u postoji skup operatora za rad sa binarnim sadržajima koji su prikazani u tabeli koja sledi.
Operator Značenje
&& Logička I operacija (AND)
|| Logička ILI operacija (OR)
^ Isključivo ILI (XOR)
>> Pomeranje udesno
<< Pomeranje ulevo
~ Komplement

U slučaju mešovitih izraza u kojima se pojavljuju različiti operatori takođe važe implicitna
pravila kojima je definisan prioritet operacija. Nabrojaćemo osnovna:
• Unarni operatori (na pr. ++) su uvek višeg prioriteta u odnosu na sve binarne.
• Aritmetičke operacije su višeg prioriteta u odnosu na relacije poređenja.
• Operatori poredenja <= i >= (manje ili jednako i veće ili jednako) su višeg prioriteta u odnosu
na jednako i nejednako.
• Poređenja su uvek višeg prioriteta u odnosu na operatore kojima se manipuliše bitovima.
• Operatori za manipulisanje bitovima su višeg prioriteta u odnosu na sve logičke operatore.
• Logičko I (&&) je višeg prioriteta u odnosu na logičko ILI ( | | ).
Celobrojni tipovi u C
Celobrojni tipovi su brojački tipovi i javljaju se kao označeni ili neoznačeni.
Celobrojne vrednosti obuhvataju celobrojne konstante, celobrojne promenljive, izraze i funkcije.
Celobrojne konstante predstavljaju podskup skupa celih brojeva čiji opseg zavisi od deklaracije ali i
od konkretne implementacije. U C jeziku celobrojne konstante se predstavljaju kao niske cifara. Ispred
koje može da stoji znak '+' za pozitivne, a obavezan je znak '-' za negativne vrednosti.
Promenljivoj osnovnog celobrojnog tipa int obično se dodeljuje memorijski prostor koji odgovara
"osnovnoj" jedinici memorije. Na taj način, opseg vrednosti tipa int u TURBO C na 16-bitnim
računarima je [-32768, +32767] = [-215,215-1], a na 32-bitnim računarima je
[-2147483648, +2147483647] = [-231,231-1].
Bitno je napomenuti da se mogu koristiti 3 brojna sistema, i to: dekadni (baza 10), oktalni (baza 8);
heksadekadni (baza 16). Heksadecimalni brojevi počinju sa 0x ili 0X. Dozvoljene cifre su 0, 1,.., 9 i
slova a, b, c, d, e, f (ili A, B, C, D, E, F). Oktalni brojevi počinju sa 0 a ostale cifre mogu biti 0, 1, ..7.
Na primer, 012 je dekadno 10, 076 je dekadno 62. Takođe, 0x12 je dekadni broj 18, 0x2f je dekadno
47, 0XA3 je dekadno 163. Celobrojne konstante koje ne počinju sa 0 su oktalne.
Opseg celih brojeva se može menjati primenom kvalifikatora long i short. Kvalifikator long može
da poveća opseg vrednosti celobrojnih promenljivih tipa int. Opseg vrednosti tipa long int (ili
skraćeno long) je [-2147483648, +2147483647] = [-231,+231-1].

25
Ivan P. Stanimirović Uvod u programiranje

Tip long int (ili long) garantuje da promenljive tog tipa neće zauzimati manje memorijskog
prostora od promenljivih tipa int.
Celobrojne konstante koje su prevelike da bi bile smeštene u prostor predviđen za konstante tipa int
tretiraju se kao long konstante. Ove konstante se dobijaju dodavanjem znaka L (ili l) na kraj konstante,
kao na primer 1265378L. Ako program ne koristi velike cele brojeve ne preporučuje se deklarisanje
promenljivih sa long, jer se time usporava izvršenje programa.
Kvalifikator short int (ili skraćeno short) smanjuje opseg celobrojnih promenljivih. Opseg
promenljivih tipa short uvek je [-215,215-1], tj. one se uvek smeštaju u 2 bajta. Upotrebom promenljivih
ovog tipa ponekad se postiže ušteda memorijskog prostora. Međutim, upotreba ovih promenljivih
može da uspori izvršavanje programa, jer se pre korišćenja u aritmetičkim izrazima ove promenljive
transformišu u tip int.
Ako smo sigurni da su vrednosti celobronih promenljivih nenegativne, one se mogu deklarisati na
jedan od sledećih načina:
unsigned int (skraćeno unsigned),
unsigned short int (skraćeno unsigned short),
unsigned long int (skraćeno unsigned long).

Time se interval pozitivnih vrednosti proširuje, jer bit za registrovanje znaka gubi to značenje.
Promenljive tipa unsigned int (skraćeno unsigned) mogu uzimati samo pozitivne celobrojne
vrednosti. Promenljive tipa unsigned imaju rang [0, 2širina_reči-1]. Prema tome, na 16-bitnim računarima
opseg promenljivih tipa unsigned int je [0,65535]=[0,216-1], dok je na 32-bitnim računarima
odgovarajući opseg jednak [0,232-1]=[0,+4294967295].
Konstante tipa long se mogu cpecificirati eksplicitno dodajući sufiks L ili l posle broja. Na primer,
777L je konstanta tipa long. Slično U ili u se može koristiti za konstante tipa unsigned. Na primer, 3U
je tipa unsigned, a 3UL je tipa unsigned long.
U slučaju greške integer overflov, program nastavlja da radi, ali sa nekorektnim rezultatom.
Promenljive celobrojnog tipa se deklarišu navođenjem imena promenljivih iza imena nekog
celobrojnog tipa. Imena promenljivih se međusobno razdvajaju zarezima, a iza spiska se navodi ';'. U
operatorima opisa je dozvoljeno izvršiti inicijalizaciju deklarisanih promenljivih.
Primer. Navedeno je nekoliko deklaracija promenljivih celobrojnih tipova.
long int x;
short int y;
unsigned int z,v,w;

Ključna reč int se može izostaviti u deklaracijama, pa se može pisati


long x;
short y, k=10;
unsigned z;
Realni tipovi podataka u C
Promenljive ovih tipova uzimaju za svoje vrednosti podskupove skupa realnih brojeva. U jeziku C
postoje tri vrste podataka realnog tipa, koji se razlikuju po tačnosti predstavljanja podataka: float (za
jednostruku tačnost), double (za dvostruku tačnost) i long double. U TURBO C vrednosti tipa float se
pamte u 4 bajta (32 bita), a double u 8 bajtova (64 bita). Efekat je da vrednosti tipa float zauzimaju 6
decimalnih mesta, a double 16 decimalnih mesta. Vrednosti tipa long double se smeštaju u 80 bitova.
U TURBO C, pozitivne vrednosti za float su iz opsega [3.4*10-38, 3.4*1038], dok su pozitivne
vrednosti za double iz opsega [1.7*10-308,1.7*10+308]. Pozitivne vrednosti tipa long double uzimaju
vrednosti iz opsega [3.4*10-4932,1.1*10+4932].
Za vrlo velike i vrlo male brojeve može se koristiti eksponencijalni zapis, koji se sastoji iz sledećih
delova:

26
Ivan P. Stanimirović Uvod u programiranje

celobrojnog dela - niz cifara,


decimalne tačke,
razlomljenog dela - niz cifara,
znaka za eksponent e ili E,
eksponenta koji je zadat celobrojnom konstantom.
Primeri realnih brojeva su: 45., 1.2345, 1.3938e-11, 292e+3.
Promenljive realnog tipa deklarišu se navođenjem liste imena promenljivih iza imena tipa.
Primer. Deklaracije promenljivih realnih tipova:
float x,y;
double z;
float p=2.71e-34;

Tip char
Tip char je jedan od fundamentalnih tipova podataka u jeziku C. Konstante i promenljive ovog tipa
se koriste za reprezentaciju karaktera. Znakovni tip (tip char) definiše uređen skup osnovnih znakova
jezika C. Takav skup obrazuje skup ASCII znakova. To znači da znakovnom tipu pripadaju i znaci
koji nemaju grafičku interpretaciju.
Svaki karakter se smešta u računaru u jednom bajtu memorije. Ako je bajt izgrađen od 8 bitova, on
može da pamti 28=256 različitih vrednosti. Promenlijve i konstante tipa char uzimaju za svoje
vrednosti karaktere odnosno cele brojeve dužine jednog bajta. To znači da se znak u memoriji
registruje u jednom bajtu. Promenljive ovog tipa se deklarišu pomoću ključne reči char.
Ako ispred deklaracije char stoji rezervisana reč signed, tada se specificira interval kodnih
vrednosti [-128,127]; ako je ispred char navedeno unsigned, tada se specificira kodni interval [0,255].
Primer. Iskazom
char ca, cb, cc;
promenljive ca, cb, cc deklarišu se kao promenljive tipa char. Karakter konstanta se piše između
apostrofa, kao: 'a', 'b', 'c'... U Turbo C se koriste ASCII kodovi karaktera, i oni predstavljaju njihovu
numeričku vrednost.
Promenljive tipa char se mogu inicijalizovati na mestu deklarisanja. Na primer, možemo pisati
char c='A', s='A', x;
int i=1;

Funkcije printf() i scanf() koriste %c za format karaktera.

Primer.
printf("%c", 'a');
printf("%c %c %c", 'A', 'B', 'C'); /* ABC */

Takođe, konstante i promenljive tipa char se mogu tretirati kao mali integeri.

Primer.
printf("%d", 'a'); /* 97 */
printf("%c",97); /* a */

Neke znakovne konstante se moraju specificirati kao ''escape'' sekvence, tj. moraju se navesti zajedno
sa znakom \ (backslash). Escape sekvence se koriste pri kreiranju izlaznih izveštaja u cilju
specificiranja upravljačkih znakova.
'\n' prelazak na novu liniju u ispisu;
'\t' horizontalni tab (pomera kursor za 5 ili 8 pozicija);
'\b' vraća kursor za jednu poziciju (povratnik, backspace);
'\f' form feed (pomera hartiju štampača na početak sledeće strane);
'\a' alarm;

27
Ivan P. Stanimirović Uvod u programiranje

'\'' apostrof;
'\\' backslash.

Primer.
printf("\"ABC\""); /* "ABC" */

U stringu je single quote običan karakter:


printf("'ABC'"); /* 'ABC' */

Karakter konstante se takođe mogu prikazati pomoću jednocifrene, dvocifrene ili trocifrene
sekvence. Na primer '\007', ' \07' ili '\7' predstavlja bell (alarm).
Za ulaz i izlaz karaktera se mogu koristiti funkcije getchar() i putchar(). Ovi makroi su definisani
u fajlu stdio.h. Za učitavanje karaktera sa tastature koristi se getchar(), dok se putchar() koristi za
prikazivanje karaktera na ekran.
C obezbeđuje standardni fajl ctype.h koji sadrži skup makroa za testiranje karaktera i skup
prototipova funkcija za konverziju karaktera. Oni postaju dostupni pomoću preprocesorske direktive
#include <ctype.h>

Makroi u sledećoj tabeli testiraju karaktere, i vraćaju vrednosti true (0) i false (=0).

makro vrednost  0 se vraća za


isalpha(c) c je slovo
isupper(c) c je veliko slovo
islower(c) c je malo slovo
isdigit(c) c je broj
isxdigit(c) c je heksadecimalan broj
isspace(c) c je blanko
isalumn(c) c je slovo ili broj
ispunkt(c) c je interpunkcijski znak
isprint(c) c je terminalni karakter
iscntrl(c) c je kontrolni karakter

Takođe, u standardnoj biblioteci <ctype.h> uključene su i funkcije toupper(c) i tolower(c) za


odgovarajuću konverziju karaktera. Ove funkcije menjaju vrednost argumenta c koja je smeštena u
memoriji.
toupper(c) menja c iz malog u veliko slovo;
tolower(c) menja veliko slovo u malo;
toascii(c) menja c u ASCII kod;

Konverzija tipova podataka i kast


Mnogi jezici visokog nivoa imaju strogu tipizaciju Takvi jezici nameću tokom prevođenja slaganje
tipova podataka koji su upotrebljeni u aritmetičkim operacijama, operacijama dodeljivanja i pozivima
funkcija. U jeziku C se mogu pisati operacije u kojima se koriste različiti tipovi podataka (mešovite
operacije). Svaki aritmetički izraz poseduje vrednost i tip. Tip rezultata aritmetičkih izraza zavisi od
tipova operanda. Ako su kod binarnih aritmetičkih operatora oba operanda istog tipa, tada je tip
rezultata jednak tipu operanada. Kada to nije ispunjeno, vrši se automatska konverzija operanda nižeg
hijerarhijskog nivoa u tip operanda višeg nivoa. Osnovni tipovi podataka imaju sledeći hijerarhijski
nivo
char<int<long<float<double.
Korišćenjem rezervisanih reči unsigned i long povišava se hijerarhijski rang, tako da je detaljniji
pregled hijerarhijskih nivoa sledeći:
char< int <unsigned <long < unsigned long <float < double < long double.
Na primer, ako su oba operanda tipa int, svaki aritmetički izraz koji je izgrađen od njih uzima
vrednost tipa int. Ako je jedna od promenljivih tipa short, ona se automatski konvertuje u

28
Ivan P. Stanimirović Uvod u programiranje

odgovarajuću vrednost tipa int.


Automatska konverzija tipova se javlja i pri dodeljivanju vrednosti. Kod operatora dodeljivanja
vrednosti, uvek se vrednost izraza sa desne strane konvertuje u vrednost prema tipu promenljive sa
leve strane operatora dodeljivanja. Ako je promenljiva d tipa double, a izraz i tipa int, tada se pri
dodeljivanju d=i vrednost promenljive i konvertuje u odgovarajuću vrednost tipa double. Ako je i
promenljiva tipa int, a d je neki izraz tipa double, tada u izrazu i=d, prevodilac vrednost izraza d
konvertuje u odgovarajuću vrednost tipa int, pri čemu se gube vrednosti decimalnih pozicija.
Osim već pomenute automatske konverzije tipova podataka može se izvršiti i eksplicitna konverzija
tipova. Eksplicitna konverzija se postiže operatorom kast (cast), oblika (tip)<izraz>. Postoje situacije
kada je konverzija tipova poželjna, iako se ne izvršava automatska konverzija. Takva situacija nastaje
na primer pri deljenju dva cela broja. U takvim slučajevima programer mora eksplicitno da naznači
potrebne konverzije. Takve konverzije su neophodne da bi se izraz tačo izračunao.

Primer. Ako je promenljiva i tipa int, tada se izrazom (double)i njena vrednost prevodi u
odgovarajuću vrednost tipa double.
Operator kast je istog prioriteta i asocijativnosti kao i ostali unarni operatori. Kast se može
primenjivati na izraze.
Primer.
(float)i+3 je ekvivalentno sa ((float)i)+3
(double)x=77 je ekvivalentno sa ((double)x)=77

Takođe, možemo pisati


x=(float)((int)y+1)
(double)(x=77)

Posle izraza x=(int)2.3+(int)4.2 vrednost za x postaje 6.


Vrste konverzije tipova
 Konverzija tipa može biti:
- standardna – ugrađena u jezik ili
- korisnička – definiše je programer za svoje tipove.
 Standardne konverzije su, na primer:
- konverzije iz tipa int u tip float, ili iz tipa char u tip int i slično.
 Konverzija tipa može biti:
- implicitna – prevodilac je automatski vrši, ako je dozvoljena,
- eksplicitna – zahteva programer.
 Jedan način zahtevanja eksplicitne konverzije:
- pomoću C operatora kast (cast): (tip)izraz.
 Jezik C++ uvodi 4 specifična kast operatora.
 Postoji i drugi mehanizam konverzije (konverzioni konstruktor).
Konstante
 Konstantni tip je izvedeni tip. Dobija se iz nekog osnovnog tipa pomoću specifikatora const.
Konstantni tip zadržava sve osobine osnovnog tipa, samo se podatak ne može menjati.
- Primeri: const float pi=3.14; const char plus='+';
 Konstanta mora da se inicijalizuje pri definisanju.
 Prevodilac često ne odvaja memorijski prostor za konstantu.
 Konstante mogu da se koriste u konstantnim izrazima koje prevodilac treba da izračuna u toku
prevođenja. Na primer, konstante mogu da se koriste u izrazima koji definišu dimenzije nizova.
 Umesto simboličkih konstanti koje se uvode sa #define preporuka je koristiti tipizirane
konstante koje se uvode sa const.
 Dosledno korišćenje konstanti u programu obezbeđuje podršku prevodioca u sprečavanju
grešaka.

29
Ivan P. Stanimirović Uvod u programiranje

Sizeof operator
Unarni operator sizeof() daje za rezultat broj bajtova potrebnih za smeštanje svog argumenta.
Vrednost izraza sizeof(obj) se izračunava za vreme kompilovanja. Argument može biti ime
promenljive, ime tipa ili izraz. Ako je obj ime promenljive, tada je vrednost izraza sizeof(obj) broj
bajtova potrebnih za registrovanje te promenljive u memoriji. Ako je operand obj ime tipa, tada je
vrednost izraza sizeof(obj) dužina tog tipa, odnosno broj bajtova potrebnih za registrovanje
elemenata tog tipa. Ako je argument neki tip, ime tog tipa se mora navesti između zagrada. Naredba
sizeof se koristi kada se generiše kôd koji zavisi od veličine tipa.
Osnovne aritmetičke operacije
Osnovne aritmetčke operacije su:
+ sabiranje,
- oduzimanje,
* množenje,
/ deljenje,
Ako su oba operanda operacije deljenja / celi brojevi tada se iz realnog broja koji predstavlja njihov
količnik odbacuje decimalna tačka i razlomljeni deo.
Na primer, 15/2=7, 2/4=0, -7/2=-3, 15%2=1, 7./4=1.74.
Operacija - može biti i unarna, i tada se koristi za promenu znaka svog argumenta (unarni minus).
Sve operacije poseduju prioritet i asocijativnost (redosled), kojima se determiniše postupak
evaluacije izraza. Ako u izrazu postoje operacije različitog nivoa prioriteta, operacije se izvršavaju po
opadajućem nivou prioriteta. Prioritet se može promeniti upotrebom zagrada. Asocijativnost odlučuje
o redosledu izvršavanja operacija istog prioriteta.
Levoasocijativne operacije se izvršavaju s leva na desno a desnoasocijativne s desna na levo.
Najviši priorirtet ima operacija promene znaka, zatim levoasocijativni multiplikativni operatori *, /
i %, dok su najnižeg nivoa prioriteta levoasocijativni aditivni operatori + i -.
Operacija inkrementiranja (uvećanja) ++ i operacija dekrementiranja (umanjenja) -- su unarne
operacije sa asocijativnošću s desna na levo. U tabeli prioriteta operatori zauzimaju sledeće mesto:
najvišeg prioriteta su unarni operatori - (promena znaka); ++, --;
nižeg prioriteta su multiplikativni *, /, %; dok su najmanjeg prioriteta aditivni operatori +, -.
Operacije ++ i -- se mogu pisati ispred argumenta (prefiksno) ili iza argumenta (postfiksno). Mogu
se primenjivati nad promenljivima a ne mogu na konstantama ili izrazima.

Primer. Može se pisati ++i, i++, --cnt, cnt-- a ne može 777++, ++(a*b-1).
Svaki od izraza ++i, i++, --i, i-- ima određenu vrednost. Izrazi ++i, i++ uzrokuju inkrementiranje
vrednosti promenljive i u memoriji za 1, dok izrazi --i, i-- uzrokuju dekrementiranje njene vrednosti za
1. Izrazom ++i vrednost za i se inkrementira pre nego što se upotrebi, dok se sa i++ vrednost za i
inkrementira posle upotrebe te vrednosti. Slična pravila važe za izraze --i, i--, samo što se radi o
dekrementiranju te vrednosti.
Operatori ++ i -- razlikuju se od operatora +, -, *, /, % po tome što menjaju vrednosti varijable u
memoriji, tj. operatori ++ i -- poseduju bočni efekat.
Primer. Kompajler koristi tipove operanada kako bi odredio rezultat izračunavanja.

30
Ivan P. Stanimirović Uvod u programiranje

Bibliotečke aritmetičke funkcije


Deo C jezika jesu standardne biblioteke koje sadrže često korišćene funkcije. Biblioteka math.h
sadrži deklaraciju funkcija iz matematičke biblioteke. Sadržaj ove datoteke se uključuje u program
naredbom
#include<math.h>.
Neke od funkcija iz ove biblioteke su date u nastavku.
Poznate su funkcije sin(x), cos(x), tan(x), exp(x), log(x), log10(x), sqrt(x), fabs(x)=|x|. Sledi opis
najvažnijih funkcija iz ove bibilioteke.
ceil(x), rezultat je najmanja celobrojna vrednost ne manja od x (plafon od x).
Rezultat funkcije floor(x) je najveća celobrojna vrednost ne veća od x (pod od x).
pow(x,y)=x^y. Ako je x=0 mora da bude y>0. Ako je x<0 tada y mora da bude ceo broj.
asin(x) vrednost funkcije arcsin(x), x[-1,1].
acos(x) vrednost funkcije arccos(x), x[-1,1].
atan(x) vrednost funkcije arctg(x), x[-/2, /2].
atan2(x,y) vrednost funkcije arctg(x/y), x[-,]. Ne može istovremeno da bude x=y=0.
sinh(x) vrednost funkcije sh(x).
cosh(x) vrednost funkcije ch(x).
tanh(x) vrednost funkcije th(x).
modf(x,&y) vrednost funkcije je razlomljeni deo realnog broja x sa predznakom tog broja. U
argumentu y, kao bočni efekat, daje se celobrojni deo broja x sa predzankom tog broja. Argumenti x i
y su tipa double.
fmod(x,y) vrednost funkcije je ostatak realnog deljenja x/y sa predznakom argumenta x. Standard ne
precizira rezultat u slučaju y=0. Argumenti x i y su tipa double. Na primer, fmod(4.7,2.3)=0.1.
U biblioteci <stdlib.h> nalaze se funkcije različite namene. Navedene su neke od njih.
abs(n) apsolutna vrednost, gde su vrednost argumenta i funkcije tipa int,
labs(n) apsolutna vrednost, gde su vrednost argumenta i funkcije tipa long,
rand() vrednost funkcije je pseudoslučajni broj iz intervala [0,RAND_max], gde RAND_max
simbolička konstanta čija vrednost zavisi od računara i nije manja od 32767,
srand(n) postavlja početnu vrednost sekvence pseudoslučajnih brojeva koju generiše rand().
Podrazumevana početna vrednost je 1. Tip argumenta je unsigned int. Funkcija ne daje rezultat.
atof(s) ova funkcija vrši konverziju realnog broja iz niza ASCII cifara (karaktera) oblika
“cc....cc... Eee”
u binarni ekvivalent. Argument s je string a rezultat je tipa double. Pre konverzije se
brišu početne praznine. Konverzija se završava kod prvog znaka koji ne može da bude deo broja.
atoi(s) ova funkcija vrši konverziju celog broja iz niza ASCII cifara (karaktera) oblika “cc...” u
binarni ekvivalent. Argument s je string a rezultat je tipa int. Početne praznine se ignorišu. Konverzija
se završava kod prvog znaka koji ne može da bude deo broja.

31
Ivan P. Stanimirović Uvod u programiranje

atol(s) ova funkcija vrši konverziju celog broja iz niza ASCII cifara (karaktera) oblika “cc...” u
binarni ekvivalent tipa long. Argument s je string a rezultat je tipa long. Početne praznine se ignorišu.
Konverzija se završava kod prvog znaka koji ne može da bude deo broja.

Operacija dodeljivanja u C
U C jeziku se operator = tretira kao operator dodeljivanja. Njegov prioritet je manji od prioriteta do
sada razmatranih operacija, a njegova asocijativnost je ``s desna na levo''. Izraz dodeljivanja vrednosti
je oblika
<promenljiva> = <izraz>;
na čijoj je desnoj strani proizvoljan izraz. Kompletan izraz je završen sa ; (semicolon). Vrednost izraza
na desnoj strani se dodeljuje promenljivoj sa leve strane. Ako su tipovi promenljive i izraza različiti,
vrši se konverzija vrednosti izraza u odgovarajuću vrednost saglasno tipu promenljive. Vrednost izraza
dodeljivanja jednaka je vrednosti izraza sa njegove desne strane.
Primer. Sledeća sekvenca izraza
y=2; z=3; x=y+z;
može se efikasnije zapisati u obliku
x=(y=2)+(z=3);
Primer. Zbog desne asocijativnosti operatora = je izraz x=y=z=0 ekvivalentan izrazu
x=(y=(z=0)).
Primer. Operator y=x++; je ekvivalentan sledećoj sekvenci operatora: y=x; x=x+1;
Operator y=--x je ekvivalentan sledećim operatorima x=x-1; y=x;

Posle izvršavanja operatora


x=y=1; z=(x+(++y))*3;
dobijaju se sledeće vrednosti promenljivih:
x=1, y=2, z=(1+2)*3=9.
Operatori
x=y=1; z=(x+(y++))*3;
x=y=1; t=(x+y++)*3;
daju sledeće vrednosti promenljivih:
x=1, y=2, z=(1+1)*3=6, t=(1+1)*3=6.
Primer.

Operatori složenog dodeljivanja su:


=, +=, -=, *=, /=, %=, ||=, &=,^=, |=
Svi ovi operatori imaju isti prioritet i asocijativnost s desna na levo. Ako su l i r proizvoljni izrazi, tada
je izraz l<op>=r jednak l=l<op> r.

Na primer,
x+=2; je ekvivalentno sa x=x+2;
x%=2; je ekvivalentno sa x=x%2;
Primer. Šta se ispisuje posle izvršenja sledećeg programa?
#include<stdio.h>

32
Ivan P. Stanimirović Uvod u programiranje

void main()
{ int x,y,z;
x=y=1;
z=(x+y++)*(y==1);
printf("%d, %d, %d\n",x,y,z);
int i=1,j;
i=i++*++i;
printf("%d\n",i);
i=j=2;
printf("%d\n",++j+i++);
printf("%d, %d\n",i,j);
}
Primer. Šta se ispisuje posle izvršenja sledećeg programa?
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void main()
{ int i,j=6;
if(j=0) i=5;
else i=1;
printf("%d\n%d\n",i,j);
}

Operacije poređenja i logičke operacije


U jeziku C postoje samo numerički tipovi. Ne postoji čak ni logički tip podataka. Za predstavljanje
logičkih vrednosti koriste se celobrojni podaci tipa int. Vrednost 0 se tumači kao logička neistina
(false), a bilo koja vrednost različita od nule tumači se kao logička istina (true).
Operacije poređenja
Operacije poređenja su:
<, <=, >, >=, ==, !=.
Rezultat izvršenja ovih operacija je 1 ako je ispunjeno poređenje, a inače je 0. Ove operacije se
izvršavaju s leva na desno. Operacije poređenja su nižeg prioriteta od aritmetičkih operacija.
Unutar operacija poređenja, operacije <, <=, >, >= su višeg prioriteta od operacija == i !=.
Na primer, x>y+3 je ekvivalentno sa x>(y+3).

Logičke operacije
Postoje tri logičke operacije:
! je operacija negacije,
&& je konjunkcija, i
|| predstavlja opreaciju disjunkcije.
Rezultat primene ovih operacija je 0 ili 1.
Operacija negacije ! je unarna, i daje rezultat 1 ako je vrednost operanda 0, a vrednost 0 ako je
vrednost operanda 1.
Operacija konjunkcije && je binarna, i daje 1 ako su oba operanda različita od 0, a 0 u suprotnom.
Ako je levi operand jednak 0 pri izvršenju operacije konjunkcije desni operand se ignoriše.
Operacija disjunkcije || je binarna, i daje 1 ako je bar jedan operand različit od 0, a 0 inače. Ako je
vrednost levog operanda jednaka 1 pri izvršenju operacije disjunkcije desni operand se ignoriše.
Najviši prioritet ima operacija negacije; sledećeg nivoa prioriteta je operator konjunkcije, dok je
najnižeg nivoa prioriteta operator disjunkcije.
Prema tome,

33
Ivan P. Stanimirović Uvod u programiranje

p||q && r je isto sa p||(q && r),


x<=y && r je isto sa (x<=y)&& r.
Primer. Napisati operatore dodeljivanja kojima se realizuje sledeće:
a) Promenljivoj p se dodeljuje vrednost 1 ako se od odsečaka x, y, z može konstruisati trougao, a inače
0.
p=((x+y>z) && (x+z>y) && (y+z>x));

b) Promenljivoj p se dodeljuje vrednost 1 ako se pravougaonik sa stranicama a i b može ceo smestiti u


pravougaonik sa stranicama c i d, a inače 0.
p=((a<c)&& (b<d) || (a<d)&& (b<c));

2.6. Diskretni tipovi podataka u programskim jezicima


Grupa diskretnih tipova obuhvata sve tipove podataka sa konačnim, diskretnim skupom vrednosti.
U takvom skupu vrednosti je definisana relacija poretka. Diskretnost i uređenost skupa vrednosti
omogućava definisanje intervala i upotrebu nekih opštih zajedničkih funkcija i atributa u ovoj grupi
tipova. U diskretne tipove podataka svrstavaju se svi celobrojni tipovi podataka, kao i svi drugi
elementarni tipovi sa diskretnim skupom vrednosti kao što su znakovni i logički tipovi. Posebno
značajni u grupi diskretnih tipova su tipovi nabrajanja (enumerated types) i intervalni tipovi nekih
jezika.

2.6.1. Nabrojivi tipovi u programskim jezicima


U programskom jeziku C se u okviru definicija tipova nabrajanja eksplicitno koristi reč enum. Gore
datim tipovima podataka u ovom jeziku odgovaraju sledeće definicije:
enum BOJE {crvena,bela,zelena,plava};
enum DANI {ponedeljak,utorak,sreda,cetvrtak,petak,subota,nedelja};
enum MESECI {jan,feb,mar,apr,maj,jun,jul,avg,sep,okt,nov,dec};
enum STATUS {ON,OFF};
enum PRAVCI {sever,jug,istok,zapad};

2.8. Upotreba typedef iskaza u C


Ključna reč typedef dozvoljava dodeljivanje alternativnih imena postojećim tipovima podataka, kao
i definisanje novih tipova podataka.
Primer. Iskazom
typedef int celi;
definiše se ime celi kao ekvivalentno ključnoj reči int. Sada se moše pisati
celi i, j, n;
Izraz
typedef double vektor[20];
definiše tip vektor kao niz od 20 elemenata tipa double.
Analogno, tip matrica kao dvodimenzionalni niz elemenata tipa double može se definisati na sledeći
način:
typedef double matrica[10][10];
Nakon ovih definicija tipova se imena vektor i matrica mogu koristiti kao tipovi podataka.

34
Ivan P. Stanimirović Uvod u programiranje

3. ULAZ I IZLAZ PODATAKA

U programskim jezicima postoji veći broj funkcija za unošenje i izdavanje podataka. Pomoću
naredbi ulaza i izlaza program dobija neophodne podatke i prikazuje dobijene rezultate. Ove funkcije
se koriste za standardni ulaz i izlaz podataka preko tastature i monitora. Postoje varijante ovih
funkcija koje se mogu koristiti za pristup datotekama.

3.1. Ulaz i izlaz podataka u jeziku C

3.1.1. Funkcije printf() i scanf()


Funkcija printf() se koristi za formatizovani izlaz podataka, a scanf() za formatizovano učitavanje
podataka. Ove funkcije se nalaze u standarnoj biblioteci stdio.h. Datoteka stdio.h sadrži podake
neophodne za pravilno funkcionisanje ulazno-izlaznih funkcija. Njen sadržaj se uključuje u program
naredbom
#include<stdio.h>.
Funkcija printf() se poziva izrazom oblika
printf(Upravljacki_string [, Arg1,Arg2,...]);
Lista argumenata može da se izostavi. Tada je jedini argument funkcije printf() upravljački string koji
se ispisuje na ekran. U opštem slučaju, funkcija printf() se primenjuje na listu argumenata koja se
sastoji iz dva dela. Prvi argument funkcije printf() je kontrolni ili konverzioni string (upravljački
string), a drugi je lista izlaznih podataka čije se vrednosti ispisuju. Konverzioni string određuje format
za štampanje liste izlaznih podataka. Najprostija specifikacija formata počinje karakterom '%', a
završava se konverzionim karakterom (formatom ili konverzionom specifikacijom).
U sledećoj tabeli su prikazani konverzioni karakteri

konverzioni karakter konverzija izlaznog niza


c karakter char
d ceo broj int
u ceo dekadni broj bez znaka
o oktalni broj int
x, X heksadekadni broj int
ld dug ceo broj long int
lo dug oktalni broj long int
lx dug heksadekadni broj long int
f fiksni zarez za float
lf double
e, E pokretni zarez za float i double
g, G kraći zapis za f ili e
s string
p vrednost pointera
Konverzija g i G su jednake konverzijama e i E ukoliko je eksponent prikazanog broja manji od -4 ili
je veći ili jednak preciznosti obuhvaćene specifikacijom d.
Opšti oblik konverzione specifikacije je:
%[+|-|][sirina][.tacnost]konverzioni_karakter
gde:
- konverzioni_karakter definiše konverziju.

35
Ivan P. Stanimirović Uvod u programiranje

- Znak - ukazuje da se argument poravnava na levoj strani zadate širine polja.


- Znakom + se kod numeričkih konverzija označava da ispred pozitivnih vrednosti treba da se napiše
predznak +.
- Znak razmaka ‘’ označava da je predznak praznina umesto +.
Bez ovih parametara konverzije, pozitivne vrednosti se prikazuju bez predznaka.
- Parametar sirina zadaje minimalnu širinu polja. Polje se proširuje za potreban broj pozicija ako
izlazna vrednost zahteva više pozicija nego što je specificirano parametrom sirina. Ako specifikacija
širine polja počinje nulom, tada se polje umesto prazninama popunjava nulama u neiskorišćenim
pozicijama ako je poravnanje po desnoj margini.
- Parametar tacnost se koristi za realne brojeve (float ili double) i određuje broj decimala iza
decimalne tačke.
Primer. (a) Posle izraza
printf("Danas je sreda \b\b\b\b\b petak \n ");
na ekranu se ispisuje tekst
Danas je petak.
(b) printf("Vrednost za x = %f\n", x);
(c) printf("n = %d x = %f %f^ %d=%lf\n", n,x,x,n,pow(x,n));
Funkcija scanf() ima za prvi argument kontrolni string koji sadrži formate koji odgovaraju ulaznim
veličinama. Drugi argument jeste lista adresa ulaznih veličina.
scanf(Upravljacki_string,Adresa1[,Adresa2,...]);
Upravljački string sadrži konverzione specifikacije koje odgovaraju ulaznim veličinama. Lista adresa
sadrži adrese promenljivih u koje se smeštaju učitane i konvertovane vrednosti. Operator adrese se
predstavlja simbolom &. Adresa promenljive se formira tako što se ispred imena promenljive piše
operator adresiranja &.

Na primer, u izrazu scanf("%d", &x); format %d uzrokuje da se ulazni karakteri interpretiraju


kao ceo broj i da se učitana vrednost smešta u adresu promenljive x.
Neka su deklarisane celobrojne promenljive i, j, k. Tada se tri celobrojne vrednosti mogu dodeliti
ovim promenljivim preko tastature pomoću operatora
scanf("%d%d%d", &i,&j,&k);
Za razdvajanje ulaznih polja u funkciji scanf() koriste se sledeći znakovi: praznina (blank),
tabulator (tab) i prelaz u novi red (enter) (tzv. beli znaci). Izuzetak se čini u slučaju ako neki od
ulaznih znakova odgovara konverzionom karakteru %c, kojim se učitava sledeći znak čak i kada je on
nevidljiv.
Pri ulaznoj konverziji opšte pravilo je da podatak čini niz znakova između dva bela znaka. Odavde
sledi da jednim pozivom funkcije scanf mogu da se učitavaju podaci iz više redova. Važi i obrnuto,
veći broj poziva funkcije scanf može da u čitava uzastopne podatke iz istog reda.
Znaci koji se pojavljuju u upravljačkom stringu a nisu konverzioni moraju se pri učitavanju pojaviti
na određenom mestu i ne učitavaju se. Na primer, ako se unese ulazni red oblika
1:23:456
tada se operatorom
scanf("%d:%d:%d", &i,&j,&k);
celobrojnim promenljivim i, j i k dodeljuju vrednosti 1, 23 i 456, redom.
Opšti oblik konverzione specifikacije je:
%[*][sirina]konverzioni_karakter
gde je:
- znak * označava da se obeleženo ulazno polje preskače i ne dodeljuje odgovarajućoj promenljivoj.

36
Ivan P. Stanimirović Uvod u programiranje

- sirina zadaje maksimalnu širinu polja. Ako je širina polja veća od navedene u konverzionoj
specifikaciji, koristi se onoliko znakova koliko je zadato maksimalnom širinom.
- konverzioni_karakter je jedan od konverzionih znakova iz sledeće tabele:
konverzioni karakter tip argumenta
c pokazivač na char
h pokazivač na short
d pokazivač na int
ld, D pokazivač na long
o pokazivač na int
lo, O pokazivač na long
x pokazivač na int
lx, X pokazivač na long
f pokazivač na float
lf, F pokazivač na double
e pokazivač na float
le, E pokazivač na double
s pokazivač na string

Primer. (i) Neka je i celobrojna i x realna promenljiva.


Ako je ulazna linija oblika
57 769 98.
tada se operatorom
scanf("%2d%*d%f",&i,&x);
promenljivim i i x dodeljuju redom vrednosti 57 i 98.0.
(ii) Ako su i, j, k celobrojne promenljive i ako se unese ulazna linija 123 456 789, posle primene
operatora
scanf("%2d%3d%2d",&i,&j,&k);
promenljive i, j, k uzimaju vrednosti 12, 3, 45.
Primer. Jednostavan C program koji demonstrira komentare i pokazuje nekoliko promenljivih i
njihove deklaracije.
#include <stdio.h>
void main()
{ int i, j; /* Ove 3 linije deklarišu 4 promenljive */
char c;
float x;
i = 4; /* i, j imaju pridružene celobrojne vrednosti */
j = i + 7;
c = 'A'; /* Karakteri su okruženi apostrofima */
x = 9.087; /* x zahteva neku realnu vrednost */
x = x * 4.5; /* Promena vrednosti u x */
/* Prikaz vrednosti promenljivih na ekran */
printf("%d %d %c %f", i, j, c, x);
}
Primer. Dekadni, oktalmi i heksadekadni sistem.
#include <stdio.h>
int main(void)
{ int dec = 20, oct = 020, hex = 0x20;
printf("dec=%d, oct=%d, hex=%d\n", dec, oct, hex);
printf("dec=%d, oct=%o, hex=%x\n", dec, oct, hex);
return 0;
}
Primer. Realni brojevi u naredbi printf.

37
Ivan P. Stanimirović Uvod u programiranje

#include <stdio.h>
#include <float.h>
int main(void)
{ double f = 3.1416, g = 1.2e-5, h = 5000000000.0;
printf("f=%lf\tg=%lf\th=%lf\n", f, g, h);
printf("f=%le\tg=%le\th=%le\n", f, g, h);
printf("f=%lg\tg=%lg\th=%lg\n", f, g, h);
printf("f=%7.2lf\tg=%.2le\th=%.4lg\n", f, g, h);
return 0;
}
f=3.141600 g=0.000012 h=5000000000.000000
f=3.141600e+00 g=1.200000e-05 h=5.000000e+09
f=3.1416 g=1.2e-05 h=5e+09
f= 3.14 g=1.20e-05 h=5e+09

3.1.2. Direktive pretprocesora u C


Simbolička konstanta je konstanta kojoj je pridružen identifikator. U programu se kasnije koristi
identifikator, a ne vrednost konstante. Simboličke konstante u jeziku C se definišu korišćenjem
direktiva pretprocesora. Ovakva definicija počinje pretprocesorskom direktivom #define (sve
pretprocesorske direktive počinju znakom #). Iza direktive pretprocesora se navodi simboličko ime
konstante a zatim konstantna vrednost koja predstavlja vrednost te konstante. Vrednost konstante se
može zadati na sledeći način:
- pomoću imena već definisane konstante;
- konstantom (celobrojnom, realnom, znakovnom, logičkom);
- konstantnim izrazom.
Iza ove direktive ne koristi se znak ';' jer pretprocesorske direktive ne pripadaju jeziku C.
Pretprocesorske direktive se moraju navesti pre prvog korišćenja imena konstante u programu. U
praksi se direktive najčešće pišu na početku programa.
Direktive #define mora da se piše u posebnom redu. Jednom naredbom može da se definiše samo
jedna konstanta. Zajedno sa nekom ovakvom direktivom ne smeju da budu druge naredbe. Jedino je
dozvoljen komentar na kraju reda.
Identifikatori simboličkih konstanti pišu se velikim slovima da bi se razlikovali od identifikatora
promenljivih koji se obično pišu malim slovima. Ovo pravilo nije nametnuto sintaksom jezika C već
stilom koji se ustalio u praksi.
Primer. Definisanje simboličkih konstanti.
#define PI 3.141592
#define N 100
#define NMIN -N
#define PIX2 (PI*2)
#define LIMT 5
#define BELL '\007'
#define PORUKA "Zdravo"

Mogućnost da se konstanta definiše pomoću pretprocesorskih direktiva omogućuje da se vrednost


konstante jednostavno zapiše i promeni na jednom mestu. Korišćenje konstanti u programu
navođenjem njihovih imena umesto odgovarajuće vrednosti povećava čitljivost programa.
Takođe, može da se uvede promenljiva kojoj se dodeljuje vrednost konstante.
Primer. Umesto izraza
#define POREZ 15
može se pisati
float POREZ=15
Metod koji koristi promenljive je neefikasan, jer se pri svakom korišćenju vrednosti promenljive
vrši obraćanje memoriji za izračunavanje njene vrednosti, čime se usporava izvršenje programa. Ovde

38
Ivan P. Stanimirović Uvod u programiranje

se radi o smeni u ''vreme izvršavanja'', za razliku od pretprocesorske direktive kojom se vrši smena ''u
toku kompilacije''.

Imenovane konstante se mogu kreirati koristeći naredbu const.

Primeri u jeziku C
Primer. Zbir dva broja u jeziku C.
#include <stdio.h>
main()
{ int x, y;
printf("Unesi dva cela broja");
scanf("%d %d", &x, &y);
printf("Njihov zbir je %5d\n",x+y);
}

Primer. Proizvod dva broja tipa long.


#include <stdio.h>
main()
{ long x=2345678, y=67890;
printf("Njihov proizvod je %ld\n",x*y);
}

Primer. Zadavanje i prikazivanje karaktera.


#include <stdio.h>
main()
{ char c='A';
printf("%c%d\n",c,c);
}

Primer. Rad sa određenim brojem decimala.


#include <stdio.h>
void main()
{float x=23.45678888, y=7.8976789;
printf("Njihov proizvod je:%f,%0.16f,%0.20f\n", x*y,x*y,x*y);
}

Primeri. Napredno korišćenje #define.


Primer .
#include <stdio.h>
#define veci(X,Y) X>Y
#define kvad(X) X*X
#define kvadrat(X) ((X)*(X))
void main()
{printf("To su %d %d %d %d\n", veci(3,2),kvad(5),kvad(5+5),kvadrat(5+5));}

39
Ivan P. Stanimirović Uvod u programiranje

Primer.
#include <stdio.h>
#define MAX 23
#define Ako if
#define Onda
#define Inace else
void main()
{ int n=24;
Ako (MAX > n) Onda printf("veci\n");
Inace printf("manji\n");
}

4. OSNOVNE UPRAVLJAČKE STRUKTURE

Svaki program sadrži naredbe dodeljivanja kojima se izračunavaju vrednosti određenih izraza i
pamte (dodeljuju) kao vrednosti odgovarajućih promenljivih. Ipak, veoma retko se bilo koji program
sastoji samo od jedne sekvence naredbi dodeljivanja kao i naredbi ulaza/izlaza. Mnogo se češće
zahteva postojanje više različitih tokova u zavisnosti od određenih uslova ili mogućnost višestrukog
izvršavanja dela programa. Naredbe koje omogućavaju definisanje toka programa nazivaju se
upravlajčke naredbe.
Upravlajčke naredbe u prvom imperativnom programskom jeziku FORTRAN bile su izvedene iz
osnovnih mašinskih naredbi. To je period kada metodologija programiranja tek počinje da se razvija
tako da još nije definisan neki osnovni skup upravljačkih naredbi. Početkom sedamdesetih Wirt
definiše metodologiju strukturnog programiranja i programski jezik Pascal sa skupom upravljačkih
struktura kojima se implementiraju osnovne algoritamske strukture. Ovaj koncept je široko prihvaćen,
tako da danas viši programski jezici iz grupe proceduralnih jezika obično raspolažu skupom
upravljačkih struktura kojima se upravlja tokom izvršenja programa u skladu sa konceptima
strukturnog programiranja. Iako se od jezika do jezika ovaj skup upravljačkih struktura donekle
razlikuje, može se reći da su ipak među njima u ovom domenu male suštinske razlike. Smatra se da je
skup naredbi kojima se upravlja tokom programa dovoljan ako obezbeđuje sledeće tri osnovne
upravlajčke strukture:
(1) Strukturu selekcije, koja omogućava izbor jedne od dve mogućnosti. U Pascal-u se obično
implementira izrazom oblika:
If B then St else Sf ;
Struktura selekcije određena je if-then i if-then-else izrazima.
(2) Strukturu višestruke selekcije, koja omogućava izbor jedne između više ponuđenih grana. U
Pascal-u se koristi case izraz oblika:
case X of
xa : Sa;
xb : Sb;
end;
(3) Strukturu iteracije, koja omogućava višestruko izvršavanje nekog bloka naredbi. U jeziku
Pascal se koristi while do petlja oblika:
while B do S;
Upravljačke strukture jednog proceduralnog jezika bi trebalo da ispunjavaju sledeće osobine:
• smisao naredbi mora da bude jasan i jednoznačan;

40
Ivan P. Stanimirović Uvod u programiranje

• sintaksa naredbe treba da bude tako postavljena da dozvoljava hijerarhijsko ugrađivanje drugih
naredbi, što mora da bude jednoznačno definisano i jasno iz samog teksta programa;
• potrebno je da postoji mogućnost lake modifikacije naredbi.

4.1. načini predstavljanja algoritama


 Tekstualni
 Grafički (pomoću blok šema)
 Pseudo kodom
 Strukturogramom
Tekstualni način
 Koriste se precizne rečenice govornog jezika
 Koristi se za lica koja se prvi put sreću sa pojmom algoritma
 Dobra osobina: razumljivost za širi krug ljudi
 Loše: nepreciznost koja proističe iz nepreciznosti samog jezika
Primer 1. Zameniti sadržaje dve memorijske lokacije, A i B
 Rešenje – potrebna je treća, pomoćna, lokacija
1. sadržaj lokacije A zapamtiti u pomoćnu lokaciju, P
2. sadržaj lokacije B zapamtiti u lokaciju A
3. sadržaj lokacije P zapamtiti u lokaciju B
4. kraj
2

A B

1 3

Primer 2
 Ciklički pomeriti u levo sadržaje lokacija A, B i C

P A B C

 iz A u P
 iz B u A
 iz C u B
 iz P u C
 kraj

Primer 3. Ciklički pomeriti u levo sadržaje lokacija a1, a2, ..., an.
1 2 3 n

41
Ivan P. Stanimirović Uvod u programiranje

P a1 a2 a3 an-1 an

n+1

• iz a1 u P
• iz ai u ai-1, za i=2,...,n kako izvršiti pomeranje
• iz P u an za k mesta?
• kraj

Euklidov algoritam za nalaženje NZD dva prirodna broja, m i n


1. Podeliti m sa n i ostatak zapamtiti u r;
2. Ako je r jednako 0, NZD je n i kraj, inače preći na korak 3;
3. Zameniti m sa n, n sa r, i preći na korak 1;

Grafičko predstavljanje algoritma


 Koriste se odredjeni grafički simboli za predstavljanje pojedinih aktivnosti u algoritmu
 Ideja je pozajmljena iz teorije grafova
 Algoritam se predstavlja usmerenim grafom
 čvorovi grafa predstavljaju aktivnosti koje se obavljaju u algoritmu
 potezi ukazuju na sledeću aktivnost koja treba da se obavi
 Polazni čvor u usmerenom grafu koji predstavlja algoritam nema dolaznih potega, a ima samo
jedan izlazni poteg (granu) početak

 Krajnji čvor u grafu koji predstavlja algoritam nema izlaznih potega, a ima samo jedan dolazni
poteg

kraj

 Blok oblika romboida koristi se za označavanje ulaznih i izlaznih aktivnosti

ulaz: izlaz:

 Blok obrade je pravougaonog oblika


obrada

 Blok odluke

da ne
uslov

42
Ivan P. Stanimirović Uvod u programiranje

 Blok spajanja potega

Osnovne algoritamske strukture


 Kombinovanjem gradivnih blokova dobijaju se osnovne algoritamske strukture
 sekvenca
 alternacija (selekcija)
 petlja (ciklus)
 Pomoću osnovnih algoritamskih struktura može se predstaviti svaki algoritam
Sekvenca
 linijska struktura koja se dobija kaskadnim povezivanjem blokova obrade

A1 • Algoritamski koraci se izvršavaju redom, jedan za drugim


• Algoritamski korak A , i=2,...,n ne može da otpočne sa izvršenjem
i
dok se korak Ai-1 ne završi

• sekvenca predstavlja niz naredbi dodeljivanja (:=)


A2

A3
•oblik naredbe:
promenljiva:=vrednost
a:=b
n:=n+1

An

Alternacija (selekcija)
 Omogućava uslovno izvršenje niza algoritamskih koraka

da
da ne uslov
uslov

S2 S2 S S1
S S1 1
1

• Blokovi označeni sa S1 i S2 mogu sadržati bilo koju kombinaciju osnovnih algoritamskih


struktura.

43
Ivan P. Stanimirović Uvod u programiranje

Primer 1. Nacrtati dijagram toka algoritama kojim se odredjuje veći od dva zadata broja korišćenjem
formule
a, a  b
max{ a, b}  
b, a  b

Naći maksimum od tri zadata broja a, b i c


max{ a, b, c}  max{max{ a, b}, c}

Petlja (ciklus)
 Omogćava da se algoritamski koraci ponavljaju više puta.

Pravila
 Ako petlja počne unutar then bloka ili else bloka, u tom bloku se mora i završiti!
 Dozvoljene su paralelne (ugnježdjene) petlje.
 su dozvoljene petlje koje se seku!

Paralelne petlje

44
Ivan P. Stanimirović Uvod u programiranje

Primer - Euklidov algoritam


poc poc

m, m,n
n

r:=“ostatak od m/n”
r:=“ostatak od m/n”
m:=n
ne
do-while n:=r
r ≠0
repeat-until
da

m:=n naredba koja ne


n:=r menja uslov! r=0
r:=“ostatak od m/n”
da

nzd:=m

nzd:=n
nzd

nzd
kraj

kraj

Predstavljanje algoritma pomoću pseudo koda


 Koristi se tekstualni način dopunjen formalizmom
 svaka od osnovnih algorotamskih struktura se predstavlja na tačno definisani način:
 sekvenca se predstavlja kao niz naredbi dodeljivanja odvojenih simbolom ;
a:=5;
b:=a*b;
c:=b-a;
 Alternacija
if (uslov) then ili if (uslov) then
niz_naredbi niz_naredbi
else endif;
niz_naredbi
endif;

if (a>b) then ili max:=a;


max:=a if (max<a) then
else max:=b
max:=b endif;
endif;
Alternacija, primer2

45
Ivan P. Stanimirović Uvod u programiranje

 max(a,b,c)
if (a>b) then
if (a>c) then
max:=a
else
max:=c
endif;
else
if (b>c) then
max:=b
else
max:=c
endif;
endif;
Petlje – pseudo kod
while (uslov) do repeat
niz_ naredbi niz_naredbi
enddo; until (uslov);
Primer: Primer:
r:=“ostatak od m/n”
while (r≠0) do repeat
m:=n; r:=“ostatak od m/n”;
n:=r; m=n;
r:=“ostatak od m/n”; n:=r;
enddo; until (r=0);
nzd:=n; nzd:=m;

Strukturogrami
 Kombinacija grafičkog i pseudo koda;
 Koriste se kao prikladna dokumentacija za već završene programe.
 Program se piše tako da se popunjavaju određene geometrijske slike
if uslov
while uslov for i:=n1,n2,n3
else
sekvenca then telo
petlje
telo telo
S1 S2 petlje petlje
until uslov

Strukturogrami – primer
if a>b if a>b
then else else
then

max:=a; max:=b; if a>c if b>c


then else then else

max:=c; max:=b; max:=c;


max:=a;
46
Ivan P. Stanimirović Uvod u programiranje

4.2. Sekvenca naredbi i blok


Sekvenca naredbi je jedan od osnovnih koncepata u strukturnim jezicima, uveden radi lakše
implementacije drugih upravljačkih struktura. Prvi put se javlja u jeziku Algol 60, u kome se naziva i
složena naredba, a definisan je kao niz naredbi ograničen zagradama begin i end:
begin
naredba_1;
……….
naredba_n
end
Sekvenca naredbi se u Algol-u 60 može pojaviti svuda gde je sintaksom dozvoljena naredba. Time
ovaj koncept postaje jako sredstvo apstrakcije naredbe.
U Algol-u 60 se prvi put javlja i koncept bloka kao uopštenje koncepta sekvence naredbi. Blok je
po definiciji upravljačka struktura koja sadrži opise lokalnih promenljivih i sekvencu naredbi. Kao i
sekvenca, zatvara se zagradama begin i end.
begin
deklaracija_1;
……….
deklaracija_m;
naredba_1;
……….
naredba_n
end

4.2.1. Globalne i lokalne promenljive


Globalna promenljiva (global variable) je takva promenljiva koja je deklarisana za upotrebu kroz
ceo program. Trajanje globalne varijable je celokupno vreme izvršenja programa: varijabla se kreira
kada program startuje, a uništava odmah po završetku programa.
Lokalna promenljiva (local variable) je takva promenljiva koja je deklarisana unutar nekog bloka,
za upotrebu samo unutar tog bloka. Trajanje lokalne varijable je aktivacija bloka koji sadrži
deklaraciju te varijable: varijabla se kreira na ulasku u blok, i uništava se na izlasku iz bloka.
Blok (block) je programska konstrukcija koja uključuje lokalne deklaracije. U svim programskim
jezicima, telo neke procedure jeste blok. Neki jezici takođe imaju blok komande, kao na primer ‘‘{ . . .
}’’ u C, C++, ili JAVA, ili ‘‘declare . . . begin . . . end;’’ u ADA. Aktivacija (activation) nekog bloka
je vremenski interval u kome se taj blok izvršava. Partikularno, aktivacija procedure je vreme interval
između poziva i vraćanja vrednosti. U toku jednog izvršenja programa blok može biti aktiviran
nekoliko puta, tako da lokalna promenljiva može imati nekoliko trajanja.
Promenljive opisane u jednom bloku su lokalne promenljive tog bloka, a globalne za sve blokove
sadržane u njemu. Ukoliko se u nekom bloku predefinišu promenljive već definisane u spoljašnjem
bloku, u unutrašnjem bloku važe te nove definicije kao lokalne definicije bloka. Van bloka prestaje
dejstvo lokalnih definicija unutrašnjeg bloka. Razmotrimo sledeći primer, koji je konstruisan sa
idejom da ilustruje dejstvo lokalnih i globalnih definicija.
Primer. Globalne i lokalne promenljive.
A: begin real a; ... Pa;
B: begin real b; ... Pb end;
C: begin real c; .. PC;
D: begin real d; . .. Pd end;
E: begin real e; ... Pe end;
end;
F: begin real f; .. Pf;
G; begin real g; ... Pg end;
end;

47
Ivan P. Stanimirović Uvod u programiranje

end;
U ovom primeru postoji sedam blokova (označeni oznakama A:, B:, C:, D:, E:, F: i G:) i u svakom
od ovih blokova opisana je po jedna promenljiva. Sledeća tabela daje podatke o svim blokovima u
programu. Slovo L označava da je promenljiva lokalna, a G da je globalna.

Blok
Promenljiva A B C D E F G
a L G G G G G G
b L
c L G G
d L
e L
f L G
g L

U sledećem primeru dat je ilustrovan pojam bloka kao i pojam lokalnih i globalnih promenljivih.
Primer. Doseg i sakrivanje u C++.
int x=0; // globalno x
void f () {
int y=x, // lokalno y, globalno x;
x=y; // lokalno x, sakriva globalno x
x=1; // pristup lokalnom x
::x=5; // pristup globalnom x
{ int x; // lokalno x, sakriva prethodno x
x=2; // pristup drugom lokalnom x
}
x=3; // pristup prvom lokalnom x
}
int *p=&x; // uzimanje adrese globalnog x

#include<stdio.h>
int x=0; // globalno x
void main ()
{ int y=x, // lokalno y, globalno x;
x=y; // lokalno x, sakriva globalno x
printf("x = %d\n",x);
x=1; // pristup lokalnom x
printf("x = %d\n",x);
::x=5; // pristup globalnom x
printf("x = %d\n",x);
{ int x; // lokalno x, sakriva prethodno x
x=2; // pristup drugom lokalnom x
printf("x = %d\n",x);
}
// x=3; // pristup prvom lokalnom x
printf("x = %d\n",x);
int *p=&x;
printf("x = %d\n",*p);
}
Primer. Blok u jeziku C.
#include<stdio.h>
void main()
{ float a,b,c,d;
a=1.0; b=2.0; c=3.0; d=4.0;
printf("Spoljasnji blok a=%f b=%f c=%f d=%f\n",a,b,c,d);
{ float c,d,e,f;
c=a+10; d=b+20; e=c+30; f=d+40;

48
Ivan P. Stanimirović Uvod u programiranje

printf("Unutrasnji blok a=%f b=%f c=%f d=%f e=%f f=%f\n",


a,b,c,d,e,f);
}
printf("Spoljasnji blok a=%f b=%f c=%f d=%f\n", a,b,c,d);
}
U ovom primeru postoje dva bloka: prvi u kome se definišu promenljive a, b, c i d i drugi u kome
su promenljive c i d predefinisane i promenljive e i f prvi put definisane. Kako je drugi blok unutar
prvog dejstvo ovih definicija je sledeće:
• a, b, c i d su lokalne promenljive prvog bloka.
• c, d, e i f su lokalne promenljive drugog bloka.
• a i b važe i u drugom bloku, ali kao globalne promenljive.
• c i d su opisane i u prvom i u drugom bloku pa se u svakom od ovih blokova mogu koristiti
nezavisno od njihove namene u drugom bloku.
• e i f se mogu koristiti samo u drugom bloku, dok su u prvom nedefinisane.
Kao posledicu ovako postavljenih definicija promenljivih naredbom za štampanje u umetnutom
bloku štampaju se brojevi 1.0, 2.0, 11.0, 22.0, 41.0 i 62.0, dok naredba za štampanje u spoljašnjem
bloku daje: 1.0, 2.0, 3.0 i 4.0.
Kako dejstvo lokalnih promenljivih prestaje po izlasku iz bloka, kod ponovnog ulaska u isti blok
one su nedefinisane i potrebno je da im se ponovo dodele neke inicijalne vrednosti.
Sekvenca naredbi je u istom ovom obliku zastupljena i u Pascal-u, dok je struktura bloka
izostavljena. U C postoje oba koncepta ali su begin i end zamenjeni zagradama { i }. To ilistruje
sledeći primer.
Kod novijih jezika kod kojih je zastupljen koncept ključnih reči kojima se otvaraju i zatvaraju
delovi upravlajčke strukture, sekvenca naredbi ne postoji kao odvojena struktura već je sastavni deo
drugih upravljačkih struktura.

4.3. Struktura selekcije


Struktura selekcije omogućava definisanje više mogućih tokova programa i jedno je od osnovnih
sredstava za pisanje fleksibilnih programa. Strukture selekcije dele se u dve osnovne grupe. Jednoj
pripadaju takozvane if-selekcije, a drugoj višestruka selekcija.
If-selekcije se obično javljaju kao if-then i if-then-else struktura, pri čemu prva omogućava izbor
posebnog toka u zavisnosti od određenog uslova, a druga izbor jedne ili druge alternative u zavisnosti
od toga da li je određeni uslov ispunjen.

4.3.1. If-then struktura


Na sledećoj slici prikazan je dijagram toka koji ilustruje grafički prikaz ove strukture na nivou
algoritma.
true
uslov
false niz naredbi

If-then struktura se obično implementira kao poseban, jednostavniji slučaj if-then-else strukture.
Jedino kod nekih starijih jezika (BASIC, FOTRAN) ona postoji kao zasebna upravljačka struktura.
U FORTRAN-u se if-then struktura naziva logičkom IF naredbom i ima sledeću formu:
IF (Iogički izraz) naredba

49
Ivan P. Stanimirović Uvod u programiranje

Naredba koja sledi iza logičkog izraza izvršava se samo ako je vrednost logičkog izraza jednaka
TRUE, inače se tok programa prenosi na sledeću naredbu.
Jedan od problema u primeni if naredbe jeste implementacija slučaja kada se izvršava veći broj
naredbi u jednoj ili then ili else grani. U programskim jezicima koji ne podržavaju koncept sekvence
naredbi, ova struktura se implementira koristeći GOTO naredbu.
Uobičajeni način korišćenja ove naredbe u FORTRAN-u IV ilustruje sledeći primer.
Primer. Logička IF naredba u FORTRAN-u. U naredbi je sa Uslov označena logička promenljiva.
IF (.NOT. Uslov) GO TO 20
I=1
J=2
K=3
20 CONTINUE
U ovom primeru, ako je vrednost promenljive Uslov jednaka FALSE program se nastavlja od
naredbe sa oznakom 20. Za vrednost TRUE iste promenljive program se nastavlja naredbom I=1 koja
sledi neposredno iza naredbe IF. Upotreba GO TO naredbe je bila neophodna s obzirom na
nepostojanje sekvence naredbi u FORTRANu IV.
Uvođenjem koncepta sekvence naredbi, if-then naredba u Algol-u dobija drugačiju sintaksu,
onakvu kakvu poznajemo u savremenim proceduralnim jezicima. U opštem slučaju njena struktura je
definisana na sledeći način:
if (logički izraz) then
begin
naredba_1;
...
naredba_n
end;
Sekvenca naredbi, obuhvaćena zagradama zagradama ili između begin i end, sastavni je deo if
naredbe. Ta sekvenca naredbi se izvršava za vrednost true logičkog izraza. Za vrednost false sekvenca
naredbi se preskače i program nastavlja sa prvom naredbom koja sledi iza zagrade end.
Primer. If-then naredba u Algol-u 60.
if (uslov) then
begin
i:=1;
j:=2;
k:=3
end;
If-then struktura se javlja u različitim oblicima u mnogim jezicima čiji su koreni u Algol-u 60,
uključujući i FORTRAN 77 i FORTRAN 90.
U FORTRAN-u se može koristiti IF-THEN struktura, prema sledećoj sintaksi:
IF(uslov)
naredba
END IF
Uočimo da se u ovom jeziku koriste ključne reči kojima se otvaraju i zatvaraju pojedini delovi
strukture.
U jeziku Pascal je if-then struktura preuzeta iz Algol-a. U jeziku C se umesto reči begin i end
koriste zagrade { i }, redom.

4.3.2. If-then-else struktura


Dijagram toka if-then-else strukture koji ilustruje smisao ove strukture na nivou algoritma prikazan je
na slici.

50
Ivan P. Stanimirović Uvod u programiranje

false true
uslov

else-grana then-grana

Ova upravljačka struktura se prvi put javlja u Algol-u 60 i to u obliku:


if (logički_izraz)
then naredba
else naredba;
Naredba koja sledi iza ključne reči then predstavlja then granu programa, a naredba iza else
predstavlja njenu else granu. Kada je vrednost logičkog izraza true izvršava se then grana, a kada je
vrednost false - else grana programa.
Ova upravljačka struktura postoji u svim proceduralnim jezicima sa određenim varijacijama u
sintaksi. U Pascal-u je prihvaćena sintaksa iz Algol-a. Sledeći primer ilustruje mogućnosti njene
primene.
Primer.
if (broj = 0) then
res := 0
else
res := 1;
Ovako definisana if-then-else struktura ima niz nedostataka koji posebno dolaze do izražaja kada se
if naredbe ugrađuju jedna u drugu. Na primer u Pascal-u je moguće napisati sledeću sekvencu naredbi:
if (sum = 0) then
if (broj = 0)
then res := 0
else res := 1;
Ova sekvenca naredbi može da bude protumačena na dva različita načina u zavisnosti od toga da li
else grana pripada prvoj ili drugoj if naredbi. U jezicima C, Pascal, kao i u više drugih jezika koji
koriste isti koncept za razrešavanje ovakvih situacija: primenjuje se semantičko pravilo da se else
grana uparuje sa najbližom neuparenom then granom. Očigledno je da u ovakvim slučajevima može
da dođe do pogrešnog tumačenja pojedinih segmenata programa. U Algol-u se ovaj problem razrešava
na sintaksnom nivou. Naime, u Algol-u nije dozvoljeno ubacivanje if naredbi u then granu već se
nadovezivanje if naredbi može vršiti samo po else grani. Kada je neophodno da se po then grani vrši
dalje grananje obavezna je upotreba zagrada kojima se naredba koja se ubacuje transformiše u
takozvane proste naredbe koje se jedino mogu naći u then grani. Prethodni primer bi, u Algol-u, bio
napisan kao u sledećem primeru.
Primer. Umetanje if naredbi u Algol-u.
if sum = 0 then
begin
if broj = 0
then res := 0
else res := 1
end;
Ako u prethodnom primeru else grana treba da bude sastavni deo prve if naredbe dati deo programa
treba da bude napisan kao u primeru koji sledi.
Primer. Umetanje if naredbi u Algol-u (druga verzija).
if sum = 0 then
begin
if broj = 0
then res := 0

51
Ivan P. Stanimirović Uvod u programiranje

end
else res := 1;
Napomena: Jedna od najčešćih grešaka je da se test za jednakost “==” zameni sa dodeljivanjem “=”.

Primer. Else se pridružuje najbližem if.

Primeri u C.
Primer. Napisati program kojim se dati brojevi x, y, z udvostručuju ako je x>= y>= z, a u protivnom
menjaju znak.
main()
{ float x,y,z;
printf("Zadati x,y,z:\n"); scanf("%f%f%f",&x,&y,&z);
if((x>=y) && (y>=z)) { x*=2; y*=2; z*=2; }
else { x=-x; y=-y; z=-z; }
printf("x=%f y=%f z=%f", x,y,z);
}

Kod else-if iskaza je važno da rezervisana reč else odgovara prethodnom slobodnom if, ukoliko to nije
drugačije određeno velikim zagradama.

Primer. Izračunati
-5, x<0,
y= x+2, 0<=x<1,
3x-1, 1<=x<5,
2x, x>=5.
void main()
{ float x,y;
scanf("%f",&x);

52
Ivan P. Stanimirović Uvod u programiranje

if(x<0) y=-5;
else if(x<1) y=x+2;
else if(x<5) y=3*x-1;
else y=2*x;
printf("y= %f\n", y);
}

Primer. Urediti tri zadata realna broja u poredak x < y < z.


#include<stdio.h>
main()
{ float x,y,z,p;
scanf("%f%f%f",&x,&y,&z);
if(x>y) { p=x; x=y; y=p; }
if(x>z) { p=x; x=z; z=p; }
if(y>z) { p=y; y=z; z=p; }
printf("x= %f y= %f z= %f\n",x,y,z);
}

Primer. Data su tri realna broja u poretku x < y < z. Umetnuti realni broj t tako da među njima bude
odnos x < y < z < t.
void main()
{ float x,y,z,t,p;
scanf("%f%f%f%f",&x,&y,&z,&t);
if(t<x) { p=t; t=z; z=y; y=x; x=p; }
if(t<y) { p=t; t=z; z=y; y=p; }
if(t<z) { p=t; t=z; z=p; }
printf("x= %f y= %f z= %f t= %f\n",x,y,z,t);
}

Primer. Diskutovati rešenje sistema linearnih jednačina


a1 x + b1 y = c1
a2 x + b2 y = c2.
void main()
{ float a1,b1,c1,a2,b2,c2,d,dx,dy,x,y;
printf("Koeficijenti prve jednacine?"); scanf("%f%f%f",&a1,&b1,&c1);
printf("Koeficijenti druge jednacine?");
scanf("%f%f%f", &a2,&b2,&c2);
d=a1*b2-a2*b1; dx=c1*b2-c2*b1; dy=a1*c2-a2*c1;
if(d!=0){x=dx/d; y=dy/d; printf("x=%f y=%f\n",x,y);}
else if(d==0 && dx==0 && dy==0)
{ printf("Sistem je neodređen ");
printf("resenje je oblika X,(%f-%fX)/%f\n",c1,a1,b1);
}
else printf("Sistem je nemoguc\n");
}
Primer. Rešavanje jednačine ax2+bx+c=0 u jezicima Pascal i C.
program Kvadratna_Jednacina;

var a,b,c,D,x1,x2,x,Re,Im:real;

begin
readln(a,b,c);
if a<>0 then begin
D:=sqr(b)-4*a*c;
if(D>0) then begin
x1:=(-b+sqrt(D))/(2*a); x2:=(-b-sqrt(D))/(2*a);
writeln('x1= ',x1:0:3,' x2= ',x2:0:3);
end
else if D=0 then begin

53
Ivan P. Stanimirović Uvod u programiranje

x1:=-b/(2*a); writeln('x1= ',x1:0:3,' x2= ',x1:0:3);


end
else begin
Re:=-b/(2*a); Im:=sqrt(-D)/(2*a);
write(Re:0:3,'+i*',Im:0:3); writeln(' ',Re:0:3,'-i*',Im:0:3);
end
end
else if b<>0 then begin
x1:=-c/b; writeln(x1:0:3);
end
else if(c<>0) then writeln('Jednacina nema resenja')
else writeln('Identitet');
end.

#include<stdio.h>
#include<math.h>
void main()
{ float a,b,c,D,x1,x2,Re,Im;
scanf("%f%f%f",&a,&b,&c);
if(a)
{ D=b*b-4*a*c;
if(D>0)
{ x1=(-b+sqrt(D))/(2*a); x2=(-b-sqrt(D))/(2*a);
printf("x1= %f x2= %f\n",x1,x2);
}
else if(D==0)
{ x1=-b/(2*a); printf("x1= %f x2= %f\n",x1,x1); }
else
{ Re=-b/(2*a); Im=sqrt(-D)/(2*a);
printf("%f+i*%f, %f-i*%f\n",Re,Im,Re,Im);
}
}
else if(b)
{ x1=-c/b; printf("%f\n",x1); }
else if(c) printf("Jednacina nema resenja\n");
else printf("Identitet\n");
}

Primer. U gradu A se nalazi zaliha goriva od V (0 < V < 2000000000) litara, od koje kamion-cisterna
treba da dostavi što je moguće veću količinu u grad B. Od grada А do gada B ima tačno d (0 < d 
2000) kilometara. Cisterna troši litar na jedan kilometar, a može da primi ukupno C (0 < C  5000)
litara za prevoz i potrošnju.
Napisati program koji za date V, d, C, ispisuje koliko najviše goriva može da se dostavi iz A u B, i
koliko PRI TOME najviše može ostati u A. Cisterna može ostati u gradu koji daje povoljniji ishod.
Test primer:
2000 100 1000 1700 0
#include <stdio.h>
void main ()
{ long V, d, C, A, B;
printf("Unesi kolicinu u gradu A: "); scanf ("%ld",&V);
printf("Unesi rastojanje između gradova: "); scanf ("%ld",&d);
printf("Unesi kapacitet cisterne: "); scanf ("%ld",&C);
A=V; B=0;
if((C>d) &&(V>=C))
{ if(C>2*d)
{ A=V%C; B=(C-2*d)*(V/C);
if(A<=d) B=B+d;

54
Ivan P. Stanimirović Uvod u programiranje

else
{ if(A-d>d){B=B+A-d; A=0;}
else B=B+d;
}
}
else {A=V-C; B=C-d;}
} y
printf ("A= %ld B= %ld\n", A, B);
5

Primer. Ispisana je sledeća spirala brojeva oko zamišljenog koordinatnog sistema:

16 15 14 13 12

17 4 3 2 11

-5 18 5 0 1 10 5 x

19 6 7 8 9

20 21 22 23 24 25

Za proizvoljan prirodan broj n odrediti njegove koordinate u tom koordinatnom sistemu.


(PASCAL)
-5
PROGRAM spirala(input,output);
VAR n, r, x, y :integer;
BEGIN
read(n); r := trunc((sqrt(n) + 1)/2);
IF n<=4*sqr(r) - 2 * r THEN
BEGIN
x:=r; y:=n - (4 * sqr(r) - 3 * r)
END
ELSE IF n <=sqr(r) THEN
BEGIN
y:=r; x := (4*sqr(r) -r) - n
END
ELSE IF n<=4*sqr(r) + 2 * r THEN
BEGIN
x:=-r; y:=(4*sqr(r) + r) - n
END
ELSE BEGIN
y:=-r; x:= n - (4*sqr(r) + 3 * r)
END;
WRITE ('n = ',n,'x = ', x,'y = ', y)
END.
(C)
#include<stdio.h>
#include<math.h>
main()
{ int n,r,x,y;
scanf("%d", &n); r=(sqrt(n)+1)/2;
if(n<=4*r*r-2*r) { x=r; y=n-(4*r*r-3*r); }
else if(n<=4*r*r) { y=r; x=4*r*r-r-n; }
else if(n<=4*r*r+2*r) { x=-r; y=4*r*r+r-n; }
else { y=-r; x=n-(4*r*r+3*r); }
printf("\n Za n=%d koordinate su x=%d y=%d\n",n,x,y);
}

55
Ivan P. Stanimirović Uvod u programiranje

4.3.3. Operator uslovnog prelaza u C


Operator uslovnog prelaza ?: je neobičan. Pre svega, to je ternarni operator, jer uzima tri izraza za
svoje argumente. Način na koji se on primenjuje je takođe neobičan:
exp1 ? exp2 : exp3;
Prvi argument je pre znaka pitanja '?'. Drugi argument je između '?' i ':', a treći posle ':'. Semantika
ovakvog izraza je sledeća. Prvo se izračunava izraz exp1. Ako je njegova vrednost različita od 0 (tj.
ako je jednaka true), tada se evaluira izraz exp2, i njegova vrednost je vrednost celog izraza. Ako je
vrednost izraza exp1 nula (false), tada se evaluira izraz exp3, i njegova vrednost se vraća kao rezultat.
Na taj način, ovaj izraz predstavlja zamenu za if-then-else naredbu.
Primer. Umesto izraza
if(y<z) x=y;
else x=z;
kojim se izračunava x=min{y,z}, može se pisati
x=(y < z) ? y:z;
Zagrade se mogu izostaviti.
Prioritet operatora uslovnog prelaza je veći od prioriteta operatora dodeljivanja, a njegova
asocijativnost je ''s desna na levo''.
Primer. Vrednost izraza
(6>2)?1:2
jednaka je 1, dok je vrednost izraza
(6<2)?1:2
jednaka 2.
Ako je izraz posle ':' takođe uslovni izraz, dobijamo else-if operator.

Primeri.
1. Vrednost izraza

s= -1, x < 0,
x * x, x>=0
može se izračunati pomoću
s=(x < 0) ? -1 : x*x;

2. Vrednost s = sgn(broj) se može izračunati pomoću izraza


s=(broj < 0) ? -1 : ((broj==0) ? 0 : 1);
3. Bez korišćenja operatora if napisati program koji za zadate x, y izračunava
z= min {x,y}, y>= 0,
max {x2,y2}, y<0.
z=(y>=0) ? ((x<y) ? x:y) : ((x*x>y*y) ? x*x : y*y);

4.4. Struktura višestruke selekcije


Struktura višestruke selekcije omogućava izbor jedne od više mogućih naredbi ili grupa naredbi u
zavisnosti od vrednosti određenog uslova. Struktura višestruke selekcije se koristi kao zamena za
komplikovane upravljačke strukture sledećeg oblika, u kojima se funkcija if mnogo puta ponavlja.
Graf na sledećoj slici ilustruje ovu upravljačku strukturu na nivou algoritma.

56
Ivan P. Stanimirović Uvod u programiranje

Kako se svaka višestruka selekcija može simulirati običnim if-then-else grananjem, na sledećoj slici
prikazan je dijagram toka koji odgovara višestrukom grananju.

Ova struktura koja je u svom razvoju pretrpela mnogo izmena do jednog modernog oblika koji se
danas u manje-više sličnim varijantama javlja u svim programskim jezicima.

4.4.1. Višestruka selekcija u C


U programskom jeziku C naredba za višestruko grananje ima dosta zastarelu koncepciju. To je
switch naredba koja u opštem slučaju ima sledeći oblik:
switch(izraz)
{ case vrednost11: [case vrednost12: … ]
operator11
......
break;
case vrednost21: [case vrednost22: …]
operator21
......
break;
......
case vrednostn1: [case vrednostn2: …]
operatorn1
......
break;
default:
operator01
......
break;
}
sledeća naredba;

57
Ivan P. Stanimirović Uvod u programiranje

Semantika ove naredbe je sledeća: izračunava se vrednost izraza izraz, koji se naziva selektor.
Vrednost izraza izraz mora da bude celobrojna (ili znakovna, koja se automatski konvertuje u
odgovarajuću celobrojnu vrednost). Dobijena vrednost se upoređuje sa vrednostima vrednost11,
vrednost12, ..., koji moraju da budu celobrojne konstante ili celobrojni konstantni izrazi. Ove
vrednosti se mogu posmatrati kao obeležja za određenu grupu operatora. Ako je pronađeno obeležje
čija je vrednost jednaka vrednosti izraza izraz, izračunavaju se operatori koji odgovaraju toj vrednosti.
Ključna reč break predstavlja kraj jedne case grane, odnosno kraj grupe operatora sadržanih u nekoj
case grani. Ako nije pronađena vrednost u case granama jednaka vrednosti izraza izraz, izračunavaju
se iskazi u default grani; ako je izostavljena alternativa default, neće se izvršiti ni jedna od alternativa
operatora switch.
Izraz prema kome se vrši selekcija i konstante u pojedinim granama treba da budu integer tipa.
Naredbe u granama mogu da budu obične ili složene naredbe i blokovi.
Iako na prvi pogled ova naredba liči na ono što imamo u Pascal-u, radi se o nestrukturnoj naredbi
koja se izvršava tako što se izborom grane određuje samo mesto odakle naredba počinje, a iza toga se
nastavlja njen sekvencijalni tok. To konkretno znači da se naredba u default grani izvršava uvek kao i
to da se naredba u k-toj grani izvršava uvek kada je selektovana neka od prethodnih grana. Da bi se
prekinulo upravljanje pod dejstvom ove naredbe kada se izvrši selektovana grana, odnosno da bi se
postigla semantika case strukture u Pascal-u, potrebno je da se na kraju svake grane upravljanje
eksplicitno prenese na kraj cele switch naredbe. U te svrhe u C-u se koristi naredba break koja
predstavlja izlazak iz switch naredbe. Kôdom iz primera u C-u je realizovano višestruko grananje iz
prethodnog primera gde je korišćena case struktura iz Pascal-a.
Primer. Program kojim se simulira digitron. Učitavaju se dva operanda i aritmetički operator.
Izračunati vrednost unetog izraza.
void main()
{ float op1, op2;
char op;
printf("Unesite izraz \n");
scanf("%f %c %f", &op1, &op, &op2);
switch(op)
{ case '+': printf("%f\n", op1+op2); break;
case '-': printf("%f\n", op1-op2); break;
case '*': printf("%f\n", op1*op2); break;
case '/': printf("%f\n", op1/op2); break;
default: printf("Nepoznat operator\n");
}
}

Operator break se koristi u okviru switch operatora (kasnije i u while, do, for operatorima) da bi se
obezbedio izlaz neposredno na naredbu iza switch strukture. Ukoliko se iza neke grupe operatora u
switch operatoru ispusti break operator, tada se u slučaju izbora te grupe operatora izvršavaju i sve
preostale alternative do pojave break operatora ili do kraja switch operatora.

Primer. Posmatrajmo sledeći program.


void main()
{ int ocena;
scanf("%d",&ocena);
switch(ocena)
{ case 5: printf("Odlican\n"); break;
case 4: printf("Vrlo dobar\n");
case 3: printf("Dobar\n");
case 2: printf("Dovoljan\n"); break;
case 1: printf("Nedovoljan\n"); break;
default: printf("Nekorektna ocena\n:");
}
}

58
Ivan P. Stanimirović Uvod u programiranje

Ukoliko je ocena = 4 ispisuje se sledeći rezultat:


Vrlo Dobar
Dobar
Dovoljan

Operator switch se može realizovati pomoću većeg broja if operatora. Međutim, programi napisani
pomoću switch operatora su pregledniji.
Primer. Za zadati redni broj meseca ispisati broj dana u tom mesecu.
void main()
{ int mesec;
char ch; /* Da li je godina prestupna */
printf("Unesi redni broj meseca: ");
scanf("%d", &mesec);
switch(mesec)
{ case 1:case 3:case 5:case 7:case 8:case 10:case 12:
printf("31 dan\n");
break;
case 4: case 6: case 9: case 11:
printf("30 dana\n);
break;
case 2: printf("Da li je godina prestupna? ");
scanf("%c%c",&ch,&ch);
/* prvo ucitavanje je fiktivno, uzima enter */
if((ch=='D') || (ch=='d')) printf("29 dana\n);
else printf("28 dana\n");
break;
default: printf("Nekorektan redni broj\n");
}
}

Primer. Odrediti sutrašnji datum.


void main()
{unsigned int d,m,g,prestupna;
printf("Unesi datum u obliku ddmmgg:\t");
scanf("%2d%2d%4d",&d,&m,&g);
if(d<1 || d>31 || m<1 || m>12)
{ printf("Nepravilan datum\n"); exit(0); }
prestupna=((g%4==0) && (g%100!=0)) ||
((g%100==0) && (g%400==0));
if(m==2 && d>28+prestupna)
{ printf("Nepravilan datum\n"); exit(0); }
switch(d)
{ case 31:
switch(m)
{ case 1:case 3:case 5:case 7:case 8:case 10: d=1; m++; break;
case 12: d=1; m=1; g++; break;
default: { printf("%2d. mesec ne moze imati 31 dan\n",m);
exit(0);
}
}
break;
case 28: if(!prestupna && (m==2)) { d=1; m=3; }
else d=29;
break;
case 29: if(prestupna && (m==2)) { d=1; m=3; }
else d=30;
break;
case 30: switch(m)

59
Ivan P. Stanimirović Uvod u programiranje

{ case 4: case 6: case 9: case 11:


d=1; m++;
break;
case 2:printf("Februar ne moze imati 30 ana\n");
exit(0);
default:d=31;
}
break;
default:d++;
}
printf("Sledeci dan ima datum:\t%2d\t%2d\t%4d\n",d,m,g);
}
Operator switch se može koristiti umesto if operatora. Na primer, umesto operatora
if(a>b) max=a;
else max=b;
može se pisati
switch(a>b)
{ case 0: max=b; break;
case 1: max=a;
}
Očigledno da ovo nije praktično.

4.5. Programske petlje


U svakom programskom jeziku obično postoje upravljačke strukture kojima može da se definiše
višestruko ponavljanje određene sekvence naredbi na istim ili različitim podacima. To su programske
petlje ili strukture iteracije. Ciklusi omogućavaju da se skupovi srodnih podataka koji se odnose na isti
pojam obrađuju na isti način.
Prema jednoj podeli, programske petlje se mogu podeliti na:
▪ brojačke i
▪ iterativne.
Kod brojačkih petlji se unapred može reći koliko puta se ponavlja telo petlje. Kod iterativnih
programskih ciklusa, nije unapred poznato koliko puta se izvršava telo petlje. Kod ovakvih ciklusa,
kriterijum za njihov završetak je ispunjenje određenog uslova.
Prema drugoj podeli, programske petlje se dele na:
▪ petlje sa preduslovom i
▪ petlje sa postuslovom.
Kod petlji sa preduslovom, izlazni kriterijum se proverava pre nego što se izvrši telo petlje, dok se kod
petlji sa postuslovom prvo izvrši telo petlje pa se zatim proverava izlazni kriterijum.
U savremenim programskim jezicima skoro bez izuzetaka postoje naredbe za definisanje petlji sa
unapred određenim brojem prolaza. To su tzv. brojačke petlje kod kojih postoji brojač (indeks petlje)
kojim se upravlja izvršavanjem petlje. Struktura brojačke petlje u Pascal-u je prikazana na sledećoj
slici.

for I:= pocetni to krajnji

niz naredbi

U ovoj petlji se naredbe u telu petlje izvršavaju za sve vrednosti brojačke promenljive I između
vrednosti izraza pocetni i vrednosti izraza krajnji.

60
Ivan P. Stanimirović Uvod u programiranje

Sa prihvatanjem strukturnog programiranja u novijim jezicima se pojavljuje i logički kontrolisana


petlja kojom se realizuje while (while-do) struktura. Ova struktura predviđa ponavljanje izvršavanja
tela petlje sve dok uslov u zaglavlju petlje ima vrednost true. Kod ovakvih petlji nije unapred poznat
broj izvršavanja tela petlje. Za ove petlje se često koristi i termin pretest petlje, jer se ispitivanje
uslova vrši pre svakog izvršavanja petlje.

ne
uslov
da
niz naredbi

Strukturnim programiranjem definisana je i until struktura (do-while struktura) koja predviđa post-
test uslova, odnosno ispitivanje uslova posle izvršenja tela petlje. Repeat-until struktura je prikazana
na sledećoj slici.

niz naredbi

uslov
ne
da
Poseban oblik petlji sa postuslovom je do-while naredba u C. Ovakva struktura sa postuslovom se
završava kada uslov nije ispunjen.

4.5.1. Programske petlje u C


While naredba u C
Ovom naredbom se realizuju programski ciklusi sa nepoznatim brojem ponavljanja, zavisno od
određenog uslova. Operator while se koristi prema sledećoj sintaksi:
while(izraz)
operator
Efekat ove naredbe je da se telo while ciklusa, označeno sa operator izvršava dok je vrednost izraza
izraz jednaka true (nenula). Kada vrednost izraza izraz postane false (nula), kontrola se prenosi na
sledeću naredbu. Telo ciklusa, označeno sa operator, izvršava se nula ili više puta. Operator može biti
prost ili složen. Svaki korak koji se sastoji iz provere uslova i izvršenja operatora naziva se ''iteracija''.
Ako odmah po ulasku u ciklus izraz ima vrednost ''netačno'' (nula), operator se neće izvršiti.
Primer. Maksimum n unetih brojeva.
main()
{ int i, n;
float max, x;
printf("Koliko brojeva zelite? "); scanf("%d", &n);
while (n<=0)
{ printf("Greska, zahtevan je ceo pozitivan broj.\n");
printf("Unesite novu vrednost: "); scanf("%d", &n);
}
printf("\n Unesite %d realnih brojeva: ", n);
scanf("%f", &x); max = x; i=1;
while (i<=n)
{ scanf("%f", &x); if(max<x) max = x; ++i; }
printf("\n Maksimalni od unetih brojeva: %g\n",max);
}

61
Ivan P. Stanimirović Uvod u programiranje

Primeri u jeziku C

Primer. Izračunati a prema iterativnoj formuli


x0 = a/2; xi+1 = xi - (xi2 - a)/(2xi) = xi +1/2*(a/xi - xi) , i = 0, 1, ...
Iterativni postupak prekinuti kada se ispuni uslov |xi+1 - xi|<10-5.
#include <stdio.h>
main()
{ float a,x0,x1;
scanf("%f",&a)
x0=a/2; x1=(x0*x0-a)/(2*x0);
while(fabs(x1-x0)<1E-5) { x0=x1; x1=(x0*x0-a)/(2*x0); }
printf("%f\n",x1);
}

Primer. Izračunati aritmetičku sredinu niza brojeva različitih od nule. Broj elemenata u nizu nije
unpred poznat.
void main()
{ int brojac=0;
float suma=0, stopcode=0, broj;
printf("Daj niz znakova zavrsen sa %d\n",stopcode);
scanf("%f",&broj);
while(broj != stopcode)
{ suma+=broj; brojac++; scanf("%f",&broj); }
printf("Srednja vrednost= %f\n",suma/brojac);
}

Primer. Dejstvo operatora ++ i - - u ciklusima.


#include <stdio.h>
void main()
{ int i=0;
printf("Prva petlja :\n");
while(i<5) { i++; printf("%5d",i); } /* 1 2 3 4 5*/
printf("\nDruga petlja :\n");
i=0;
while(i++<5) printf("%5d",i); /* 1 2 3 4 5*/
i=0;
printf("\nTreca petlja :\n");
while(++i<5) printf("%5d",i); /* 1 2 3 4*/
}
Primer. Suma celih brojeva unetih preko tastature.
#include <stdio.h>
main()
{ int x,sum=0;
while(scanf("%d",&x)==1) sum+=x;
printf("Ukupan zbir je %d\n",sum);
}

Primer. Ispitati da li je zadati prirodan broj n prost.


#include <math.h>
void main()
{ int i,n,prost;
scanf("%d",&n);
prost=(n%2!=0) || (n==2); i=3;
while(prost && i<=sqrt(n))
{ prost = n%i!=0; i+=2; }

62
Ivan P. Stanimirović Uvod u programiranje

if(prost) printf("%d je prost\n",n);


else printf("%d nije prost\n",n);
}
Primer. Dati su tegovi mase 3k kg, k = 0,1,2,... i to iz svake vrste po jedan. Napisati program koji
određuje koje tegove bi trebalo postaviti levo a koje desno da bi se izmerio predmet težine A kg koji se
nalazi na levom tasu.
#include <stdio.h>
void main()
{ int dteg,lteg,s,a;
printf("Unesite tezinu\n");
scanf("%d",&a);
s=1;
while (a>0)
{ dteg=a%3;
if (dteg==2){ dteg=0; lteg=1; }
else lteg=0;
printf("Teg od %dkg staviti levo: %d, desno: %d\n",s,lteg,dteg);
s*=3;
a=(a+lteg)/3;
}
}

#include <stdio.h>

void main() {
int t, p = 0;
scanf("%d", &t);
while (t > 1) {
if (t % 3 == 1)
{ printf("3^%d ide na desnu\n", p); t--; }
else if (t % 3 == 2)
{ printf("3^%d ide na levu\n", p); t++; }
else { p++; t /= 3; }
}
printf("3^%d ide na desnu\n", p);
}

Primer. Izračunati

x 2k

k 0
(1) k
(2k )!
, x  /2
.
Sumiranje prekinuti kada je apsolutna vrednost poslednjeg dodatog člana manja od zadate tačnosti e.
Koristi se
 x2
ak  ak 1
2k (2k  1)
void main()
{ double c,a,e,x;
int k=0;
scanf("%lf%lf",&x, &e);
while(fabs(a)>=e)
{ k++; a=-(x*x/(2*k*(2*k-1)))*a; c+=a; }
printf("cos(%.2lf)=%.7lf",x,c);
}

Primer. Heksadekadni broj prevesti u dekadni. Unošenje heksadekadnog broja prekinuti kada se
unese karakter koji ne pripada skupu karaktera '0', ... , '9', 'A', ... , 'F'.

63
Ivan P. Stanimirović Uvod u programiranje

#include <stdio.h>
void main()
{int broj,u,k;
char cif;
broj=0;u=1;
printf("unesi heksadekadni broj\n"); scanf("%c",&cif);
u=((cif<='F')&&(cif>='0'));
while (u)
{ if ((cif>='A')&&(cif<='F')) k=cif-55; else k=cif-48;
broj=broj*16+k; scanf("%c",&cif); u=((cif<='F')&&(cif>='0'));
}
printf("%d\n",broj);
}

Primer. Napisati program koji simulira rad džepnog kalkulatora. Program učitava niz brojnih
vrednosti razdvojenih znakovima aritmetičkih operacija +, -, *, / kao i izračunavanje vrednosti izraza
koji je definisan na ovaj način. Aritmetičke operacije se izvršavaju s leva na desno, bez poštovanja
njihovog prioriteta.
#include <stdio.h>
void main()
{ double result, num;
char op;
printf("\n\n"); scanf("%lf" , &num); scanf("%c" , &op);
result = num ;
while (op != '=')
{ scanf("%lf" , &num) ;
switch (op)
{ case '+' : result += num ; break;
case '-' : result -= num ; break;
case '*' : result *= num ; break;
case '/' : result /= num ; break;
}
scanf("%c" , &op);
}
printf("Rezultat je %.10lf." , result) ;
}

4. Dati su tegovi mase 3k kg, k = 0,1,2,... i to iz svake vrste po jedan. Napisati program koji određuje
koje tegove bi trebalo postaviti levo a koje desno da bi se izmerio predmet težine A kg koji se nalazi na
levom tasu.
#include <stdio.h>
void main()
{
int dteg,lteg,s,a;
printf("Unesite tezinu\n");
scanf("%d",&a);
s=1;
while (a>0)
{ dteg=a%3;
if (dteg==2)
{
dteg=0;
lteg=1;
}
else lteg=0;
printf("Teg od %dkg staviti levo: %d, desno:
%d\n",s,lteg,dteg);
s*=3;
a=(a+lteg)/3;

64
Ivan P. Stanimirović Uvod u programiranje

}
}

Primena while ciklusa u obradi teksta u C


Često puta se pri radu sa tekstovima umesto funkcija scanf() i printf() koriste bibliotečke funkcije
getchar() i putchar(). Pre korišćenja ovih funkcija mora da se navede pretprocesorska direktiva
#include<stdio.h>. Ove funkcije se koriste za ulaz i izlaz samo jednog karaktera. Funkcija
putchar() ima jedan znakovni argument. Pri njenom pozivu potrebno je da se unutar zagrada navede
znakovna konstanta, znakovna promenljiva ili funkcija čija je vrednost znak. Ovaj znak se prikazuje
na ekranu. Funkcija getchar() nema argumenata. Rezultat njenog poziva je znak preuzet iz
tastaturnog bafera. Ovom funkcijom se ulazni znak unosi u program.
Primer. Izračunati koliko je u zadatom tekstu uneto znakova 'a', 'b', zajedno 'c' i 'C', kao i broj
preostalih karaktera.
#include <stdio.h>
void main()
{ int c, a_count=0, b_count=0, cC_count=0, other_count=0;
while((c=getchar()) != EOF)
switch (c)
{ case 'a': ++a_count; break;
case 'b': ++b_count; break;
case 'c': case 'C': ++cC_count; break;
default: ++other_count;
}

printf("\n%9s%5d\n%9s%5d\n%9s%5d\n%9s%5d\n%9s%5d\n",
"a_count:", a_count, "b_count:", b_count,
"cC_count:", cC_count, "other:", other_count,
"Total:", a_count+b_count+cC_count+other_count);
}

Primer. Unos teksta je završen prelazom u novi red. Prebrojati koliko je u unetom tekstu znakova
uzvika, znakova pitanja a koliko tačaka.
#include <stdio.h>
void main()
{ char c;
int uzv,upt,izj;
uzv=upt=izj=0;
while((c=getch())!='\n')
switch(c)
{ case '!':++uzv; break;
case '?':++upt; break;
case '.':++izj; break;
}
printf("\n"); printf("Uzvicnih ima %d\n",uzv);
printf("Upitnih ima %d\n",upt); printf("Izjavnih ima %d\n",izj);
}

Kod organizacije while ciklusa mora se voditi računa o tome da telo ciklusa menja parametre koji
se koriste kao preduslov za ciklus, tako da posle određenog broja iteracija postane “netačan”. U
protivnom, ciklus će biti beskonačan.
Do-while naredba u C
Do-while naredba je varijanta while naredbe. Razlikuje se od while naredbe po tome što je uslov na
kraju ciklusa:
do
operator
while(izraz);

65
Ivan P. Stanimirović Uvod u programiranje

sledeća naredba;
Telo ciklusa je označeno sa operator, i izvršava se jedanput ili više puta, sve dok izraz ne dobije
vrednost 0 (false). Tada se kontrola prenosi na sledeću naredbu.

Primeri
Primer. Ispis celog broja s desna na levo.
void main()
{ long broj;
printf("Unesite ceo broj"); scanf("%ld",&broj);
printf("Permutovani broj");
do { printf("%d",broj%10); broj /= 10; } while(broj);
printf("\n");
}

Primer. Izračunati približno vrednost broja  = 3.14159 koristeći formulu


/4 = 1-1/3+1/5-1/7+…
Sumiranje prekinuti kada apsolutna vrednost člana koji se dodaje bude manja od zadate vrednosti eps.
void main()
{ int znak=1;
float clan,suma,eps,i=1.0;
scanf("%f",&eps); clan=suma=1.0;
do
{ clan=znak/(2*i+1); suma+=clan; znak=-znak; i++; }
while(1/(2*i+1)>=eps);
printf("Broj Pi=%f\n",4*suma);
}
For naredba u C
U leziku C, naredba for je povezana sa while naredbom. Preciznije, konstrukcija
for(pocetak; uslov; korekcija)
operator
sledeća naredba
ekvivalentna je sa
pocetak;
while(uslov)
{ operator
korekcija
}
pod uslovom da uslov nije prazan.
Operator koji predstavlja telo ciklusa može biti prost ili složen.
For ciklus oblika
for(; uslov ;) operator
ekvivalentan je while ciklusu
while(uslov) operator

Takođe, ekvivalentni su sledeći beskonačni ciklusi:


for(;;) operator
i
while(1) operator.
For naredba oblika
for (pocetak; uslov; korekcija) operator
može se predstaviti sledećim dijagramom toka

pocetak

66

netačno
uslov <> 0
Ivan P. Stanimirović Uvod u programiranje

Izrazi u zaglavlju petlje mogu da budu i izostavljeni. Na primer, petlja bez drugog izraza izvršava
se kao da je njegova vrednost true, što znači kao beskonačna petlja. Ako su izostavljeni prvi i treći
izraz, telo ciklusa je prazno.
U jeziku C se za definisanje petlje sa unapred definisanim brojem izvršenja tela petlje može
koristiti for naredba. Međutim, for naredba u C je mnogo fleksibilnija od odgovarajućih naredbi u
drugim jezicima. Naime, izrazi u zaglavlju petlje mogu da objedine više naredbi. To znači da se u
okviru petlje može istovremeno definisati više uslova upravljanja vezanih za različite promenljive koje
čak mogu da budu i različitih tipova. Razmotrimo sledeći primer.

Primeri
Primer. Suma prvih n prirodnih brojeva se može izračunati na više različitih načina.
1. sum=0; for(i=1; i<=n; ++i) sum += i;
2. sum=0; i=1; for(; i<=n;) sum += i++;
3. for(sum=0, i=1; i<=n; sum += i, i++);
Primer. Faktorijel prirodnog broja urađen na dva slična načina.
void main()
{ int i,n;
long fak=1;
printf("\n Unesite broj"); scanf("%d",&n);
for(i=1; i<=n; ++i) fak *=i;
printf("%d! = %ld \n",n,fak);
}

void main()
{ int i,n;
long fak=1;
printf("\n Unesite broj"); scanf(" %d",&n);
for(fak=1,i=1; i<=n; fak*=i,++i);
printf("%d! = %ld \n",n,fak);
}

Primer. Izračunati 1! + 2! +…+ n!.


void main()
{ int i,n; long fakt,s;
scanf("%d",&n);
for(s=0, fakt=1, i=1; i<=n; fakt*=i, s+=fakt, i++);
printf("Suma=%ld\n",s);
}

Isti izraz se može izračunati na sledeći način


void main()
{ int n; long s;

67
Ivan P. Stanimirović Uvod u programiranje

scanf("%d",&n);
for(s=0; n>0; s=s*n+n--);
printf("Suma=%ld\n",s);
}

Primer. Izračunati sve trocifrene Armstrongove brojeve.


void main()
{ int a,b,c, i;
for(i=100;i<=999;i++)
{ a=i%10; b=i%100/10; c=i/100;
if(a*a*a+b*b*b+c*c*c==i) printf("%d\n",i);
}
}

Primer. Program za određivanje savršenih brojeva do zadatog prirodnog broja. Savršen broj je jednak
sumi svojih delitelja.
void main()
{ int i,m,n,del,s;
scanf("%d",&m)
for(i=2;i<=m;i++)
{ n=i; s=1;
for(del=2; del<=i/2; del++) if(n%del==0) s+=del;
if(i==s) printf("%d\",i);
}
}

Primer. Tablica ASCII kodova.


void main()
{ signed char c; unsigned char d;
for(c=-128; c<=127; c++) printf("c = %d %c\n",c,c);
for(d=0; d<=255; d++) printf("d = %d %c\n",d,d);
}
Primer. (Pascal) Izračunati

x 2k
cos(x)  
k 0 ( 2k )!

sa tačnošću . Sumiranje prekinuti kada bude ispunjen uslov


|(x2k)((2k)!)| <  .
program suma;
var x,eps,a,s:real;
k:integer;
begin
writeln('Unesite promenljivu x i tacnost '); readln(x,eps);
k:=0; a:=1; s:=a;
while abs(a)>=eps do
begin
a:=sqr(x)/((2*k+1)*(2*k+2))*a; s:=s+a; k:=k+1;
end;
writeln('Suma = ',s:0:6);
end.

Primer. U ravni je dato N tačaka svojim koordinatama (x, y). Napisati program na programskom
jeziku C, koji na svom izlazu daje ukupan broj tačaka koje pripadaju oblastima I, II, III odnosno IV, i
broj tačaka koje ne pripadju ni jednoj od naznačenih oblasti. Oblasti su definisane kružnicom i
pravama kao na slici, a njihove jednačine glase:
K: x2 + (y-1)2 = 1
AB: y = x, BC: y = -x + 2, CD: y = x + 2, DA: y = -x.

68
Ivan P. Stanimirović Uvod u programiranje

Broj tačaka kao i njihove koordinate uneti sa tastature na početku programa.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void main()
{ int n, i;
float x, y;
// Brojaci tacaka u odgovarajucim oblastima.
int br1 = 0, br2 = 0, br3 = 0, br4 = 0, brOstalo = 0 ;
// Promenljie koje definisu polozaje tacaka
int unutarK, ispodAB, iznadBC, iznadCD, ispodDA;
printf("Unesite broj tacaka\n"); scanf("%d", &n);
for (i = 0; i < n; i++)
{ printf("Unesite kordinate tacke %d\n", i + 1); scanf("%f %f", &x, &y);
unutarK = (x*x + (y-1)*(y-1)) < 1;
ispodAB = y < x;
iznadBC = y > -x + 2;
iznadCD = y > x + 2;
ispodDA = y < -x;
if (unutarK)
{ // Tacka je unutar kruznice
if (ispodAB) br1++;
else if (iznadBC) br2++;
else if (iznadCD) br3++;
else if (ispodDA) br4++;
}
}
brOstalo = n - br1 - br2 - br3 - br4;
printf("Brojevi tacaka u oblsatima I, II, III, IV respektivno iznose:
%d %d %d %d\n", br1, br2, br3, br4);
printf("Broj tacaka koje ne pripadaju ni jednoj oblasti iznosi: %d\n",
brOstalo);
}

4.6. Formalizacija repetitivnih iskaza


Neka je B logički izraz, a S iskaz. Tada:
while B do S (1)
označava ponavljanje radnje definisane iskazom S sve dok izračunavanje izraza B daje vrednost true.
Ako je vrednost izraza B jednaka false na samom početku procesa obavljanja radnje definisane sa (1),
iskaz S neće biti uopšte izvršen. Iskaz (1) se grafički predstavlja na sledeći način:

(2)

69
Ivan P. Stanimirović Uvod u programiranje

Efekat iskaza while B do S može se rigorozno definisati tako što se kaže da je on ekvivalentan
efektu iskaza:
if B then
begin
S;
while B do S (3)
end.

(4)

Ovakva definicija znači da dijagrami (2) i (4) opisuju ekvivalentne procese izvršenja (radnje).
Primer while B do S iskaza dat je u programu (5), koji izračunava sumu h(n) = 1+1/2+ . . . +1/n.
var n : integer; h : real;
h :=0;
while n>0 do (5)
begin
h := h+1/n; n := n—1
end.
Drugi oblik repetitivnog iskaza je:
repeat S until B, (6)
gde je S niz iskaza a B logički izraz. Iskaz (6) definiše sledeću radnju: izvršava se iskaz S, a zatim se
izračunava izraz B. Ako je rezultat izračunavanja izraza B jednak false, ponovo se izvršava iskaz S, i
tako dalje. Proces ponavljanja radnje definisane sa S završava se kada izračunavanje izraza B da true.
Struktura ovako definisanog repetitivnog iskaza predstavlja se sledećim dijagramom:

(7)

Poređenjem (2) i (7) zaključujemo da se u (7) iskaz S mora izvršiti bar jednom, dok se u (2) on ne
mora uopšte izvršiti. Kako se u prvom slučaju B izračunava pre svakog izvršenja iskaza S, a u drugom
nakon svakog izvršenja iskaza S, razlozi efikasnosti nalažu da B bude u što je moguće prostijoj formi.
Rigorozna definicija radnje određene iskazom repeat S until B daje se na taj način što se
kaže da je ona ekvivalentna radnji koju određuje iskaz:
begin
S;
if B then
repeat S until B

70
Ivan P. Stanimirović Uvod u programiranje

end. (8)

(9)

Ovo znači da dijagrami (7) i (9) opisuju ekvivalentne radnje. Kako se u (2) i (7) pojavljuju
zatvorene putanje ili petlje, oba ova iskaza se često i nazivaju petljama. U njima se S se naziva telom
petlje.
Primer repeat iskaza dat je u programu (10), koji izračunava sumu h(n)=1+1/2+ . . .+ 1/n:
var n: integer; h: real;
h:=0;
repeat
h:= h+1/n; n:=n-1 (10)
until not(n>0).
Fundamentalni problem vezan za repetitivnu kompoziciju iskaza ilustrovaćemo primerima (5) i
(10). Proces izvršenja iskaza (10) je konačan samo ako u početku važi n>0. Za n<0 (10) predstavlja
beskonačnu petlju. S druge strane, program (5) se ponaša korektno, čak i ako je n<0, tj. proces
njegovog izvršavanja je konačan. Vidimo, dakle, da pogrešno koncipiran repetitivni iskaz može
opisivati radnju beskonačnog vremenskog trajanja.

4.7. Nasilni prekidi ciklusa


Petlje razmatrane u prethodnim primerima imaju zajedničku karakteristiku da se iz petlje izlazi ili
na kraju, kada se završi sekvenca naredbi koja čini telo petlje, ili na samom početku pre nego i
započne ta sekvenca naredbi, zavisno od vrste petlje i ispunjenja uslova. U takvim slučajevima, petlja
se završava na osnovu izlaznog kriterijuma, koji je postavljen kao preduslov ili postuslov. Međutim, u
određenim slučajevima pogodno je da programer sam odredi mesto izlaska iz petlje. U novijim
programskim jezicima, obično postoji jednostavan mehanizam za uslovni ili bezuslovni izlazak iz
petlje. U programskim jezicima C i Pascal takva naredba se naziva break.
U programskom jeziku C za bezuslovni izlazak iz najbliže petlje koristi se naredba break. Tada je
njeno značenjem slično kao i kod switch naredbe.
Primer. Naredba break za bezuslovni izlazak iz petlje u C.
sum=0;
while (sum < 2000)
{ scanf(“%d”, &podatak);
if(podatak < 0) break;
sum = sum + podatak;
}
U svakom prolazu kroz petlju u ovom primeru učitava se po jedan podatak i dodaje sumi. Zaglavljem
petlje je definisano da se sumiranje izvršava sve dok se sumiranjem ne dostigne vrednost 2000.
Međutim, ukoliko se učita negativni podatak, petlja se prekida i program se nastavlja sa prvom
naredbom iza petlje.

71
Ivan P. Stanimirović Uvod u programiranje

U jeziku C postoji i naredba continue koja se takođe koristi za upravljanje tokom izvršenja petlje.
Ovom naredbom se samo preskače ostatak petlje i program nastavlja novim prolazom kroz petlju
počevši od prve naredbe petlje. Efekat te naredbe opisan je u narednom primeru.
Primer. Efekat naredbe continue u C.
sum=0;
while (sum < 2000)
{ scanf(“%d”, &podatak);
if (podatak < 0) continue;
sum = sum + podatak;
}
U ovom slučaju, kada se učita negativni podatak preskače se naredba za modifikovanje sume i
program nastavlja ponovnim prolaskom kroz petlju. To znači da će u ovom slučaju petlja uvek da se
završi kada se dostigne vrednost sum >= 2000, što u prethodnom primeru nije uvek bio slučaj.

4.8. Naredbe za bezuslovno grananje


Za bezuslovno grananje u programu koristi se GOTO naredba. U suštini, to je jedna od najmoćnijih
naredbi koja u sprezi sa naredbom selekcije omogućava da se implementiraju i najsloženiji algoritmi.
Problem je jedino u tome, što tako definisan kôd može da bude veoma nepregledan, a takvo
programiranje podložno greškama.
Po konceptu strukturnog programiranja GOTO naredba je izbačena iz upotrebe, jer se nastoji da se
program definiše umetanjem struktura jednu u drugu i da pri tome sve strukture imaju jedan ulaz i
jedan izlaz. Postoji nekoliko jezika u kojima GOTO naredba uopšte ne postoji, na primer Modula 2.
Međutim u mnogim jezicima koji podržavaju koncept strukturnog programiranja naredba GOTO je
zadržana i ostaje pogodno sredstvo za rešavanje mnogih problema.

4.8.1. Oznake (labele)


Skok (jump) prenosi kontrolu na specificiranu tačku u programu. Tipična forma bezuslovnog skoka
je izraz ‘‘goto L;’’, čime se kontrola toka programa direktno prenosi na tačku označenu sa L, što se
naziva obeležje (label).

72
Ivan P. Stanimirović Uvod u programiranje

Primer. Sledeći fragment programa (u C-like jeziku) sadrži bezuslovni skok:


if (E1)
C1
else {
C2
goto X;
}
C3
while (E2) {
C4
X: C5
}
Ovde obeležje X označava partikularnu tačku programa, preciznije, početak komande C5. Na taj način,
skok ‘‘goto X;’’ prenosi kontrolu na početak komande C5.
Sledeća slika prikazuje dijagram toka koji odgovara ovom fragmentu programa. Napomenimo da
jedna komanda if i komanda while imaju prepoznatljive poddijagrame, koji su označeni. Fragment
programa, kao celina ima jedan ulaz i jedan izlaz, ali komanda if ima dva izlaza, dok while komanda
ima dva ulaza.

Neograničeni skokovi omogućavaju komande koje imaju višestruke ulaze i višestruke izlaze. Oni
imaju tendenciju da produkuju ‘‘špagetti’’ kôd, tako nazvan zato što je njihov dijagram toka zamršen.
‘‘Špagetti’’ kôd ima tendenciju da bude teško razumljiv. Većina glavnih programskih jezika
podržava skokove, ali su realno zastareli u modenim jezicima. Čak i u jezicima koji podržavaju
skokove, njihova upotreba je ograničena restrikcijom dometa svakog obeležja: skok ‘‘goto L;’’ je
legalan samo unutar dosega L. U C, na primer, doseg svakog obeležja je najmanje obuhvaćen blok
komandom (‘‘{ . . . }’’). Prema tome, mogući su skokovi unutar blok komande, ili iz jedne blok
komande izvan neke ograđene blok komande; međutim, nemoguć je skok unutar neke blok komande
od spolja, niti iz jednog tela funkcije u drugo.
C skokovi nisu ograničeni da spreče ‘‘špagetti’’ kodovanje.
Skok unutar blok komande je relativno jednostavan, dok je skok izvan blok naredbe
komplikovaniji. Takav skok mora da uništi lokalne promenljive bloka pre nego što se transfer prenese
na destinaciju skoka.
Primer. Skok izvan blok naredbe. Uočimo sledeći (veštački) C kod:
#include<stdio.h>
void main()
{ char stop = '.',ch='!';
do { char ch;

73
Ivan P. Stanimirović Uvod u programiranje

ch = getchar();
if (ch == EOF) goto X;
putchar(ch);
} while (ch != stop);
printf("done");
X: printf("%c\n",ch);
}
Skok ‘‘goto X;’’ prenosi kontrolu izvan blok komande {. . .}. Prema tome, on takođe uništava lokalnu
promenljivu ch iz bloka. Po izlasku iz ciklusa, prikazuje se vrednost ‘!’ kao vrednost promenljive ch.
Skok izvan tela procedure je još komplikovaniji. Takav skok mora da uništi lokalne promenljive i
da terminira aktivaciju procedure pre prenosa kontrole na takvu destinaciju. Velike komplikacije
nastaju kada je destinacija skoka unutar tela rekurzivne procedure: koje rekurzivne aktivacije se
terminiraju kada se skok izvrši?
Prema tome, površno su skokovi veoma jednostavni, dok u suštini oni uvode neželjenu
kompleksnost u semantiku jezika visokog nivoa.
Za označavanje naredbi, na koje se pod dejstvom GOTO naredbe prenosi upravljanje, u
programskim jezicima se koristi koncept oznaka (labela). Iskaz Goto je prost iskaz koji ukazuje na to
da dalju obradu treba nastaviti u drugom delu programskog teksta, to jest sa mesta na kome je labela.
U nekim jezicima (C-u, Algol-u 60 na primer) koriste se identifikatori kao oznake. U drugim
(FORTRAN i Pascal na primer) to su neoznačene celobrojne konstante. U Adi su oznake takođe
identifikatori, ali obuhvaćeni zagradama << i >>, dok se za razdvajanje oznaka od naredbi na koje se
odnose u mnogim jezicima koristi dvotačka (:). Evo nekih primera:
Primer naredbe GOTO za skok na označenu naredbu u Adi.
goto KRAJ;

<<KRAJ>> SUM := SUM + PODATAK;
Isti primer napisan u C-u bio bi sledećeg oblika:
goto kraj;

kraj: sum := sum + podatak;

U svim programskim jezicima obično su definisana određena pravila koja ograničavaju korišćenje
naredbe GOTO. Na primer, u Pascal-u oznake moraju eksplicitno da budu opisane u odeljku
deklaracije naredbi. One se ne mogu prenositi kao argumenti potprograma niti modifikovati. Kao deo
GOTO naredbe može da bude samo neoznačena konstanta, ali ne i izraz ili promenljiva koja dobija
vrednost oznake.

Svaka labela poseduje sledeće osobine:


1. mora se pojaviti u odeljku deklaracija labela, pre svog pojavljivanja u bloku,
2. mora prethoditi jednom i samo jednom iskazu koji se pojavljuje u iskaznom delu bloka.
3. ima oblast važenja u celokupnom tekstu tog bloka, isključujući sve ugnježdene blokove koji
ponovo deklarišu tu labelu.
Primer. U beskonačnom ciklusu unositi dva realna broja i računati njihov proizvod.
program mnozi;
uses crt;
label 1;
var a,b:real;
begin
1:
write(' Prvi broj? '); readln(a); write(' Drugi broj? '); readln(b);
writeln(' Njihov proizvod je '); writeln(a*b:20:0);

74
Ivan P. Stanimirović Uvod u programiranje

goto 1;
end.
Primer. Primeri upotrebe Goto naredbe (programski deo):
label 1; { blok A }
...
procedure B; { blok B }
label 3, 5;
begin
goto 3 ;
3 : Writeln(‘Dobar dan');
5 : if P then
begin S; goto 5 end ; { while P do S }
goto 1 ;
{ ovo uzrokuje prevremen zavrsetak aktivacije procedure B}
Writeln('Doviđenja')
end; { blok B }
begin
B;
1: Writeln(‘program')
{ "goto 3" nije dozvoljen u bloku A )
end { blok A }
Skokovi izvana u strukturirani iskaz nisu dozvoljeni. Stoga su sledeći primeri nepravilni.
Primeri sintaksno nepravilnih programa:
a) for I := 1 to 10 do
begin
S1;
3: S2
end ;
goto 3
b) if B then goto 3;
...
if B1 then 3 : S
c) procedure P;
procedure Q;
begin ...
3 :S
end ;
begin ...
goto 3
end.
Iskaz Goto treba sačuvati za neuobičajene ill retke situacije gde je potrebno razbiti prirodnu
strukturu algoritma. Dobro je pravilo da bi trebalo izbegavati upotrebu skokova pri izražavanju
pravilnih ponavljanja i uslovnih izvršavanja iskaza, jer takvi skokovi uništavaju odraz strukture obrade
u tekstualnim (statičkim) strukturama programa. Štaviše, nedostatak slaganja između tekstualne i
obradne (tj. statičke i dinamičke) strukture poguban je po jasnoću progama i čini proveru ispravnosti
programa mnogo težom. Postojanje iskaza Goto u Pascal programu često ukazuje na to da programer
još nije naučio "misliti" u Pascalu (jer je u nekim drugim programskim jezicima Goto neophodna
konstrukcija).

75
Ivan P. Stanimirović Uvod u programiranje

5. POTPROGRAMI

U programiranju se često javlja potreba da se neki deo programa više puta ponovi u jednom
programu. Takođe, često puta se ista programska celina javlja u više različitih programa. Ovakva
nepotrebna ponavljanja se izbegavaju pomoću potprograma.
Potprogrami se uvek koriste sa idejom da se izbegne ponavljanje istih sekvenci naredbi u slučaju
kada u programu za to postoji potreba. Međutim, potprogrami su mnogo značajniji kao sredstvo za
struktuiranje programa. Pri razradi programa metodom dekompozicije odozgo naniže, svaka
pojedinačna aktivnost visokog nivoa može da se zameni pozivom potprograma. U svakoj sledećoj
etapi ide se sve niže i niže u tom procesu dekompozicije sve dok se rešenje kompleksnog programa ne
razbije na jednostavne procedure koje se konačno implementiraju. Kako napredujemo u veštini
računarskog programiranja, tako programe pišemo u nizu koraka preciziranja. Pri svakom koraku
razbijamo naš zadatak u više podzadataka, definišući tako više parcijalnih programa. Koncepti
procedure i funkcije omogućavaju da izložimo podzadatke kao konkretne potprograme.
Može se reći da su potprogrami osnovno sredstvo apstrakcije u programiranju. Potprogramom se
definiše skup izlaznih veličina u funkciji ulaznih veličina. Realizacija tih zavisnosti definisana je u
potprogramu.
Potprogrami se definišu kao programske celine koje se zatim po potrebi pozivaju i realizuju, bilo u
okviru istog programa u kome su i definisani, bilo u drugim programima.
Istaknimo neke opšte karakteristike potprograma kakvi se najčešće sreću u savremenim
programskim jezicima.
(1) Svaki potprogram ima jednu ulaznu tačku. Izuzetak od ovog pravila postoji jedino u
FORTRAN-u, gde je moguće definisati više različitih ulaza u potprogram.
(2) Program koji poziva potprogram prekida svoju aktivnost sve dok se ne završi pozvani
potprogram. To znači da se u jednom trenutku izvršava samo jedan potprogram.
(3) Po završetku pozvanog potprograma upravljanje se vraća programu koji ga je pozvao, i to na
naredbu koja sledi neposredno iza poziva potprograma.
Potprogram karakterišu sledeći osnovni elementi:
• ime potprograma,
• lista imena i tipova argumenata (fiktivni argumenti),
• lokalni parametri potprograma,
• telo potprograma,
• sredina (okruženje) u kojoj potprogram definisan.
Ime potprograma je uvedena reč, odnosno identifikator, kojom se potprogram imenuje i kojim se
vrši njegovo pozivanje.
Lista fiktivnih parametara: u nekim programskim jezicima ova lista može da sadrži samo imena
fiktivnih argumenata, čime je određen njihov broj i redosled navođenja, Kod novijih programskih
jezika u listi argumenata se navode i atributi o tipu argumenata kao i o načinu prenošenja u
potprogram. Fiktivnim argumentima definiše se skup ulazno-izlaznih veličina potprograma. Kod
poziva potprograma se fiktivni argumenti (parametri) zamenjuju stvarnim argumentima. Fiktivni i
stvarni argumenti moraju da se slažu po tipu, dimenzijama i redosledu navođenja u listi argumenata.
Lokalni parametri. U samoj proceduri mogu da budu definisani lokalni elementi procedure i to
promenljive, konstante, oznake, a u nekim jezicima i drugi potprogrami.

76
Ivan P. Stanimirović Uvod u programiranje

Telo potprograma čini sekvenca naredbi koja se izvršava nakon poziva potprograma. U telu
potprograma se realizuje kôd potprograma.
Okolinu (okruženje) potprograma predstavljaju vrednosti globalnih promenljivih okruženja u
kome je potprogram definisan i koje se po mehanizmu globalnih promenljivih mogu koristiti u
potprogramu.
U programskim jezicima se obično sreću dva tipa potprograma:
• funkcijski potprogrami (funkcije),
• potprogrami opšteg tipa (procedure).

5.1. Funkcije
Funkcijski potprogrami po konceptu odgovaraju matematičkim funkcijama. Lista argumenata u
deklaraciji ovih potprograma se obično sastoji se samo od ulaznih argumenata, na osnovu kojih se u
telu potprograma izračunava vrednost koja se prenosi u pozivajuću programsku jedinicu. Ulazne
vrednosti se u funkciji ne menjaju.
U jezicima Pascal i FORTRAN se za prenošenje vrednosti iz potprograma u pozivajuću jedinicu
koristi promenljiva koja se identifikuje sa imenom funkcije. U telu takvih funkcija mora da postoji bar
jedna naredba dodele kojom se rezultat dodeljuje imenu funkcije. Kaže se da funkcija prenosi vrednost
u glavni program preko svog imena.
U novijim programskim jezicima obično postoji naredba return kojom se eksplicitno navodi
vrednost koja se iz potprograma prenosi u glavni program. Naredba return se koristi u jeziku C. U
jeziku C se ne koristi reč function, jer su svi potprogrami funkcije. Ako funkcija vraća jedan rezultat
naredbom return ispred njenog imena se piše tip rezultata, inače se piše službena reč void.
Funkcijski potprogrami se pozivaju slično matematičkim funkcijama, tako što se u okviru izraza
navede ime funkcije sa imenima stvarnih parametara umesto fiktivnih. Koristeći gore navedene
primere, suma prvih 999 celih brojeva se može izračunati pozivom funkcije SUM na sledeći način:
SUMA := SUM(999) (Pascal)
ili
SUMA = SUM(999) (C, FORTRAN).
Funkcija se koristi u slučaju kada se vraća jedna veličina u rezultujuću programsku jedinicu.

5.1.1. Poziv i definicija funkcija u C


Program se sastoji iz jedne ili više funkcija, pri čemu se jedna od njih naziva main(). Kada
programska kontrola naiđe na ime funkcije, tada se poziva ta funkcija. To znači da se programska
kontrola prenosi na pozvanu funkciju. Kada se funkcija završi upravljanje se prenosi u pozivajuću
programsku jedinicu. Izvršenje programa počinje sa main().
Funkcije se dele u dve grupe: funkcije koje vraćaju vrednost u pozivajuću programsku jedinicu i
funkcije koje ne vraćaju vrednost.
Za svaku funckiju moraju se definisati sledeći elementi:
- tip vrednosti koju funkcija vraća,
- ime funkcije,
- lista formalnih parametara,
- deklaracija lokalnih promenljivih,
- telo funkcije.
Opšta forma definicije funkcija je:
tip ime(lista_parametara)
{ deklaracije lokalnih promenljivih
operator1

77
Ivan P. Stanimirović Uvod u programiranje


operatorN
}

Deo definicije koji se nalazi pre prve zagrade '{' naziva se zaglavlje funkcijske definicije, a sve
između velikih zagrada se naziva telo funkcijske definicije.
Tip funkcije zavisi od tipa vrednosti koja se vraća. Takođe, koristi se službena reč void ako funkcija
ne vraća vrednost. Ako je tip rezultata izostavljen podrazumeva se int.
Parametri su po sintaksi identifikatori, i mogu se koristiti u telu funkcije (formalni parametri).
Navođenje formalnih parametara nije obavezno, što znači da funkcija može da bude bez formalnih
parametara.
Poziv funkcije koja daje rezultat realizuje se izrazom
ime(spisak_stvarnih_parametara)
koji predstavlja element drugih izraza. U slučaju da funkcija ne vraća rezultat, dopisuje znak `;', čime
poziv funkcije postaje operator:
ime(spisak_stvarnih_parametara);
Između formalnih i stvarnih parametara mora da se uspostavi određena korespodencija po broju,
tipu i redosledu.
Kada se formalni parametri definišu u zaglavlju funkcije, tada se za svaki parametar posebno
navodi tip. Tada je zaglavlje funkcije sledećeg oblika:
tip ime(tip param1,...,tip paramn)
U programskom jeziku C, formalni parametri se mogu deklaristati ispod zaglavlja funkcije. Tada se
svi parametri istog tipa mogu deklarisati odjednom, koristeći jedinstveno ime tipa.
Return naredba
Među operatorima u telu funkcije može se nalaziti operator return, koji predstavlja operator
povratka u pozivajuću funkciju. Ako se operator return ne navede, funkcija se završava izvršenjem
poslednjeg operatora u svom telu, i ne vraća rezultat.
Naredba return se koristi iz dva razloga:
- Kada se izvrši naredba return, kontrola toka programa se vraća u pozivajuću jedinicu.
- Osim toga, ako neki izraz sledi iza ključne reči return, tj. ako se naredba return koristi u obliku
return izraz ili return(izraz), tada se vrednost izraza izraz vraća u pozivajuću programsku
jedinicu. Ova vrednost mora da bude u skladu sa tipom funkcije u zaglavlju funkcijske definicije.
Naredba return u jeziku C ima jednu od sledeće dve forme:
return;
ili
return(izraz); odnosno return izraz;

Na primer, može se pisati


return(3);
return(a+b);
Dobra je praksa da se izraz čija se vrednost vraća piše između zagrada.
Opšti oblik definicije funkcije:
<povratni_tip|void> ime(<tip> par1, <tip> par2, …, <tip> parN)
{ <lokalne promenljive>
<blok instrukcija>
Return <povratna vrednost> // Izostavlja se ako je funkcija tipa void
}

78
Ivan P. Stanimirović Uvod u programiranje

Primer. Uzmimo kao primer funkciju za izračunavanje sume prvih n prirodnih brojeva. Radi
poređenja isti potprogram napisan je u različitim programskim jezicima:
Pascal
function SUM (n: integer) : integer;
var i, POM : integer; { Opis lokalnih promenljivih }
begin { Telo funkcije }
POM := 0:
for i := 1 to n do POM := POM + i;
SUM := POM {Vrednost koja se prenosi u glavni program}
end;
FORTRAN
INTEGER FUNCTION SUM(N)
INTEGER N
DO 10 I = 1, N
10 SUM = SUM + I
END
PROGRAM SUMA
INTEGER S,N
READ(*,10)N
10 FORMAT(I2)
S=SUM(N)
WRITE(*,20)S
20 FORMAT(I4)
C
#include<stdio.h>
int SUM (int n)
{ int POM = 0;
for(int i = 1; i <= n; i++)POM = POM + i ;
return POM;
}
void main()
{ int n;
scanf("%d",&n); printf("%d\n",SUM(n));
}
Prototip funkcije
U tradicionalnom stilu C jezika, funkcija se može koristiti pre nego što je definisana. Definicija
funkcije može da sledi u istom ili u nekom drugom fajlu ili iz biblioteke. Nepoznavanje broja
argumenata odnosno tipa funkcije može da uzrokuje greške. Ovo se može sprečiti prototipom funkcije,
kojim se eksplicitno ukazuje tip i broj parametara koje funkcija zahteva i tip rezultujućeg izraza. Opšta
forma prototipa funkcije je sledeća:
tip ime (lista_tipova_parametara);
U ovom izrazu je lista_tipova_parametara lista tipova odvojenih zarezima. Kada je funkcija pozvana,
argumenti se konvertuju, ako je moguće, u navedene tipove.
Na primer, sintaksno su ispravni sledeći prototipovi:
void poruka1(int);
int min(int, int);
Takođe, prototip funkcije može da uključi i imena parametara, čime se može obezbediti dodatna
dokumentacija za čitaoca.
Na primer, možemo pisati
double max(duble x, double y);

Primeri

79
Ivan P. Stanimirović Uvod u programiranje

Primer. Izračunati minimum dva cela broja. Funkcija min(x,y) vraća rezultat tipa int, te se eksplicitno
navođenje tipa rezultata može izostaviti. U pozivajućoj funkciji (u ovom slučaju je to funkcija main())
naveden je prototip funkcije min.
#include<stdio.h>
void main()
{ int min(int,int);
int j,k,m;
printf("Unesi dva cela broja: ");scanf("%d%d",&j,&k);
m=min(j,k); printf("\n%d je minimum za %d i %d\n\n", m,j,k);
}
min(int x,int y)
{ if (x<y) return(x); else return(y); }

Primer. Minimum i maksimum slučajnih brojeva.


#include<stdio.h>
#include<stdlib.h>
void main()
{ int n;
void slucajni(int);
printf("Koliko slucajnih brojeva?"); scanf("%d",&n);
slucajni(n);
}

void slucajni(int k)
{ int i,r,mini,maxi;
int min(int, int), max(int, int);
srand(10);
r=mini=maxi=rand(); printf("%d\n",r);
for(i=1;i<k;++i)
{ r=rand();printf("%d\n",r);
mini=min(r,mini);maxi=max(r, maxi);
}
printf("Minimum: %7d\n Maximum:%7d\n", mini,maxi);
}
int min(int i, int j)
{ if(i<j) return(i); else return(j); }
int max(int i, int j)
{ if(i>j) return(i); else return(j); }
Primer. Izračunavanje broja kombinacija m-te klase od n elemenata po formuli
n   n!
 m
  m!(n  m)!
Pascal
program fakt1;

var m,n:integer;
bk:longint;

function fakt(k:integer):longint;
var i:integer; p:longint;
begin
p:=1;
for i:=2 to k do p:=p*i;
fakt:=p;
end;

begin
readln(n,m);
bk:=fakt(n) div fakt(m) div fakt(n-m);
writeln('Broj kombinacija je ',bk);

80
Ivan P. Stanimirović Uvod u programiranje

end.
C
#include<stdio.h>
void main()
{ int m,n; long bk;
long fakt(int);
scanf("%d%d",&n,&m);
bk=fakt(n)/fakt(m)/fakt(n-m);
printf("Broj kombinacija je %ld\n",bk);
}

long fakt(int k)
{ int i; long p=1;
for(i=2; i<=k; i++) p*=i;
return(p);
}
Izračunavanje vrednosti n! se može izdvojiti u posebnom potprogramu. Tada se prethodno napisani
potprogrami mogu napisati na sledeći način.
Pascal (II način)
program fakt2;

var m,n:integer;
bk:longint;

function komb(p,q:integer):longint;
function fakt(k:integer):longint;
var i:integer;
p:longint;
begin {fakt}
p:=1;
for i:=2 to k do p:=p*i;
fakt:=p;
end;
begin {komb}
komb:= fakt(p) div fakt(q) div fakt(p-q)
end;

begin
readln(n,m);
bk:=komb(n,m); writeln('Broj kombinacija je ',bk);
end.
C (II način)
#include<stdio.h>
void main()
{ int m,n; long bk;
long komb(int, int);
scanf("%d%d",&n,&m);
bk=komb(n,m); printf("Broj kombinacija je %ld\n",bk);
}

long komb(int p, int q)


{ long fakt(int);
return fakt(p)/fakt(q)/fakt(p-q);
}

long fakt(int k)
{ int i; long p=1;
for(i=2; i<=k; i++) p*=i;
return(p);
}

81
Ivan P. Stanimirović Uvod u programiranje

Primer. Izračunati
x3 x5 x 2 n1
sin( x)  x    ...  (1) n1  ...
3! 5! (2n  1)!
Sumiranje prekinuti kada se ispuni uslov |a/S| <= , gde je  zadata tačnost, S predstavlja tekuću
vrednost sume, dok a predstavlja vrednost člana koji se dodaje.
#include<stdio.h>
void main()
{ double x,eps;
double sinus(); scanf("%lf%lf",&x,&eps);
printf("Sinus je %lf\n", sinus(x,eps));
}

/* apsolutna vrednost */
double abs(x) { return (x>0)?x:-x; }

/* sinus */
double sinus(double x, double eps)
{ double sum, clan; int k; clan=x; k=0; sum=clan;
while(abs(clan)>eps*abs(sum))
{ k+=1; clan*=-(x*x)/(2*k*(2*k+1)); sum+=clan; }
return(sum);
}

Primer. Svi prosti brojevi do datog prirodnog broja n.


#include<stdio.h>
#include <math.h>
int prost(int k)
{ int i=3;
if(k%2==0) return(0);
if(k==3) return(1);
while((k%i!=0) && (i<=sqrt(k))) i+=2;
if(k%i==0) return(0); else return(1);
}

void main()
{ int i,n; int prost(int);
printf("Dokle? "); scanf("%d", &n);
for(i=3; i<=n; i++) if(prost(i)==1) printf("%d\n",i);
}

Primer. Trocifreni brojevi jednaki sumi faktorijela svojih cifara


#include<stdio.h>
long fakt(int k)
{ long f=1,i=1;
for(;i<=k;i++) f*=i;
return(f);
}

void main()
{ long i; unsigned a,b,c;
for(i=100;i<=999;i++)
{ a=i%10; b=i%100/10; c=i/100;
if(fakt(a)+fakt(b)+fakt(c)==i) printf("%d\n",i);
}
}

Primer. Unositi prirodne brojeve dok se ne unese vrednost <=0. Izračunati NZS unetih brojeva.
void main()
{int k,ns,nzs=0; scanf("%d", &k);
if(k<=0) printf("%d\n",nzs);

82
Ivan P. Stanimirović Uvod u programiranje

else
{ ns=nzs=k; scanf("%d", &k);
while(k>0)
{nzs=funnzs(ns,k); ns=nzs; scanf("%d",&k); };
printf("nzs = %d\n",nzs);
} }
int funnzs(int a, int b)
{ int nz;
if(a>b)nz=a;
else nz=b;
while( ((nz % a) !=0) || ((nz % b)!=0) ) nz++;
return(nz);
}

Primer. Dekadni broj iz intervala [0, 3000] prevesti u rimski brojni sistem.
#define hi 'M'
#define ps 'D'
#define st 'C'
#define pd 'L'
#define ds 'X'
#define pe 'V'
#define je 'I'

void rim(int);
void main()
{ int n;
printf("Unesi prirodan broj -> "); scanf("%d", &n);
printf("\nOdgovarajuci rimski broj je: ");
rim(n); printf("\n");
}

void rim(int n)
{ while(n>= 1000) { printf("%c",hi); n-=1000; }
if(n>=900) {printf("%c",st); printf("%c",hi); n-=900;}
if(n>= 500) { printf("%c",ps); n-=500; }
if(n>=400)
{ printf("%c",st); printf("%c",ps); n-=400; }
while(n>=100) { printf("%c",st); n-=100; }
if(n>=90)
{ printf("%c",ds); printf("%c",st); n-=90; }
if(n>= 50) { printf("%c",pd); n-=50; }
if(n>=40)
{ printf("%c",ds); printf("%c",ps); n-=40; }
while(n>= 10) { printf("%c",ds); n-=10; }
if(n==9)
{ printf("%c",je); printf("%c",ds); n-=9; }
if(n>= 5) {printf("%c",pe); n-=5; }
if(n==4) {printf("%c",je); printf("%c",pe); n-=4; }
while(n>=1) { printf("%c",je); n--; } }

Primer. Najbliži prost broj datom prirodnom broju.


#include<stdio.h>
int prost(int n)
{ int i=2,prosti=1;
while ((i<=(n/2))&&(prosti)) {prosti=(n%i)!=0; i++;}
return(prosti); }

void main()
{int m,n,i=1,prosti=1; int prost(int n);
printf("Broj za koji se racuna najblizi prost broj");
scanf("%d",&m);

83
Ivan P. Stanimirović Uvod u programiranje

if(m==1) printf("najblizi prost broj je 2\n");


else if (prost(m))
printf("najblizi prost broj je%d\n",m);
else
{ while (i<=(m-1)&&(prosti))
{ if (prost(m+i))
{ prosti=0; printf("najblizi prost je%d\n",(m+i)); }
if(prost(m-i) && (!prosti))
{prosti=0; printf("najblizi prost je %d\n",(m-i)); }
i++;
} }
getch();
}

5.1.2. Makroi u jeziku C


Makro je ime kome je pridružena tekstualna definicija. Postoje dve vrste makroa: makro kao
objekat (koji nema parametre) i makro kao funkcija (koji ima parametre).
Primer. Primeri makroa kao objekata.
#define OPSEG "Greska: Ulazni parametar van opsega"
Makro kao funkcija se definiše izrazom oblika
#define ime(lista_identifikatora) tekst_zamene
Pri definiciji makroa definiše se lista njegovih formalnih parametara, dok se prilikom pozivanja
makroa koriste stvarni parametri.
Primer. Makro kojim se ispituje da li je njegov argument paran broj.
#define NETACNO 0
#define TACNO 1
#define PARAN(broj) broj%2 ? NETACNO : TACNO
void main()
{ int n1=33;
if(PARAN(n1)) printf("%d je paran\n",n1);
else printf("%d je neparan\n",n1);
}
U pozivu makroa paran(a+b) ispituje se parnost broja a+b pomoću izraza a+b%2 umesto izraza
(a+b)%2. Da bi se ovakve greške izbegle, potrebno je da se formalni parametri pišu između zagrada.
U našem slučaju, pravilna je sledeća definicija makroa PARAN:
#define PARAN(broj) ((broj)%2) ? NETACNO : TACNO

5.2. Procedure
Procedurama se definišu potprogrami opšteg tipa, kojima se može realizovati svaki algoritam koji
sǎm za sebe ima određeni smisao. Procedurama se obično u glavni program prenosi jedan ili skup
rezultata.
Opis potprograma opšteg tipa obično ima sledeću strukturu:
procedure IME_PROCEDURE (Lista argumenata)
Opisi lokalnih promenljivlh;
Telo procedure
end;
Opis počinje nekom ključnom reči kojom se eksplicitno navodi da definišemo proceduru. U
mnogim programskim jezicima koristi se reč procedure, mada ima i izuzetaka, na primer u
FORTRAN-u se koristi SUBROUTINE. Identifikator IME_PROCEDURE je uvedena reč kojom se
imenuje potprogram. Ime potprograma se koristi za poziv potprograma. Za razliku od funkcija, lista

84
Ivan P. Stanimirović Uvod u programiranje

argumenata kod procedura može da sadrži ulazne, izlazne i ulazno-izlazne argumente. Obično se
zahteva da se u listi argumenata navede njihov tip i način prenošenja vrednosti između glavnog
programa i potprograma. U Adi na primer, argumenti mogu da budu ulazni, izlazni i ulazno-izlazni što
se eksplicitno navodi rečima in, out i inout uz odgovarajuće argumente.
Deklaracija procedure služi da definiše programski deo i da ga pridruži identifikatoru, tako da se
moze aktivirati procedurnim iskazom. Deklaracija ima isti oblik kao i program, osim što započinje
zaglavljem procedure umesto zaglavljem programa.

5.3. Prenos argumenata


Funkcije i procedure se koriste tako što se tamo gde je potrebno u kôdu programa, pozivaju sa
spiskom stvarnih argumenata. Pri tome stvarni argument zamenjuju fiktivne. Prenos argumenata
između glavnog programa i potprograma može da se ostvari na više različitih načina. Semanticki
posmatrano, to može da bude po jednom od tri semantička modela. Potprogram može da primi
vrednost od odgovarajućeg stvarnog parametra (koji se stavlja na mesto ulaznog parametra), može da
mu preda vrednost (ako se postavlja na mesto izlanog formalnog parametra) ill da primi vrednost i
preda rezultat glavnom programu (kada se stvarni parametar postavlja na mesto ulazno-izlaznog
parametra). Ova tri semantička modela nazivaju se in, out i inout, respektivno i prikazana su na slici.
Sa druge strane, postoje dva konceptualna modela po kojima se ostvaruje prenos parametara između
glavnog programa i potprograma. Po jednom, vrednosti parametara se fizički prebacuju (iz glavnog
programa u potprogram ili u oba smera), a po drugom prenosi se samo informacija o tome gde se
nalazi vrednost stvarnog parametra. Najčešće je to jednostavno pokazivač (pointer) na memorijsku
lokaciju parametra.

5.3.1. Prenos po vrednosti (Call by Value)


Sastoji se u tome što se pri pozivu funkcije vrednosti stvarnih argumenata kopiraju u pomoćne
memorijske lokacije fiktivnih argumenta koje su definisane u potprogramu. Funkcija preuzima kopije
vrednosti stvarnih parametara, dok su originali yaštićeni od promena. Zbog toga se ova tehnika
prenosa može koristiti samo za prenos ulaznih argumenata potprograma, a ne i za vraćanje rezultata
glavnom programu. Razmotrimo situaciju koja nastane kada se potprogram PP sa argumentima x i y
pozove sa stvarnim argumentima p i q. To znači imamo deklaraciju potprograma oblika
PP(x,y:integer) i njegov poziv PP(p,q). Za smeštaj vrednosti parametara x i y u potprogramu su
rezervisane memorijske lokacije promenljivih p i q, čiji je sadržaj u trenutku prevođenja potprograma
nedefinisan. U glavnom programu, sa druge strane, postoje memorijske lokacije za smeštaj stvarnih
vrednosti p i q. Vrednosti ovih memorijskih lokacija moraju da budu definisane pre poziva
potprograma. Kada se pozove potprogram, vrši se kopiranje vrednosti iz memorijskih lokacija p i q u
lokacije fiktivnih argumenata x i y u potprogramu, što je ilustrovano na slici.
Glavni program Funkcija

85
Ivan P. Stanimirović Uvod u programiranje

Osnovni nedostatak prenosa po vrednosti je u tome što se za formalne parametre potprograma


rezerviše memorijski prostor. Uz to i sama operacija kopiranja vrednosti može da utiče na efikasnost
programa. Ovi nedostaci posebno dolaze do izražaja kada se prenose strukture podataka, kao na primer
veliki vektori i matrice.
Obično se u okviru programskih jezika implicitno ili eksplicitno navodi da se argumenti prenose po
vrednosti. U Algolu se to postiže pomoću reči value, u Adi sa in, dok se u Pascal-u ovaj način
podrazumeva kada nije navedeno var uz sekciju formalnih argumenata. U FORTRAN-u se argumenti
prenose po vrednosti kada su stavljeni između kosih crta. U jeziku C se prenos po vrednosti
podrazumeva za sve parametre koji nisu pokazivači.
Prenos parametara po vrednosti u C
Funkcija se može pozvati stavljajući posle njenog imena odgovarajuću listu stvarnih argumenata
između zagrada. Ovi argumenti se moraju slagati sa brojem i tipom formalnih parametara u definiciji
funkcije. Svaki argument se izračunava, i njegova vrednost se uzima umesto formalnog parametra.
Međutim, vrednost stvarnog parametra ostaje nepromenjena u pozivajućoj programskoj jedinici. Kada
se koristi poziv po vrednosti, u momentu kada se koristi izraz kao stvarni argument funkcije, pravi se
kopija njegove vrednosti, i ona se koristi u funkciji. Pretpostavimo da je v promenljiva, a f() funkcija.
Tada poziv funkcije f(v) ne menja vrednost promenljive v u funkciji f, jer se koristi kopija vrednosti v
u funkciji f().
Poziv po vrednosti je ilustrovan sledećim primerom.

Primer. Pronaći sve brojeve-blizance do zadatog broja n. Dva broja su blizanci ako su prosti i
razlikuju se za 2.
#include<stdio.h>
#include<math.h>
void main()
{ int n,i;
int prost(int);
scanf("%d",&n);
for (i=3;i<=n;i++)
if ((prost(i)) && (prost(i-2))) printf("%d %d\n",i-2,i);

86
Ivan P. Stanimirović Uvod u programiranje

int prost(int k)
{ int i=2,prosti=1;
while((i<=sqrt(k)) && (prosti)) { prosti=((k%i)!=0); i++; }
return(prosti);
}

U nekim drugim programskim jezicima (FORTRAN), takav poziv funkcije može da promeni
vrednost za v. Mehanizam izvršen u tom slučaju se naziva poziv po adresi (call by Reference). Da bi
se u C postigao efekat poziva po adresi moraju se koristiti pointeri promenljivih u listi parametara
prilikom definisanja funkcije, kao i adrese promenljivih koje su argumenti u pozivu funkcije.

5.3.2. Prenos po rezultatu (Call by Result)


Prenos po rezultatu je tehnika koji se primenjuje za prenos izlaznih (out) parametara u jeziku Ada.
Kada se argumenti prenose po rezultatu, njihove vrednosti se izračunavaju u lokalnim memorijskim
lokacijama formalnih argumenata potprograma, pri čemu nema prenosa vrednosti parametara iz
glavnog programa u potprogram. Međutim, pre nego što se upravljanje tokom izvršenja prenese u
glavni program, ove vrednosti se kopiraju u memorijske lokacije stvarnih argumenata. Stvarni
argumenti u ovom slučaju moraju da budu promenljive. Kao i kod prenosa po vrednosti, za fiktivne
argumente potprograma rezervišu se lokalne memorijske lokacije.
Kod ovog načina prenosa mogući su i neki negativni efekti, kao što je na primer kolizija stvarnih
argumenata, koja nastaje u slučajevima kada se potprogram poziva tako da isti stvarni argument
zamenjuje više fiktivnih argumenata. Razmotrimo sledeći primer u kome se potprogram definisan kao
procedure PP(x,y:real) poziva sa PP(p1,p1).U ovom primeru problem je u tome što se u
potprogramu aktuelni parametar p1 dobija vrednost iz dve različite memorijske lokacije (koje
odgovaraju formalnim parametrima x i y). Nije unapred poznato koju će od ovih vrednosti argument
p1 imati po završetku potprograma. To zavisi od toga koja je vrednost poslednji put dodeljena
stvarnom argumentu.

5.3.3. Prenos po vrednosti i rezultatu (Call by Value-Result)


Prenos po vrednosti i rezultatu je način prenosa ulazno-izlaznih (inout) argumenata. To je u suštini
kombinacija prenosa po vrednosti i prenosa po rezultatu. Vrednosti stvarnih argumenta kopiraju se u
memorijske lokacije fiktivnih argumenata potprograma. To su lokalne memorijske lokacije
potprograma i sve izmene nad argumentima pamte se u ovim lokacijama. Pre vraćanja upravljanja
glavnom programu, rezultati potprograma se iz ovih lokalnih memorijskih lokacija ponovo kopiraju u
memorijske lokacije stvarnih argumenata. Ovaj način prenosa se često naziva i prenos kopiranjem
(call by copy) jer se stvarni argumenti najpre kopiraju u potprogram, a zatim ponovnim kopiranjem
rezultati vraćaju u glavni program.
Nedostaci i negativni efekti koji su prisutni kod prenosa po vrednosti i prenosa po rezultatu ostaju i
kod ovog načina prenosa.

5.3.4. Prenos po referenci (Call by Reference)


Kod ovog načina prenosa nema kopiranja vrednosti parametara iz glavnog programa u potprogram
ill obrnuto. U potprogram se samo prenosi referenca (obično samo adresa) memorijske lokacije u kojoj
je sačuvana vrednost stvarnog argumenta. Efekat je kao da se reference stvarnih argumenata
preslikavaju u reference fiktivnih. Potprogam pristupa istim memorijskim lokacijama kojima i glavni
program, nema rezervisanja memorijskih lokacija za fiktivne argumente u okviru potprograma. Sve
promene nad argumentima koje se izvrše u okviru potprograma neposredno su vidljive i u glavnom
programu. Zbog toga je ovo način prenosa koji se koristi za prenos ulazno-izlaznih argumenata. U
mnogim programskim jezicima to je osnovni način prenosa argumenata i podrazumeva se implicitno

87
Ivan P. Stanimirović Uvod u programiranje

(Algol, FORTRAN). U Pascal-u se koristi uvek kada uz argumente stoji var. U jeziku C se za prenos
po referenci koriste pokazivači.
Glavni program Funkcija

Prednosti prenosa po referenci su u njegovoj efikasnosti kako u pogledu vremena tako i u pogledu
memorijskog prostora. Nema potrebe za dupliranja memorijskog prostora niti se gubi vreme u
kopiranju vrednosti argumenata iz jednih memorijskih lokacija u druge. Međutim, treba imati u vidu
da se ovaj prenos implementira indirektnim adresiranjem pa se tu ipak nešto gubi na efikasnosti.
Takođe, mogući su i određeni bočni efekti u određenim posebnim slučajevima poziva potprograma.
Razmotrićemo neke od njih.
Kao u slučaju prenosa po rezultatu i ovde je moguća kolizija između stvarnih argumenata. Uzmimo
na primer potprogram PP u Pascal-u sa dva argumenta koji se prenose po vrednosti, čija je deklaracija
oblika
procedure PP(var x,y: integer);
Ako se ovaj potprogram pozove tako da se oba fiktivna argumenta zamene istim stvarnim
parametrom, na primer sa PP(m, m); , dolazi do kolizije jer se oba fiktivna argumenta referenciraju na
istu memorijsku lokaciju stvarnog argumenta m.
Kod prenosa po referenci kolizija može da nastane između elemenata programa koji se prenose kao
stvarni argumenti potprograma i onih koji se prenose kao globalni parametri. Razmotrimo sledeći
primer u Pascal-u:
program LocalGlobal;
var global: integer;
procedure PPG(var local: integer);
begin
local := local+1; writeln('global = ',global);local := local+global;
end;
begin
global := 2; PPG(global); writeln(global);
end.
Odgovarajući primer u jeziku C je predstavljen sledećim kôdom:
#include<stdio.h>
int global;
void PPG(int *local)
{ (*local)++;
printf("global = %d\n",global);
*local = *local+global;
}

void main()
{ global = 2;
PPG(&global);
printf("%d\n",global);
}

88
Ivan P. Stanimirović Uvod u programiranje

Posle poziva potprograma PPG biće odštampana vrednost je 6. Zaista, vrednost 2 dodeljena
promenljivoj global u potprogramu najpre koriguje naredbom local:=local+1; (posle čega je
global=3), a zatim i naredbom local:=local+global; (posle čega je local=global=3).
Promenljiva global se u potprogramu koristi i kao globalna promenljiva i kao stvarni argument, pa se i
promene argumenta potprograma i promene same promenljive global registruju u istoj memorijskoj
lokaciji. Napomenimo da bi u ovom primeru prenos sa kopiranjem (call by value-result) dao drugačiji
rezultat. U tom slučaju, vrednost stvarnog argumenta global kopira se u memorijsku lokaciju fiktivnog
argumenta local i u potprogramu se sve promene argumenta registruju u toj lokaciji. U prvoj naredbi
dodeljivanja promenljiva local dobija vrednost 3, a u drugoj se ova vrednost inkrementira za 2, što je
vrednost globalne promenljive global (dodeljena pre ulaska u potprogram). Time argument local
dobija vrednost 5, i to je vrednost koja se po završetku potprograma kopira natrag u memorijsku
lokaciju stvarnog argumenta global. To znači da se u ovom slučaju štampa vrednost 5. Slična analiza
istog programa moguća je i za slučaj prenosa argumenta potprograma po vrednosti. U tom slučaju
vrednost stvarnog argumenta global se kopira u potprogram ali su sve promene u potprogramu
nevidljive za glavni program, pa se po završetku potprograma štampa vrednost 2 koja je dodeljena
promenljivoj global pre poziva potprograma.
Poziv po adresi pomoću pokazivača u C
Deklaracije pointera i dodeljivanje

Pointeri se koriste za pristup memoriji i manipulaciju adresama. Vrednosti pokazivača jesu adrese
promenljivih. Do sada smo već videli upotrebu adresa kao argumenata u naredbi scanf(). Ako je v
promenljiva, tada je &v adresa (lokacija) u memoriji u kojoj je smeštena vrednost za v. Operator & je
unarni, ima asocijativnost sdesna na levo, a prioritet kao i ostali unarni operatori. Pointerske
promenljive se mogu deklarisati u programu, a onda koristiti tako da uzimaju adrese za svoje
vrednosti.
Na primer, deklaracija
int *p;
deklariše promenljivu p tipa ''pointer na int''. Rang vrednosti svakog pointera uključuje posebnu
adresu 0, definisanu kao NULL u <stdio.h>, kao i skup pozitivnih celih brojeva koji se
interpretiraju kao mašinske adrese.
Primer. Pointeru p se vrednosti mogu dodeljivati na sledeći način:.
p=&i;
p=0;
p=NULL; /* isto što i p=0; */
p=(int*)1507 /* apsolutna adresa u memoriji */ }
U prvom primeru p je ''pointer na i'', odnosno ''sadrži adresu od i''. Treći i drugi primer
predstavljaju dodelu specijalne vrednosti 0 pointeru p. U četvrtom primeru kast je nužan da bi se
izbeglo upozorenje kompajlera, a koristi se aktuelna memorijska lokacija kao vrednost promenljive p.
Ovakve naredbe se ne koriste u korisničkim programima, već samo u sistemskim.
Adresiranje i operator indirekcije
Neka su date deklaracije
int i, *p;
Tada naredbe
p=&i; scanf("%d",p);
uzrokuju da se sledeća uneta vrednost smešta u adresu zadatu pointerom p. Ali, s obzirom da p
ukazuje na i, to znači da se vrednost smešta u adresu od i.
Operator indirekcije * je unarni i ima isti prioritet i asocijativnost sa desna ulevo kao i ostali unarni
operatori. Ako je p pointer, tada *p predstavlja vrednost promenljive na koju ukazuje p. Direktna
vrednost za p je memorijska lokacija, dok je *p indirektna vrednost od p, tj. vrednost memorijske
lokacije sadržane u p. U suštini, * je inverzni operator u odnosu na operator &.

89
Ivan P. Stanimirović Uvod u programiranje

Na taj način, pointeri se mogu koristiti za dodelu vrednosti nekoj promenljivoj. Na primer, neka su
date deklaracije
int *p,x;

Tada se izrazima
p=&x; *p=6;
promenljivoj x dodeljuje vrednost 6.
Primer. Uočimo deklaracije
float x,y, *p;
i naredbe
p = &x; y=*p;
Prvom naredbom se adresa od x pridružuje pointeru p, a drugom se vrednost na koju ukazuje p
dodeljuje y. Ove dve naredbe su ekvivalentne sa
y=*&x;
odnosno
y=x.
Primer. Ilustracija pokazivača.

Primer. Neka je dat sledeći kôd:


char c1,c2='A',*p,*q;
p=&c1; q=&c2; *p=*q;
Adrese od c1 i c2 pridružuju se promenljivima p i q u prva dva izraza. Poslednja naredba izjednačuje
vrednost na koju ukazuje p i vrednost na koju ukazuje q. Ove tri naredbe su ekvivalentne sa c1=c2.

Primer.
void main()
{ int i=777,*p;
p=&i; printf("Vrednost za i:%d\n",*p);
printf("Adrese za i: %u ili %p\n",p,p);
}

Formati %u i %p se koriste za prikazivanje vrednosti promenljive p u obliku neoznačenog


decimalnog broja, odnosno heksadecimalnog broja, respektivno.
Primer. Izrazima
int i=777, *p=&i;
je inicijalizovano p, a ne *p. Promenljiva p je tipa ''pointer na int'', i njena početna vrednost je &i.
Primer.
#include <stdio.h>
void main()
{ int x=7, y=10;

90
Ivan P. Stanimirović Uvod u programiranje

printf("x=%d &x=%p\n", x,&x);


printf("y=%d &y= %p%u\n",y,&y, &y);
}

void main()
{ int i=5, *pi=&i; printf("i= %d ili = %d\n", i, *pi); }

Primer. Postoji velika razlika između

Using pointers allows us to:


– Achieve call by reference (i.e. write functions which change their parameters)
– Handle arrays efficiently
– Handle structures (records) efficiently
– Create linked lists, trees, graphs etc.
– Put data onto the heap
– Create tables of functions for handling Windows events, signals etc.
Call by reference (poziv po adresi) koristeći pokazivače
Prenos vrednosnih parametara je pogodan kada funkcija vraća jednu izlaznu veličinu bez izmene
svojih stvarnih parametara. Međutim, kada je potrebno da funkcija menja vrednosti svojih stvarnih
parametara, ili ukoliko funkcija vraća više izlaznih veličina, može se koristiti druga tehnika predaje
parametara: prenos adrese stvarnih parametara.
Adrese promenljivih se mogu koristiti kao argumenti funkcija u cilju izmene zapamćenih vrednosti
promenljivih u pozivajućoj programskoj jedinici. Tada se pointeri koriste u listi parametara pri
definisanju funkcije. Kada se funkcija poziva, moraju se koristiti adrese promenljivih kao argumenti.

91
Ivan P. Stanimirović Uvod u programiranje

Primer. Primer u jeziku C kojim se ilustruju globalna promenljiva i prenos po adresi. Rezultat je kao
u slučaju prenosa po adresi.
#include<stdio.h>
int global;
void PPG(int *local)
{ (*local)++; printf("global = %d\n",global); *local = *local+global;}
void main()
{ global = 2; PPG(&global); printf("%d\n",global); }

Primer. Date su vrednosti za dve celobrojne promenljive i i j. Urediti ih u poredak i<= j.


#include <stdio.h>
void upis(int *x, int *y);
void sredi(int *x, int *y);
void ispis(int x,int y);
void main()
{ int x,y;
upis(&x,&y); sredi(&x,&y); ispis(x,y);
}

void upis(int *x, int *y)


{ printf("Unesi dva cela broja"); scanf("%d%d",x,y); }

void sredi(int *x, int *y)


{ int pom;
if(*x>*y) { pom=*x; *x=*y; *y=pom; }
}

void ispis(int x, int y)


{ printf("\n To su brojevi %d %d\n",x,y); }

Tehnika predaje parametara po adresi (Call by reference) se sastoji iz sledećih baznih pravila:
1. deklarisati formalne parametre funkcije kao pointere;
2. koristiti operatore indirekcije u telu funkcije;
3. pri pozivu funkcije koristiti adrese kao argumente.
Kako sredi() radi sa pokazivačima? Kada predajete pokazivač, predajete adresu objekta i tako
funkcija može manipulisati vrednošću na toj adresi. Da bi sredi() promenila stvarne vrednosti,

92
Ivan P. Stanimirović Uvod u programiranje

korišćenjem pokazivača, funkcija sredi(), trebalo bi da bude deklarisana da prihvata dva int
pokazivača. Zatim, dereferenciranjem pokazivača, vrednosti x i y će, u stvari, biti promenjene.
Primer. Predavanje po referenci korišcenjem pokazivača.
1: // Prenos parametara po referenci
2:
3: #include <iostream.h>
4:
5: void swap(int *x, int *y);
6:
7: int main()
8: {
9: int x = 5, y = 10;
10:
11: cout << "Main. Pre swap, x:”<<x<<" y: "<<y<<"\n";
12: swap(&x,&y);
13: cout<<"Main. Posle swap., x: "<<x<<" y: "<<y<<"\n";
14: return 0;
15: }
16:
17: void swap(int *px, int *py)
18: {
19: int temp;
20:
21: cout<<"Swap. Pre swap, *px: "<<*px<<" *py:"<<*py<<"\n";
22:
23: temp = *px;
24: *px = *py;
25: *py = temp;
26:
27: cout<<"Swap. Posle swap, *px: "<<*px<<" *py: "<<*py<<"\n";
28:
29: }
Izlaz:
Main. Pre swap, x:5 y: 10
Swap. Pre swap, *px: 5 *py:10
Swap. Posle swap, *px: 10 *py:5
Main. Posle swap, x:10 y: 5
U liniji 5 prototip funkcije swap() pokazuje da će njegova dva parametra biti pokazivači na int, a ne
int promenljive, Kada se pozove swap() u liniji 12, kao argumenti se predaju adrese od x i y. U liniji
19 lokalna promenljiva, temp, deklarisana je u funkciji swap() - nije potrebno da temp bude pokazivač;
ona će čuvati samo vrednost od *px (to jest, vrednost promenljive x u pozivajućoj funkciji), tokom
života funkcije. Posle povratka iz funkcije, promenljiva temp više neće biti potrebna.
U liniji 23 promenljivoj temp se dodeljuje vrednost memorijske lokacije koja je jednaka vrednosti
pokazivača px. U liniji 24 vrednost na adresi px se dodeljuje vrednosti na adresi py. U liniji 25
vrednost čuvana u temp (to jest, originalna vrednost na adresi px) stavlja se u adresu py.
Efekat ovoga je da će vrednosti u pozivajućoj funkciji, čije su adrese predate funkciji swap(), biti
zamenjene.
Prenos po referenci koristeći reference u C++

Prethodni program radi, ali sintaksa funkcije swap() je problematična zbog dve stvari. Prvo,
ponavljajuća potreba za dereferenciranjem pokazivača unutar funkcije swap() čini je podložnom
greškama i teškom za čitanje. Drugo, potreba da se preda adresa promenljivih u pozivajućoj funkciji
čini unutrašnji rad funkcije swap() više nego očiglednim za korisnike.

93
Ivan P. Stanimirović Uvod u programiranje

Cilj C++ je da spreči korisnika funkcije da se brine o tome kako ona radi. Zbog toga se prenos po
adresi u C++ može uraditi pomoću referenci.
Primer.
#include<iostream.h>
void f(int i, int &j){ // i je poziv po vrednosti, j po referenci
i++; // stvarni argument si se neće promeniti
j++; // stvarni argument sj će se promeniti
}
void main () {
int si=0,sj=0;
f(si,sj);
cout<<"si="<<si<<", sj="<<sj<<endl;
}
Izlaz: si=0, sj=1

Primer. Prepisana funkcija swap() sa referencama.


1: //Predavanje po referenci
2: // koriščenjem referenci!
3:
4: #include <iostream.h>
5:
6: void swap(int &rx, int &ry);
7:
8: int main()
9: {
10: int x = 5, y = 10;
11:
12: cout<<"Main. Pre swap, x: "<<x<<" y: "<<y<<"\n";
13: swap(x,y);
14: cout<<"Main. Posle swap, x: "<<x<<" y: "<<y<<"\n";
15: return 0;
16: }
17:
18: void swap (int &rx, int &ry)
19: {
20: int temp;
21:
22: cout<<"Swap. Pre swap, rx: "<<rx<<" ry: "<<ry<<"\n";
23:
24: temp =rx;
25: rx =ry;
26: ry =temp,
27:
28: cout<<"Swap. Posle swap, rx: "<<rx<<" ry: "<<ry<<"\n";
29:
30: }
Rezultat je isti kao u prethodnom primeru.
Kao i u primeru si pokazivačima, deklarisane su dve promenljive u liniji 10, a njihove vrednosti se
štampaju u liniji 12. U liniji 13 poziva se funkcija swap(), ali uočite da se predaju x i y, a ne njihove
adrese. Pozivajuća funkcija main() jednostavno predaje promenljive, kao i u slučaju poziva po
vrednosti.
Kada se pozove swap(), izvršenje programa "skače" na liniiju 18, gde se promenljive rx i ry
identifikuju kao reference. Njihove vrednosti se štampaju u liniji 22, ali uočite da se za štampanje ne
zahtevaju posebni operatori. Promenljive rx i ry su alijasi za originalne vrednosti i mogu se samostalno
koristiti.

94
Ivan P. Stanimirović Uvod u programiranje

U linijama 24-26 vrednosti se zamenjuju, a onda se štampaju u liniji 28, Izvršenje programa
"skače" u pozivajuću funkcuju i u liniji 14 vrednosti se štampaju u main(). Zato što su parametri za
swap() deklarisani kao reference, vrednosti iz main() se predaju po referenci i time se, takođe, menjaju
i u main().
Reference obezbeđuju pogodnost i lakoću upotrebe normalnih promenljivih, sa snagom i
sposobnošću predavanja po referenci koju imaju pokazivači.
Primer. Prenos parametra na dva načina.
#include<iostream.h>
int* f(int* x) {
(*x)++;
return x; // Vrednost za x se prenosi u stvarni parametar
}

int& g(int& x) {
x++; // Isti efekat kao u f()
return x; // Vrednost za x se prenosi u stvarni parametar
}

int main() {
int a = 0;
f(&a); // Ružno, ali eksplicitno
cout << "a = " << a << "\n";
g(a); // Jasno, ali sakriveno
cout << "a = " << a << "\n";
return 0;
}
Primer. Modifikacija prethodnog primera, koja se sastoji u upotrebi pokazivača p. Naredbom
p=f(&a); identifikovani su p i &a.

#include<iostream.h>
int* f(int* x) {
(*x)++;
return x; // Vrednost za x se prenosi u stvarni parametar
}

int& g(int& x) {
x++; // Isti efekat kao u f()
return x; // Vrednost za x se prenosi u stvarni parametar
}

void main() {
int a = 0,*p;
p=f(&a); // Ružno, ali eksplicitno
cout << "a = " << a << "\n"; //a=1
cout << "*p = " << *p << "\n"; //*p=1
g(a); // Jasno, ali sakriveno
cout << "a = " << a << "\n"; //a=2
cout << "*p = " << *p << "\n"; // *p=2
}
Vraćanje višestrukih vrednosti
Kao što je rečeno, pomoću naredbe return funkcije mogu vratiti samo jednu vrednost. Šta učiniti
ako je potrebno da vratite dve vrednosti iz funkcije? Jedan način da rešite ovaj problem je da funkciji
predate objekte po referenci. Kako predavanje po referenci dozvoljava funkciji da promeni originalne
objekte, ovo efektno dozvoljava funkciji da vrati više informacija. Povratna vrednost funkcije se može
rezervisati za izveštavanje o greškama.

95
Ivan P. Stanimirović Uvod u programiranje

Ovo se može ostvariti referencama, ili pokazivačima. Sledeći primer demonstrira funkciju koja
vraća tri vrednosti: dve kao pokazivačke parametre i jednu kao povratnu vrednost funkcije.
Primer. Vraćanje vrednosti pomoću pokazivača.
1:
2: // Vraćanje više vrednosti iz funkcije
3:
4: #include <iostream.h>
5:
6: typedef unsigned short USHORT;
7:
8: short Factor(USHORT, USHORT*, USHORT*);
9:
10: int main()
11: {
12: USHORT number, squared, cubed;
13: short error;
14:
15: cout << "Unesite broj (0-20): ";
16: cin >> number;
17:
18: error = Factor(number, &squared, &cubed);
19:
20: if(!error)
21: {
22: cout << "broj: " << number << "\n";
23: cout << "kvadrat: " << squared << "\n";
24: cout << "kub: " << cubed << "\n";
25: }
26: else
27: cout << "Doslo je do greske!!\n";
28: return 0;
29: }
30:
31: short Factor(USHORT n, USHORT *pSquared, USHORT *pCubed)
32: {
33: short Value = 0;
34: if (n > 20)
35: Value = 1;
36: else
37: {
38: *pSquared = n*n;
39: *pCubed = n*n*n;
40: Value = 0;
41: }
42: return Value;
43: }
U liniji 12 number, squared i cubed su definisani kao USHORT. Promenljivoj number se dodeljuje
broj baziran na korisničkom ulazu. Ovaj broj i adresa od squared i cubed se predaju funkciji Factor().
Funkcija Factor() ispituje prvi parametar, koji se predaje po vrednosti. Ako je on veći od 20
(maksimalan broj kojim ova funkcija može rukovati), ona postavlja povratnu vrednost (Value) na
jednostavnu vrednost greške (Value =1). Uočite da povratna vrednost 0 iz funkcije Factor() pokazuje
da je sve prošlo dobro, i uočite da tunkcija vraća ovu vrednost u liniji 42.
Stvarne potrebne vrednosti, kvadrat i kub promenljive number, vraćaju se menjanjem pokazivača
koji su predati funkciji.
U linijama 38 i 39 pokazivačima se dodeljuju njihove povratne vrednosti. U liniji 40 return Value
dobija uspešnu vrednost.
Jedno poboljšanje u ovom programu bi moglo biti deklarisanje sledećeg:

96
Ivan P. Stanimirović Uvod u programiranje

enum ERROR_VALUE {SUCCESS, ERROR};


Zatim, umesto vraćanja 0, ilii, program bi mogao da vrati SUCCESS, ili ERROR.
Vraćanje višestrukih vrednosti po referenci
Prethodni program se može učiniti lakšim za čitanje i održavanje, korišćenjem referenci, umesto
pokazivača. Sledeći primer prikazuje isti program, prepisan radi korišćenja referenci i uključivanja
ERROR enumeracije.
Primer. Vraćanje višestrukih vrednosti korišćenjem referenci.
1: //
2: // Vraćanje više vrednosti iz funkcije
3: // konščenje referenci
4:
5: #include <iostream.h>
6:
7: typedef unsigned short USHORT;
8: enum ERR_CODE {SUCCESS, ERROR};
9:
10: ERR_CODE Factor(USHORT, USHORT &, USHORT &);
11:
12: int main()
13: {
14: USHORT number, squared, cubed;
15: ERR_CODE result;
16:
17: cout << "Unesite broj (0 - 20): ";
18: cin >> number;
19:
20: result = Factor(number, squared, cubed);
21:
22: if (result == SUCCESS)
23 {
24 cout << "broj: " << number << "\n";
25 cout << "kvadrat: " << squared << "\n";
26 cout << "kub: " << cubed << "\n";
27 }
28 else
29 cout << "Doslo je do greske!!\n";
30: return 0;
31: }
32:
33: ERR_CODE Factor(USHORT n, USHORT &rSquared, USHORT &rCubed)
34: {
35: if (n > 20)
36: return ERROR; // jednostavan kôd za grešku
37: else
38: {
39: rSquared = n*n;
40: rCubed = n*n*n;
41: return SUCCESS;
42: }
43: }
Ovaj program je identičan prethodnom, uz dva izuzetka. Enumeracija ERR_CODE čini
izveštavanje o grešci u linijama 36 i 41, kao i rukovanje greškama u liniji 22.
Ipak, veća promena je ta da je Factor() sada deklarisana da prihvata reference na squared i cubed, a
ne na pokazivače, što čini manipulaciju ovim parametrima daleko jednostavnijom i lakšom za
razumevanje.

97
Ivan P. Stanimirović Uvod u programiranje

Predavanje po referenci, zbog efikasnosti


Svaki put kada predate objekat funkciji po vrednosti, pravi se njegova kopija. Svaki put kada
vratite po vrednosti objekat iz funkcije, pravi se druga kopija.
Ovi objekti se kopiraju na stek. Zato ovo uzima vreme i memoriju. Za male objekte, kao što su
ugrađene celobrojne vrednosti, to je trivijalna cena. Međutim, za veće korisnički kreirane objekte,
cena je veća. Veličina korisnički kreiranih objekata na steku je suma veličina svih njegovih
promenljivih članica. Svaka od njih, dalje, može biti korisnički kreiran objekat i predavanje tako
masivne strukture njenim kopiranjem na stek može biti veoma skupo zbog performansi i korišćenja
memorije.
Postoji, takođe, i druga cena. Sa klasama koje kreirate, svaka ova privremena kopija se kreira kada
kompajler pozove specijalan konstruktor: konstruktor kopije. Za sada, dovoljno je da znate da se
konstruktor kopije poziva svaki put kada se privremena kopija objekta stavi na stek.
Primer. Urediti tri broja x, y, z u neopadajući poredak x<= y<= z.
void razmeni(int *a, int *b)
{ int pom; pom=*a; *a=*b; *b=pom; }

void main()
{ int x,y,z; void razmeni(int*, int*);
scanf("%d%d%d", &x,&y,&z);
if(x>y) razmeni(&x,&y); if(x>z) razmeni(&x,&z);
if(y>z) razmeni(&y,&z);
printf("x= %d y= %d z= %d\n",x,y,z);
}

Primer. Napisati proceduru kojom se izračunava najmanji zajednički sadržalac i najveći zajednički
delilac dva prirodna broja.
#include<stdio.h>
void unos(int *,int *); void nzds(int,int, int *,int *);
void main()
{ int x,y, nzd,nzs;
unos(&x, &y); nzds(x,y,&nzd,&nzs);
printf("Nzd unetih brojeva = %d a nzs= %d\n",nzd,nzs);
}

void unos(int *a, int *b)


{ printf("\nZadati dva cela broja: "); scanf("%d%d",a,b); }

void nzds(int a, int b, int *nd, int *ns)


{ if(a>b) *ns=a; else *ns=b;
int v=*ns;
while(*ns%a !=0 || *ns%b !=0)(*ns)+=v;
while(a!=b) { if(a>b)a-=b; else if(b>a)b-=a; }
*nd=a;
}

Primer. Sa tastature se unosi jedan ceo broj, a za njim neodređen broj celih brojeva. Napisati
proceduru kojom se izračunava minimum i maksimum unetih brojeva.
#include<stdio.h>
void minmax(int *,int*);
void main()
{ int mn,mx; minmax(&mn,&mx);
printf("Minimum je %d a maksimum %d\n",mn,mx);
}

void minmax(int *min, int *max)


{ int n;
*min=*max=scanf("%d",&n);

98
Ivan P. Stanimirović Uvod u programiranje

while(scanf("%d",&n)==1)
if(n<*min)*min=n;
else if(n>*max)*max=n;
}

Primer. Napisati funkciju za izračunavanje determinante kvadratnog trinoma ax2+bx+c. Napisati


proceduru kojom se izrašavaju sledeće aktivnosti:
a) Određuje da li su rešenja realna i različita, realna i jednaka ili konjugovano-kompleksna;
b) u slučaju da su rešenja realna izračunava njihove vrednosti, a u slučaju da su rešenja
konjugovano-kompleksna izračunava realni i imaginarni deo tih rešenja.
Napisati proceduru za štampanje odgovarajućih izveštaja. U glavnom programu unositi
koeficijente kvadratnih jednačina u beskonačnom ciklusu i prikazivati odgovarajuće rezultate
koristeći proceduru za prikazivanje izveštaja.
#include<stdio.h>
#include<math.h>
float diskriminanta(float, float, float);
void solution(float, float, float, float *, float *,int *); void
rezultati(float, float, float, float *,float *,int *);
void main()
{ float a,b,c, x1,x2; int tip;
while(1)
{ printf("Unesi koeficijente -> "); scanf("%f%f%f", &a,&b,&c);
rezultati(a,b,c,&x1, &x2, &tip);
} }
float diskriminanta(float a, float b, float c)
{ return(b*b-4.0*a*c); }
void solution(float a,float b,float c, float *x,float *y,int *t)
{ float d;
d=diskriminanta(a,b,c);
if(d>0){*t=0; *x=(-b+sqrt(d))/(2*a);*y=(-b-sqrt(d))/(2*a); }
else if(d==0) { *t=1; *x=*y=-b/(2*a);}
else { *t=2; *x=-b/(2*a); *y=sqrt(-d)/(2*a); }
}
void rezultati(float a,float b,float c, float *x, float *y, int *t)
{solution(a,b,c,x,y,t);
if(*t==0)
{printf("Resenja su realna i razlicita\n");
printf("x1=%f x2=%f\n",*x,*y);}
else if(*t==1)
{printf("Resenja su realna i jednaka\n");
printf("x1=x2=%f\n",*x);}
else { printf("Resenja su konjugovano-kompleksna\n");
printf("x1 = %f + i* %f\n",*x,*y);
printf("x2 = %f -i* %f\n",*x,*y);
} }

Primer. Napisati proceduru za deljenje dva cela broja na proizvoljan broj decimala. Deljenik, delilac
i broj decimala zadati u posebnoj proceduri.
#include<stdio.h>
#include<conio.h>
void unos(int *, int*, int *);
void deljenje(int, int, int);
main()
{ int n,i,bdec, brojilac, imenilac;
clrscr(); printf("Koliko puta? "); scanf("%d", &n);
for(i=1; i<=n; i++)
{ unos(&brojilac, &imenilac, &bdec);

99
Ivan P. Stanimirović Uvod u programiranje

deljenje(brojilac, imenilac, bdec);


} }
void unos(int *br, int *im, int *bd)
{ printf("Brojilac = ?"); scanf("%d",br);
printf("Imenilac = ? "); scanf("%d",im);
printf("Broj decimala = ? "); scanf("%d",bd);
}
void deljenje(int br, int im, int bd)
{ int i;
if(br*im<0) printf("-");
br=br<0?-br:br; im=im<0?-im:im;
printf("\n%d.",br/im); br %= im;
for(i=1; i<=bd; i++)
{ br *=10; printf("%d",br/im); br %=im; }
printf("\n");
}

Primer. a) Napisati proceduru za unošenje brojioca i imenioca jednog razlomka. U toj proceduri, po
potrebi, vrednost imenioca promeniti tako da bude pozitivan.
b) Napisati rekurzivnu funkciju za izračunavanje najvećeg zajedničkog delioca dva prirodna broja.
c) Napisati funkciju za izračunavanje najvećeg zajedničkog sadržaoca dva prirodna broja.
d) Napisati proceduru za kraćenje brojioca i imenioca zadatim prirodnim brojem.
e) Napisati proceduru za sabiranje dva razlomka. Pri sabiranju razlomaka koristiti najveći zajednički
sadržalac za imenioce jednog i drugog razlomka. Zatim skratiti brojilac i imenilac izračunatog
razlomka najvećim zajedničkim deliocem za brojilac i imenilac.
f) U glavnom programu učitati brojilac i imenilac za n razlomaka i izračunati zbir svih razlomaka.
#include<stdio.h>
#include<math.h>
#include<conio.h>
/* razlomci.c */
int nzd(int, int); int nzs(int, int); void unos(int *, int *);
void sabiranje(int, int,int, int, int *, int *);

void kracenje(int *, int*, int); main()


{ int i,n, broj,imen, brojilac, imenilac, brez, irez;
clrscr(); printf("Koliko razlomaka sabirate? ");
scanf("%d", &n);
for(i=1; i<=n; i++)
{unos(&brojilac, &imenilac);
if(i==1){ brez=brojilac; irez=imenilac; }
else
{broj=brez; imen=irez;
sabiranje(brojilac,imenilac,broj,imen, &brez,&irez);
}
printf("%d/%d\n", brez, irez);
}
void unos(int *br, int *im)
{ printf("Brojilac -> " ); scanf("%d",br);
printf("Imenilac -> " ); scanf("%d",im);
if(*im<0) {*br=-*br; *im=-(*im); }
}
int nzd(int br, int im)
{ if(br == im) return(br);
else if(br>im)return(nzd(br-im,im));
else return(nzd(br,im-br));
}
int nzs(int br, int im)
{ int ns;

100
Ivan P. Stanimirović Uvod u programiranje

if(br>im) ns=br; else ns=im;


while((ns %br !=0) || (ns %im != 0))ns++;
return(ns);
}
void kracenje(int *br, int *im, int k)
{ *br /=k; *im /=k; }

void sabiranje(int pb,int pi,int db,int di,int *rb,int *ri)


{ int ns, nd;
ns=nzs(pi,di); *ri=ns; *rb=pb*ns/pi+db*ns/di;
nd=nzd(*rb, *ri);
kracenje(rb, ri, nd);
}

Primer. Napisati proceduru za učitavanje i ispis kompleksnih brojeva kao i procedure za izvođenje
osnovnih aritmetičkih operacija sa kompleksnim brojevima. Napisati test program.
#include<stdio.h>
#include<math.h>
void unos(float *,float *, float *, float *);
void saberi(float, float, float, float, float *, float *);
void oduzmi(float, float, float, float, float *, float *);
void mnozi(float, float, float, float, float *, float *);
void deli(float, float, float, float, float *, float *);
void ispis(float, float);
void main()
{ float x1,y1,x2,y2,re,im;
unos(&x1,&y1,&x2,&y2);
saberi(x1,y1,x2,y2, &re,&im); printf("\nNjihov zbir je: ");
ispis(re,im); printf("\n");
oduzmi(x1,y1,x2,y2, &re,&im);
printf("\nNjihova razlika je: "); ispis(re,im); printf("\n");
mnozi(x1,y1,x2,y2,&re,&im);
printf("\nNjihov proizvod je: "); ispis(re,im); printf("\n");
deli(x1,y1,x2,y2,&re,&im);
printf("\nNjihov kolicnik je: "); ispis(re,im);
printf("\n");
}
void unos(float *re1, float *im1, float *re2, float *im2)
{ printf("Prvi kompleksni broj? "); scanf("%f%f", re1,im1);
printf("Drugi kompleksni broj? "); scanf("%f%f", re2,im2);
}
void saberi(float re1,float im1,float re2,float im2,
float *rez, float *imz)
{*rez=re1+re2; *imz=im1+im2; }
void oduzmi(float re1, float im1, float re2, float im2,
float *rez, float *imz)
{*rez=re1-re2; *imz=im1-im2; }
void mnozi(float re1, float im1, float re2, float im2,
float *rez, float *imz)
{*rez=re1*re2-im1*im2; *imz=re1*im2+re2*im1; }
void deli(float re1, float im1, float re2, float im2,
float *rez, float *imz)
{*rez=(re1*re2+im1*im2)/(re2*re2+im2*im2);
*imz=(-re1*im2+re2*im1)/(re2*re2+im2*im2);
}
void ispis(float x, float y)
{ printf("\n %f",x);
if(y<0) printf("-"); else printf("+");
printf("i*%f\n",fabs(y));
}

101
Ivan P. Stanimirović Uvod u programiranje

Primer. a) Napisati funkciju NZD(a,b) kojom se izračunava najveći zajednički delilac za prirodne
brojeve a i b.
b) Koristeći funkciju NZD(a,b) izračunati NZD(a,b,c).
d) Napisati funkciju skratic(int a, int b, int *c, int *d) koja razlomak a/b (b0) dovodi do neskrativog
razlomka c/d.
e) Napisati funkciju skrati(int a, int b, int &c, int &d) koja razlomak a/b (b0) dovodi do neskrativog
razlomka c/d.
f) U funkciji main:
- Za tri učitana prirodna broja naći njihov NZD.
- Za dva razlomka koji su učitani preko tastature i učitani operacijski znak (+ za sabiranje, - za
oduzimanje, * za množenje, / za deljenje) odrediti rezultat računanja u neskrativom obliku.
#include<stdio.h>
#include<math.h>

int NZD(int a, int b)


{ int r;
while(a%b) { r=a%b; a=b; b=r; }
return(b);
}

int NZD3(int a, int b, int c)


{ return(NZD(a,NZD(b,c))); }

void skratic(int a, int b, int *c, int *d) /* Verzija za C */


{ int nd=NZD(a,b);
*c=a/nd; *d=b/nd;
}

void skrati(int a, int b, int &c, int &d) /* Verzija za C++ */


{ int nd=NZD(a,b);
c=a/nd; d=b/nd;
}

int NZS(int a, int b)


{ int p, n;
if(a<b) { p=a; a=b; b=p; }
n=a;
while(n%b) n+=a;
return n;
}

void operacija(int a, int b, int c, int d, char ch, int &br, int &im)
{ int as, bs, cs, ds;
skrati(a,b,as,bs); skrati(c,d,cs,ds);
switch(ch)
{ case '+': im=NZS(bs,ds), br=as*im/bs+cs*im/ds; break;
case '-': im=NZS(bs,ds), br=as*im/bs-cs*im/ds; break;
case '*': br=as*cs; im=bs*ds; break;
case '/': br=as*ds; im=bs*cs; break;
}
int nd=NZD(br, im);
im= im/nd; br=br/nd;
}

void ispis(int br, int im)


{ if(br*im<0)printf("-");
printf("%d/%d\n",abs(br),abs(im));
}

102
Ivan P. Stanimirović Uvod u programiranje

void main()
{ int a,b,c,d;
printf("a,b = ? "); scanf("%d%d",&a,&b);
printf("c= ? "); scanf("%d",&c);
printf("NZD3(%d,%d,%d)=%d\n",a,b,c,NZD3(a,b,c));
int br,im;
skratic(a,b,&br,&im); // skrati(a,b,br,im);
printf("Prvi razlomak? "); scanf("%d%d",&a,&b);
printf("Drugi razlomak? "); scanf("%d%d",&c,&d);
char op;
printf("Operacija = ? "); scanf("%c",&op); scanf("%c",&op);
operacija(a,b,c,d,op,br,im);
printf("Skraceni razlomak = "); ispis(br,im);
}
Primer. Napisati funkciju koja vraća n dana stariji datum.
Rešenje u C++:
#include<stdio.h>

int prestupna(int g)
{ return ((g%4==0) && !(g%100==0))||(g%400==0); }

void sutra(int & d, int & m, int & g)


{ switch(m)
{ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
if (d<=30) d++;
else
{ d=1;
if(++m==13)
{ m=1; g++; }
} break;
case 4: case 6: case 9: case 11:
if (d<30) d++;
else
{ d=1; m++; } break;
case 2:
if(++d>28+prestupna(g))
{ d=1; m++; } break;
}
}

void main()
{ int d,m,g,n;
scanf("%d%d%d",&d,&m,&g); scanf("%d",&n);
for(int i=1;i<=n;sutra(d,m,g),i++);
printf("%d. %d. %d.\n",d,m,g);
}

Rešenje u C:
#include<stdio.h>
int prestupna(int g)
{ return ((g%4==0) && !(g%100==0))||(g%400==0); }

void sutra(int *d, int *m, int *g)


{ printf("Na pocetku %d. %d. %d.\n",*d,*m,*g);
switch(*m)
{ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
if (*d<=30) (*d)++;
else
{ *d=1; if(++(*m)==13){ *m=1; (*g)++; }
} break;

103
Ivan P. Stanimirović Uvod u programiranje

case 4: case 6: case 9: case 11:


if (*d<30) *d++;
else { *d=1; (*m)++; } break;
case 2: if(++(*d)>28+prestupna(*g))
{ *d=1; (*m)++; } break;
}
printf("U funkciji %d. %d. %d.\n",*d,*m,*g);
}

void main()
{ int d,m,g,n;
printf("Datum = ? "); scanf("%d%d%d",&d,&m,&g);
printf("Posle koliko dana ? "); scanf("%d",&n);
for(int i=1;i<=n;sutra(&d,&m,&g),i++);
printf("%d. %d. %d.\n",d,m,g);
}
Primer. Napisati funkciju
int* biggest_of_two(int*, int*);
koja vraća pokazivač na minimum dva cela broja.
U glavnom programu učitati tri cela broja a, b, c a zatim izračunati njihov minimum.
#include <stdio.h>
int* biggest_of_two(int*, int*);
int main(void)
{ int a, b, c;
int *p;
scanf("%d%d%d",&a,&b,&c);
p = biggest_of_two(&a, &b);
printf("the biggest of %i and %i is %i\n", a, b, *p);
printf("the biggest of %i %i and %i is %i\n", a, b, c,
*biggest_of_two(&a, biggest_of_two(&b, &c)));
return 0;
}

int* biggest_of_two(int * p, int * q)


{ return (*p > *q) ? p : q; }

C dozvoljava upotrebu pokazivača na proizvoljni tip, uključujući i pokazivače.

Primer. Šta se ispisuje izvršenjem sledećeg programa?


#include<stdio.h>
void main()
{ int i=10,j=7,k;
int *p = &i;
int *q = &j;
int **pp=&p;
**pp+=1;
*pp=&k;

104
Ivan P. Stanimirović Uvod u programiranje

**pp=*q;
i=*q***pp;
printf("i = %d\n",i); // 49
i=*q/(**pp);
printf("i = %d\n",i); // 1
}

5.4. Globalne promenljive kao parametri potprograma


Sve promenljive definisane u okruženju u kome je definisan i sam potprogram mogu se koristiti i u
potprogramu po konceptu globalnih promenljivih. Potprogram može da bude i bez spiska argumenata
i da sve veze sa okruženjem ostvaruje preko globalnih promenljivih.
Primer. Potrebno je napisati program kojim se izračunava izraz
tanh(a  n  b) tanh2 (a  m  b)
D  .
tanh2 (a 2  b 2 ) tanh(a 2  b 2 )
Za izračunavanje vrednosti tanh(x) koristiti potprogram kojim se ova funkcija izračunava prema
jednoj od relacija:
e x  ex e2x 1
tanh  x ili tanh  .
e  ex e2x 1
Slede četiri moguća rešenja ovog problema u kojima se koriste različiti potprogrami sa i bez
parametara. Rešenja su data u programskom jeziku Pascal.
(a) Rešenje funkcijskim potprogramom bez argumenata. Rezultat se dodeljuje imenu funkcije.
Vrednost za x se unosi u funkciju preko globalnog parametra.
program TANH1;
var D,a,b,m,n,R1,R2,R3,x : real;
function th: real;
var R :real;
begin
R:=exp(2*x); th := (R-1)/(R+1)
end;
begin
read(a,b,m,n);
x:=a*n+b; R1:=th; x:=a+m*b; R2:=th;
x:=a*a+b*b; R3:=th; x:=a*a-b*b;
D:=R1/(R3*R3)-R2*R2/th; writeln(D);
end.

#include<stdio.h>
#include<math.h>

float D,a,b,m,n,R1,R2,R3,x;

float th()
{ float R;
R=exp(2*x); return ((R-1)/(R+1));
}

void main()
{ scanf("%f%f%f%f",&a,&b,&m,&n);
x=a*n+b; R1=th(); x=a+m*b; R2=th();
x=a*a+b*b; R3=th(); x=a*a-b*b;
D=R1/(R3*R3)-R2*R2/th(); printf("%f\n",D);
}

105
Ivan P. Stanimirović Uvod u programiranje

(b) Rešenje pomoću procedure bez argumenata. Rezultat se dodeljuje globalnom parametrom. Takođe,
i vrednost za x se unosi preko globalnog parametra.
program TANH2;
var D,a,b,m,n,R1,R2,R3,x,y : real;
procedure th;
begin
y := exp(2*x); y := (y-1)/(y+1)
end;
begin
read(a,b,m,n);
x := a*n+b; th; R1 := y;
x := a+m*b; th; R2 := y;
x := a*a+b*b; th; R3 := y;
x := a*a-b*b; th;
D := R1/(R3*R3)- R2*R2/y; writeln(D);
end.

#include<stdio.h>
#include<math.h>

float D,a,b,m,n,R1,R2,R3,x,y;

void th()
{ y=exp(2*x); y=(y-1)/(y+1); }

void main()
{ scanf("%f%f%f%f",&a,&b,&m,&n);
x=a*n+b; th(); R1=y; x=a+m*b; th(); R2=y;
x=a*a+b*b; th(); R3=y; x=a*a-b*b; th();
D=R1/(R3*R3)- R2*R2/y; printf("%f\n",D);
}
(c) Program sa funkcijskim potprogramom sa argumentima. Rezultat se dodeljuje imenu funkcije.
Vrednost za x se unosi pomoću parametra funkcije.
program TANH3;
var D,a,b,m,n : real;
function th(x: real):real;
var R : real;
begin
R := exp(2*x); th:= (R-1)/(R+1)
end;
begin
read(a,b,m,n);
D := th(a*n+b)/(th(a*a+b*b)*th(a*a+b*b)) –
th(a+m*b)*th(a+m*b)/th(a*a-b*b);
writeln(D)
end.

#include<stdio.h>
#include<math.h>

float D,a,b,m,n;

float th(float x)
{ float R=exp(2*x);
return ((R-1)/(R+1));
}

void main()
{ scanf("%f%f%f%f", &a,&b,&m,&n);
D= th(a*n+b)/(th(a*a+b*b)*th(a*a+b*b)) -

106
Ivan P. Stanimirović Uvod u programiranje

th(a+m*b)*th(a+m*b)/th(a*a-b*b);
printf("%f\n",D);
}
(d) Rešenje pomoću procedure sa argumentima. Prvi argument je izlazni a drugi ulazni.
program TANH4;
var D,a,b,m,n,Rl,R2,R3,R4 :real;
procedure th(var y: real; x: real);
begin
y := exp(2*x); y := (y-1)/(y+1)
end;
begin
read(a,b,m,n);
th(Rl, a*n+b); th(R2, a+m*b); th(R3,a*a+b*b); th(R4,a*a-b*b);
D:=Rl/(R3*R3)-R2*R2/R4; writeln(D)
end.

#include<stdio.h>
#include<math.h>

float D,a,b,m,n,Rl,R2,R3,R4;
void th(float *y, float x)
{ *y=exp(2*x); *y=(*y-1)/(*y+1); }

void main()
{ scanf("%f%f%f%f", &a,&b,&m,&n);
th(&Rl, a*n+b); th(&R2, a+m*b); th(&R3,a*a+b*b); th(&R4,a*a-b*b);
D=Rl/(R3*R3)-R2*R2/R4; printf("%f\n",D);
}

#include<stdio.h>
#include<math.h>

float D,a,b,m,n,Rl,R2,R3,R4;
void th(float &y, float x)
{ y=exp(2*x); y=(y-1)/(y+1); }

void main()
{ scanf("%f%f%f%f", &a,&b,&m,&n);
th(Rl, a*n+b); th(R2, a+m*b); th(R3,a*a+b*b); th(R4,a*a-b*b);
D=Rl/(R3*R3)-R2*R2/R4; printf("%f\n",D);
}
U programskom jeziku FORTRAN konceptu globalnih promenljivih na neki način odgovara
koncept COMMON područja. Sve promenljive koje su zajedničke za više programskih modula
obuhvataju se sa COMMON i pamte se u zasebnom memoriskom bloku koji je dostupan svim
potprogramima koji se referenciraju na isto COMMON područje.
Primeri

Primer. (C) Za paran broj N proveriti hipotezu Goldbaha. Prema toj hipotezi, svaki paran broj veći
od 2 može se predstaviti zbirom dva prosta broja.
Rešenje se sastoji u proveri da li je za svaki prost broj i (i = 3, ... , n/2) broj n-i takođe prost. Da li
je broj prost proverava se funkcijom prost.
#define nepar(x) ((x)%2)?1:0)
#include "math.h"

int prost(long n)
{ long i,koren; int q;
koren=floor(sqrt(n)); q=(nepar(n) || (n==2);

107
Ivan P. Stanimirović Uvod u programiranje

i=3;
while ((q) && (i<=koren)) { q=((n % i) != 0); i=i+2; };
return (q);
};

void main()
{long n,i;
int q;
do { printf("\nunesite paran broj: "); scanf("%ld",&n); }
while((n<4) || ((n % 2) != 0));
i=2; q=0;
while ((i<= n/2) && (!q))
{ q=(prost(i) && prost(n-i));
if (q) printf("\nTo su brojevi %ld i %ld",i,n-i);
i++;
};
if (!q) printf("\n Hipoteza ne vazi za %ld ",n);
}
Primer. Napisati funkcijski potprogram koji izračunava n-ti stepen broja x koristeći relaciju
1, n=0
xn = (xk)2, n=2k
x(xk)2, n=2k+1
Napisati program za stepenovanje koji u beskonačnom ciklusu učitava realan broj x i prirodan broj n i
izračunava xn.
program Stepenovanje2;
type PrirodniBroj = O..Maxint;
var Pi, PiKvadrat : Real ;
function Stepen(Osnova:Real; Eksponent:PrirodniBroj): Real;
var Rezultat:Real;
begin
Rezultat := 1;
while Eksponent > 0 do
begin
while not Odd(Eksponent) do
begin
Eksponent := Eksponent div 2; Osnova := Sqr(Osnova)
end;
Eksponent:= Eksponent-1; Rezultat := Rezultat*Osnova
end;
Stepen:=Rezultat
end { Stepen };
begin
repeat
readln(x); readln(n);
Writeln(x:11:6, n:3, Stepen(x,n):11:6);
until false
end { Stepenovanje2 }.
Test primeri:
2.000000 7 128.000000
3.141593 2 9.869605
3.141593 4 97.409100
Primer. (PASCAL) Napisati funkciju koja izračunava vrednost verižnog razlomka

108
Ivan P. Stanimirović Uvod u programiranje

1
v ( m) 
1
1
1
2
...
1
m2
1
m 1
m
Napisati program kojim se izračunava suma
1 1 1
S  1   ...  (1) n .
v(3) v(5) v(2n  1)
program verizni_razlomci;
var s,znak:real;
i,n:integer;
function verizni(m:integer):real;
var s:real;
i:integer;
begin
s:=0;
for i:=m downto 1 do s:=1/(s+i);
verizni:=s;
end;

begin
readln(n);
s:=1.0; znak:=-1;
for i:=1 to n do
begin
s:=s+znak/verizni(2*i+1); znak:=-znak;
end;
writeln(s);
end.

Primer. Naći najveći, najmanji i drugi po veličini element između unetih realnih brojeva, bez
korišćenja nizova.
program najveci;
var max1,max2,min,x:real;
n,i:integer;
begin
write('Koliko brojeva? '); readln(n);
if n>2 then
begin
writeln('Unesi ',n,' brojeva'); read(x);
max1:=x; min:=x; read(x);
if x>=max1 then
begin
max2:=max1; max1:=x
end
else if x>=min then max2:=x
else begin
max2:=min; min:=x;
end;
for i:=3 to n do
begin
read(x);
if x>=max1 then
begin
max2:=max1; max1:=x
end
else if x>max2 then max2:=x

109
Ivan P. Stanimirović Uvod u programiranje

else if x<min then min:=x;


end;
writeln('Najveci je ',max1:10:6);
writeln('Drugi po velicini je ',max2:10:6);
writeln('Najmanji je ',min:10:6);
end
else writeln('Manjak brojeva')
end.
Primer. Šta se ispisuje posle izvršenje sledećeg programa?
program UzgredniEfekat(Output);
var A, Z : Integer ;
function Skriven(X:Integer):Integer;
begin
Z := Z-X { uzgredni efekat na Z};
Skriven := Sqr(X)
end { Skriven } ;
begin
Z := 10; A := Skriven(Z); Writeln(A,' ', Z);
Z := 10 ; A := Skriven(10) ; A := A*Skriven(Z);
Writeln(A,' ', Z) ;
Z := 10; A := Skriven(Z); A := A*Skriven(10);
Writeln(A,' ', Z)
end { UzgredniEfekat}

#include<stdio.h>
int a,z;
int Skriven(int x)
{ z=z-x; // uzgredni efekat na z
return x*x;
}
void main()
{ z=10; a=Skriven(z); printf("%d %d\n",a,z);
z=10; a=Skriven(10); a*=Skriven(z);
printf("%d %d\n",a,z);
} // { UzgredniEfekat}

Rezultat:
100 0
0 0
10000 -10

5.5. Rekurzivni potprogrami


Funkcija, odnosno procedura je rekurzivna ako sadrži naredbu u kojoj poziva samu sebe. Rekurzija
može biti direktna, kada funkcija direktno poziva samu sebe. Takođe, rekurzija može biti i indirektna,
kada funkcija poziva neku drugu proceduru ili funkciju, koja poziva polaznu funkciju (proceduru).
U realizaciji rekurzije moraju se poštovati dva osnovna principa:
- Mora da postoji rekurentna veza između tekućeg i prethodnog (ili narednog) koraka u
izračunavanju.
- Mora da postoji jedan ili više graničnih uslova koji će prekinuti rekurzivno izračunavanje.
Neki programski jezici dozvoljavaju poziv potprograma u telu samog tog potprograma. Takvi
potprogrami nazivaju se rekurzivnim i pogodno su sredstvo za rešavanje problema koji su rekurzivno
definisani.

110
Ivan P. Stanimirović Uvod u programiranje

Tipičan primer rekurzivnog potprograma je potprogram za izračunavanje faktorijela funkcije


definisanog sa:
n*(n-l)!, za n>0
n! =
1, za n = 0
Primer. Program za izračunavanje faktorijela realizovan u Pascal-u:
function FAKT(N:integer): integer;
begin
if N>0 then FAKT := N*FAKT(N-l)
else FAKT := 1
end;
Koncept rekurzivnih potprograma se najbolje može sagledati pomoću grafa poziva potprograma na
kome se predstavlja svaki od poziva potprograma. Na slici je prikazan graf poziva potprograma FAKT
za N = 4.

U praksi se često sreću i problemi u kojima postoji višestruka rekurzija. Jedan od takvih je problem
izračunavanja članova Fibonačijevog niza brojeva. Fibonačijeva funkcija je definisana kao:
f(n-l) + f(n-2), n>1
f(n) = 1, n=1
1, n=0
Potprogram za izračunavanje članova Fibonačijevog niza biće dvostruko rekurzivan. Dajemo
implementaciju u Pascal-u:
function Fib(n: Integer): integer;
begin
if n > 1 then
Fib := Fib(n-l) + Fib(n-2)
else Fib := 1;
end;
U ovom potprogramu rekurzija dakle nije u stvaranju jedne, već dve kopije iste funkcije. Moguće
su i trostruke, cetvorostruke, itd. rekurzije jer broj poziva kopija ničim nije ograničen. Graf poziva
ovakve dvostruke rekurzije razlikuje se od grafika rekurzija iz prethodnog primera.

Još jedan od klasičnih rekurzivnih problema je čuveni problem Hanojskih kula.

111
Ivan P. Stanimirović Uvod u programiranje

Primer. Hanojske kule.


procedure Hanoj (n,sa,na,preko : integer);
begin
if n > 0 then
begin
Hanoj(n-1, sa preko, na);
Write(sa, ' ->’, na);
Hanoj(n-1, preko, na, sa);
end
end;
Prema staroj indijskoj legendi, posle stvaranja sveta je Bog Brama (Brahma) postavio tri
dijamantska stuba i na prvi postavio 64 zlatna prstena različitih prečnika tako da svaki naredni bude
manji od prethodnog. Sveštenici hrama moraju da prebacuju te prstenove sa prvog na treći stub
koristeći pri tome drugi, all samo jedan po jedan i to tako da se veći prsten ne može naći iznad manjeg.
Kad svi prstenovi budu prebačeni na treći stub nastupiće kraj sveta.
Ovde ce biti prikazan primer programa koji vrši ovu operaciju prebacivanja i koji ne zavisi od broja
prstenova. Međutim uobičajeno je da se ovaj primer izvodi za manji broj krugova 3 do 5 već samim
tim što je najmanji broj potrebnih poteza 2n - 1. Za slučaj sa 64 kruga dolazimo do broja od
18.446.744.073.709.551.615 poteza.
U opstem slučaju, međutim, problem se sastoji u tome da se n prstenova prebaci sa prvog stuba (1)
na treći stub (3) preko drugog stuba (2). Cilj je, dakle, ostvarljiv u tri "koraka". Sve prstenove osim
najvećeg (n-tog), prebaciti na drugi stub, koristeći treći stub. Zatim n-ti prsten prebaciti na treći stub, a
onda na njega staviti pomoćnu gomilu sa drugog stuba, koristeći prvi stub kao pomoćni. Da bi se ovo
izvelo potrebno je ceo postupak izvesti za n -1 prsten, a za to je potrebno izvršiti istu proceduru za n -
2 prstena itd. Tako dolazimo do rekurzije.
Procedura se poziva za naprimer Hanoj(3,1,3,2).
Razmotrićemo još primer rekurzivnog potprograma za generisanje svih mogućih permutacija bez
ponavljanja skupa sa n elemenata P(n), dat kao prethodni primer.

5.5.1. Primeri rekurzivnih funkcija u C


Primer. Jedmostavni primeri rekurzivnih funkcija.

#include <stdio.h>
void fun1(int);
void fun2(int);
void fun3(int);
void main()
{ printf("\n fun1(5)\n"); fun1(5);
printf("\n fun2(5)\n"); fun2(5);
printf("\n fun3(5)\n"); fun3(5);
}

void fun1(int n)
{ printf("%2d",n); if(n) fun1(n-1); return; }

void fun2(int n)
{ if(n) fun2(n-1); printf("%2d",n); return; }

void fun3(int n)
{ printf("%2d",n); if(n) fun3(n-1); printf("%2d",n); return;
}

Test primeri:
fun1(5)
5 4 3 2 1 0

112
Ivan P. Stanimirović Uvod u programiranje

fun2(5)
0 1 2 3 4 5

fun3(5)
5 4 3 2 1 0 0 1 2 3 4 5

Primer. Rekurzivno izračunavanje faktorijela.


#include <stdio.h>
long fact(short);
void main()
{ short n; long rezultat;
scanf("%d",&n); rezultat = fact(n);
printf("Faktorijel od %d = %ld\n", n,rezultat);
}

long fact(short n)
{ if(n<=1)return(1L); else return(n*fact(n-1)); }

Primer. Napisati rekurzivnu funkciju za izračunavanje n-tog člana Fibonačijevog niza:

fib(n)= 1, n=1 ili n=0,


fib(n-1)+fib(n-2), n>1 .

#include <stdio.h>
long fib(short);
void main()
{ short n;
scanf("\n %d", &n);
printf("%d-ti clan Fibonacijevog niza = %ld\n", n,fib(n));
}

long fib(short n)
{ if(n<=1)return((long)1); else return(fib(n-1)+fib(n-2));}

Broj rekurzivnih poziva pri izračunavaju Fibonačijevih brojeva može se smanjiti na sledeći način:
long fib(long a, long b, short n);
{ if(n==2)return b;
else { b=a+b; a=b-a; n--; return fib(a,b,n); }
}

Primer. Zadati broj tipa int ispisati znak po znak.


#include <stdio.h>
void printd(int n)
{ if(n<0) { putchar('-'); n=-n; }
if(n/10) printd(n/10);
putchar(n%10+'0');
}
void main()
{int n; scanf("%d", &n); printd(n); }

Primer. Rekurzivno izračunavanje najvećeg zajedničkog delioca dva cela broja.


#include <stdio.h>
int nzd(int n, int m)
{ if(n==m) return(m);
if(n<m) return(nzd(n,m-n));
else return(nzd(n-m,m));
}
void main()
{ int p,q;
scanf("%d%d",&p,&q); printf("nzd(%d,%d)=%d\n",p,q,nzd(p,q));

113
Ivan P. Stanimirović Uvod u programiranje

Primer. Rekurzivno izračunati Akermanovu funkciju A(n,x,y), koja je definisana na sledeći način:
A(n, x, y) = x+1, za n=0
A(n, x, y) = x, za n=1, y=0,
A(n, x, y) = 0, za n=2, y=0
A(n, x, y) = 1, za n=3, y=0
A(n, x, y) = 2, za n>3, y=0
A(n, x, y) = A(n-1, A(n, x, y-1), x), inače.

#include <stdio.h>
long aker(int,int,int);
void main()
{ int x,y,n;
printf("Unesit n"); scanf("%d",&n); printf("Unesit x");
scanf("%d",&x); printf("Unesit y"); scanf("%d",&y);
printf("A(%d,%d,%d)=%ld\n",n,x,y,aker(n,x,y));
}
long aker(int n, int x, int y)
{ int pom;
if(n==0)return(x+1); if(n==1 && y==0) return(x);
if(n==2 && y==0) return(0); if(n>3 && y==0) return(2);
else { pom=aker(n,x,y-1); return(aker(n-1,pom,x)); }
}
Primer. Koristeći rekurzivnu definiciju proizvoda dva prirodna broja napisati odgovarajuću funkciju.
#include <stdio.h>
long p(int a, int b)
{ if(b==1) return(a); return(a+p(a,b-1)); }
void main()
{ int x,y;
printf("Unesi dva prirodna broja "); scanf("%d%d",&x,&y);
printf("%d*%d=%ld\n",x,y,p(x,y));
}

Primer. Napisati rekurzivni program za izračunavanje sume cifara zadatog prirodnog broja.
#include <stdio.h>
int sumacif(long n)
{ if(!n)return(0); else return(n%10+sumacif(n/10)); }

void main()
{ long k;
printf("Unesi dug ceo broj "); scanf("%ld",&k);
printf("Suma cifara od %ld=%d\n",k,sumacif(k));
}

Primer. Napisati rekurzivni program za izračunavanje količnika dva prirodna broja na proizvoljan
broj decimala.
#include <stdio.h>
void kolicnik(int ind, int n, int m, int k)
{ if(ind) printf("%d.",n/m);
else printf("%d",n/m);
if(k) kolicnik(0,(n%m)*10,m,k-1); }

void main()
{ int n,m,k;
printf("Brojilac? "); scanf("%d",&n);
printf("Imenilac? "); scanf("%d",&m);

114
Ivan P. Stanimirović Uvod u programiranje

printf("Broj decimala? "); scanf("%d",&k);


kolicnik(1,n,m,k);
}

Primer. Hanojske kule.


#include <stdio.h>
void main()
{ int bd; void prebaci();
printf("Broj diskova = ? "); scanf("%d",&bd);
prebaci(bd,1,3,2);
}

void prebaci(int n, int sa, int na, int preko)


{ if(n) { prebaci(n-1,sa,preko,na);
printf("%d->%d ",sa,na); prebaci(n-1,preko,na,sa);
}

Primer. Sa tastature se učitava bez greške formula oblika


<formula>::=<cifra>|M(<formula>,<formula>)|m(<formula>,<formula>)
<cifra>::=0|1|2|3|4|5|6|7|8|9
M- maksimum, m-minimum.
Napisati rekurzivnu funkciju kojim se izračunava vrednost izraza.
Na primer, M(4,m(6,9))=6.
#include<iostream.h>
#include<stdio.h>
int f()
{ char ch,z;
int x,y;
ch=getchar(); if(ch>='0' && ch<='9') return ch-'0';
//sada je ch= M ili m
z=getchar(); // cita otvorenu zagradu
x=f();
z=getchar(); // cita zarez
y=f();
z=getchar(); // cita zatvorenu zagradu
switch(ch)
{ case 'M': return (x>y)?x:y;
case 'm': return (x>y)?y:x;
}
}

void main()
{ cout<<"----> "<<f()<<endl; }

5.6. Implementacija potprograma


Prilikom prevođenja programa kompilator vrši planiranje memorijskog prostora koji će biti
dodeljen programu (Storage allocation). Pored toga što treba da se rezerviše memorijski prostor za
smeštaj kôda programa i podataka koji se obrađuju u njemu, za svaki od potprograma koji se poziva iz
programa generiše se i jedan aktivacioni slog u koji se smeštaju podaci koji se preuzimaju od glavnog
programa, lokalni podaci potprograma i takozvane privremene promenljive koje generiše kompilator
prilikom generijsanja mašinskog koda. Struktura jednog aktivacionog sloga data je na slici.
Rezultati koje vraća potprogram
Stvarni argumenti
Opcioni upravljački linkovi aktivacionog sloga glavnog programa
Opcioni linkovi za pristup podacima u drugim aktivacionim slogovima

115
Ivan P. Stanimirović Uvod u programiranje

Podaci o statusu
Lokalni podaci
Privremene promenljive koje generiše kompilator

Za smeštaj aktivacionih slogova koristi se jedna od sledeće tri strategije: statička, pomoću steka i
dinamička. U zavisnosti od toga koja je strategija primenjena zavisi da li će ill ne biti mogući
rekurzivni pozivi potprograma.
Kod statičkog smeštanja aktivacionih slogova, kompilator unapred rezerviše fiksan memorijski
prostor čiji se sadrzaj obnavlja kod svakog poziva potprograma. To znači da kod ovakvog smestanja
nisu mogući rekurzivni pozivi potprograma jer se kod svakog novog poziva potprograma gubi
informacija o prethodnom pozivu. Ovakva tehnika primenjuje se na primer kod realizacije kompilatora
za programski jezik FORTRAN, pa se u njemu zbog toga ne mogu koristiti rekurzije.
Kod strategije koja se zasniva na primeni steka za smeštaj aktivacionih slogova koristi se stek u
koji se za svaki poziv potprograma smešta jedan aktivacioni slog. Ova tehnika dozvoljava rekurziju jer
se kod svakog novog poziva potprograma generiše novi slog i smešta u stek. Na kraju potprograma
slog se izbacuje iz steka. To znači da je u toku izvršavanja programa ovaj stek dinamički zauzet
aktivacionim slogovima onih potprograma koji su trenutno aktivni. Od veličine memorijskog prostora
koji je dodeljen steku zavisi i dubina rekurzivnih poziva potprograma. Na slici ispod prikazana je
promena strukture steka u toku izvršavanja programa u kome se poziva rekurzivni potprogram za
izračunavanje Fibonačijevih brojeva za n = 4.

116
Ivan P. Stanimirović Uvod u programiranje

117
Ivan P. Stanimirović Uvod u programiranje

Treća, dinamička strategija sastoji se u tome da se za svaki poziv potprograma generiše aktivacioni
slog koji se smešta u poseban deo memorije nazvan Heap. U ovom slučaju aktivacioni slogovi
potprograma povezuju se u dinamičku strukturu podataka koja odgovara stablu poziva potprograma.
Očigledno je da i ova tehnika dozvoljava rekurziju.

5.7. Scope rules (domen važenja)


Komponovana naredba (blok) je serija deklaracija iza koje sledi serija naredbi između zagrada { i }.
Funkcije se mogu tretirati kao imenovani blokovi sa parametrima i dozvoljenom return naredbom.
Bazično pravilo domena važenja je da su identifikatori dostupni samo u bloku u kome su
deklarisani. Jedno ime u spoljašanjem bloku važi dok se ne redefiniše u unutrašnjem. Tada je ime u
spoljašnjem bloku skriveno (ili maskirano) tim imenom unutrašnjeg bloka.

Primer.
/* spoljasnji blok */
int a=2; printf("%d\n",a) /* 2 */
/* unutrašnji blok */
int a=3; print("%d\n",a); /* 3 */

118
Ivan P. Stanimirović Uvod u programiranje

printf("%d\n",a); /*2 */

5.8. Memorijske klase u C


Svaka promenljiva i funkcija u C ima dva atributa: tip i memorijsku klasu. Memorijske klase su
definisane ključnim rečima auto, extern, static ili register
Promenljive deklarisane unutar tela funkcije jesu, podrazumevano (by default), memorijske klase
automatic. promenljive ove klase deklarišu se eksplicitno ključnom rečju auto.
Primer. Deklaracija unutar nekog bloka
char c; int i,j,k; …
je ekvivalentna sa
auto char c; auto int i,j,k; …
Kada je blok unet, sistem rezerviše adekvatnu memoriju za promenljive klase auto. Ove promenljive
se tretiraju kao ''lokalne'' za blok. Kada se izađe iz bloka sistem više ne pamti vrednosti ovih
promenljivih.
Sve funkcije i promenljive deklarisane izvan tela funkcija imaju memorijsku klasu external, i one
su globalne za sve funkcije deklarisane posle njih.

Primer.
#include<stdio.h>
int a=7;
void main()
{ void f(void);
void g(void);
{ printf("%d\n",a); /* 7 */
f(); printf("%d\n",a); /* 8 */
g(); printf("%d\n",a); /* 8 */
}

void f()
{ printf("%d\n",a); /*7 */
a++; printf("%d\n",a); /* 8 */
}

void g()
{ int a=10;
printf("%d\n",a); /* 10 */
}

Promenljiva je globalna na nivou modula ako je deklarisana van svih funkcija u modulu.
memorijski prostor se trajno dodeljuje, a memorijska klasa te promenljive je extern. Globalnost je
određena mestom deklaracije. Globalna promenljiva može da bude maskirana lokalnom
promenljivom istog imena.
Da bi globalna promenljiva bila dostupna iz drugih modula, ona mora da se u tim modulima
definiše pomoću ključne reči extern.
Primer. Izrazom oblika
extern int a;
promenljiva a se ne deklariše, već definiše, tj. ne dodeljuje se memorijski prostor, nego se C
prevodilac informiše o tipu promenljive. Eksterna promenljiva se može inicijalizovati isključivo na
mestu svoje deklaracije.
Primer. Dat je sledeći program koji se nalazi u dve datoteke (dva modula). U datoteci modul1.c se
nalazi program

119
Ivan P. Stanimirović Uvod u programiranje

#include <stdio.h>
#include “modul2.c”
char c='w';
void main()
{ void f();void g();
printf("pre funkcije f: c= %c\n",c);
f(); printf("posle funkcije f: c= %c\n",c);
g(); printf("posle funkcije g: c= %c\n",c);
}
Promenljiva c je globalna, pa se njoj može pristupiti iz drugih modula pomoću ključne reči extern.
Neka je datoteka modul2.c sledećeg sadržaja
extern char c;
void f()
{ c = 'a'; }

void g()
{ char c='b'; }
Dobijaju se sledeći rezultati:
Pre funkcije f: c=w
Posle funkcije f: c=a
Posle funkcije g: c=a

Funkcija f menja vrednost eksterne promenljive c, a to mogu i druge funkcije iz ove datoteke
(modula).
Ako datoteka modul2.c ima sadržaj
f() { extern char c; c='a'; }
takođe se menja vrednost promenljive c. Međutim, to nebi mogle da učine druge funkcije iz datoteke
modul2.c.
Statičke promenljive se koriste u dva slučaja. U prvom slučaju, omogućava lokalnoj promenljivoj
da zadrži vrednost kada se završi blok u kome je deklarisana. Druga primena je u vezi sa globalnom
deklaracijom, i omogućuje mehanizam privatnosti globalnih promenljivih.
Primer. (1.primena)
#include<stdio.h>
void fun1()
{ static int x=0; int y=0;
printf("static=%d auto = %d\n",x,y); ++x,++y;
}
void main()
{ int i; for(i=0; i<3; ++i) fun1(); }

Izlaz je:
static=0 auto=0
static=1 auto=0
static=2 auto=0

U vezi sa drugom primenom, koristi se činjenica da su statičke promenljive lokalne u okviru


modula, jer im mogu pristupiti samo funkcije iz istog modula.

Pored promenljivih, i funkcije mogu da se definišu kao extern ili static. Memorijska klasa extern
se uzima po definiciji. Statičke funkcije su dostupne samo funkcijama iz istog modula.

Korišćenje registarskih promenljivih omogućava programeru da utiče na efikasnost izvršenja


programa. Ako funkcija često koristi neku promenljivu, može se zahtevati da se njena vrednost
memoriše u brzim registrima centralne procesorske jedinice (CPU), uvek kada se funkcija izvršava.
Registarske promenljive su najčešće promenljive za kontrolu petlje i lokalne promenljive u

120
Ivan P. Stanimirović Uvod u programiranje

funkcijama. Promenljiva se može učiniti registarskom pomoću ključne reči register.

Primer.
register char c;
register int i;

Promenljiva deklarisana kao registarska takođe je i automatska. Ako nema slobodnih registara u
CPU, C prevodilac ne prepoznaje grešku.
Primer. Promenljiva i deklariše se kao registarska neposredno pre upotrebe u for petlji.
register int i;
for(i=0;i<5;++i) ...
Završetak bloka u kome je deklarisana registarska promenljiva oslobađa registar.
5.8.1. Životni vek objekata
Životni vek objekta: vreme u toku izvršavanja programa u kojem objekat postoji i za koje mu se
može pristupati. Na početku životnog veka, objekat se kreira, poziva se njegov konstruktor, ako ga
ima. Na kraju životnog veka se objekat uništava, poziva se njegov destruktor, ako ga ima.
5.8.2. Vrste objekata po životnom veku
 Po životnom veku, objekti se dele na:
statičke, automatske, dinamičke, tranzijentne (privremene).
 Vek atributa klase = vek objekta kome pripadaju.
 Vek formalnog argumenta = vek automatskog objekta.
Formalni parametri se inicijalizuju vrednostima stvarnih argumenata.
Statički i automatski objekti
 Automatski objekat je lokalni objekat koji nije deklarisan kao static.
Životni vek: od njegove definicije, do napuštanja oblasti važenja.
Kreira se iznova pri svakom pozivu bloka u kome je deklarisan.
Prostor za automatske objekte se alocira na stack-u.
 Statički objekat je globalni objekat ili lokalni deklarisan kao static.
Životni vek: od izvršavanja definicije do kraja izvršavanja programa.
Globalni statički objekti:
 kreiraju se samo jednom, na početku izvršavanja programa,
 kreiraju se pre korišćenja bilo koje funkcije ili objekta iz istog fajla,
 nije obavezno da se kreiraju pre poziva funkcije main(),
 prestaju da žive po završetku funkcije main().
Lokalni statički objekti počinju da žive pri prvom nailasku toka programa na njihovu
definiciju.
Primer.
int a=1;
void f() {
int b=1; // inicijalizuje se pri svakom pozivu
static int c=1; // inicijalizuje se samo jednom
cout<<"a="<<a++<<" b="<<b++<<" c="<<c++<<endl;
}
void main() {
while (a<3) f();
}

izlaz:
a = 1 b = 1 c = 1
a = 2 b = 1 c = 2

121
Ivan P. Stanimirović Uvod u programiranje

6. STRUKTURNI TIPOVI PODATAKA

Pojam struktura podataka, nizova, slogova, skupova i datoteka je poznat i prisutan u višim
programskim jezicima od samog njihovog nastanka. U okviru strukturnih tipova podataka, vrednosti
koje tip obuhvata definisane su kao jednorodne ili raznorodne strukture podataka. U jeziku Pascal
postoji mogućnost definisanja strukturnih tipova koji omogućavaju rad sa nizovima, slogovima,
skupovima i datotekama. Skupovi se kao strukturni tipovi podataka ređe sreću kod drugih programskih
jezika, dok su nizovi, slogovi i datoteke postali standardni koncept, prisutan u mnogim programskih
jezicima (Ada, C).

6.1. Polja u programskim jezicima


Niz (Polje) (array) je indeksirana sekvenca komponenti istog tipa. Polja u programskim jezicima
jesu jednodimenzionalne ili višedimenzionalne strukture podataka koje obuhvataju više vrednosti istog
tipa. Može se reći, da jednodimenzionalna polja odgovaraju pojmu vektora, a višedimenzionalna
pojmu matrica. Bilo koji niz koji ima komponente nekog tipa T pri čemu su vrednosti indeksa iz
nekog tipa S predstavlja preslikavanje S → T. Dužina (length) niza jeste broj njegovih komponenti,
koji se označava sa #S. Nizovi se mogu naći u svakom imperativnom i objektno orijentisanom jeziku.
Tip S mora da bude konačan, tako da je niz konačno preslikavanje. U praksi, S je uvek rang uzastopnih
vrednosti, što se naziva rang indeksa niza (array’s index range). Granice opsega indeksa nazivaju se
donja granica (lower bound) i gornja granica (upper bound).
Kao i sve druge promenljive u programu, i niz se mora deklarisati pre nego što se upotrebi.
Deklaracijom niza kompajleru se saopštavaju sledeći podaci o nizu: ime (koje je predstavljeno nekim
identifikatorom), tip elemenata niza i veličinu niza (broj elemenata tog niza). Bazične operacije nad
nizovima jesu:
• konstruisanje (construction) niza iz njegovih komponenti;
• indeksiranje (indexing), tj. selektovanje partikularne komponente niza, kada je zadat njegov
indeks. Indeks koji se koristi za selekciju komponente niza jeste vrednost koja se izračunava.
Programski jezici C i C++ ograničavaju indeks niza na celobrojne vrednosti čija je donja granica 0.
Opšti oblik deklaracije niza u jeziku C je
<tip elemenata> <ime tipa> [<celobrojni izraz>];

PASCAL omogućava da rang za indeks niza može biti odabran od strane programera, jedina
restrikcija je rang indeksa mora da bude diskretan primitivni tip.
Za opis ovih struktura u nekim programskim jezicima se koristi ključna reč array. Takav je slučaj u
jeziku PASCAL. Opšti oblik deklaracije niza u PASCALu je
array[<tip indeksa>] of <tip elemenata>;
Razmotrimo sledeći primer u jeziku PASCAL:
type VEKTOR = array [1..10] of real;
var A,B : VEKTOR;
Ovom definicijom definisan je tip VEKTOR, kao niz od 10 elemenata tipa real. Promenljive A i B
su deklarisane kao promenljive tipa VEKTOR. Svakoj od promenljivih A i B odgovara struktura
podataka koja se sastoji od 10 komponenti tipa real. Svakoj od komponenti vektora opisanog na ovaj
način može se pristupiti preko indeksa. U nekim jezicima (Pascal) koristi se i notacija sa uglastim
zagradama na primer A[3] i A[J]. U ovakvim slučajevima indeks može da bude definisan i kao
celobrojni izraz. Ove indeksirane promenljive mogu se u programu upotrebiti svuda gde se javljaju i
proste promenljive odgovarajućeg tipa. U datom primeru A(J) i B(J) su promenljive tipa real. Evo
nekih primera koji ilustruju upotrebu niza:
A[3]:= 0.0; - Trećem elementu vektora A dodeljuje se vrednost 0;

122
Ivan P. Stanimirović Uvod u programiranje

X := A[3]; - promenljiva X dobija vrednost trećeg elementa vektora A.


Polja se realizuju kao statičke strukture podataka, što znači da se za svaki određeni vektor rezerviše
unapred definisani prostor u memoriji računara. Granice indeksa u definiciji tipa mogu da budu date i
preko promenljivih ili čak i preko izraza, ali ove vrednosti treba da budu poznate u tački programa u
kojoj se pojavljuje definicija tipa. Evo nekih definicija takvog oblika u jeziku Pascal:
type VEKTOR1 = array [1 .. N] of float;
type VEKTOR2 = array [N .. N+M] of float;
U svim ovim primerima, za definisanje indeksa je iskorišćen interval u skupu celih brojeva
(integer). To je i prirodno, jer se najčešće za indeksiranje i u matematici koriste celobrojne vrednosti.
U Pascal-u i Adi se za definisanje indeksa može koristiti bilo koji diskretni tip podataka. Razmotrimo
sledeći primer u kome se kreira tabela sa podacima o količini padavina u svakom mesecu jedne godine
u jeziku Ada:
type PADAVINE is delta 0.1 range 0.0 .. 200.0;
type MESECI is JAN,FEB,MAR,APR,MAJ,JUN,JUL,AVG,SEP,OKT,NOV,DEC);
type KOL_PAD is array [MESECI] of PADAVINE;

U programu se mogu koristiti promenljive tipa KOL_PAD.


PODACI: KOL_PAD;
Analogni tip podataka u jeziku Pascal je dat sledećim definicijama:
type MESECI = (JAN,FEB,MAR,APR,MAJ,JUN,JUL,AVG,SEP,OKT,NOV,DEC);
type KOL_PAD = array [MESECI] of real;
var PODACI: KOL_PAD;
U ovom primeru definisan je strukturni tip podataka KOL_PAD, za čije indeksiranje se koristi
diskretni tip nabrajanja MESECI, tako da vektor PODACI ima ukupno 12 komponenti, od kojih svaka
odgovara jednom mesecu u godini. Svakoj od ovih komponenti pristupa se preko imena meseca kao
indeksa. Na taj način, u programu će PODACI[MART] biti promenljiva kojoj se dodeljuje vrednost
koja odgovara padavinama u mesecu martu. Diskretni tipovi podataka se mogu koristiti za definisanje
opsega indeksa, tako što se u okviru skupa vrednosti određenog diskretnog tipa koristi samo interval
vrednosti. Na primer, u razmatranom primeru moglo je da bude postavljeno ograničenje da se
razmatraju padavine u letnjem periodu godine. U tom slučaju, pogodno je indeks vektora PODACI
definisati tako da ima samo komponente koje odgovaraju letnjim mesecima.

6.2. Jednodimenzionalni nizovi u C


Deklaracija jednodimenzionalnog niza se sastoji od imena tipa iza koga sledi identifikator (ime
niza) i na kraju celobrojni izraz između srednjih zagrada. Vrednost ovog izraza mora da bude
pozitivan ceo broj i predstavlja veličinu niza. Indeksiranje elemenata niza počinje od 0.
Opšta forma izraza kojom se deklariše niz je sledeća:
<tip elemenata> <ime> [<celobrojni izraz>];
Veličina niza zadaje se konstantom ili konstantnim celobrojnim izrazom. Na primer, izrazom
int b[100] deklariše se niz sa 100 celobrojnih vrednosti. Niz b se sastoji od 100 celobrojnih
(indeksiranih) promenljivih sa imenima b[0], ..., b[99].
Komponentama niza se pristupa navođenjem imena niza i celobrojnog izraza između srednjih
zagrada. Ovim izrazom se definiše indeks željenog elementa niza. Ako je indeks manji od 0 ili veći ili
jednak od broja elemenata u nizu, neće se pristupiti elementu niza.

Nizovi mogu da imaju memorijsku klasu auto, extern, static, a ne mogu biti memorijske klase
register.
Nizovi se mogu inicijalizovati u naredbi deklaracije.
Primer. Posle inicijalizacije

123
Ivan P. Stanimirović Uvod u programiranje

float x[7]={-1.1,0.2,33.0,4.4,5.05,0.0,7.7};
dobija se
x[0]=-1.1, x[1]=0.2, … x[6]=7.7.
Lista elemenata koji se koriste za inicijalizaciju vektora može biti manja od broja njegovih
elemenata. Ako je niz memorijske klase static ili extern, njegovi preostali elementi postaju 0. U
slučaju da je niz memorijske klase auto, za ove vrednosti će biti neke vrednosti koje su zaostale od
ranije u delu memorije koja se koristi za smeštanje elemenata niza. Ako extern ili static niz nije
inicijalizovan, tada kompajler automatski inicijalizuje sve elemente na 0.
Ako je niz deklarisan bez preciziranja dužine, i pritom inicijalizovan, tada se dužina niza implictno
određuje prema broju inicijalizatora.
Na primer, izraz int a[]={3,4,5,6}; proizvodi isto dejstvo kao i izraz
int a[4]={3,4,5,6};
Primer. Deklaracije nizova.

Primer. Pristup elementima nizova.

Primeri.
Primer. Izračunati broj pojavljivanja svakog velikog slova u unetom tekstu.
#include <stdio.h>
#include <ctype.h>
void main()
{ int c,i, slova[26];
for(i=0;i<26;++i) slova[i]=0;
while((c=getchar()) !=EOF)
if(isupper(c)) ++slova[c-'A'];
for(i=0;i<26;++i)

124
Ivan P. Stanimirović Uvod u programiranje

{ if(i%6==0) printf("\n");
printf("%5c:%4d", 'A'+i, slova[i]);
}
printf("\n\n");
}

Primer. Napisati program kojim se izračunava n-ti stepen broja 2, gde je n<= 500, i traženi stepen
nema više od 200 cifara.
void main()
{ int i,n,d=0,j,p, x[200]; // d+1 je broj cifara u stepenu, p je prenos
printf("\n Unesi stepen --> "); scanf("%d",&n);
x[0]=1;
for(i=0; i<n; i++)
{ p=0;
for(j=0; j<=d; j++){x[j]=x[j]*2+p; p=x[j]/10; x[j] %=10; }
if(p!=0) { d++; x[d]=p; }
}
printf("%d. stepen broja 2 je ",n);
for(i=d; i>=0; i--)printf("%d",x[i]);
}
Primer. Binarno traženje.
Posmatra se sledeći matematički problem: zadat je uređen realni niz a[0]<a[1]<…<a[n-1] i realan
broj b; ustanoviti da li se b nalazi u nizu, i ako se nalazi odrediti indeks p za koji važi a[p]=b.
Najjednostavnije, ali i najneefikasnije je takozvano linearno pretraživanje: redom se upoređuju
elementi niza a sa brojem b, do prvog elementa niza a za koji je a[i]>=b. Ako je a[i]=b, tada je p = i
traženi indeks. Ako je a[i]>b, tada se broj b ne nalazi u nizu a.
Za brzo pretraživanje se koristi algoritam binarnog pretraživanja.
Pretpostavimo da postoji p[0, n-1] takav da je a[p] = b. Izaberemo srednji element niza a sa
indeksom s = (0+n-1)/2. Ako je a[s]=b, tada je p=s traženi indeks, a pretraživanje se prekida. Ako je
ispunjen uslov b < a[s], tada se indeks p nalazi u intervalu [0,s-1], a inače se nalazi u intervalu [s+1,n-
1]. U oba slučaja, prepolovljen je interval pretraživanja.
Napisati funkciju koja prema opisanom algoritmu određuje indeks onog elementa rastućeg niza a
koji je jednak zadatoj vrednosti b, a inače vraća rezultat -1.
#include<stdio.h>
void main()
{ float br, a[100];
int n,i,p;
int bintra(float a[], int n, float b);
printf("\nBroj elemenata? "); scanf("%d",&n);
printf("Elementi niza "); for(i=0; i<n; i++)scanf("%f", &a[i]);
printf("Jedan realan broj? "); scanf("%f",&br);
p=bintra(a, n, br);
printf("Pozicija broja %f u nizu je %d\n",br,p);
}

int bintra(float a[], int n, float b)


{ int l,d,s;
l=0; d=n-1;
while(l<=d)
{ s=(l+d)/2;
if(b==a[s]) return(s);
else if(b<a[s])d=s-1;
else l=s+1;
}
return(-1);

125
Ivan P. Stanimirović Uvod u programiranje

Odgovarajuća rekurzivna funkcija je


#include<stdio.h>
main()
{ float br, a[100];
int n,i,p;
int bintra1(float a[], int l, int d, float b);
printf("\nBroj elemenata? "); scanf("%d",&n);
printf("Elementi niza ");
for(i=0; i<n; i++)scanf("%f", &a[i]);
printf("Jedan realan broj? "); scanf("%f",&br);
p=bintra1(a, 0, n-1, br);
printf("Pozicija broja %f u nizu je %d\n",br,p);
}

int bintra1(float a[], int l, int d, float b)


{ int s;
if(l>d) return(-1);
else
{ s=(l+d)/2;
if(b==a[s]) return(s);
else if(b<a[s])return bintra1(a,l,s-1,b);
else return bintra1(a,s+1,d,b);
}
}
1. (C) Napisati funkciju koja učitava broj elemenata u nizu kao i elemente niza. Napisati funkciju
koja od dva neopadajuća niza a[0..m-1] i b[0..n-1] formirati rastući niz c[0..k-1] u kome se elementi
koji se ponavljaju u polaznim nizovima pojavljuju samo jednom. Napisati test program.
#include<stdio.h>
int a[50], b[50], c[50];

void citaj(int x[], int *n)


{ printf("Broj elemenata = ? "); scanf("%d",n);
printf("Elementi?\n"); for(int i=0; i<*n; i++)scanf("%d",x+i);
}

void formiraj(int a[], int b[], int c[], int m, int n, int *k)
{ int i=0,j=0,last;
last = ((a[0]<b[0])?a[0]:b[0])-1;
*k=0;
while(i<m || j<n)
if(i==m){ for(int l=j; l<n; l++)c[(*k)++]=b[l]; j=n;}
else if(j==n){ for(int l=i; l<m; l++)c[(*k)++]=a[l]; i=m; }
else if(a[i]<b[j])
{ if(a[i]!=last) {c[(*k)++]=a[i]; last=a[i];}
i++;
}
else if(b[j]<a[i])
{ if(b[j]!=last){ c[(*k)++]=b[j]; last=b[j]; }
j++;
}
else
{ if(a[i]!=last) {c[(*k)++]=a[i]; last=a[i];}
i++; j++;
}
}

void main()
{ int i,m,n,k;

126
Ivan P. Stanimirović Uvod u programiranje

citaj(a,&m); citaj(b,&n);
formiraj(a,b,c,m,n,&k);
for(i=0; i<k;i++)printf("c[%d] = %d\n",i,c[i]);
}
Primer. Postupkom Eratostenovog sita ispisati sve proste brojeve od 2 do n. Postupak se sastoji u
sledećem:
 Formira se niz koji sadrži prirodne brojeve 2 do n.
 Iz niza se izbacuju svi brojevi koji su deljivi sa 2, 3. Brojevi deljivi sa 4 su izbačeni zbog
deljivosti sa 2, i tako dalje.
 U nizu ostaju prosti brojevi.
#include <stdio.h>
void main() {
int a[1001], n, i, j;
scanf("%d",&n);
for (i=2; i<=n; i++) a[i]=1;
for (i=2; i<=n; i++)
if (a[i]) {
j=2*i; while (j<=n) { a[j]=0; j+=i; }
}
for (i=2; i<=n; i++) if (a[i]) printf("%d\n",i);
}
Primer. Napisati funkciju za deljenje polja P na dva dela, pri čemu u polje P1 ulaze svi elementi polja
P veći od zadatog broja k, a u polje P2, svi elementi polja P manji od k. Elementi polja P1 i P2 treba
da budu sortirani.
#include<stdio.h>
#include<iostream.h>

void main(void){
int p[20],p1[20],p2[20],n,i,j,zadati,br1,br2;

cout<<"\n Unesite dimenziju niza:"; cin>>n;


cout<<"\n Unesite elemente niza:\n";
for(i=0; i<n; i++) cin>>p[i];
cout<<"\n Unesite zadati element:"; cin>>zadati;
br1=0; br2=0;
for(i=0; i<n; i++)
{ if(p[i]>zadati) { p1[br1]=p[i]; br1++; }
else { p2[br2]=p[i]; br2++; };
};
for(i=0; i<br1-1; i++)
{ for(j=i+1; j<=br1-1; j++)
{ if(p1[i]>p1[j]){ zadati=p1[i]; p1[i]=p1[j]; p1[j]=zadati; };
};
};

for(i=0; i<br2-1; i++)


{ for(j=i+1; j<=br2-1; j++)
{ if(p2[i]>p2[j]){ zadati=p2[i]; p2[i]=p2[j]; p2[j]=zadati; };
};
};
cout<<"\n Polje P1\n";
for(i=0; i<br1; i++) cout<<"\n P1["<<i<<"]="<<p1[i];
cout<<"\n\n\n Polje P2\n";
for(i=0; i<br2; i++) cout<<"\n P2["<<i<<"]="<<p2[i];
cout<<"\n\n";
}
Primer. Definisati sve varijacije sa ponavljanjem i varijacije bez ponavljanja.

#include <stdio.h>

127
Ivan P. Stanimirović Uvod u programiranje

bool mark[33];

void ispisi_varijacije_sa_ponavljanjem(int x, int n, int k, int a[], int


v[]) {
int i;
if (x==k) {
printf(" ");
for(i=0; i<k; i++) printf("%d ", v[i]);
printf("\n");
} else {
for(i=0; i<n; i++) {
v[x]=a[i];
ispisi_varijacije_sa_ponavljanjem(x+1,n,k,a,v);
}
}
}

void ispisi_varijacije_bez_ponavljanja(int x, int n, int k, int a[], int


v[]) {
int i;
if (x==k) {
printf(" ");
for(i=0; i<k; i++) printf("%d ", v[i]);
printf("\n");
} else {
for(i=0; i<n; i++) if (!mark[i]) {
mark[i]=true;
v[x]=a[i];
ispisi_varijacije_bez_ponavljanja(x+1,n,k,a,v);
mark[i]=false;
}
}
}

int main() {
int n,i,k,a[33],v[33];
scanf("%d", &n);
for(i=0; i<n; i++) scanf("%d", &a[i]);

printf("unesite k: "); scanf("%d", &k);

printf("Sve varijacije(n,k) sa ponavljanjem: \n");


ispisi_varijacije_sa_ponavljanjem(0,n,k,a,v);

printf("Sve varijacije(n,k) bez ponavljanja: \n");


ispisi_varijacije_bez_ponavljanja(0,n,k,a,v);

//printf("Sve kombinacije: \n");


//ispisi_sve_kombinacije(n,a);

return 0;
}

Problem ranca
#include <cstdio>

int main (){


int C, m, d[1000], t[100], v[100], uzeti[1000];
scanf("%d%d", &C, &m);

128
Ivan P. Stanimirović Uvod u programiranje

for (int i=0; i<m; i++) scanf("%d%d", t+i, v+i);

d[0]=0;
uzeti[0]=0;

for (i=1; i<=C; i++){


d[i]=0;
for (int j=0; j<m; j++){
if (i-t[j]>=0) {
int tmp=d[i-t[j]]+v[j];
if (tmp>d[i]) {
d[i]=tmp;
uzeti[i]=j;
}
}
}
}

printf("Optimalna vrednost ranca sa nosivoscu %d je: %d\n", C, d[C]);


printf("Uzeti predmeti redom su: \n");
i=C;
int k=1;
while (i>0){
k++;
printf("Tezina %d-tog predmeta je: %d i vrednost %d-tog
predmeta je: %d\n", k, t[uzeti[i]], k, v[uzeti[k]]);
i-=t[uzeti[i]];
}

return 0;
}

Primer (C) Dat je skup S od n (n  100) različitih prirodnih brojeva od kojih ni jedan nije veći od 200.
Napisati program koji pronalazi jedan podskup A datog skupa S koji zadovoljava sledeća dva uslova:
a) Suma elemenata skupa A je deljiva sa tri;
b) Od svih podskupova skupa S koji zadovoljavaju osobinu a), podskup A ima najveću sumu
svojih elemenata.
Ulazni podaci se učitavaju iz fajla zad1.dat. U prvom redu fajla se nalazi broj n, a u nastavku
fajla se nalazi n elemenata skupa S (svaki element je naveden u posebnom redu fajla).
Program treba da napravi fajl zad1.res i u njega treba da upiše sumu elemenata podskupa A (u
prvom redu fajla) i sve elemente podskupa A (u nastavku fajla, svaki element se upisuje u posebnom
redu fajla).
Primer:
zad1.dat zad1.res
4 147
29 29
15 15
11 103
103

#include <stdio.h>
int main(){
FILE *f,*g;
int am1,am2,bm1,bm2,n,i,a[100],ost,i1,i2,i3,i4;
long sumaniza;
f=fopen("zad12.dat","r");
g=fopen("zad12.res","w");
fscanf(f,"%d",&n);
am1=am2=bm1=bm2=ost=0;

129
Ivan P. Stanimirović Uvod u programiranje

sumaniza=0;
i1=i2=i3=i4=-1;
for(i=0;i<n;i++)
{
fscanf(f,"%d",&a[i]);
if(((a[i]%3)==1)&&((am1==0)||(am1>a[i])))
{
am2=am1;
am1=a[i];
i1=i;
}
else if(((a[i]%3)==1)&&((am2==0)||(am2>a[i])))
{
am2=a[i];
i2=i;
}
if(((a[i]%3)==2)&&((bm1==0)||(bm1>a[i])))
{
bm2=bm1;
bm1=a[i];
i3=i;
}
else if(((a[i]%3)==1)&&((bm2==0)||(bm2>a[i])))
{
bm2=a[i];
i4=i;
}
sumaniza+=a[i];
ost=((ost+a[i])%3);
}
if(((ost==1)&&(i1==-1)&&(i4==-1))||
((ost==2)&&(i2==-1)&&(i3==-1)))
{
fprintf(g,"0\n0\n");
fclose(f);
fclose(g);
return 0;
}
if(ost==0)
{
fprintf(g,"%ld\n",sumaniza);
for(i=0;i<n;i++)
fprintf(g,"%d\n",a[i]);
}
else if(ost==1)
{
if(am1<bm1+bm2)
{
fprintf(g,"%ld\n",sumaniza-am1);
for(i=0;i<n;i++)
if(i!=i1)
fprintf(g,"%d\n",a[i]);
}
else
{
fprintf(g,"%ld\n",sumaniza-bm1-bm2);
for(i=0;i<n;i++)
if((i!=i3)&&(i!=i4))
fprintf(g,"%d\n",a[i]);
}
}

130
Ivan P. Stanimirović Uvod u programiranje

else
{
if(bm1<am1+am2)
{
fprintf(g,"%ld\n",sumaniza-bm1);
for(i=0;i<n;i++)
if(i!=i3)
fprintf(g,"%d\n",a[i]);
}
else
{
fprintf(g,"%ld\n",sumaniza-am1-am2);
for(i=0;i<n;i++)
if((i!=i1)&&(i!=i2))
fprintf(g,"%d\n",a[i]);
}
}
fclose(f);
fclose(g);
return 0;
}

Kratko objašnjenje rešenja.


Prvo postavimo sve promenljive na odgovarajuće početne položaje. Zatim iz datoteke najpre učitamo broj
elemenata skupa S a zatim i sve elemente skupa S. Pri učitavanju izdvajamo po dva najmanja elementa skupa S
koji pri deljenu sa tri daju ostatke jedan odnosno dva. Ova dva elementa su bitna jer će mo odgovarajuči skup A
dobiti zapravo izbacivanjem najviše dva elementa skupa S koji daju potrebne ostatke pri deljenju sa tri, a da bi
suma elememenata novodobijenog skupa A bila maksimalna potrebno je da elementi koje izbacujemo budu
najmanji mogući. Zatim ispitujemo ostatak zbira elemenata skupa S pri deljenju brojem tri i u zavisnosti od tog
ostatka ispitujemo najmanje elemente koji daju odgovarajući ostatak i u izlaznu datoteku štampamo skup S bez
elemenata koje smo izbacili.
Zadatak 1. Dato je n tegova (n  20), čije su mase realni brojevi. Podeliti tegove u dve grupe, tako da
ukupne mase tegova u grupama budu što približnije. štampati minimalnu razliku, i za svaku od grupa
mase tegova u toj grupi, kao i ukupnu masu tegova u grupi.
#include<stdio.h>
#include<math.h>
main()
{ float teg[20];
int grupa[20], grupa1[20];
int i,j,k,n;
float razlika, minrazlika, suma,suma1, minsuma1;
printf("\n Broj tegova? "); scanf("%d", &n);
printf("\nMase tegova? \n");
for(i=0; i<n; i++) scanf("%f", &teg[i]);
suma=0;
for(i=0; i<n; i++)
{ grupa[i]=0; suma += teg[i]; }
minrazlika = suma;
printf("suma = %f\n", suma);
do { suma1=0;
for(i=0; i<n; i++) if(grupa[i]) suma1 += teg[i];
razlika=fabs(suma-2*suma1);
if(razlika < minrazlika)
{ minrazlika=razlika;
minsuma1=suma1;
for(i=0; i<n; i++) grupa1[i]=grupa[i];
}
j=n;
while(j>=0 && grupa[j]) { grupa[j]=0; j--; }

131
Ivan P. Stanimirović Uvod u programiranje

if(j>=0) grupa[j]=1;
}
while(j>=0);
printf("\nMinimalna razlika =
%f\n",minrazlika);
printf("Prva grupa ima sledece tegove:\n");
for(i=0; i<n; i++) if(grupa1[i])printf("%f ",teg[i]);
printf("\nUkupna masa tegova prve grupa je %f",
minsuma1);
printf("\nDruga grupa ima sledece tegove:\n");
for(i=0; i<n; i++) if(!grupa1[i])printf("%f ",teg[i]);
printf("\nUkupna masa tegova druge grupa je %f",
(suma-minsuma1));
}

Primer. Pretpostavimo da želite da postavite broj sobe na vratima. U prodavnici je moguće kupiti
skup plastičnih cifara. Svaki skup sadrži po jednu cifru od 0 do 9. Broj sobe je između 1 i 1,000,000.
Odrediti koliko skupova cifara je potrebno kupiti u prodavnici da bi ste ispisali broj sobe, imajući u
vidu da 6 možete iskoristiti i kao 9 i obrnuto. U prvom redu datoteke zad1.in se nalazi broj n, a u
ostalih n redova po jedan broj koji označava broj koji bi trebalo ispisati. U datoteci zad1.out upisati
minimalni broj skupova cifara koji uz pomoć kojih možemo ispisati dati broj.

zad1.in zad1.out
4 2
122 2
9999 l
12635 6
888888
Primer. U prvom redu datoteke 'zadl.in' nalazi se ceo broj n (1  n  1000). U svakom od sledećih n
redova nalaze se po dva cela broja x i y (-10000  x,y  10000) koji predstavljaju koordinate tačke u
ravni. Napisati program koji u datoteku 'zadl.out' upisuje, na dve decimale, rastojanje od koordinatnog
početka tačke koja je najbliža koordinatnom početku. Iza rastojanja, odvojeno prazninom, upisati redni
broj te najbliže tačke u datoteci.
zad1.in zad1.out
7 5.00 5
-9 12
-12 -16
5 12
15 8
3 4
-8 -6
20 -15
Primer. Meteorološka stanica meri temperaturu jednom u minutu. Stanica ima termometar koji ne daje
uvek tačne rezultate pri merenju temperature. Zbog nedostatka sredstava, odlučeno je da se umesto
novog termometra finansira izrada programa koji uklanja netačne rezultate merenja i kao rezultat daje
prosečnu temperaturu. Merenje se računa u netačno u dva slučaja:
a. Izmerena temperatura je manja od-50 stepeni;
b. Izmerena temperatura se od svake od temperatura merenih u prethodna 2 minuta i
sledeća dva minuta razlikuje za više od 2.
Napisati program koji za zadati niz izmerenih temperatura izračunava srednju vrednost ispravnih
temperatura.
U ulaznoj datoteci 'zad2.in' dati su broj n (1  n  1000) koji predstavlja broj merenja, kao i brojevi t1,
..., tn koji predstavljaju izmerene vrednosti (- 60  ti 50, i {1,...,n}). U izlaznu datoteku 'zad2.out'
upisati, na dve decimale, srednju vrednost ispravno izmerenih temperatura.

132
Ivan P. Stanimirović Uvod u programiranje

zad2.in zad2.out
5 12.00
9 11 12 13 15
7 0.16
0 0 0 2 5 0 10

6.3. Veza između nizova i pointera u C


Ime niza je konstantni pokazivač na početak niza, tj. adresa njegovog nultog elementa. Ime niza je
samo po sebi jedna adresa, ili vrednost pointera (pointer je promenljiva koja uzima adrese za svoje
vrednosti). Kada je niz deklarisan, kompajler alocira baznu adresu i dovoljan memorijski prostor za
smeštanje svih elemenata niza. Kompajler jezika C sam prevodi oznake niza u pokazivače, pa se
korišćenjem pokazivača povećava efikasnost u radu sa nizovima.
Primer. Neka je data deklaracija
#define N 100
long a[N], *p;
Pretpostavimo da je prva adresa za smeštanje niza a jednaka 300 (ostale su 304,308,…,696).
Naredbe
p = a; p=&a[0];
su ekvivalentne. U oba slučaja promenljiva p uzima za svoju vrednost adresu nultog elementa niza a.
Preciznije, promenljivoj p se dodeljuje vrednost 300.
Takođe, naredbe
p=a+1; p=&a[1];
su ekvivalentne i dodeljuju vrednost 304 promenljivoj p. Analogno, naredbe p = a + i i p = &a[i] su
ekvivalentne, za svaki element a[i] niza a. Ako su elementima niza a pridružene vrednosti, one se
mogu sumirati koristeći pointer p, na sledeći način:
sum=0;
for(p=a; p<&a[N]; sum += *p, ++p);

Isti efekat se može postići sledećim postupkom:


sum=0;
for(i=0;i<N;++i) sum += *(a+i);

Napomenimo da je izraz *(a+i) ekvivalentan sa a[i]. Takođe, može se pisati p = &(*(a+i)) umesto
izraza p = a + i, odnosno p = &a[i].
Primer. Još jedan način sumiranja nizova.
p=a; sum=0;
for(i=0;i<N;++i) sum += p[i];

Međutim, postoji razlika između pointera i nizova. Kako je ime niza a konstantni pointer, a ne
promenljiva, ne mogu se koristiti izrazi
a = p++a a+=2.
To znači da se adresa niza ne može menjati.
Primer. Napisati program koji transformiše niz celih brojeva tako da na početku budu negativni a na
kraju nenegativni elementi tog niza.
#include<stdio.h>
void main(void)
{ int niz[100], p,i,k,n;
printf("\nBroj elemenata --> "); scanf("%d",&n);
for(i=0; i<n; i++)
{ printf("niz[%d]=--> ",i+1); scanf("%d",niz+i); }

133
Ivan P. Stanimirović Uvod u programiranje

p=0; k=n-1;
while(p<k)
{ while(niz[p]<0 && p<k)p++;
while(niz[k]>=0 && p<k)k--;
if(p<k)
{ int pom=niz[p]; niz[p]=niz[k]; niz[k]=pom; }
}
for(i=0; i<n; i++)printf("niz[%d] = %d ",i,niz[i]); printf("\n");
}
Dato je jedno rešenje koje koristi ime niza kao pokazivač.
#include<stdio.h>
void main(void)
{ int niz[100], *p,*k,i,n;
printf("\nBroj elemenata --> "); scanf("%d",&n);
for(i=0; i<n; i++){printf("niz[%d]= --> ",i+1); scanf("%d",niz+i); }
p=niz; k=niz+n-1;
while(p<k)
{ while(*p<0 && p<k)p++;
while(*k>=0 && p<k)k--;
if(p<k) { int pom; pom=*p; *p=*k; *k=pom; }
}
for(i=0; i<n; i++)printf("niz[%d]= %d ",i,*(niz+i)); printf("\n");
}
Neka je, za ovaj primer zadat broj elemenata n = 4, i neka su elementi -1,2,-3,4. Neka je vrednost
pokazivača p=&a[0] jednaka heksadekadnom broju 0x0012fdf0. Ako je program napisan u
programskom jeziku C++, tada svaka vrednost tipa int zauzima po 4 bajta, pa je vrednost pokazivača
k=&a[3] jednaka heksadekadnom broju 0x0012fdfc. Adrese i sadržaj lokacija koje su zauzete
zadatim elementima niza predstavljene su u sledećoj tabeli:
Element niza Adresa prvog bajta Adresa drugog bajta Adresa trećeg bajta Adresa četvrtog bajta
a[0] 0x0012fdf0= &a[0] 0x0012fdf1 0x0012fdf2 0x0012fdf3
a[1] 0x0012fdf4= &a[1] 0x0012fdf5 0x0012fdf6 0x0012fdf7
a[2] 0x0012fdf8= &a[2] 0x0012fdf9 0x0012fdfa 0x0012fdfb
a[3] 0x0012fdfc= &a[3] 0x0012fdfd 0x0012fdfe 0x0012fdff

Primer. Sortiranje niza pointerskom tehnikom. Kao algoritam izabrano je sortirane izborom
uzastopnih minimuma.
#include<stdio.h>
void upis(int *a, int *n)
{ int i;
printf("Broj elemenata? "); scanf("%d",n);
printf("Elementi? ");
for(i=0; i<*n; i++) scanf("%d",a+i);
}

void ispis(int *a, int n)


{ int i;
for(i=0; i<n; i++)printf("%d ",*(a+i));
}

void uređenje(int *a, int n)


{ int i,j,pom;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(*(a+i)>*(a+j))
{pom=*(a+i); *(a+i)=*(a+j); *(a+j)=pom; }
}

void main()

134
Ivan P. Stanimirović Uvod u programiranje

{ void upis(int *, int*); void ispis(int *, int);


int x[100],k;
upis(x, &k); uređenje(x,k); ispis(x,k);
}

6.3.1. Pointerska aritmetika


U jeziku C dozvoljene su aritmetičke operacije nad pokazivačima. Dozvoljeno je:
- dodeliti pokazivaču adresu promenljive ili nulu (vrednost NULL);
- uvećati ili umanjiti vrednost pokazivača;
- dodati vrednosti pokazivača neki ceo broj;
- oduzeti od vrednosti pokazivača neki ceo broj;
- porediti dva pokazivača pomoću operacija ==, !=, i tako dalje;
- oduzeti od jednog pokazivača drugi, ako ukazuju na objekte istog tipa.
Pointerska aritmetika predstavlja veliku prednost jezika C u odnosu na druge jezike visokog nivoa.
U sledećoj tabeli su uvedene pretpostavke:
a: vektor sa elementima tipa T,
n: celobrojni izraz,
v: zraz tipa T,
pa1, pa2: ukazatelj na tip T, kojima se ukazuje na elemente vektora a.
U njoj su prikazana neka pravila pointerske (adresne) aritmetike:

Oznaka Značenje Tip rezultata


a ukazatelj na prvi element vektora a ukazatelj na T
&a[0] ukazatelj na prvi element vektora a ukazatelj na T
&a[n] ukazatelj na n+1 element vektora a ukazatelj na T
*pa1 element vektora na koji pa1 ukazuje T
*pa1 = v dodeljuje vrednost v elementu na koji pa1 ukazuje T
++pa1 postavlja pa1 na sledeći element vektora a ukazatelj na T
--pa1 postavlja pa1 na prethodni element vektora a ukazatelj na T
*++pa1 inkrementira pa1, a zatim pristupa elementu na koji pa1 ukazuje T
pristupa elementu vektora a na koji pa1 ukazuje, zatim
*pa1++ T
inkrementira pa1
ukazuje na n-ti naredni (prethodni) element počev od elementa
pa1n ukazatelj na T
na koji pa1 ukazuje
vrednost v dodejluje n-tom narednom elementu u odnosu na
*(pa1+n) = v T
element na koji pa1 ukazuje
ispituje vrednosti adresa u pa1 i pa2 pomoću relacionih
pa1>pa2 int
operatora
*(a+n) n-ti element vektora a T

Primer.
void main()
{ double a[2], *p, *q;
p=&a[0]; q=p+1;
printf("%d\n",q-p); /* 1 */
printf("%d\n",(int)q-(int)p); /* 8 */
}

Primer. Date su deklaracija


int x[4], *pti;
i dodela
pti=x;

135
Ivan P. Stanimirović Uvod u programiranje

Ako je niz x smešten počev od adrese 56006(=&x[0]), odrediti lokacije i elemente niza x na koji
ukazuju pti, pti+1, pti+2 i pti+3.

Rešenje. Dodavanje jedinice pokazivaču pti automatski uvećava adresu na koju on ukazuje za 2, jer
se radi o pokazivaču na tip int. Znači, pti, pti+1, pti+2 i pti+3 ukazuju redom na adrese 56006, 56008,
56010, 56012 i na elemente x[0], x[1], x[2], x[3] niza x.
Iz prethodnog primera zaključujemo
*(x+2)=x[2], x+2=&x[2].
Izraz *x+2 jednak je izrazu (*x)+2 i predstavlja uvećanje vrednosti nultog elementa niza x za 2.

U sledećoj tabeli je prikazan odnos između * i ++.

6.4. Nizovi i dinamička alokacija memorije u C


Za razliku od vektora i skalarnih promenljivih, kojima se implicitno dodeljuje memorija prilikom
njihovog stvaranja i oslobađa prilikom brisanja, nezavisno od volje programera, dinamičke strukture
zahtevaju eksplicitno dodeljivanje i oslobađanje memorije.
U biblioteci stdlib.h nalaze se definicije funkcija malloc, calloc, free i realloc, kojima se može
eksplicitno upravljati memorijom. Definicija i semantika ovih funkcija je sledeća:
1. char *malloc(size)
rezerviše memorijski blok veličine size uzastopnih bajtova. Argument size je tipa unsigned. U slučaju
da rezervacija memorije uspe, ova funkcija vraća pointer na tip char, koji ukazuje na rezervisani
memorijski blok, a inaće vraća 0. Ova funkcija ne menja sadržaj memorije koja je izdvojena.
2. char *calloc(n, size)
rezerviše memorijski blok dovoljan za smeštanje n elemenata veličine size bajtova, tj. rezerviše n*size
uzastopnih bajtova. Rezervisani memorijski prostor se inicijalizuje na 0. Ako je rezervacija uspešna,
rezultat je pointer na char, koji ukazuje na rezervisani memorijski blok, a inače 0.
3. void free(point)
oslobađa memorijski prostor koji je rezervisan funkcijama calloc ili malloc. Argument point je pointer
na char, koji ukazuje na memorijski prostor koji se oslobađa. Ova funkcija ne vraća vrednost.
Pokazivač point mora da ima vrednost koja je dobijena primenom funkcija malloc() i calloc().
4. char *realloc(point, size)
oslobađa rezervisani memorijski blok i rezerviše novi, veličine size bajtova. Argument point je pointer
na char i ukazuje na memorijski blok koji se realocira. Argument size je tipa unsigned i određuje
veličinu realociranog memorijskog prostora.
Primer. Naredbama
int *pint;
pint = (int *)malloc(400);
izdvaja se 400 uzastopnih bajtova. Ovaj memorijski prostor je dovoljan za smeštanje 200 celih brojeva
u jeziku C, odnosno 100 celih brojeva u C++.

136
Ivan P. Stanimirović Uvod u programiranje

Takođe, vrednost izraza


pint = (int*)malloc(400);
je pokazivač na tip int, koji se dobija konverzijom pokazivača na char pomoću kast operatora. Ako tip
int zauzima 4 bajta, tada pint+1 uvećava pokazivač za 4 bajta, i predstavlja adresu sledećeg celog
broja. Na taj način, 400 bajtova se koristi za smeštanje 100 celih brojeva.
Ako želimo da izdvojimo onoliko memorije koliko je potrebno za za čuvanje vrednosti izraza ili
podataka određenog tipa, koristi se operator sizeof na jedan od sledeća dva načina:
sizeof(izraz); - vraća memorijski prostor koji je dovoljan za smeštanje izraza izraz;
sizeof(T); - vraća memorijski prostor koji je dovoljan za čuvanje vrednosti tipa T.

Primer. Pomoću operatora


pint = (int *)malloc(sizeof(int));
izdvaja se memorijski prostor za celobrojnu vrednost. Adresa te oblasti se dodeljuje promenljivoj pint.
Noviji C prevodioci ne zahtevaju promenu tipa pokazivača koji vraća funkcija malloc(), jer je njen
rezultat tzv. generički pokazivač oblika void *, koji pokazuje na objekat bilo kog tipa.
Primer. Operatorima
long *plong;
plong = (long*)calloc(100, sizeof(long));
izdvaja se (i inicijalizuje na 0) memorijski prostor dovoljan za smeštanje 100 vrednosti tipa long (400
uzastopnih bajtova).
Primer. Izostavljanje uzastopno jednakih elemenata niza.
#include<stdio.h>
#include<stdlib.h>
void redukcija (float *a, int *n)
{ int i, j;
for (i=1, j=0; i<*n; i++) if (a[j] != a[i]) a[++j] = a[i];
*n = j + 1;
}

/* Ispitivanje potprograma "redukcija" */

void main ()
{ float *a; int n, i;
while (1) {
printf ("n? "); scanf ("%d", &n);
if (n < 0) break;
a=(float *)malloc(n*sizeof(float));
printf ("A? "); for (i=0; i<n; scanf ("%f", &a[i++]));
redukcija (a, &n);
a=(float *)realloc(a,n*sizeof(float));
printf ("A= "); for (i=0; i<n; printf("%f ", a[i++]));
printf ("\n\n");
}
}
Primer. Iz zadatog niza izbaciti sva pojavljivanja njegovog maksimalnog elementa. Zadatak uraditi
dinamičkom alokacijom memorije.
#include<stdio.h>
#include<stdlib.h>
void main()
{ int i,n,im,k=0;
float max, *a;
scanf("%d",&n);

137
Ivan P. Stanimirović Uvod u programiranje

a=(float *)malloc(n*sizeof(float));
for(i=0;i<n;scanf("%f",&a[i++]));
im=0; max=a[0];
for(i=1;i<n;i++) if(a[i]>max) { max=a[i];im=i; }
k=im-1;
for(i=im+1; i<n; i++) if(a[i]!=max)a[++k]=a[i];
a=(float *)realloc(a,(k+1)*sizeof(float));
for(i=0;i<=k;printf("a[%d]=%f ",i,a[i++]));
}
Primer. Učitavanje, sortiranje i ispis nizova pomoću potprograma.
#include <stdio.h>
#include <stdlib.h>

void ucitaj(int *a, int &n) {


scanf("%d",&n);
for (int i=0; i<n; i++)scanf("%d",a+i);
}

void razmeni(int &a, int &b) {


int p=a; a=b; b=p;
}

void SORT(int **a, int n) {


int *A;
A=*a;
for (int i=0; i<n-1; i++)
for (int j=i+1; j<n; j++)
if (*(A+i)>*(A+j)) razmeni(*(A+i),*(A+j));

int ispisi(int *a, int n) {


for (int i=0; i<n; i++) printf("%d, ",a[i]);
printf("\n");
return 0;
}

int main() {
int n,*a;
a=(int *)malloc(2000*sizeof(int));
ucitaj(a,n);
SORT(&a,n);
ispisi(a,n);
return 0;
}

Bubble sort
#include <stdio.h>
#include <math.h>
void bubbleSort(float *a, int n)
{int i,j; float p;
j=(n-1);
while(j>=1)
{for(i=0;i<j;i++)
if(a[i]>a[i+1])
{ p=a[i]; a[i]=a[i+1]; a[i+1]=p; }
j=j-1;
}
}
void main()
{int i,n;float a[10];

138
Ivan P. Stanimirović Uvod u programiranje

scanf("%d",&n);
for(i=0;i<n;i++)scanf("%f",&a[i]);
bubbleSort(a,n);
for(i=0;i<n;i++) printf("%f ",a[i]);
}

Drugi oblici funkcije SORT:

void SORT(int **a, int n) {


for (int i=0; i<n-1; i++)
for (int j=i+1; j<n; j++)
if (*(*a+i)>*(*a+j)) razmeni(*(*a+i),*(*a+j));

void SORT(int **a, int n) {


for (int i=0; i<n-1; i++)
for (int j=i+1; j<n; j++)
if (*(&(*a)[i])>*(&(*a)[j]))
razmeni(*(&(*a)[i]),*(&(*a)[j]));

#include <stdio.h>
#include <stdlib.h>

void ucitaj(int *a, int &n) {


scanf("%d",&n);
for (int i=0; i<n; i++)scanf("%d",a+i);
}

void razmeni(int &a, int &b) {


int p=a; a=b; b=p;
}

void SORT(int ***a, int n) {


for (int i=0; i<n-1; i++)
for (int j=i+1; j<n; j++)
if ((*(*a))[i]>(*(*a))[j])
razmeni((*(*a))[i],(*(*a))[j]);

int ispisi(int *a, int n) {


for (int i=0; i<n; i++) printf("%d, ",a[i]);
printf("\n");
return 0;
}

int main() {
int n,*a,**b;
a=(int *)malloc(2000*sizeof(int));
ucitaj(a,n);
b=&a;
SORT(&b,n);
ispisi(a,n);
return 0;
}

Primer. Nizovi kao skupovi pomoću dinamičke alokacije memorije.

139
Ivan P. Stanimirović Uvod u programiranje

#include<stdio.h>
#include<stdlib.h>
int sadrzi(const float *s1, int n1, float b);
void dodaj(float **s1, int *n1, float b);
void presek(const float *s1, int n1, const float *s2, int n2,
float **s3, int *n3);
void unija(const float *s1, int n1, const float *s2, int n2,
float **s3, int *n3);
/* void razlika(const float *s1, int n1, const float *s2, int n2,
float **s3, int *n3); n*/
void citaj(float **s, int *n);
void pisi(const float *s, int n, const char *f);

int sadrzi(const float *s1, int n1, float b)


{ int d=0, g=n1-1,p;
while(d<=g)
if(s1[p=(d+g)/2]==b)return 1;
else if(s1[p]<b)d=p+1;
else g=p-1;
return 0;
}

void dodaj(float **s1, int *n1, float b)


{ float *s=*s1; int n=*n1,i;
if(!sadrzi(s,n,b))
{ *s1=s=(float *)realloc(s,(n+1)*sizeof(float));
for(i=n-1; i>=0&&s[i]>b;i--)s[i+1]=s[i];
s[i+1]=b; *n1=n+1;
}
}

void presek(const float *s1, int n1, const float *s2, int n2,
float **s3, int *n3)
{ int n=0,i1=0,i2=0;
float *s=(float *) malloc((n1<n2 ? n1 : n2)*sizeof(float));
while(i1<n1 && i2<n2)
if(s1[i1]<s2[i2])i1++;
else if(s1[i1]>s2[i2])i2++;
else s[n++]=s1[i1++],i2++;
*s3=(float *)realloc(s,(*n3=n)*sizeof(float));
}

void unija(const float *s1, int n1, const float *s2, int n2,
float **s3, int *n3)
{ int n=0, i1=0, i2=0;
float *s=(float *)malloc((n1+n2)*sizeof(float));
while(i1<n1 || i2<n2)
if(i1==n1) s[n++]=s2[i2++];
else if(i2==n2)s[n++]=s1[i1++];
else if(s1[i1]<s2[i2])s[n++]=s1[i1++];
else if(s2[i2]<s1[i1])s[n++]=s2[i2++];
else s[n++]=s1[i1++],i2++;
*s3=(float *)realloc(s,(*n3=n)*sizeof(float));
}

void citaj(float **s1, int *n1)


{ int n,i;
float *s;
scanf("%d",&n); *n1=n;
if(n>=0)
{ *s1=s=(float *)malloc(n*sizeof(float));
for(i=0; i<n; scanf("%f",&s[i++]));

140
Ivan P. Stanimirović Uvod u programiranje

}
else *s1=0;
}
void pisi(const float *s, int n, const char *f)
{ int i;
putchar('{');
for(i=0;i<n; i++)
{ if(i>0) putchar(','); printf(f,s[i]); }
putchar('}');
}

void main()
{ float *s1, *s2, *s3;
int n1,n2,n3;
while(1)
{ citaj(&s1,&n1); if(n1<0)break;
citaj(&s2,&n2); if(n2<0)break;
printf("s1 "); pisi(s1,n1,"%.2f"); putchar('\n');
printf("s2 "); pisi(s2,n2,"%.2f"); putchar('\n');
presek(s1,n1,s2,n2,&s3, &n3);
printf("s1*s2 "); pisi(s3,n3,"%.2f"); putchar('\n');
unija(s1,n1,s2,n2,&s3, &n3);
printf("s1+s2 "); pisi(s3,n3,"%.2f"); putchar('\n');
free(s1); free(s2); free(s3);
}
}
Primer. Za svaku vrstu robe u magacinu beleži se njena šifra i količina, kao dva cela broja. Za
magacin A dati su nizovi sa i ka od na elemenata, sa značenjem da robe sa šifrom sa[i] ima u količini
ka[i], i da ukupno ima na vrsta robe u magacinu. Za magacin B dati su analogni podaci u nizovima sb i
kb od nb elemenata. Podaci o robi su uređeni po rastu šifara. Formirati nizove sz i kz koji daju podatke
o zbirnom stanju u magacinima A i B, i koji su takođe uređeni po siframa artikala. Koristiti dinamičku
alokaciju nizova.
#include<stdio.h>
#include<stdlib.h>
void main()
{ int *sa,*ka,*sb,*kb, *sz,*kz;
int i,ia,ib,iz,na,nb,nz;
printf("Broj vrsta robe u magacinu A? "); scanf("%d",&na);
sa=(int *)malloc(na*sizeof(int)); ka=(int *)malloc(na*sizeof(int));
for(i=0; i<na; i++)
{ printf("cifra i kolicina za %d. artikal? ",i);
scanf("%d%d", &sa[i], &ka[i]);
}
printf("Broj vrsta robe u magacinu B? "); scanf("%d",&nb);
sb=(int *)malloc(nb*sizeof(int)); kb=(int *)malloc(nb*sizeof(int));
for(i=0; i<nb; i++)
{ printf("cifra i kolicina za %d. artikal? ",i);
scanf("%d%d", &sb[i], &kb[i]);
}
sz=(int *)malloc((na+nb)*sizeof(int)); kz=(int *)malloc((na+nb)*sizeof(int));
ia=ib=iz=0;
while (ia<na && ib<nb)
if(sa[ia]<sb[ib])
{ sz[iz]=sa[ia]; kz[iz++]=ka[ia++]; }
else if(sa[ia]>sb[ib])
{ sz[iz]=sb[ib]; kz[iz++]=kb[ib++]; }
else // sa[ia]=sb[ib]
{ sz[iz]=sa[ia]; kz[iz++]=ka[ia++]+kb[ib++]; }
while(ia<na)
{ sz[iz]=sa[ia]; kz[iz++]=ka[ia++]; }
while(ib<nb)
{ sz[iz]=sb[ib]; kz[iz++]=kb[ib++]; }

141
Ivan P. Stanimirović Uvod u programiranje

nz=iz-1;
sz=(int *)realloc(sz,nz*sizeof(int));
kz=(int *)realloc(kz,nz*sizeof(int));
for(i=0;i<nz; printf("sifra %d kolicina %d\n",sz[i],kz[i++]));
free(sa); free(sb); free(ka); free(kb); free(sz); free(kz);
}

Primer. Napisati program kojim se zamenjuje prvo pojavljivanje stringa s1 u stringu s stringom s2.
Stringovi s1 i s2 mogu biti različitih dužina. Sve stringove pamtiti u dinamičkoj zoni memorije i za
svaki od njih rezervisati onoliko memorijskog prostora koliko je neophodno.

#include <stdio.h>
#include <stdlib.h>

void main()
{ char *s,*s1,*s2,c;
int n,n1,n2,i,j,k;
printf("Duzine stringova = ? "); scanf("%d%d%d",&n,&n1,&n2);
scanf("%c",&c);
s=(char *)malloc(n+1); s1=(char *)malloc(n1+1); s2=(char *)malloc(n2+1);
printf("Unesite stringove\n");
gets(s); gets(s1); gets(s2);

//Pronalazi s1 u s
//i je pocetna adresa od koje trazimo u s,
// j je broj pronadjenih znakova iz s1 u s
for(i=0,j=0;i<=n-n1 && j<n1; )
{ if(s[i+j]==s1[j])j++;
else {j=0; i++; }
}

if(j<n1)printf("s1 se ne sadrzi u s\n");


else
{ if(n2>n1) //s se prosiruje
{ k=n2-n1;
realloc(s,n+k+1);
for(j=n; j>=i+n1; j--)s[j+k]=s[j];
}
else if(n1>n2)// s se smanjuje
{ k=n1-n2;
for(j=i+n1; j<=n; j++)s[j-k]=s[j];
realloc(s,n-k+1);
}
printf("i = %d\n",i);
for(j=0; j<n2; j++) s[i+j]=s2[j];
printf("Transformisani string je %s\n",s);
}
}

Test primer.
Duzine strigova = ? 9 3 2
Unesite stringove
rat i mir
mir
mi
Transformisani string je rat i mi

6.5. Višedimenzionalna polja


Kod rešavanja mnogih problema postoji potreba za radom sa višedimenzionalnim strukturama

142
Ivan P. Stanimirović Uvod u programiranje

podataka. U programskim jezicima se za rad sa ovakvim strukturama podataka mogu definisati


višedimenzionalna polja, kao jednorodne strukture podataka u okviru kojih se pojedinačnim
elementima pristupa preko dva ili više indeksa. Posebno su značajne dvodimenzionalne strukture, koje
odgovaraju pojmu matrica i omogućavaju rešavanje veoma široke klase problema u kojima se koriste
matrične reprezentacije podataka.

6.5.1. Višedimenzionalni nizovi u C


Jednim parom zagrada definišu se jednodimenzionalni nizovi. Svaki par zagrada definiše jednu
dimenziju niza. Na primer, sledeće deklaracije su korektne:
int a[100]; int b[3][5]; int c[7][9][2];

U jeziku C proizvoljni k-dimenzionalni niz poseduje veličinu svake od svojih k dimenzija.


Primer. Zadavanje elemenata matrice na mestu njene deklaracije.
#include <stdio.h>
main()
{ int i,j,a[2]={1,2}, b[2][3]={{45,67,88},{67,777,54}}, s=0;
for(i=0;i<2;++i) s+=a[i];
printf("\nSuma elemenata niza je:%d\n",s);
for(i=0;i<2;i++)
for(j=0;j<3;j++) printf("b[%d%d]=%d\n",i,j,b[i][j]);
}
Primer. Program za množenje matrica koji koristi korisnički tip mat za definiciju matrica reda 33.
void main()
{int i, j, k;
typedef double mat[3][3];
static mat m1={{1.0,2.0,3.0},{4.0,5.0,6.0},{7.0,8.0,9.0}},
m2={{9.0,8.0,7.0},{6.0,5.0,4.0},{3.0,2.0,1.0}};
mat m3;
for(i=0; i<3; ++i)
for(j=0; j<3; ++j)
for(m3[i][j]=0, k=0; k<3; ++k)
m3[i][j]+= m1[i][k]*m2[k][j];
printf("\nProizvod matrica\n");
for (i=0; i<3; ++i)
for (j=0; j<3; ++j)
printf("%15.2f%c", m3[i][j], (j==2) ? '\n' : ' ');
}

6.5.2. Pokazivači i višedimenzionalni nizovi u C


Dvodimenzionalni nizovi (matrice) se u memoriji registruju po vrstama, koristeći uzastopne
memorijske lokacije. Na primer, dvodimenzionalni niz int a[3][2] se u memoriji raspoređuje u
sledećem poretku:
a[0][0], a[0][1], a[1][0], a[1][1], a[2][0], a[2][1] .
Ako se deklariše pokazivač p pomoću
int *p
posle dodele p = a pointer p uzima za svoju vrednost adresu elementa koji leži u nultoj vrsti i nultoj
koloni matrice a (tj. adresu prvog elementa matrice a). Takođe, važe sledeće pointerske jednakosti:
p=&a[0][0], p+1=&a[0][1], p+2=&a[1][0], p+3 =&a[1][1], p+4=&a[2][0], p+5=&a[2][1].

Dvodimenzionalni nizovi jesu jednodimenzionalni nizovi jednodimenzionalnih nizova. Na primer,


ako je r ime dvodimenzionalnog niza, tada je r[i] jednodimenzionalni niz koji sadrži elemente i-te
vrste matrice r.

143
Ivan P. Stanimirović Uvod u programiranje

U našem slučaju, vrste matrice a date su izrazima a[0], a[1] i a[2]. S obzirom na poznata svojstva
jednodimenzionalnih nizova, važe sledeće jednakosti:
a[0]=&a[0][0], a[1]=&a[1][0], a[2]=&a[2][0] .
Osim toga, važe sledeće jednakosti:
a[i]=&a[i][0], a[i] + j = &a[i][j], a[i][j] = *( a[i] + j), &a[i][j] = a+i*2+j.
Takođe je
a[j][k]=*(a+j*duzina_vrste +k).

Neka je mat[][7] dvodimenzionalni niz. Tada je


mat[i][j]=*(mat[i]+j)=(*(mat+i))[j]=*(mat+i*7+j)= *(&mat[0][0]+i*7+j)= *((*(mat+i))+j).
U gornjim primerima zagrade su neophodne zbog toga što operator selekcije ima viši prioritet u
odnosu na operator indirekcije.
Primer. Definisan je tip Matrica u jeziku C++. Napisane su funkcije za ispis i upis elemenata
matrice, za transponovanje matrice, za sabiranje dve matrice, kao i funkcija za ciklično pomeranje
vrsta u matrici.
#include<stdio.h>

typedef float matrica[10][20];

void main()
{ int m,n;
matrica a,b,c;
void pisi(int, int, matrica);
void citaj(int &, int &, matrica);
void saberi(int, int, matrica, matrica,matrica);
void rotiraj(int, int, matrica);
void transponuj(int, int, matrica);
citaj(m,n,a);
citaj(m,n,b);
saberi(m,n,a,b,c); pisi(m,n,c);
rotiraj(m,n,c); pisi(m,n,c);
transponuj(m,n,c); pisi(n,m,c);
}
void citaj(int &k, int &l, matrica x)
{ int i,j;
scanf("%d%d",&k,&l);
for(i=0;i<k; i++)
for(j=0; j<l; j++)
scanf("%f",x[i]+j);
}

void pisi(int k, int l, matrica x)


{ int i,j;
for(i=0;i<k; i++)
{ for(j=0; j<l; j++)
printf("%.2f ",x[i][j]);
printf("\n");
}
printf("\n");
}

void saberi(int k, int l, matrica x, matrica y, matrica z)


{ int i,j;
for (i=0;i<k;i++)
for (j=0;j<l;j++)
z[i][j]=x[i][j]+y[i][j];
}

144
Ivan P. Stanimirović Uvod u programiranje

void uzmi(int n, float *x, float *y)


{ int j;
for(j=0; j<n; j++)x[j]=y[j];
}

void rotiraj(int m, int n, matrica a)


{ int i;
float p[20];
uzmi(n,p,a[m-1]);
for(i=m-2;i>=0;i--)
uzmi(n,a[i+1],a[i]);
uzmi(n,a[0],p);
}

void transponuj(int m, int n, matrica a)


{ int i,j;
for(i=0; i<m; i++)
for(j=i+1; j<n; j++)
{ float p=a[i][j]; a[i][j]=a[j][i]; a[j][i]=p; }
}
Primer. Napisati potprogram koji pronalazi minimalni element niza i njegov indeks. U glavnom
programu učitati matricu mn i uz pomoć formiranog potprograma naći minimalni element u matrici i
njegove indekse.
#include <stdio.h>
void minunizu(int a[], int n, int *mn, int *k)
{ int i;
*k=0; *mn=a[0];
for(i=1; i<n; i++)if(a[i]<*mn) { *k=i; *mn=a[i]; }
}

void main()
{ int m,n,i,j, min, ind; int a[10][10], b[10], p[10];
printf("Dimenzije matrice?: "); scanf("%d%d", &m,&n);
printf("\nElementi matrice?: ");
for(i=0; i<m; i++)
for(j=0; j<n; j++) scanf("%d", &a[i][j]);
for(i=0; i<m; i++)
minunizu(a[i], n, &b[i], &p[i]);
// Moze i minunizu(a[i], n, b+i, p+i);
minunizu(b,m, &min, &ind);
i=ind; j=p[ind];
printf("Minimal-ni je na poziciji [%d,%d] i jednak je %d\n",i,j,min);
}

Primer. Konstruisati magični kvadrat dimenzija nn, za n neparno.


#include<stdio.h>
void main()
{ int i,j,k,n, mag[29][29];
printf("Dimenzije kvadrata? ");
scanf("%d", &n);
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
mag[i][j]=0;
i=1; j=(n+1)/2; k=1;
while(k<=n*n)
{ mag[i][j]=k++;
if(i==1 && j==1) i++;
else if(i==1) { i=n; j--; }

145
Ivan P. Stanimirović Uvod u programiranje

else if(j==1) { j=n; i--; }


else if(mag[i-1][j-1]!=0) i++;
else { i--; j--; }
}
for(i=1; i<=n; i++)
{ for(j=1; j<=n; j++) printf("%4d",mag[i][j]); printf("\n"); }
}
Primer. Data je celobrojna matrica A reda nn, gde je n neparan broj. Matrica A predstavlja magični
kvadrat sa jednim pogrešnim brojem. Napisati program koji pronalazi grešku, ispravlja je, štampa
odgovarajuću poruku i ispravljeni magični kvadrat.
void main()
{ int i,j,n, ik,iv, s1,s2,s3,s,suma, mag[29][29];
printf("Dimenzije kvadrata? "); scanf("%d", &n);
printf("Zadati magicni kvadrat sa jednom greskom\n");
for(i=1; i<=n; i++)
for(j=1; j<=n; j++) scanf("%d", &mag[i][j]);
s1=s2=s3=0;
for(j=1; j<=n; j++)
{ s1 += mag[1][j]; s2 += mag[2][j]; s3 += mag[3][j]; }
if(s1==s2 || s1==s3) suma=s1;
else suma=s2;
i=0;
do
{ i++; s=0; for(j=1; j<=n; j++)s+=mag[i][j]; }
while(s==suma);
iv=i;
j=0;
do
{j++; s=0; for(i=1; i<=n; i++)s+=mag[i][j];}
while(s==suma);
ik=j;
printf("Greska je u vrsti %d i koloni %d\n",iv,ik);
printf("Pogresna vrednost je %d\n",mag[iv][ik]);
printf("Pravilna vrednost je %d\n",mag[iv][ik]+suma-s);
mag[iv][ik]=mag[iv][ik]+suma-s;
printf("Pravilni magicni kvadrat je:\n");
for(i=1; i<=n; i++)
{ for(j=1; j<=n; j++) printf("%4d",mag[i][j]);
printf("\n");
}
}

Primer. Napisati program koji najefikasnijim postupkom izračunava n-ti stepen matrice A. Takav
stepen se može izračunati rekurzivno sa najmanjim brojem matričnih množenja na sledeći način:
A, n=1
An = (Ak)2, n = 2k
A(Ak)2, n = 2k+1
#include<stdio.h>
void mnozi(int n, int a[10][10], int b[10][10], int c[10][10])
{ int i,j,k;
int s;
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{ s=0;
for(k=0; k<n; k++) s+=a[i][k]*b[k][j];
c[i][j]=s;
}
}

146
Ivan P. Stanimirović Uvod u programiranje

void kopi(int n, int a[10][10], int b[10][10])


{ int i,j;
for(i=0; i<n; i++)
for(j=0; j<n; j++) b[i][j]=a[i][j];
}

void citaj(int n, int a[10][10])


{ int i,j;
printf("Unesi %d*%d elemenata matrice\n", n,n);
for(i=0; i<n; i++)
for(j=0; j<n; j++) scanf("%d",&a[i][j]);
}

void pisi(int n, int a[10][10])


{ int i,j;
for(i=0; i<n; i++)
{ for(j=0; j<n; j++) printf("%d ",a[i][j]);
printf("\n");
}
}

void stepen(int m, int n, int a[10][10], int b[10][10])


{ int c[10][10], p[10][10];
if(m==1) kopi(n,a,b);
else { stepen(m/2,n,a,c);
mnozi(n,c,c,p);
if(m%2==1)mnozi(n,p,a,b);
else kopi(n,p,b);
}
}

void main()
{ int n,m;
int a[10][10], b[10][10];
printf("Red kvadratne matrice = "); scanf("%d", &n);
citaj(n,a);
printf("Stepen = "); scanf("%d", &m);
stepen(m,n,a,b); pisi(n,b);
}

Primer. Svaki element matrice koji predstavlja maksimum svoje vrste i minimum svoje kolone
naziva se sedlasta tačka. Pronaći sve sedlatse tačke u zadatoj matrici.
#define MAXX 100
#define MAXY 100
#include<stdio.h>
#include<conio.h>
#include<limits.h>
#include<stdlib.h>
int a[MAXX][MAXY], mini[MAXX], maxi[MAXY],m,n;

void main()
{ int i,j;
printf("Dimenzije matrice? "); scanf("%d%d",&m,&n);
printf("Elementi?\n");
for(i=0;i<m;i++)
for(j=0;j<n;j++) scanf("%d", &a[i][j]);
for(i=0;i<m;i++)maxi[i]=maximum(i);
for(j=0;j<n;j++)mini[j]=minimum(j);
for(i=0;i<m;i++)
for(j=0;j<n;j++)

147
Ivan P. Stanimirović Uvod u programiranje

if(maxi[i]==a[i][j] && mini[j]==a[i][j])


printf("a[%d][%d]=%d ",i,j,a[i][j]);
}

int minimum(int kol)


{ int i,rez=INT_MAX;
for(i=0;i<m;i++) rez=min(rez,a[i][kol]);
return(rez);
}

int maximum(int vrs)


{ int j,rez=INT_MIN;
for(j=0;j<n;j++) rez=max(rez,a[vrs][j]);
return(rez);
}
Još jedno rešenje:
void main()
{ int a[100][100],p[100], q[100];
int m,n,i,j,k;
scanf("%d%d", &m,&n);
for(i=0;i<m;i++)
for(j=0;j<n;j++) scanf("%d", &a[i][j]);
for(i=0; i<m; i++)
{ k=0;
for(j=1;j<n;j++) if(a[i][j]>a[i][k])k=j;
p[i]=k;
}
for(j=0; j<n; j++)
{ k=0;
for(i=1;i<m;i++)
if(a[i][j]<a[i][k])k=i;
q[j]=k;
}
for(i=0;i<n;i++)
if(q[p[i]]==i) printf("%d %d\n",i,p[i]);
}
Primer. Data je matrica Amn celih brojeva. Element a[i,j] je vrh ako je veći od svojih susednih
elemenata koji su iznad, ispod, sa leve i sa desne strane. Visina vrha je razlika između elementa i
njegovog najvišeg suseda. Napisati program koji će formirati niz vrhova sortiran u nerastući redosled
po visini.
#include<stdio.h>
int vrh(int i, int j, int m, int n, int a[10][10])
{ if(i==0 && j==0)
return(a[i][j]>a[i][j+1] && a[i][j]>a[i+1][j]);
else if(i==m-1 && j==n-1)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1]);
else if(i==0 && j==n-1)
return(a[i][j]>a[i][j-1] && a[i][j]>a[i+1][j]);
else if(i==m-1 && j==0)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j+1]);
else if(i==0)
return(a[i][j]>a[i][j-1] &&
a[i][j]>a[i+1][j] && a[i][j]>a[i][j+1]);
else if(j==0)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j+1]&&
a[i][j]>a[i+1][j]);
else if(i==m-1)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1] &&

148
Ivan P. Stanimirović Uvod u programiranje

a[i][j]>a[i][j+1]);
else if(j==n-1)
return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1] &&
a[i][j]>a[i+1][j]);
else return(a[i][j]>a[i-1][j] && a[i][j]>a[i][j-1] &&
a[i][j]>a[i+1][j] && a[i][j]>a[i][j+1]);
}

int min2(int x, int y)


{if(x<y) return(x); else return(y); }

int min3(int x, int y, int z)


{ int min;
min=x; if(y<min) min=y; if(z<min) min=z;
return(min);
}

int min4(int x, int y, int z, int w)


{ int min;
min=x; if(y<min) min=y; if(z<min) min=z; if(w<min)min=w;
return(min);
}

int visina(int i, int j, int m, int n, int a[10][10])


{ int min2(int,int);
int min3(int,int,int);
int min4(int,int,int,int);
if(i==0 && j==0)
return(min2(a[i][j]-a[i][j+1],a[i][j]-a[i+1][j]));
else if(i==m-1 && j==n-1)
return(min2(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1]));
else if(i==0 && j==n-1)
return(min2(a[i][j]-a[i][j-1],a[i][j]-a[i+1][j]));
else if(i==m-1 && j==0)
return(min2(a[i][j]-a[i-1][j],a[i][j]-a[i][j+1]));
else if(i==0)
return(min3(a[i][j]-a[i][j-1],a[i][j]-a[i+1][j],
a[i][j]-a[i][j+1]));
else if(j==0)
return(min3(a[i][j]-a[i-1][j],a[i][j]-a[i][j+1],
a[i][j]-a[i+1][j]));
else if(i==m-1)
return(min3(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1],
a[i][j]-a[i][j+1]));
else if(j==n-1)
return(min3(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1],
a[i][j]-a[i+1][j]));
else return(min4(a[i][j]-a[i-1][j],a[i][j]-a[i][j-1],
a[i][j]-a[i+1][j],a[i][j]-a[i][j+1]));
}

void main()
{ int vrh(int i, int j, int m, int n, int a[10][10]);
int visina(int i, int j, int m, int n, int a[10][10]);
int i,j,a[10][10], vrhovi[25],visine[25], pom,k=0,m,n;
scanf("%d%d", &m,&n);
for(i=0;i<m;i++)
for(j=0;j<n;j++) scanf("%d",&a[i][j]);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
if(vrh(i,j,m,n,a))
{ vrhovi[k]=a[i][j]; visine[k]=visina(i,j,m,n,a); k++;}

149
Ivan P. Stanimirović Uvod u programiranje

for(i=0;i<k-1;i++)
for(j=i+1;j<k;j++)
if(visine[i]<visine[j])
{ pom=visine[i]; visine[i]=visine[j]; visine[j]=pom;
pom=vrhovi[i]; vrhovi[i]=vrhovi[j]; vrhovi[j]=pom;
}
printf("\nNiz vrhova i visina:\n");
for(i=0;i<k;i++)printf("Vrh: %d visina: %d\n",vrhovi[i],visine[i]);
}

Primer. Dat je niz a0,... , ak-1 celih brojeva. Napisati program kojim se formira kvadratna matrica reda
n takva da je niz ai, i = 0,... , k-1 upisan spiralno u tu matricu u smeru kretanja kazaljke na satu.
Ukoliko niz ima manje od n2 elemenata, posle svakih k upisanih elemenata početi upisivanje od
prvog.
#include <stdio.h>
int dodi[4]={0,1,0,-1};
int dođ[4]={1,0,-1,0}; /* desno, dole, levo, gore */

void main()
{ int a[10], k, mat[20][20], n, n1, smer, i,j,br,pombr,broj;
printf("Broj elemenata u nizu? "); scanf("%d", &k);
printf("elementi niza?\n"); for(i=0;i<k;i++) scanf("%d",&a[i]);
printf("Dimenzija matrice? "); scanf("%d", &n);
n1=n; i=j=br=smer=0;
for(broj=1; broj<=n*n; broj++)
{ /* ciklus za postavljanje elemenata u matricu */
mat[i][j]=a[br];
/* i, j su indeksi matrice, a br je indeks niza */
br++;
if(br==k)br=0; /* kad br dođe do k, vraca se na 0 */

i+=dodi[smer]; j+=dođ[smer];
if(i==n1 || j==n1 || (i==n-n1&&smer>0) || j==n-n1-1)
/* sada se menja smer dodavanja */
{ if(i==n1) i=n1-1; if(j==n1) j=n1-1;
if(i==n-n1 && smer>0) i=n-n1+1;
if(j==n-n1-1)j=n-n1;
smer++; /* sledeci smer */
if(smer==4) /* upotrebljeni su svi smerovi */
{ smer=0; /* ponovo na desno */
n1--;
}
i+=dodi[smer]; j+=dođ[smer];
}
}
for(i=0;i<n;i++)
{for(j=0;j<n;j++) printf("%d ",mat[i][j]); printf("\n"); }
}
Primer. Neka je dato n koncentričnih krugova takvih da svaki od njih ima m otvorenih vrata.
Prolaskom kroz bilo koja vrata dobija se izvestan broj nenegativnih poena. Ako je data matrica A
dimenzije nm čiji element a[i,j] označava broj poena koji se osvaja prolaskom kroz j-ta vrata i-tog
kruga, napisati program koji trasira put kroz n vrata tako da se sakupi dati broj poena s.
Kroz svaka vrata se prolazi tačno jedanput.

program krugovi;
type opseg=0..10;
niz=array[opseg] of integer;
matrica=array[opseg,opseg] of integer;
var a:matrica;

150
Ivan P. Stanimirović Uvod u programiranje

x:niz;
i,j,m,n,s:integer;
q:boolean;
function suma(x:niz; k:opseg):integer;
var i,j,s1:integer;
begin
s1:=0;
for i:=1 to k do s1:=s1+a[i,x[i]];
suma:=s1;
end;

procedure pisi(x:niz; n:integer);


var i:integer;
begin
for i:=1 to n do
begin
write('Na ',i,'. krugu vrata ',x[i],' poeni ',a[i,x[i]],' ');
writeln;
end;
end;

procedure trazi(k:opseg);
var i:opseg;
begin
i:=1;
while (i<=n) and not q do
begin
x[k]:=i;
if suma(x,k)<=s then
begin
if (k=n) and (suma(x,k)=s) then
begin
pisi(x,n); q:=true;
end
else trazi(k+1);
end;
i:=i+1;
end;
end;

begin
write('Uneti broj krugova i broj vrata na svakom krugu ');
readln(n,m); write('Unesi sumu '); readln(s);
writeln('Unesi broj poena na vratima ');
for i:=1 to n do
begin
for j:=1 to m do read(a[i,j]); readln;
end;
q:=false;
trazi(0); if not q then writeln('Nema resenja ');
end.
Primer. Problem n dama.
#include <stdio.h>

int a[50][50],n;
void cepaj(int);
int radi(int,int);
void ispis();

void main()

151
Ivan P. Stanimirović Uvod u programiranje

{ scanf("%d",&n); radi(0); }

void ispis()
{
int i,j;
for (i=0; i<n; i++)
{ for (j=0; j<n; j++) printf("%d ",a[i][j]); printf("\n"); }
printf("\n\n\n");
}

void radi(int j)
{ for (int i=0; i<n; i++)
if (cepa(i,j))
{ a[i][j]=1;
if (j<n-1) dalje(j+1);
else ispis();
a[i][j]=0;
}
}

int dalje(int i, int j)


{ for (int k=0; k<j; k++)
{ if ((a[i][k]==1) || (a[i-j+k][k]==1) || (a[i+j-k][k]==1))
return(0); }
return(1);
}
Primer. Data je sahovska tabla dimenzija n×m. Na polju sa koordinatama (i,j) je data figura. jedan
potez se sastoji u pomeranju figure za jedno polje gore, dole, levo ili desno. Napisati program koji za
date n,m,i,j određuje najmanji broj poteza kojim se figura dovodi u ugao table.
#include<stdio.h>
#include<math.h>
void plusOne(int a[], int n, int k)
{ int i,j;
if(a[k-1]<n-1) a[k-1]++;
else
{ i=k-2; j=1;
while((a[i]>=n-1-j) && (i>0))
{ i--; j++; }
a[i]++;
for(j=i+1;j<k;j++)a[j]=a[j-1]+1;
}
}

int jedanRed(int x[], int n)


{ int i,j,min=2000000000,rast;
for(i=0;i<n;i++)
{ rast=0;
for(j=0;j<n;j++)
if(i!=j) rast+=abs(x[i]-x[j]);
if(rast<min) min=rast;
}
return min;
}

int main()
{ int n,potezi[50],x[50],y[50],pomx[50],pomy[50],nizIndexa[50],i,j;
scanf("%d",&n);
for(i=0;i<n;i++)scanf("%d%d",&x[i],&y[i]);
potezi[0]=0; potezi[1]=0;
int min,rez;
for(i=2;i<=n;i++)

152
Ivan P. Stanimirović Uvod u programiranje

{ min=2000000000;
nizIndexa[0]=0;
for(j=1;j<i;j++)
nizIndexa[j]=nizIndexa[j-1]+1;
while(nizIndexa[0]<=(n-i))
{ rez=0;
for(j=0;j<i;j++)
{pomx[j]=x[nizIndexa[j]]; pomy[j]=y[nizIndexa[j]]; }
rez+=jedanRed(pomx,i)+jedanRed(pomy,i);
if(rez<min) min=rez;
plusOne(nizIndexa,n,i);
}
potezi[i]=min;
}
for(i=0;i<=n;i++)printf("%4d", potezi[i]);
printf("\n");
return 0;
}

Primer. Na obali nekog ostrva nalazi se n gradova označenih brojevima od 0 do n-1. Oko celog ostrva
je izgrađen autoput koji prolazi kroz svaki od gradova. U nizu d su data rastojanja između gradova,
tako da d[i] predstavlja dužinu autoputa između gradova i i i+1 (d[n-1] predstavlja dužinu puta između
grada n-1 i 0). Napisati program koji za sve gradove određuje niz najkraćih rastojanja do ostalih
gradova.
#include<stdio.h>
float rastojanje(int i, int j, int n, float d[10])
{ float rl,rd;
int k;
rl=rd=0;
for(k=i; k<=j-1;k++)rl=rl+d[k];
for(k=j; k<=n-1; k++)rd=rd+d[k];
for(k=0;k<=i-1;k++)rd=rd+d[k];
if(rl<rd) return(rl);
else return(rd);
}

void main()
{ float rastojanje(int i, int j, int n, float d[10]);
int k,n,i,j;
float d[10], rastojanja[10][10];
printf("Broj gradova? "); scanf("%d",&n);
printf("Rastojanja?\n"); for(k=0;k<n;k++) scanf("%f",&d[k]);
for(i=0; i<n-1;i++)
for(j=i+1;j<n;j++)
{ rastojanja[i][j]=rastojanje(i,j,n,d);
rastojanja[j][i]=rastojanja[i][j];
}
for(j=0;j<n;j++)rastojanja[j][j]=0;
for(i=0;i<=n-1;i++)
{for(j=0;j<=n-1; j++)
printf("Rastojanje između %d i %d = %f\n",i,j,rastojanja[i][j]);
printf("\n");
}
}
51. (PASCAL) Napisati funkciju kojom se utvrdjuje da li je zadata matrica A dimenzija m x n
ortonormirana. Matrica je ortonormirana ako je skalarni proizvod svakog para različitih vrsta jednak 0,
a skalarni proizvod vrste sa samom sobom 1.
Ulaz: Dva pozitivna cela broja m i n koji predstavljaju dimenzije matrice.
Izlaz: Tekst Matrica je ortonormirana, ako je matrica ortonormirana, a inače tekst Matrica nije ortonormirana.

153
Ivan P. Stanimirović Uvod u programiranje

program ortomormirana;
type opseg=1..10;
niz=array[opseg]of real;
matrica=array[opseg]of niz;
var a:matrica; m,n:opseg;ort:boolean;

function skalpr(n:opseg; v1,v2:niz):real;


var i:opseg;
s:real;
begin
s:=0;
for i:=1 to n do s:=s+v1[i]*v2[i];
skalpr:=s
end;

function isort(m,n:opseg; a:matrica):boolean;


var lg:boolean;
i,j:opseg;
sp:real;
begin
lg:=true;
for i:=1 to m do
for j:=i to m do
begin
sp:=skalpr(n,a[i],a[j]);
if ((i=j)and(sp<>1))or((i<>j)and(sp<>0)) then
lg:=false;
end;
isort:=lg;
end;

procedure ucitaj(m,n:opseg; var x:matrica);


var i,j:opseg;
begin
for i:=1 to m do
begin
for j:=1 to n do read(x[i,j]);
readln
end;
end;

begin
readln(m,n);
ucitaj(m,n,a);
ort:=isort(m,n,a);
if ort then writeln('Matrica je ortonormirana ')
else writeln('Matrica nije ortonormirana ');
end.
Test primeri:
3 3 3 3
1 0 0 1 1 0
0 1 0 0 1 0
0 0 1 0 0 1
Matrica je ortonormirana Matrica nije ortonormirana

54. (PASCAL) Data je matrica A(nn) čiji su elementi:


true, ako postoji direktan jednosmeran put između gradova i i j,
a[i,j] =
false, u suprotnom.

154
Ivan P. Stanimirović Uvod u programiranje

Napisati program kojim se formira i ispisuje matrica iz koje se vidi koji gradovi imaju vezu sa
najmanje jednim presedanjem.
Ulaz: Matrica A(nn).

Izlaz: Matrica veze C(nn).


program gradovi;
const g=10;
type matrica=array[1..g,1..g] of boolean;
var n:integer;veza,jednopres:matrica;
procedure citajveze(n:integer; var veza:matrica);
var i,j,v:integer;
begin
writeln('Unesi veze (1-da,0-ne) izmedju gradova');
for i:=1 to n do
begin
for j:=1 to n do
begin
read(v);
if v=1 then veza[i,j]:=true
else veza[i,j]:=false;
end;
readln;
end;
end;

procedure pisiveze(brgradova:integer;a:matrica);
var i,j:integer;
begin
writeln('Matrica veze (1-da, 0-ne)');
for i:=1 to brgradova do
begin
for j:=1 to brgradova do
if a[i,j] then write('1':2)
else write('0':2);
writeln;
end;
end;

procedure pro(brgradova:integer;a,b:matrica;var c:matrica);


var log:boolean;
i,j,k:integer;
begin
for i:=1 to brgradova do
for j:=1 to brgradova do
begin
log:=false;
for k:=1 to brgradova do
log:=log or (a[i,k] and b[k,j]);
c[i,j]:=log;
end;
end;

begin
write('Broj gradova? '); readln(n);
writeln('Veze između gradova?');
citajveze(n,veza);
pro(n,veza,veza,jednopres);

155
Ivan P. Stanimirović Uvod u programiranje

pisiveze(n,jednopres);
end.
Test primer:
Broj gradova? 3
Unesi veze (1-da,0-ne) izmedju gradova
1 0 1
0 1 0
0 1 1
Matrica veze (1-da,0-ne)
1 1 1
0 1 0
0 1 1
116. (PASCAL) Raspoređeno je 15 kuglica na sledeći način: u prvoj vrsti se nalazi 5 kuglica, u drugoj
4, u trećoj 3, u četvrtoj 2 i u petoj 1. Obeležiti svaku kuglicu jednim od brojeva 1,...,15, tako da svaka
kuglica ima jedinstven broj i da važi jednakost
aij=|ai-1,j-ai-1,j+1|, i= 2,3,4,5, j=1,5-i+1.

program kuglice;
type niz=array[1..15] of integer;
matrica =array[1..5,1..5] of integer;
var i,j,k,l,m,br,indu :1..15;
upotrebljen:niz;
a:matrica;
procedure ispis(a:matrica);
var i,j:1..5;
begin
for i:=1 to 5 do
begin
for j:=1 to 5-i+1 do write(a[i,j]:3);writeln
end;
end;

function razliciti(k:integer; a:niz):boolean;


var i,j:1..15;
bol:boolean;
begin
bol := true;
for i:=1 to k do
for j:=i+1 to k do
if a[i]=a[j] then bol:=false;
razliciti:=bol;
end;

begin
for i:=1 to 15 do
for j:=1 to 15 do
for k:=1 to 15 do
for l:=1 to 15 do
for m:=1 to 15 do
begin
a[1,1]:=i;a[1,2]:=j;
a[1,3]:=k;a[1,4]:=l;a[1,5]:=m;

for br:=1 to 5 do
upotrebljen[br]:=a[1,br];
indu:=5;
for br:=1 to 4 do
begin
a[2,br]:=abs(a[1,br]-a[1,br+1]);
indu:=indu+1;

156
Ivan P. Stanimirović Uvod u programiranje

upotrebljen[indu]:=a[2,br];
end;
for br:=1 to 3 do
begin
a[3,br]:=abs(a[2,br]-a[2,br+1]);
indu:=indu+1;
upotrebljen[indu]:=a[3,br];
end;
for br:=1 to 2 do
begin
a[4,br]:=abs(a[3,br]-a[3,br+1]);
indu:=indu+1;
upotrebljen[indu]:=a[4,br];
end;
a[5,1]:=abs(a[4,1]-a[4,2]);
indu:=indu+1;
upotrebljen[indu]:=a[5,1];
if razliciti(indu,upotrebljen) then
begin
writeln;writeln;
ispis(a);readln;
end;
end;
end.
Test primer:
Resenje 1 Resenje 2
6 14 15 3 13 13 3 15 14 6
8 1 12 10 10 12 1 8
7 11 2 2 11 7
4 9 9 4
5 5

117. (PASCAL) Zadata je crno-bela matrica (0 definiše belu boju, a 1 crnu). Napisati program kojim
se bele oblasti te matrice boje različitim bojama (boje se definišu sa 2,3,...). Ispisati obojenu matricu.
program bojenje;
const k=20; l=20;
type matrica = array[1..k,1..l] of integer;
var m,n,i,j,boja:integer;
tabla:matrica;
prx,pry:array[1..4] of integer;
procedure ispis(m,n:integer; a:matrica);
var i,j:integer;
begin
for i:=1 to m do
begin
for j:=1 to n do write(a[i,j]:3);
writeln;
end;
end;
procedure upis(m,n:integer; var a:matrica);
var i,j:integer;
begin
for i:=1 to m do
begin
for j:=1 to n do read(a[i,j]);readln;
end;
end;
function moze(x,y:integer; a:matrica):boolean;
begin

157
Ivan P. Stanimirović Uvod u programiranje

if(x>=1)and(x<=m)and(y>=1)and(y<=n) then
moze:=a[x,y]=0
else moze:=false;
end;
procedure oboji(x,y,boja:integer; var a:matrica);
var i:integer;
begin
a[x,y]:=boja;
for i:=1 to 4 do
if moze(x+prx[i],y+pry[i],a) then
oboji(x+prx[i],y+pry[i],boja,a)
end;

begin
write('Dimenzije? '); readln(m,n);
upis(m,n,tabla);
prx[1]:=-1; pry[1]:=0; { gore }
prx[2]:=0; pry[2]:=1; { desno }
prx[3]:=1; pry[3]:=0; { dole }
prx[4]:=0; pry[4]:=-1; { levo }
boja:=1;
for i:=1 to m do
for j:=1 to n do
if tabla[i,j]=0 then
begin
boja:=boja+1; oboji(i,j,boja,tabla);
end;
ispis(m,n,tabla);
end.
Test primer:
Dimenzije? 3 4 Dimenzije? 4 5
0 0 1 0 0 0 0 0 1
0 1 1 0 0 0 1 1 0
0 0 0 1 0 0 0 0 0
2 2 1 3 1 0 0 0 1
2 1 1 3 2 2 2 2 1
2 2 2 1 2 2 1 1 2
2 2 2 2 2
1 2 2 2 1

118. (PASCAL) Napisati program kojim se određuje minimalan broj (P,Q) konja kojima se mogu
kontrolisati sva polja šahovske table dimenzije mn. (P,Q) konj je figura koja se u jednom skoku
premešta za P polja po horizontali i Q polja po vertikali. Običan šahovski konj je (1,2) konj.
program konj;
const k=30; l=30;
type matrica =array[1..k,1..l] of boolean;
var m,n,p,q,x,y,mink:integer;
tabla:matrica;
skokpox,skokpoy:array[1..8] of integer;
function moze(x,y:integer):boolean;
begin
if (x>=1)and(x<=m)and(y>=1)and(y<=n) then
moze := not tabla[x,y]
else moze:=false
end;

procedure konjana(x,y:integer);
var i:integer;
begin
tabla[x,y]:=true;

158
Ivan P. Stanimirović Uvod u programiranje

for i:=1 to 8 do
if moze(x+skokpox[i],y+skokpoy[i]) then
konjana(x+skokpox[i],y+skokpoy[i]);
end;

begin
write('p,q= ? ');readln(p,q); write('m,n= ? ');
readln(m,n);
for x:=1 to m do
for y:=1 to n do tabla[x,y]:=false;
skokpox[1]:=-q;skokpoy[1]:=p;skokpox[2]:=-p;
skokpoy[2]:=q;skokpox[3]:=p; skokpoy[3]:=q;
skokpox[4]:=q; skokpoy[4]:=p;
skokpox[5]:=q; skokpoy[5]:=-p;
skokpox[6]:=p; skokpoy[6]:=-q;
skokpox[7]:=-p; skokpoy[7]:=-q;
skokpox[8]:=-q; skokpoy[8]:=-p;
mink:=0;
for x:=1 to m do
for y:=1 to n do
if not tabla[x,y] then
begin
konjana(x,y); mink:=mink+1;
end;
writeln('Minimalni broj konja je ',mink);
end.
Test primer:
p,q= ? 1 1 p,q= ? 3 3
m,n= ? 8 8 m,n= ? 8 8
minimalan broj konja je 2 minimalan broj konja je 18
p,q= ? 1 3 p,q= ? 4 4
m,n= ? 8 8 m,n= ? 8 8
minimalan broj konja je 2 minimalan broj konja je 32

119. (PASCAL) Data je realna matrica X dimenzije mn i celi brojevi Ip i Jp, (1<= Ip<=m,
1<=Jp<=n). Svakom elementu matrice pridružuje se jedno polje na tačno određen način. Polje je
određeno sa tri elementa: koordinatama (i,j) i realnim brojem koji predstavlja njegovu visinu. Broj
X[i,j] određuje visinu polja sa koordinatama (i,j). U polju sa koordinatama (Ip,Jp) nalazi se loptica.
Loptica prelazi sa polja A na polje B ako važe sledeći uslovi:
- polja A i B su susedna, što znači da imaju zajedničku stranicu;
- visina polja B je strogo manja od visine polja A, i
- polje B ima najmanju visinu u odnosu na sva polja susedna u odnosu na A.
Loptica se zaustavlja u polju u odnosu na koje ne postoji polje na koje može da pređe. Takvo polje se
naziva završno. Odrediti polje na kome će se loptica zaustaviti kao i put od početnog polja (Ip, Jp) do
završnog.
program lopta1;
type matrica=array[1..30,1..30] of integer;
var x:matrica;
m,n,i,j,ip,jp:integer;
function moze(a,b:integer):boolean;
begin
moze:= (a>=1)and(a<=m)and(b>=1)and(b<=n)
end;
procedure uradi(ip,jp:integer; x:matrica; m,n:integer);
var q:boolean;
poz,poz1,a,b,min,min1:integer;
begin
q:=true; poz:=ip; poz1:=jp;

159
Ivan P. Stanimirović Uvod u programiranje

writeln('Put: ');
while q do
begin
min:=x[poz,poz1]; a:=poz; b:=poz1; min1:=min;
if moze(a-1,b)and(x[a-1,b]<x[poz,poz1])
and(x[a-1,b]<min) then
begin
if poz1<>b then
poz1:=b; poz:=a-1;
min:=x[a-1,b];
end;
if moze(a+1,b)and(x[a+1,b]<x[poz,poz1])
and(x[a+1,b]<min)then
begin
if poz1<>b then
poz1:=b; poz:=a+1;
min:=x[a+1,b];
end;
if moze(a,b-1)and(x[a,b-1]<x[poz,poz1])
and(x[a,b-1]<min) then
begin
if poz<>a then
poz:=a; poz1:=b-1;
min:=x[a,b-1];
end;
if moze(a,b+1)and(x[a,b+1]<x[poz,poz1])
and(x[a,b+1]<min) then
begin
if poz<>a then
poz:=a; poz1:=b+1;
min:=x[a,b+1];
end;
q:=min<>min1;min:=min1;
if q then
writeln(poz:6,poz1:6,' ',x[poz,poz1]);
end;
writeln('Zavrsno polje: ');
writeln(poz:6,poz1:6,' ',x[poz,poz1]);
end;

begin
writeln('Unesite dimenzije matrice');readln(m,n);
writeln('Unesite elemente');
for i:=1 to m do
begin
for j:=1 to n do read(x[i,j]);
readln;
end;
writeln('Unesite ip i jp:');
readln(ip,jp); uradi(ip,jp,x,m,n);
end.
Test primer:
Unesite dimenzije matrice Unesite ip i jp:
3 3 1 3
Unesite elemente Put:
1 2 3 1 2 2
6 5 4 1 1 1
7 8 9 Zavrsno polje:
1 1 1

120. (PASCAL) Napisati funkcije (rekurzivnu i iterativnu verziju) koje za datu relaciju nad

160
Ivan P. Stanimirović Uvod u programiranje

maksimalno devetočlanim skupom ispituju refleksivnost, simetričnost i tranzivnost. Relacija je


opisana matricom istinitosnih vrednosti: ako je element aij matrice A jednak true, to znači da je i-ti
element skupa u relaciji sa j-tim elementom. Data je tekstualna datoteka. Svaki red datoteke ima oblik
n i1 j1 i2 j2 ... ik jk,
gde je n dimenzija matrice, a il i jl (l=1,...,k) indeksi elemenata koji su u relaciji. Dakle, jedan
red datoteke opisuje jednu relaciju.
Napisati program koji prebrojava nekorektne redove u datoteci, redove koji opisuju relaciju
ekvivalencije, kao i redove koji opisuju relaciju poretka (uređenja).
program pmfokt22;
const maxn=9;
type relacija = array[1..maxn,1..maxn] of boolean;

function ucitaj(var dat:text;var n:integer;


var r:relacija):boolean;
var i,j:integer;
ind:boolean;
begin
ind:=true;
read(dat,n);
for i:=1 to n do
for j:= 1 to n do r[i,j]:=false;
while not eoln(dat) do
begin
read(dat,i);
if(i<1) or (i>n) or eoln(dat) then ind:=false;
if ind then
begin
read(dat,j);
if (j<1) or (j>n) then ind:=false;
end;
if ind then r[i,j]:=true;
end;
ucitaj:=ind;
end;

(* Iterativne funkcije *)
function refleks(n:integer; r:relacija):boolean;
var i:integer;
ind:boolean;
begin
ind:=true;
for i:=1 to n do ind:=ind and r[i,i];
refleks:=ind;
end;

function simet(n:integer; r:relacija):boolean;


var i,j:integer;
ind:boolean;
begin
ind:=true;
for i:=1 to n-1 do
for j:=i+1 to n do
ind:=ind and r[i,j]=r[j,i];
(* if r[i,j]<>r[j,i] then ind:=false *)
simet:=ind;
end;

function antisimet(n:integer; r:relacija):boolean;


var i,j:integer;

161
Ivan P. Stanimirović Uvod u programiranje

ind:boolean;
begin
ind:=true;
for i:=1 to n-1 do
for j:=i+1 to n do
if (i<>j) and r[i,j] and r[j,i] then ind:=false;
antisimet:=ind;
end;

function tranzit(n:integer; r:relacija):boolean;


var i,j,k:integer;
ind:boolean;
begin
ind:=true;
for i:=1 to n do
for j:=1 to n do
for k:=1 to n do
if r[i,j] andr [j,k] and (not r[i,k]) then
ind:=false;
tranzit:=ind;
end;

(* Rekurzivne verzije funkcija *)


function refleksr(n:integer; r:relacija):boolean;
begin
if n=1 then
refleksr:= r[1,1]
else refleksr:=refleksr(n-1,r)and r[n,n];
end;

function simetr(n:integer; r:relacija):boolean;


var i:integer;
ind:boolean;
begin
if n<=1 then simetr:=true
else begin
ind:=true;
for i:=1 to n do ind:=ind and (r[i,n]=r[n,i]);
simetr:=simetr(n-1,r) and ind;
end;
simetr:=ind;
end;

function antisimetr(n:integer; r:relacija):boolean;


var i,j:integer;
ind:boolean;
begin
if n<=1 then antisimetr:=true
else begin
ind:=true;
for i:=1 to n-1 do
if r[i,n] and r[n,i] and (i<>n) then
ind:=false;
antisimetr:=ind and antisimetr(n-1,r);
end;
end;

function tranzitr(n:integer; r:relacija):boolean;


var i,j:integer;
ind:boolean;
begin

162
Ivan P. Stanimirović Uvod u programiranje

if n<=2 then tranzitr:=true


else
begin
ind:=true;
for i:=1 to n do
for j:=1 to n do
if r[i,j] and r[j,n] and(not r[i,n]) then
ind:=false;
tranzitr:=ind and tranzitr(n-1,r);
end;
end;

procedure uradi;
var brekv, brpor, brnekor:integer;
f:text;
r:relacija;
n:integer;
ref,sim,asim,tr,refr,simr,asimr,trr:boolean;
begin
brekv:=0; brpor:=0; brnekor:=0;
assign(f,'c:\relacije'); reset(f);
while not eof(f) do
begin
if not ucitaj(f,n,r) then
brnekor:=brnekor+1
else
begin
ref:=refleks(n,r); (* ref:=refleksr(n,r *)
sim:=simet(n,r); (* sim:=simetr(n,r); *)
asim:=antisimet(n,r);
(* asim:=antisimetr(n,r); *)
tr:=tranzit(n,r); (* tr:=tranzitr(n,r); *)
if ref and sim and tr then brekv:=brekv+1;
if ref and asim and tr then brpor:=brpor+1;
end;
end;
writeln('Iterativna verzija: ');
writeln('Bilo je ',brekv,' relacija ekvivalencije');
writeln('Bilo je ',brpor,' relacija poretka');
writeln('Bilo je ',brnekor,' nekorektnih relacija');
close(f);
end;

begin
uradi;
end.

156. (PASCAL) Mali Đurica je počeo da skija. Đurica je egzibicionista i ne skija po stazama, već
skija kako stigne. Zbog toga, služba spasavanja je rešila da napravi program koji će izračunati sva
moguća mesta na kojima se Đurica može naći. Mapa terena se zadaje kao matrica dimenzija m  n,
gde svaki element matrice h[i, j], predstavlja visinu mesta sa koordinatama (i, j). Đurica se spusta
uvek u pravcu samo jedne koorditane (ne dijagonalno), i to isključivo sa mesta koje je više, na mesto
koje je niže (h[istart, jstart] > … > h[i, j] > … > h[ikraj, jkraj]). Za zadato startno mesto i mapu
terena, treba odštampati broj mesta na kojima se Đurica može naći (uključujući i startno mesto).
Ulazni podaci nalaze se u fajlu ZAD2.DAT. U prvom redu ulaznog fajla nalaze se celi brojevi m i n (1
≤ m ≤ 100, 1 ≤ n ≤ 100), gde je m broj redova, a n broj kolona mape terena. U sledećih m redova nalazi
se po n celih brojeva koji predstavljaju elemente matrice h[i, j] (0 ≤ h[i, j] ≤ 10000). U sledećem redu
nalaze se brojevi r i k koji predstavljaju red i kolonu startnog mesta (1 ≤ r ≤ m, 1 ≤ k ≤ n).

163
Ivan P. Stanimirović Uvod u programiranje

Izlazne podatke treba upisati u fajl ZAD2.RES. Fajl treba da sadrži samo jedan broj x, koji predstavlja
broj mesta na kojima se Đurica može nalaziti:

{A+,B-,D+,E+,F+,G+,I+,L+,N-,O+,P-,Q+,R+,S+,T-,V+,X+,Y+}
{M 65520,300000,600000}

const inp='zad2.dat';
out='zad2.res';

var a:array[0..101,0..101] of 0..10000;


mark:array[0..101,0..101] of boolean;
n,m,i,j,r,k,br:integer;
f:text;

procedure radi(x,y:byte);
begin
inc(br);
mark[x,y]:=true;
if x<m then
if (a[x+1,y]<a[x,y]) and not mark[x+1,y] then
radi(x+1,y);
if y<n then
if (a[x,y+1]<a[x,y]) and not mark[x,y+1] then
radi (x,y+1);
if x>1 then
if (a[x-1,y]<a[x,y]) and not mark[x-1,y] then
radi(x-1,y);
if y>1 then
if (a[x,y-1]<a[x,y]) and not mark[x,y-1] then
radi(x,y-1);
end;

begin
assign(f,inp); reset(f);
read(f,m,n);
for i:=1 to m do
for j:=1 to n do read(f,a[i,j]);
read(f,r,k); br:=0; close(f);
radi (r,k);
assign(f,out); rewrite(f);
write(f,br); close(f);
end.
Test primeri:
ZAD2.DAT ZAD2.RES Objašnjenje: Sva mesta na
kojima se Đurica može naći su
podvučena.
6 7 14 0 0 0 10 10 10 10
0 0 0 10 10 10 10 0 0 0 10 10 10 10
0 0 0 10 10 10 10 10 2 10 6 10 0 1
10 2 10 6 10 0 1 10 3 10 7 7 4 2
10 3 10 7 7 4 2 10 4 5 7 8 10 10
10 4 5 7 8 10 10 10 3 10 10 9 10 10
10 3 10 10 9 10 10
6 5

60. (C) Napisati proceduru kojom se učitavaju elementi pravougaone matrice x dimenzija mn, gde je
m i n <=10. Napisati funkciju koja određuje najdužu rastuću seriju brojeva u nizu celih brojeva.
Koristeći ovu funkciju, napisati funkciju koja određuje indeks vrste u matrici x koja sadrži najdužu
rastuću seriju.
Ulaz: Pozitivni celi brojevi m i n koji predstavljaju dimenzije matrice x, a zatim m n elemenata matrice x.
Izlaz: Redni broj vrste u matrici x koja sadrži najdužu rastuću seriju brojeva.

164
Ivan P. Stanimirović Uvod u programiranje

#include<stdio.h>
int naj(int x[], int n)
{ int i;
float s, max;
s=max=1;
for(i=1;i<n; i++)
if(x[i]>x[i-1]) s++;
else
{
if (s>max) max=s;
s=1;
}
if(s>max) max=s;
return(max);
}
void ucitaj(int x[][10], int m, int n)
{ int i,j;
for(i=0; i<m; i++)
for(j=0; j<n; j++) scanf("%d", &x[i][j]);
}
int najduza(int a[][10], int m, int n)
{ int i,max=0, k, ind;
for(i=0; i<m; i++)
{ k=naj(a[i],n);
if(k>max)
{ max=k; ind=i; }
}
return(ind+1);
}

void main()
{ int x[10][10];
int mx, m, n;
scanf("%d%d", &m,&n);
ucitaj(x,m,n);
mx=najduza(x,m,n);
printf("Vrsta sa najduzom serijom je %d.\n",mx);
}
Test primeri:
3 5 2 3
2 7 -2 3 4 2 3 4
1 1 0 -2 3 2 1 3
2 3 4 5 0

Vrsta sa najduzom serijom je 3. Vrsta sa najduzom serijom je 1.

152. (C) Napisati program koji kvadratnu matricu dimenzije dimdim popunjava prirodnim brojevima
od 1 do dim2 po spirali. Očigledno je da će maksimalni upisan broj biti dim2. Suština zadatka je naći
uslov koji treba da ispunjavaju vrste i kolone da bi došlo do skretanja u određenom pravcu. Za
skretanje udesno uslov je da je i+j<dim+1. Za skretanje naniže uslov je da je i<j. Za skretanje ulevo
uslov je da je i+j<>dim+1. Za skretanje naviše uslov je da je i>j+1.

void main()
{ int i,j,dim,brojac,kraj;int spirala[21][21];
do { printf("\nUnesite dimenziju matrice: ");
scanf("%d",&dim); }
while (dim<1 || dim>20);
brojac=0;i=1;j=0;kraj=dim*dim;
do
{

165
Ivan P. Stanimirović Uvod u programiranje

while ((brojac < kraj) && (i+j<dim+1))


{ j++;brojac++; spirala[i][j]=brojac;}
while ((brojac < kraj) && (i<j))
{ i++;brojac++; spirala[i][j]=brojac;}
while ((brojac < kraj) && (i+j!=dim+1))
{ j--;brojac++; spirala[i][j]=brojac;}
while ((brojac < kraj) && (i>j+1))
{ i--;brojac++; spirala[i][j]=brojac;}
}
while (brojac!=kraj);

printf("\n");
for (i=1;i<=dim;i++)
{ for (j=1;j<=dim;j++)
printf("%3d ",spirala[i][j]);
printf("\n");
}
}
Rešenje 2.
#include <stdio.h>
void main()
{ int a[100][100]; int i,j,p,q,b,n,z,m,k,e,k2,e2,r;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
for (j=1;j<=m;j++) a[i][j]=0;
i=1;j=1;b=1;k=n;e=m;p=0;q=1;k2=1;e2=1;z=n*m;
while (b<=z)
{ a[i][j]=b;
if((j==e)&&(i==k2)) { p=1; q=0; };
if((i==k)&&(j==e)) { q=-1; p=0; };
if((i==k)&&(j==e2)) { p=-1; q=0; };
if((j==e2)&&(i==k2)) { p=0; q=1;};
if((j==e2)&&(i==k2+1))
{ p=0;q=1;k2++;e2++;e--;k--; };
b++; i=i+p; j=j+q;
}
for (i=1;i<=n;i++)
{ printf("\n");
for (j=1;j<=m;j++) printf("%4d",a[i][j]);
}
}
Test primer:

Unesite dimenziju matrice:15


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
56 57 58 59 60 61 62 63 64 65 66 67 68 69 16
55 104 105 106 107 108 109 110 111 112 113 114 115 70 17
54 103 144 145 146 147 148 149 150 151 152 153 116 71 18
53 102 143 176 177 178 179 180 181 182 183 154 117 72 19
52 101 142 175 200 201 202 203 204 205 184 155 118 73 20
51 100 141 174 199 216 217 218 219 206 185 156 119 74 21
50 99 140 173 198 215 224 225 220 207 186 157 120 75 22
49 98 139 172 197 214 223 222 221 208 187 158 121 76 23
48 97 138 171 196 213 212 211 210 209 188 159 122 77 24
47 96 137 170 195 194 193 192 191 190 189 160 123 78 25

153. (C) Napisati program kojim se u matrici dimenzija mn upisuju brojevi do zadatog broja, prateći
put kuglice koja polazi od elementa sa koordinatama (0,0) i odbija se od zidova matrice. Ostali
elementi matrice su 0.

166
Ivan P. Stanimirović Uvod u programiranje

#include<stdio.h>
main()
{ int a[100][100];
int i,j,p,q,n,m,b,k;
scanf("%d",&n); scanf("%d",&m);
for (i=0;i<n;i++)
for (j=0;j<m;j++) a[i][j]=0;
scanf("%d",&k);
i=0;j=0; p=q=1; b=2;
a[i][j]=1;i=j=1;
while (b<=k)
{ a[i][j]=b; b++;
if ((i==(n-1))||(i==0)) p=p*(-1);
if ((j==(m-1))||(j==0)) q=q*(-1);
i=i+p; j=j+q;
}
for (i=0;i<n;i++)
{ printf("\n");
for (j=0;j<m;j++)
printf("%d\t",a[i][j]);
}
}
Test primeri:
2 4 4 3 3 4

1 0 3 0 1 0 0
0 2 0 4 0 4 0
0 0 3
Još jedno rešenje
#include <stdio.h>

typedef int mat[100][100];

void ispis( int m, int n, mat a)


{ int i,j;
for (i=0;i<m; i++)
{for (j=0;j<n; j++)
printf("%d\t", a[i][j]);
printf("\n");}
}

void main()
{ int n,m;
mat a = {{0,0}};
int cnt;
scanf("%d %d %d", &m, &n, &cnt);
int dx=1;
int dy=1;
int cx=0;
int cy=0;
int curr=0;
while (cnt--)
{
a[cx][cy] = ++curr;
cx+=dx;
cy+=dy;
if ((cx>=m)||(cx<0))
{
dx*=-1;

167
Ivan P. Stanimirović Uvod u programiranje

cx+=2*dx;
}
if ((cy>=n)||(cy<0))
{
dy*=-1;
cy+=2*dy;
}
}

ispis(m, n, a);

}
154. (C) Napisati program koji učitava dimenziju šahovske table (broj kvadrata) i veličinu svakog
kvadrata na tabli, a zatim generiše matricu koja odgovara uokvirenoj šahovskoj tabli. U gornjem
levom uglu šahovske table uvek je crni kvadrat. Crnom polju odgovara znak '*', a belom znak ' '.
#include<stdio.h>

void promeni(char *ch)


{ if((*ch)== '*') *ch=' ';
else *ch='*';
}

void generisi(int d,int v, char a[80][80])


{ int i,j,k,l,p,q;
char znak,znak1;
p=1; q=1; znak1='*';
for(i=1; i<=d; i++)
{ for(k=1; k<=v; k++)
{ znak=znak1;
for(j=1; j<=d; j++)
{ for(l=1; l<=v; l++)
{ if(q>d*v) q=1;
a[p][q]=znak; q=q+1;
}
promeni(&znak);
}
p=p+1;
}
promeni(&znak1);
}
a[0][0]=(char)201;
a[0][d*v+1]=(char)187;
a[d*v+1][0]=(char)200;
a[d*v+1][d*v+1]=(char)188;
for(j=1; j<=d*v; j++)
{ a[0][j]=(char)205;a[d*v+1][j]=(char)205; }
for(i=1; i<=d*v; i++)
{ a[i][0]=(char)186;a[i][d*v+1]=(char)186; }
}

void main()
{ char a[80][80];
int i,j,dim,vel;
clrscr();
scanf("%d%d",&dim,&vel);
generisi(dim,vel,a);
for(i=0; i<=dim*vel+1; i++)
{ for(j=0; j<=dim*vel+1; j++) putchar(a[i][j]);
printf("\n");
}

168
Ivan P. Stanimirović Uvod u programiranje

}
Rešenje 2.
#include<stdio.h>

void generisi(int d,int v, char a[80][80])


{ int i,j;
for(i=1; i<=d*v; i++)
for(j=1; j<=d*v; j++)
if( ((i-1)/v+(j-1)/v)%2==0)
a[i][j]='*';
else a[i][j]=' ';
a[0][0]=(char)201;
a[0][d*v+1]=(char)187;
a[d*v+1][0]=(char)200;
a[d*v+1][d*v+1]=(char)188;
for(j=1; j<=d*v; j++)
{ a[0][j]=(char)205;
a[d*v+1][j]=(char)205;
a[j][0]=(char)186;
a[j][d*v+1]=(char)186; }
}

void main()
{ char a[80][80];
int i,j,dim,vel;
clrscr();
scanf("%d%d",&dim,&vel);
generisi(dim,vel,a);
for(i=0; i<=dim*vel+1; i++)
{ for(j=0; j<=dim*vel+1; j++)
putchar(a[i][j]);
printf("\n");
}
}
Test primeri:

Primer. (C) U svakom od tri kontejnera se nalazi izvesna količina smeđih, zelenih i belih boca koje
treba da se recikliraju. Da bi staklo moglo da se reciklira u svakom kontejneru moraju da se nalaze
boce iste boje. Napisati program koji određuje minimalni broj premeštanja boca tako da posle
premestanja u svakom kontejneru budu boce iste boje. Pri jednom premeštanju se prebacuje jedna
boca iz bilo kog u neki drugi kontejner, a kontejneri su dovoljno veliki da mogu da sadrže sve boce.
U tekstualnom fajlu zad2.dat nalaze se 3 reda sa po 3 broja u svakom, koji opisuju početno
stanje: broj smeđih, zelenih i belih boca u prvom kontejneru, zatim u drugom i na kraju u trećem. U

169
Ivan P. Stanimirović Uvod u programiranje

izlazni fajl zad2.res ispisati minimalan broj premeštanja koji je potreban da se postigne to završno
stanje.

Test Primer:
zad2.dat zad2.res
1 2 3 30
4 5 6
7 8 9

#include<stdio.h>
int main(){
FILE *f,*g;
int i,j,k,m[3][3],r,a;
f=fopen("zad2.dat","r");
g=fopen("zad2.res","w");
for(i=0;i<3;i++)
for(j=0;j<3;j++)
fscanf(f,"%d",&m[i][j]);
r=-1;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
for(k=0;k<3;k++)
if ((i!=j)&&(i!=k)&&(j!=k)){

a=m[0][i]+m[1][i]+m[0][j]+m[2][j]+m[1][k]+m[2][k];
if(a<r) r=a;
else if(r==-1) r=a;
}
fprintf(g,"%d",r);
fclose(f);
fclose(g);
return 0;
}

Kratko objašnjenje rešenja


Za rešavanje ovog zadatka dovoljne su nam 2. Prva for petlja koja se sastoji iz dve for petlje služi za
učitavanje broja flaša koje se nalaze u kontejnerima i za smeštanje tih brojeva u matricu m dimenzije 33.
Druga složena petlja, koja se sastoji od tri for petlje ispituje sva moguća premestanja flaša tako da
novodobijeni raspored zadovoljava postavljeni uslov. Od svih premestanja bira se premestanje sa najmanjim
brojem poteza i broj premeštanja se smesta u promenljivu r, koja se zatim i upisuje u izlaznu datoteku kao
krajnji i tačni rezultat našeg programa.

6.5.3. Matrice i dinamička alokacija memorije


1. Dinamička matrica se predstavlja strukturom koja sadrži dimenzije i pokazivač na elemente
matrice. Sastaviti na jeziku C program za transponovanje matrice celih brojeva. Polaznu matricu a i
transponovanu matricu b smestiti u dinamičku zonu memorije i deklarisati ih sa
int **a, **b.
Program bi trebalo da u beskonačnom ciklusu obrađuje proizvoljan broj početnih matrica. Beskonačni
ciklus prekinuti kada se za dimenzije ulazne matrice zada vrednost koja je  0.

#include<stdio.h>
#include<stdlib.h>

void main()
{ int **a, **b, m,n,i,j;

170
Ivan P. Stanimirović Uvod u programiranje

while(1)
{ printf("\nBroj vrsta i kolona? "); scanf("%d%d", &m,&n);
if(m<=0 || n<=0)break;
a=(int **)malloc(m*sizeof(int *));
for(i=0; i<m; i++)
{ a[i]=(int *)malloc(n*sizeof(int));
printf("Elementi %2d. vrste:\n",i+1);
for(j=0; j<n; scanf("%d",&a[i][j++]));
}
b=(int **)malloc(n*sizeof(int *));
for(i=0; i<n; i++)
{ b[i]=(int *)malloc(m*sizeof(int));
for(j=0; j<m; j++)b[i][j]=a[j][i];
}
printf("Transponovana matrica:\n");
for(i=0;i<n;i++)
{ for(j=0;j<m;printf("%d ",b[i][j++]));
printf("\n");
}
}
for(i=0; i<m; free(a[i++])); free(a);
for(i=0; i<n; free(b[i++])); free(b);
}

U programu koji sledi rešen je isti problem, samo što su napisane funkcije za učitavanje elemenata
matrice kao i za transponovanje matrice.

#include <stdio.h>
#include <stdlib.h>

void Citaj(int*** a, int* n, int* m)


{ int i, j;
scanf("%d%d", n, m);

*a = (int**) malloc(*n*sizeof(int*));
for (i = 0; i < *n; i++)
(*a)[i] = (int*) malloc(*m*sizeof(int));
for (i = 0; i < *n; i++)
for (j = 0; j < *m; j++)
scanf("%d", *(*a+i)+j); // ili &((**a)[i][j])

void Transponuj(int*** at, int** a, int n, int m)


{ int i, j;
*at = (int**) malloc(m*sizeof(int*));
for (i = 0; i < m; i++)
(*at)[i] = (int*) malloc(n*sizeof(int));
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
(*at)[i][j] = a[j][i];
}

int main()
{ int n, m, i, j;
int** a; int** at;
Citaj(&a, &n, &m);
for (i = 0; i < n; i++)
{ for (j = 0; j < m; j++)printf("%d ", a[i][j]);
printf("\n");
}

171
Ivan P. Stanimirović Uvod u programiranje

printf("\n");

Transponuj(&at, a, n, m);

for (i = 0; i < m; i++)


{ for (j = 0; j < n; j++) printf("%d ", at[i][j]);
printf("\n");
}

for (i = 0; i < n; i++) free(a[i]);


free(a);
for (i = 0; i < m; i++) free(at[i]);
free(at);
return 0;
}

#include <stdio.h>
#include <stdlib.h>

void Citaj(int*** a, int* n, int* m)


{ int i, j;
scanf("%d%d", n, m);

*a = (int**) malloc(*n*sizeof(int*));
for (i = 0; i < *n; i++)
(*a)[i] = (int*) malloc(*m*sizeof(int));
for (i = 0; i < *n; i++)
for (j = 0; j < *m; j++)
scanf("%d", *(*a+i)+j); // ili &((**a)[i][j])

void Transponuj(int** at, int** a, int n, int m)


{ int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
at[i][j] = a[j][i];
}

int main()
{ int n, m, i, j;
int** a; int** at;
Citaj(&a, &n, &m);
at = (int**) malloc(m*sizeof(int*));
for (i = 0; i < m; i++)
at[i] = (int*) malloc(n*sizeof(int));

for (i = 0; i < n; i++)


{ for (j = 0; j < m; j++)printf("%d ", a[i][j]);
printf("\n");
}
printf("\n");

Transponuj(&at, a, n, m);

for (i = 0; i < m; i++)


{ for (j = 0; j < n; j++) printf("%d ", at[i][j]);
printf("\n");
}

172
Ivan P. Stanimirović Uvod u programiranje

for (i = 0; i < n; i++) free(a[i]);


free(a);
for (i = 0; i < m; i++) free(at[i]);
free(at);
return 0;
}

6.6. STRINGOVI
U programskim jezicima, string je sekvenca karaktera. String konstanta može da ima proizvoljan broj
karaktera, uključujući i string bez karaktera. Broj karaktera u stringu se naziva dužina stringa.
Jedinstveni string koji ne sadrži karaktere naziva se prazan string.
Stringovi su podržani u svim modernim programskim jezicima. Tipične operacije nad stringovima
su:
• dužina (length);
• upoređenje na jednakost (equality comparison);
• leksikografsko poređenje (lexicographic comparison);
• selekcija karaktera u stringu (character selection);
• selekcija podstringa (substring selection);
• nadovezivanje (concatenation);
• konverzija stringa u numeričku vrednost i obratno.

6.6.1. Stringovi u C
U jeziku C, string je jednodimenzionalni niz elemenata tipa char koji se završava karakterom '\0'.
String se može posmatrati i kao pointer na char.
Inicijalizacija i obrada stringova
Karakteru u stringu može da se pristupi ili kao elementu niza ili pomoću pointera na char. Svaki
string se završava karakterom '\0'. String konstanta je proizvoljan niz znakova između navodnika. Svi
znaci zahvaćeni znacima navoda, kao i null znak '\0' smeštaju se u uzastopnim memorijskim
lokacijama.
Na primer, string s = "ABC" može da se zapamti u memoriju kao sekvenca od 4 karaktera s[0] =
'A', s[1] = 'B', s[2] = 'C', s[3] = '\0', od kojih je poslednji null karakter '\0'. Bez poslednjeg karaktera '\0'
niz nije kompletiran, te predstavlja samo niz karaktera.
Primer. Dodeljivanje početne vrednosti string promenljivoj.
#define MAXREC 100
void main()
{ char w[MAXREC];

w[0]='A'; w[1]='B'; w[2]='C'; w[3]='\0';
}

Sada je jasno da su karakter 'a' i string "a" dva različita objekta. String "a" je niz koji sadrži dva
karaktera: 'a' i '\0'.
Stringovi su nizovi karaktera, pa se mogu inicijalizovati na mestu deklaracije, kao i nizovi brojeva.
Osim toga, praktičnije je da se string inicijalizuje konstantnom vrednošću tipa string umesto “znak po
znak”.

Primer. Možemo pisati


char s[]="abc"; umesto char s[]={'a', 'b', 'c', '\0'};

173
Ivan P. Stanimirović Uvod u programiranje

Takođe, može se inicijalizovati pointer na char kao konstantni string:


char *p="abc";

Efekat ove naredbe da se string "abc" smešta u memoriju, a pointer p se inicijalizuje baznom adresom
tog stringa.
U slučaju kada se niz znakova zadate dužine inicijalizuje string konstantom, tada se neiskorišćeni
elementi niza inicijalizuju null znakom '\0'.

Primer. Transformacija stringa: u stringu koji se učitava zameniti svaki znak 'e' znakom 'E', dok se
svaka praznina zamenjuje prelazom u novi red i tabulatorom. Učitavanje znakova u stringu se
završava prelazom u novi red.
#include <stdio.h>
#define MAX 50
void main()
{ char line[MAX], *change(char *);
void read(char *);
printf("Unesi jedan red: ");
read(line);
printf("\n%s\n\n%s\n\n","Posle promene red je: ", change(line));
}

void read(char *s)


{ int c, i=0;
while ((c=getchar()) !='\n') s[i++]=c;
s[i]='\0';
}

char *change(char *s)


{ static char new_string[MAX];
char *p=new_string;
/* pointer p je inicijalizovan na baznu adresu od new_string */
for (; *s != '\0'; ++s)
if(*s=='e') *p++='E';
else if(*s==' ') { *p++='\n'; *p++='\t'; }
else *p++=*s;
*p='\0';
return(new_string);
}

#include <stdio.h>

char s[105];

174
Ivan P. Stanimirović Uvod u programiranje

int main()
{
//scanf("%[^\n]s",s);
gets(s);
int p=0;
int cnt=0;
while (s[p])
cnt+=s[p++]==' ';
p=0;
while (s[p]) p++;
int pl=p+cnt-1;
while (p)
{
if (s[p-1]=='e')
s[p-1]='E';
if (s[p-1]==' ')
{
p--;
s[pl]='\t';
pl--;
s[pl]='\n';
pl--;
}
else
{
p--;
s[pl]=s[p];
pl--;
}
}
puts(s);
}

Testiranje i konverzija znakova


Standardna biblioteka <ctype.h> sadrži deklaracije funkcija za testiranje znakova. Sve funkcije iz
te biblioteke imaju jedan argument tipa int, čija vrednost je ili EOF ili je predstavljena kao unsigned
char. Rezultat svake od ovih funkcija je tipa int. Funkcije vraćaju rezultat različit od nule (tačno), ako
argument zadovoljava opisani uslov, a 0 ako ne zadovoljava. Najčešće korišćene funkcije iz ove
biblioteke su:
isdigit(c) ispituje da li je c decimalna cifra;
islower(c) ispituje da li je c malo slovo;
isupper(c) ispituje da li je c veliko slovo;
isalpha(c) ispituje da li je islower(c) ili isupper(c) tačno;
isalnum(c) ispituje da li je isalpha(c) ili isdigit(c) tačno;
iscntrl(c) ispituje da li je c kontrolni znak (kontrolni znaci imaju kodove 0... 31);
isspace(c) razmak, novi red, povratnik, vertikalni ili horizontalni tabulator.
Takođe, postoje i dve funkcije za promenu veličine slova.
int tolower(int c) konvertuje c u malo slovo;
int toupper(int c) konvertuje c u veliko slovo.
Ako je karakter c veliko slovo, tada funkcija tolower(c) vraća odgovarajuće malo slovo, a inače vraća
c. Ako je karakter c malo slovo, tada funkcija toupper(c) vraća odgovarajuće veliko slovo, a inače
vraća nepromenjeno c.
Primer. Prebrojavanje reči unutar stringa. String se završava prelazom u novi red ili karakterom EOF.
Reči unutar stringa su razdvojene prazninama.

175
Ivan P. Stanimirović Uvod u programiranje

#include <stdio.h>
#include <ctype.h>
#define MAX 30
void main()
{ char line[MAX];
void read(char *);
int cnt(char *);
printf("\n Unesi string : "); read(line);
printf("\n Broj reci = %d\n", cnt(line));
}

void read(char *s)


{ int c,i=0;
while ((c=getchar()) !=EOF && c!='\n') s[i++]=c;
s[i]='\0';
}

int cnt(char *s)


{ int br=0;
while (*s!='\0')
{ while (isspace(*s)) ++s;
/* preskoci praznine izmedju reci na pocetku */
if(*s!='\0') /* naci rec */
{ ++br;
while(!isspace(*s)&& *s!='\0') /*preskoci rec*/
++s;
}
}
return(br);
}

Primer. String je deklarisan kao statički niz karaktera a zatim je inicijalizovan nekom string
konstantom. Napisati program koji ispisuje string u direktnom i inverznom poretku.
#include<stdio.h>
void main()
{ static char s[]="Konstantni string";
char *p;
p=s; printf("\nIspis stringa:\n");
while(*p) putchar(*p++);
printf("\nIspis u inverznom poretku:\n");
while(--p>=s) putchar(*p);
putchar('\n');
}
Učitavanje i ispis stringova

Vrednosti stringova se mogu i učitavati. Pri učitavanju stringova bitno je da se rezerviše dovoljno
memorijskog prostora za smeštanje stringova. Program ne može da predvidi maksimalnu dužinu
stringa i da rezerviše potreban memorijski prostor. Zbog toga je programer obavezan da predvidi
maksimalnu dužinu stringova koji se učitavaju. String može da dobije vrednost pomoću funkcije
scanf(), koristeći format %s. Na primer, možemo pisati:
scanf("%s", w);
Svi znaci, do prvog znaka EOF ili do prve praznine se uzimaju kao elementi stringa w. Posle toga se
null karakter stavlja na kraj stringa. Napomenimo da nije korišćena adresa &w u drugom argumentu
funkcije scanf(). Kako je ime niza u stvari bazna adresa niza, očigledno je w ekvivalentno sa &w[0].
Stoga je operator adresiranja ispred imena niza w nepotreban.
Za učitavanje stringova najčešće se koristi funkcija gets(). Ovom funkcijom se prihvataju svi znaci
sa tastature, sve dok se ne unese znak za novi red '\n'. Znak za prelaz u novi red se ignoriše, dok se svi

176
Ivan P. Stanimirović Uvod u programiranje

ostali karakteri dodeljuju stringu koji se učitava. Kao poslednji znak učitanog stringa uvek se postavlja
null karakter '\0'.
Prototip funkcije gets() je oblika char *gets(char *)

Ukoliko je učitavanje završeno korektno, vrednost ove funkcije je pokazivač na adresu u kojoj je
smešten prvi znak stringa s. U suprotnom slučaju, vraćena vrednost je NULL (nulta adresa, koja je u
datoteci stdio.h definisana sa 0). To znači da se kontrola pravilnosti ulaza može kontrolisati izrazom
while(gets(ime)==NULL);

Primer. Učitavanje stringa i njegovo prikazivanje na ekran.


#include<stdio.h>
void main()
{ char ime[100]; char *pok;
pok=gets(ime);
printf("1. nacin: %s\n",ime); printf("2. nacin: %s\n",pok);
}

Primer. Reč je data kao niz od n karaktera (n<300). Napisati program koji nalazi najduži palindrom u
toj reči. Palindrom je podniz od uzastopnih elemenata koji se jednako čita s leva i s desna.

177
Ivan P. Stanimirović Uvod u programiranje

#include <stdio.h>
void main()
{ char a[300];
int i,j,n,maxi,maxl,maxj,l;
int pal(char *, int, int);
printf("Unesi broj karaktera reci\n"); scanf("%d",&n);
printf("Unesi rec:\n"); scanf("%c", &a[0]);
for (i=0; i<n; i++) scanf("%c", &a[i]);
a[i]='\0';
maxl=0;
for (i=0; i<n; i++)
for (j=i; j<n; j++)
{ if(pal(a,i,j))
{ l=(j-i)+1; if (l>maxl){ maxl=l; maxj=j; maxi=i; }
}
}
printf("\nNajduzi palindrom je od pozicije %d do %d\n", maxi,maxj);
for (i=maxi; i<=maxj; i++) printf("%c",a[i]);
printf("\n");
}

int pal (char *a, int i, int j)


{ int p; int l,k,m; char b[300];
l=(j-i)+1; k=0;
for (m=i; m<=j; m++) b[++k]=a[m];
p=1; k=1;
while(p && k<=l/2)
if(b[k] != b[l-k+1]) p=0;
else k++;
return(p);
}

Još jedno rešenje za funkciju pal dato je u sledećem kodu


int pal (char *a, int i, int j)
{ int m; char *p, *q;
p=q=a;
for(m=0; m<i; m++){ p++; q++; }
for(m=i; m<j; m++)q++;
while(q>=p)
if(*q != *p) return 0;
else { p++; q--; }
return 1;
}

Primer. U beskonačnom ciklusu se učitavaju stringovi i ispituje da li su palindromi. Stringovi se


tretiraju kao pointeri na karaktere.
void main()
{ char s[30];
printf("\n Stringovi u beskonačnom ciklusu\n");
while(1)
{ printf("Zadati string\n"); gets(s);
if(palindrom(s)) printf("Jeste palindrom\n");
else printf("Nije palindrom\n");
}
}

int palindrom(char *strpok)


{ char *strpok1=strpok;
while(*strpok1)++strpok1;

178
Ivan P. Stanimirović Uvod u programiranje

--strpok1;
while(strpok < strpok1) if(*strpok++ != *strpok1--) return(0);
return(1);
}
Primer. Ispitati da li je uneti string palindrom
#include<cstdio>
#include<cstring>
#include<algorithm>

void main()
{
char s[100], s2[100];
int i,j,n,b;
scanf("%s",s);
n=strlen(s);
i=0; b=0;
j=n-1;
while ((i<n/2)&&(j>n/2)&&(b==0))
{
if (s[i]!=s[j]) b++;
i++;
j--;
}
if (b==0) printf("Palindrom je.\n");
else printf("Nije palindrom\n");

char *a,*c;
a=s;
c=s;
while (*c) c++;
c--;
b=1;
while ((a<c)&&b)
{
if (*a!=*c) b=0;
else {a++; c--;}
}
if (b) printf("Palindrom je.\n");
else printf("Nije palindrom\n");

strcpy(s2,s);
std::reverse(s2,s2+strlen(s2)-1);
printf("%s\n",
(!strcmp(s, s2)) ? "Nije palindrom." : "Jeste palindrom.");
}

Primer. Učitava se tekst, sve do znaka ENTER. Štampati izveštaj, u kome se nalaze dužine reči
sadržanih u tekstu, kao i broj reči date dužine.
#include<stdio.h>
#define MAX 80
int separator(char ch)
{ return(ch==','||ch==' '||ch==';'||ch=='('||ch==')'||
ch==' '||ch=='!'||ch=='?')||ch=='\n'; }
void main()
{ char ch;
int i,l=0;
int b[MAX];
for(i=1; i<=MAX; i++)b[i]=0;
while((ch=getchar()) != '\n')
{ if(!separator(ch)) l++;

179
Ivan P. Stanimirović Uvod u programiranje

else if(l>0) { b[l]++; l=0; }


}
ch=getchar();
if(l>0) { b[l]++; l=0; }
printf("%s %s\n","Duzina reci","Broj ponavljanja");
for(i=1;i<=MAX;i++)
if(b[i]>0) printf("%d %d\n",i,b[i]);
}

Već je pokazano da se vrednosti stringova mogu ispisivati pomoću funkcije printf, koristeći format
%s. Takođe, za ispis stringova se može koristiti standardna funkcija puts. Funkcija puts ima jedan
argument, koji predstavlja pokazivač na početnu adresu stringa koji se ispisuje. Funkcija puts ispisuje
sve karaktere počev od pozicije određene argumentom funkcije do završnog karaktera \0'.
Primer. Zadati string s koristeći funkciju gets(). Napisati funkciju za izbacivanje svih nula sa kraja
stringa, kao i funkciju za izbacivanje nula sa početka učitanog stringa. U glavnom programu izbaciti
sve početne i završne nule u zadatom stringu.
#include <stdio.h>
void main()
{ char s[30];
void ukloni_kraj(char *);
void ukloni_pocetak(char *);
printf("\n Zadati string:\n"); gets(s);
ukloni_kraj(s);
printf("\nString bez zadnjih nula = "); puts(s);
ukloni_pocetak(s);
printf("\nString bez pocetnih i zadnjih nula = "); puts(s);
}

void ukloni_pocetak(char *s)


{ char *t=s;
while(*t && *t=='0') t++;
/* Nađen je prvi karakter razlicit od \0 */
while(*t) *s++=*t++;
/* Kopira preostale karaktere na pocetak stringa */
*s='\0';
}

void ukloni_kraj(char *s)


{ char *t=s;
while(*t)t++;
t--;
while(*t=='0')t--;
t++; *t='\0';
}
Primer. Napisati program kojim se u jednoj liniji unosi korektno zapisan postfiksni izraz, a zatim
izračunava njegova vrednost. Operandi u izrazu su prirodni brojevi razdvojeni blanko simbolom, a
operacije su iz skupa {+, -, *, /}, pri čemu je / celobrojno deljenje.
Na primer, postfiksnom izrazu 3 2 7 + - 4 * odgovara infiksni izraz (3-(2+7))*4=-24.
#include<stdio.h>
#include<string.h>
#include<stdio.h>
void main()
{ char izraz[80], *s;
int a[41],n,greska,x,st;
while(1)
{ gets(izraz); n=0; greska=0; s=izraz;
while(*s && !greska)

180
Ivan P. Stanimirović Uvod u programiranje

{ if(*s>='0' && *s<='9')


{ x=0; st=1;
while (*s>='0' && *s<='9')
{ x+=(*s-'0')*st; st*=10; s++; }
a[n++]=x;
}
else if(*s!=' ')
{ switch(*s)
{ case '+': a[n-2]+=a[n-1]; break;
case '-': a[n-2]-=a[n-1]; break;
case '*': a[n-2]*=a[n-1]; break;
case '/': if(a[n-1]) a[n-2]/=a[n-1];
else greska=1;
}
n--;
}
s++;
}
if(!greska) printf("%d\n",a[0]);
else printf("greska, deljenje nulom\n");
}
}

Standardne funkcije za rad sa stringovima u C


Standardna biblioteka sadrži veći broj funkcija za manipulaciju stringovima. Ove funkcije nisu deo C
jezika, ali su napisane u jeziku C. U njima su često promenljive deklarisane u memorijskoj klasi
register, da bi se obezbedila njihovo brže izvršavanje. Sve te funkcije zahtevaju da se string završava
null karakterom, a njihov rezultat je integer ili pointer na char. Prototipovi ovih funkcija su dati u
header fajlu <string.h>.
unsigned strlen(char *s) Prebrojava sve karaktere pre '\0' u s, i vraća nađeni broj.
int strcmp(char *s1, char *s2) Rezultat je ceo broj <0, =0 ili >0, zavisno od toga da li je s1
u leksikografskom poretku manje, jednako ili veće od s2.
int strncmp(char *s1, char *s2, int n) Slična je funkciji strcmp, osim što ova funkcija upoređuje
najviše n karaktera niske s1 sa odgovarajućim karakterima
niske s2.
char *strcat(char *s1, char *s2) Stringovi s1 i s2 se spajaju, a rezultujući string se smešta u
s1. Rezultat je pointer na s1. U stvari, povezuje nisku s2 sa
krajem niske s1. Mora da se alocira dovoljno memorije za s1.
char *strncat(char *s1, char *s2, int n) Nadovezuje najviše n znakova niske s2 sa krajem niske s1.
Nisku s1 završava karakterom \0 i vraća s1.
char *strcpy(char *s1, char *s2) String s2 se kopira u memoriju, počev od bazne adrese na
koju ukazuje s1. Sadržaj od s1 se gubi. Rezultat je pointer s1.
char *strncpy(char *s1, char *s2, int n) Kopira najviše n znakova stringa s2 u memoriju, počev od
bazne adrese na koju ukazuje s1. Rezultat je pointer s1.
char *strchr(char *s, char c) Rezultat primene ove funkcije je pointer na prvo
pojavljivanje karaktera c u stringu s, ili NULL ako se c ne
sadrži u s.
char *strstr(char *s1, char *s2) Ova funkcija vraća pokazivač na prvi znak u s1 počev od
koga se s2 sadrži u s1.
int atoi(char *s) Ova funkcija prevodi string s sastavljen od ASCII znakova u
ekvivalentan ceo broj. Ispred decimalnog broja koji je
sadržan u s može da stoji proizvoljan broj nula, praznina ili

181
Ivan P. Stanimirović Uvod u programiranje

znakova tabulacije, i ono se ignorišu. String s može počinjati


znakom minus (-), i tada je rezultat konverzije negativni ceo
broj. Broj se završava null karakterom ‘\0’ ili bilo kojim
znakom koji nije cifra. Ova funkcija se nalazi u standardnoj
biblioteci stdlib.h.
float atof(char *s) Ova funkcija prevodi string s sastavljen od ASCII znakova u
ekvivalentan realni broj. Ova funkcija se nalazi u standardnoj
biblioteci stdlib.h.

Funkcija strlen može da se implementira na sledeći način:


unsigned strlen(register char *s)
{ register unsigned n;
for (n=0; *s!='\0'; ++s) ++n;
return(n);
}
Primer.
char s1[100], s2[100], t[100];
strcpy(s1, "recenica 1"); strcpy(s2, "rec 2");
strlen(s1); /* 10 */
strlen(s1+9); /* 1 */
strcmp(s1, s2); /* pozitivan broj */
s3=strcpy(t,s1+9); /* t="1" */
strcat(t," "); /* t="1 " */
strcat(t,s1+9); /* t="1 1"*/
printf("%s",s3); /* 1 1*/
printf("%s",t); /* 1 1*/

Primer. Funkcija strcpy se može implementirati na sledeći način:


char *strpy(char *s1, char *s2)
{ char u;
u=s2;
while(s1++=s2++);
return(u);
}

Primer. Kažemo da se string U pojavljuje u stringu T sa pomakom s, ili da se U pojavljuje u T počev


od pozicije s ako su ispunjeni sledeći uslovi:
0 <= s <= Tn - Un,
T[s+j] = U[j] za 0 <= j < Un,
gde je Tn broj elemenata u stringu T a Un dužina stringa U.
Odrediti sva pojavljivanja stringa U u stringu T.
#include<string.h>
void sekv_sm (char *t, char *u)
{ int s, j;
int tn, un;
tn = strlen(t); un = strlen(u);
for (s = 0; s <= tn-un; s++)
{ for (j = 0; j < un; j++) if (t[s+j] != u[j]) break;
if(j == un) printf("Uzorak se pojavljuje sa pocetkom %d.\n", s);
}
}

void main()
{ char *s1, *s2;

182
Ivan P. Stanimirović Uvod u programiranje

printf("Prvi string? "); gets(s1);


printf("Drugi string? "); gets(s2);
sekv_sm(s1,s2);
}
Primer. Napisati C program za uređivanje niza imena po abecednom redosledu. Broj imena nije
unapred poznat. Svako ime se učitava u posebnom redu. Niz imena se završava imenom koje je
jednako “...”.
#include<stdio.h>
#include<string.h>
#define N 100
#define D 40

void main()
{ char ljudi[N][D+1], osoba[D+1];
int i,j,m,n=0;
//Citanje neuredjenog niza imena
do
gets(ljudi[n]);
while(strcmp(ljudi[n++],"...")!=0);
n--;

//Uredjivanje niza imena


for(i=0;i<n-1;i++)
{ m=i;
for(j=i+1; j<n; j++)
if(strcmp(ljudi[j],ljudi[m])<0)m=j;
if(m!=i)
{ strcpy(osoba,ljudi[i]); strcpy(ljudi[i],ljudi[m]);
strcpy(ljudi[m],osoba);
}
}

//Ispisivanje uredjenog niza imena


for(i=0; i<n; puts(ljudi[i++]));
}

II način
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 100
#define D 40

void main()
{ char **ljudi, osoba[D+1];
int i,j,m,n=0;
ljudi=(char **)malloc(N*sizeof(char *));
//Citanje neuredjenog niza imena
do
{ ljudi[n]=(char *)malloc((D+1)*sizeof(char));
gets(ljudi[n]);
}
while(strcmp(*(ljudi +n++),"...")!=0);
n--;

//Uredjivanje niza imena


for(i=0;i<n-1;i++)
{ m=i;
for(j=i+1; j<n; j++)
if(strcmp(ljudi[j],ljudi[m])<0)m=j; // *(ljudi+i)=ljudi[i]

183
Ivan P. Stanimirović Uvod u programiranje

if(m!=i)
{ strcpy(osoba,ljudi[i]); strcpy(ljudi[i],ljudi[m]);
strcpy(ljudi[m],osoba);
}
}

//Ispisivanje uredjenog niza imena


for(i=0; i<n; puts(ljudi[i++]));
}

Primer. Na kružnom putu dužine mn kilometara postoji n benzinskjh stanica (1 < n < 100, 1 < m <
1000). Na stanici i ima ukupno si litara benzina. Između svake dve stanice je rastojanje m kilometara.
Automobil polazi iz jedne od stanica, a može da započne kretanje u bilo kom od dva smera. Na početku
mu je rezervoar prazan, a pri prolazu kroz svaku od stanica uzima celokupnu količinu goriva iz stanice
(rezervoar ima neograničenu zapreminu). Automobil troši b (1  b  10) litara po kilometru. Odrediti
da li postoji stanica iz koje automobil može da započne kretanje i obiđe celu stazu.
U ulaznoj datoteci 'zad3.in' dati su, redom, brojevi n, m, b, s1, ..., sn. U izlaznu datoteku 'zad3.out'
upisati reč 'MOGUĆE' ako postoji tražena stanica, a u suprotmom reč 'NEMOGUĆE'.
zad3.in zad3.out Objašnjenje
3 1 1 MOGUĆE Na putu su tri stanice. Automobil može da
2 2 0 krene iz bilo koje od prve dve.
3 1 2 NEMOGUĆE Pošto automobil troši 21 na kilometar, iz
4 0 1 koje god stanice da pode, ne može da obiđe
celu stazu.

6.7. Strukture i nabrojivi tipovi u c


Strukture su složeni tipovi podataka koje se, za razliku od nizova, sastoje od komponenti
(segmenata) različitog tipa. Komponente sloga se obično nazivaju polja. Svako polje poseduje ime i
tip. Imena polja se grade kao i drugi identifikatori.

6.7.1. Članovi strukture


Slično slogovima u Pascalu, strukture dozvoljavaju da se različite komponente ujedine u
pojedinačnu strukturu. Komponente strukture su takođe imenovane i nazivaju se članovi (odnosno
elementi ili polja). Elementi struktura su različitih tipova generalno, i mogu se prilagođavati problemu.
Strukture se definišu pomoću ključne reči struct. U najopštijem obliku, strukture se opisuju na sledeći
način:
struct [oznaka]
{ tip ime_elementa1[, ime_elementa2...];

}[<ime_promenljive 1>[, <ime_ promenljive 2>...]];

Rezervisana reč struct služi kao informacija kompajleru da neposredno iza nje sledi opis neke
strukture. Zatim sledi neobavezni identifikator, označen sa oznaka, koji predstavlja ime strukture. Ime
dodeljeno strukturi se može kasnije koristiti pri deklaraciji promenljivih strukturnog tipa. Iza imena
strukture, između velikih zagrada, deklarišu se pojedini delovi strukture. Elementi strukture mogu biti
proizvoljnih tipova, pa i nove strukture. Iza poslednje zagrade piše se znak ';'. Između zatvorene
zagrade } i znaka ; opciono se mogu navesti imena promenljivih strukturnog tipa.
Primer. Sledećom definicijom strukture opisani su osnovni podaci o studentu: ime, broj indeksa i
upisana godina studija.
struct student { char *ime;
int indeks;

184
Ivan P. Stanimirović Uvod u programiranje

int godina;
} s1,s2,s3;
Osim toga, promenljive s1, s2, s3 se deklarišu kao promenljive koje mogu da sadrže konkretne
vrednosti saglasno tipu struct student, tj. podatke o studentima. Svaki slog o studentu sadrži tri
komponente: ime, indeks i godina. Komponenta ime je string, dok su komponente indeks i godina
celobrojnog tipa.

Struktura može da se koristi kao šablon za deklaraciju tipova podataka. Na primer, neka je
deklarisana struktura student na sledeći način:
struct student { char *ime;
int indeks;
int godina;
};

Sada se mogu deklarisati strukturne promenljive strukturnog tipa struct student. Na primer, možemo
pisati
struct student pom, razred[100];

Tek posle ovakvih deklaracija se alocira memorija za promenljivu pom i niz razred.
Objedinjavanje opisa strukture čije je ime izostavljeno sa deklaracijama promenljivih koristi se
kada se šablon strukture ne koristi na drugim mestima u programu. Na primer, možemo pisati
struct
{ char *ime;
int indeks;
int godina;
} s1,s2,s3;

Strukturna promenljiva se može inicijalizovati na mestu svoje deklaracije:


static struct student pom= { "Milan", 1799, 3};

Članovima strukture se direktno pristupa pomoću operatora '.'.


Na primer, vrednosti članovima strukture student mogu se dodeljivati na sledeći način:
strcpy(pom.ime, "Milan");
pom.indeks= 1799;
pom.godina= 3;

Takođe, članovima strukture se mogu zadati željene vrednosti pomoću funkcija scanf() i gets():
gets(pom.ime);
scanf("%d",&pom.indeks);
scanf("%d",&pom.godina);

Ako se opis strukture navede van svih funkcija, ta struktura se može koristiti u svim funkcijama
koje su definisane posle opisa strukture. Uobičajeno je da se definicija strukture navede na početku
izvornog programa, pre opisa promenljivih i funkcija. U velikim programima opisi struktura se obično
pišu u posebnom fajlu.

185
Ivan P. Stanimirović Uvod u programiranje

186
Ivan P. Stanimirović Uvod u programiranje

Primer. Prebrojati studente treće godine.


Može se prvo napisati fajl cl.h:
#define N 10
struct student { char ime[30];
int indeks;
int godina;
};

Ovaj header fajl može se koristiti kao informacija u modulima koje čine program.
#include "cl.h"
#include<stdio.h>
#include<string.h>
void main()
{ int broji(student *);
student s[10];
int i;
for(i=0; i<N; i++)
{ printf("%d ti student : ",i);
gets(s[i].ime);
scanf("%d", &s[i].indeks); scanf("%d", &s[i].godina);
getchar();
}
printf("Studenata trece godine ima %d\n", broji(s));
}

int broji(student *sts)


{ int i, cnt=0;
for (i=0; i<N; ++i)
cnt += sts[i].godina==3;
return(cnt);
}
Drugi način:
#include "cl.h"
#include<stdio.h>
#include<string.h>
void main()
{ int broji(student *);
void ucitaj(student *s);
student s[10];
ucitaj(s);
printf("Studenata trece godine ima %d\n", broji(s));
}

void ucitaj(student *s)


{ int i;
for(i=0; i<N; i++)
{ printf("%d ti student : ",i);
gets(s[i].ime);
scanf("%d", &s[i].indeks); scanf("%d", &s[i].godina);
getchar();
}
}

int broji(student *sts)


{ int i, cnt=0;
for (i=0; i<N; ++i)
cnt += sts[i].godina==3;
return(cnt);
}

187
Ivan P. Stanimirović Uvod u programiranje

Treći način:
#include "cl.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{ int broji(student *);
void ucitaj(student *);
student *s=(student *)malloc(N*sizeof(student));
ucitaj(s);
printf("Studenata trece godine ima %d\n", broji(s));
}

void ucitaj(student *s)


{ int i;
for(i=0; i<N; i++)
{ printf("%d ti student : ",i);
gets(s[i].ime);
scanf("%d", &s[i].indeks); scanf("%d", &s[i].godina);
getchar();
}
}

int broji(student *sts)


{ int i, cnt=0;
for (i=0; i<N; ++i)
cnt += sts[i].godina==3;
return(cnt);
}

Strukture se mogu inicijalizovati od strane programera na mestu svoje deklaracije.


Primer. U sledećem kôdu je definisan nabrojivi tip Month i strukturni tip Date.
enum Month {jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec};
struct Date {Month m; byte d;};
Ova struktura ima skup vrednosti
Date = Month×Byte = {jan,feb, ..., dec}×{0, ..., 255}.

#include<stdio.h>

enum Month {jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec};


struct Date {
Month m;
unsigned short d;
};
void main()
{ struct Date someday = {jan, 1}; // deklaracija i incijalizacija
//Sledeci kod ilustruje selekciju elemenata strukture
printf("%d/%d\n", someday.m + 1, someday.d);
someday.d = 29; someday.m = feb;
printf("%d/%d\n", someday.m+1, someday.d);
}
Primer. Primeri inicijalizacije struktura.
1. Struktura datum:
struct datum
{ int dan, mesec, godina; };
struct datum d={11, 4, 1996};
1. Struktura karta:

188
Ivan P. Stanimirović Uvod u programiranje

enum tip {‘p’,’h’,’k’,’t’};


struct karta
{ int vrednost;
tip boja;
};
struct karta k={12, 't'};
Primer. Deklaracija strukture datum i inicijalizacija strukturne (i statičke) promenljive danas.
#include <stdio.h>
void main()
{ struct datum
{ int dan;
int mesec;
int godina;
} danas={9, 4, 1996};
printf("%d.%d.%d.\n",danas.dan,danas.mesec,danas.godina);
}

Primer. Program za korekciju tekućeg vremena u sekundama.


void main()
{ struct vreme
{ int sat;
int minut;
int sekund;
} tekuce,naredno;
printf("Unesi tekuce vreme [cc:mm:ss]:");
scanf("%d:%d:%d",&tekuce.sat,&tekuce.minut,&tekuce.sekund);
naredno=tekuce;
if (++naredno.sekund==60)
{ naredno.sekund=0;
if(++naredno.minut==60)
{ naredno.minut=0;
if(++naredno.sat==24) naredno.sat=0;
}
}
printf("Naredno vreme: %d:%d:%d\n", naredno.sat,
naredno.minut, naredno.sekund);
}

6.7.2 Strukturni tipovi i pokazivači u C


Mogu se definisati pokazivačke promenljive koje će pokazivati na strukturne promenljive.
Vrednosti ovakvih pokazivačkih promenljivih jesu adrese strukturnih promenljivih na koje pokazuju.
Na primer, za definisani strukturni tip podataka student može se definisati pokazivačka promenljiva
pstudent:
struct student *pstudent;
Sada se elementima strukture student može pristupiti koristeći operator indirekcije '*' i operator '.':
(*pstudent).ime
(*pstudent).indeks
(*pstudent).godina

U cilju pristupa elementima strukturne promenljive pomoću pokazivača na tu promenljivu uveden


je operator ''strelica u desno'' ->. Generalno pravilo je sledeće: ako je pokazivačkoj promenljivoj
pointer_strukture dodeljena adresa neke strukture, tada je izraz
pointer_strukture ->ime_člana
ekvivalentan izrazu

189
Ivan P. Stanimirović Uvod u programiranje

(*pointer_strukture).ime_člana
U poslednjem izrazu zagrade nisu neophodne.

Operatori -> i '.' imaju asocijativnost sleva udesno.


Na primer elementima strukture pstudent pristupa se na sledeći način:
pstudent->ime
pstudent->indeks
pstudent->godina

Sve eksterne i statičke promenljive, uključujući strukturne promenljive, koje nisu eksplicitno
inicijalizovane, automatski se inicijalizuju na vrednost nula.
Primer. Neka je definisana struktura licnost na sledeći način:
struct licnost
{ char ime[30];
char adresa[50];
unsigned starost;
}

Takođe, neka je definisana pokazivačka promenljiva osoba:


struct licnost *osoba;
Elementima strukture osoba može se pristupiti pomoću operatora indirekcije '*' i operatora '.':
(*osoba).ime
(*osoba).adresa
(*osoba).starost

Takođe, elementima strukturne promenljive na koju ukazuje pointer osoba, može se pristupiti i na
sledeći način:
osoba->ime
osoba->adresa
osoba->starost

Formalni parametar funkcije može biti promenljiva nekog strukturnog tipa S kao i pokazivač na
strukturu S. Ukoliko je formalni parametar strukturna promenljiva, tada se kao stvarni parametar
navodi strukturna promenljiva ili neka konstantna vrednost strukturnog tipa S. U pozivu te funkcije,
kao stvarni parametar, predaje se kopija vrednosti te strukturne promenljive. Na taj način, ne menja se
vrednost strukturne promenljive koja je predata kao stvarni parametar. U slučaju kada je formalni
parametar funkcije pointer na strukturu, tada se kao stvarni parametar predaje adresa strukturne
promenljive koja se koristi kao stvarni parametar. Time je omogućeno ne samo korišćenje vrednosti
pokazivačke promenljive (pomoću operatora indirekcije), već i promena tih vrednosti.
Takođe, strukture se mogu koristiti kao elementi nizova. Nizovi struktura se deklarišu analogno
ostalim nizovima. Na primer, za definisane strukture licnost i student mogu se koristiti nizovi
struct licnost osobe[20]
struct student studenti[50]

Ovakvim deklaracijama opisan je niz struktura osobe od najviše 20 elemenata, kao i niz struktura
studenti sa najviše 50 elemenata. Svaki element niza osobe predstavlja jednu strukturnu promenljivu
tipa licnost.
Primer. U ovom primeru je definisana matrica kompleksnih brojeva i dodeljene su početne vrednosti
njenim elementima. Svaki element matrice predstavljen je parom realnih brojeva.
static struct complex
{ double real;
double imag;
} m[3][3]=
{ { {1.0,-0.5}, {2.5,1.0}, {0.7,0.7} },
{ {7.0,-6.5}, {-0.5,1.0}, {45.7,8.0} },

190
Ivan P. Stanimirović Uvod u programiranje

};

Elementi strukture mogu biti nove strukture. Struktura koja sadrži bar jedan element strukturnog
tipa naziva se hijerarhijska struktura.
Primer. Definisana je struktura licnost koja sadrži element datumrodjena strukturnog tipa datum:
struct datum
{ unsigned dan;
unsigned mesec;
unsigned godina;
}
struct licnost
{ char *ime;
datum datumrodjenja;
}

Strukturna promenljiva danas može se definisati pomoću izraza


struct datum danas;
Pointer p na ovu strukturu deklariše se iskazom
struct datum *p;

Postavljanje pointera p na adresu strukturne promenljive danas ostvaruje se naredbom


p=&danas;
Sada se strukturnoj promenljivoj danas može pristupiti indirektno, pomoću pointera p na jedan od
sledeća dva ekvivalentna načina:
(*p).godina=1996;  p->godina=1996;
(*p).mesec=4;  p->mesec=4;
(*p).dan=11;  p->dan=11;

Takođe, pointeri mogu biti članovi strukture.


Primer. Izraz
struct pointeri
{ int *n1;
int *n2;
};

definiše strukturu pointeri sa dva ukazatelja n1 i n2 na tip int. Sada se može deklarisati strukturna
promenljiva ukaz:
struct pointeri ukaz;
void main()
{ int i1, i2;
struct { int *n1;
int *n2;
}ukaz;
ukaz.n1=&i1; ukaz.n2=&i2;
*ukaz.n1=111; *ukaz.n2=222;
/* indirektno dodeljivanje vrednosti promenljivim i1, i2 */
printf("i1=%d *ukaz.n1=%d\n", i1, *ukaz.n1);
printf("i2=%d *ukaz.n2=%d\n", i2, *ukaz.n2);
}
Primer. Dva ekvivalentna pristupa elementima strukture.
struct Simple { int a; };
int main() {
Simple so, *sp = &so;
sp->a;
so.a;
}

191
Ivan P. Stanimirović Uvod u programiranje

Primer. Prebrojavanje studenata treće godine.


#include "cl.h"
#include<stdio.h>
#include<string.h>
void main()
{ int i;
student s[10];
int broji(student *);
void citaj(student *,int);
for(i=0; i<N; i++)
citaj(&s[i],i);
printf("Studenata trece godine ima %d\n", broji(s));
}

int broji(student *sts)


{ int i, cnt=0;
for (i=0; i<N; ++i)
cnt += sts[i].godina==3;
return(cnt);
}

void citaj(student *st, int i)


{ printf("%d ti student : ",i);
gets(st->ime); scanf("%d", &(st->indeks));
scanf("%d", &(st->godina));
getchar();
}

192
Ivan P. Stanimirović Uvod u programiranje

6.7.3. Definicija strukturnih tipova pomoću typedef


Mogu se uvesti i strukturni tipovi podataka pomoću operatora typedef. Novi strukturni tipovi se
definišu izrazom oblika
typedef struct
{ <tip polja> <ime polja>;
...
} <ime>;
Primer. Definicija strukturnog tipa datum.
typedef struct
{ int dan;
int mesec;
int godina;
} datum;

Sada se identifikator datum može koristiti kao samostalan tip podataka. Na primer, iskazom
datum rodjendan[10];
deklariše se vektor rodjendan kao jednodimenzionalni vektor sa elementima tipa datum.
Primer. Ime string kao tip za pokazivače na tip char uvodi se pomoću operatora typedef na sledeći
način:
typedef char *string;
Sada je
string str1, str2;
ekvivalentno sa
char *str1, *str2;

Primer. Implementacija osnovnih aritmetičkih operacija nad kompleksnim brojevima. Kompleksni


brojevi su predstavljeni strukturom kom.
#include <stdio.h>
#include <math.h>
/* UVEDENI TIPOVI */
struct kom
{ float prvi,drugi; };
/* NAJAVE FUNKCIJA */
void upis(struct kom *p);
void ispis(struct kom p);
struct kom zbir(struct kom p,struct kom q);
struct kom proiz(struct kom p,struct kom q);
void main()
{
struct kom a,b,c;
upis(&a);upis(&b);
c=zbir(a,b);
printf("Njihov zbir je ");ispis(c);
c=proiz(a,b);
printf("Njihov proizvod je ");ispis(c);
}
void upis(struct kom *p)
/* Da bi upisani kompleksan broj bio zapamcen
koriste se pointeri. Prema tome, koriste se oznake
(*p).prvi=p->prvi, (*p).drugi=p->drugi */
{
float x,y;
scanf("%f%f",&x,&y); p->prvi=x;p->drugi=y;
}

193
Ivan P. Stanimirović Uvod u programiranje

void ispis(struct kom p)


{ if(p.drugi>0) printf("\n %f + i*%f\n",p.prvi,p.drugi);
else printf("\n %f – i*%f\n",p.prvi,fabs(p.drugi));
}

struct kom zbir(struct kom p,struct kom q)


/* U C-jeziku vrednost funkcije MOZE DA BUDE struct tipa */
{ struct kom priv;
priv.prvi=p.prvi+q.prvi;priv.drugi=p.drugi+q.drugi;
return(priv);
}

struct kom proiz(struct kom p,struct kom q)


{ struct kom priv;
priv.prvi=p.prvi*q.prvi-p.drugi*q.drugi;
priv.drugi=p.prvi*q.drugi+p.drugi*q.prvi;
return(priv);
}

Ovaj zadatak se može uraditi uz korišćenje typedef izraza. Kompleksni brojevi se reprezentuju novim
tipom kompl.
#include <stdio.h>
#include <math.h>
typedef struct
{ float prvi,drugi; } kompl;
void upis(kompl *p); void ispis(kompl p);
kompl zbir(kompl p,kompl q); kompl proiz(kompl p,kompl q);
void main()
{ kompl a,b,c;
upis(&a); upis(&b); c=zbir(a,b); ispis(c);
c=proiz(a,b); ispis(c);
}

void upis(kompl *p)


{ float x,y;
printf(" Daj dva broja :\n"); scanf("%f%f",&x,&y);
p->prvi=x;p->drugi=y;
}

void ispis(kompl p)
{ printf("\n %f *i+ %f\n",p.prvi,p.drugi); }

kompl zbir(kompl p,kompl q)


{ kompl priv;
priv.prvi=p.prvi+q.prvi;priv.drugi=p.drugi+q.drugi;
return(priv);
}

kompl proiz(kompl p,kompl q)


{ kompl priv;
priv.prvi=p.prvi*q.prvi-p.drugi*q.drugi;
priv.drugi=p.prvi*q.drugi+p.drugi*q.prvi;
return(priv);
}
Primer. Tačka u ravni je definisana kao strukturom Tacka koja sadrži dva broja tipa double. Krug je
definisan strukturom koja sadrži centar tipa Tacka i poluprečnik tipa double. Napisati funkciju koja
ispitatuje da li se dva kruga seku. U funkciji main je dato n krugova. Sa ulaza se učitava n, a u

194
Ivan P. Stanimirović Uvod u programiranje

narednih n redova su zadati centar i poluprečnik svakog kruga. Ispisati redne brojeve svaka dva kruga
koji se seku.
#include<stdio.h>
#include<math.h>

typedef struct
{double x,y; } Tacka;

typedef struct
{ Tacka O; double R; } Krug;

int intersect(Krug a, Krug b)


{ double d;
d=sqrt(pow(a.O.x-b.O.x,2)+ pow(a.O.y-b.O.y,2));
return (d<a.R+b.R)&& (d>fabs(a.R-b.R));
}

void main()
{ int i,j,n;
Krug a[100];
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%lf%lf%lf",&a[i].O.x,
&a[i].O.y,&a[i].R);
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(intersect(a[i],a[j]))
printf("%d %d\n",i,j);
}

#include<stdio.h>
#include<math.h>
struct Tacka{ double x,y; };
struct Krug{ Tacka O; double R; };

void CitajKrug(Krug *K)


{ scanf("%lf%lf%lf", &K->O.x,
&K->O.y,&K->R);
}

int Intersect(Krug K1, Krug K2)


{ double
d=sqrt(pow(K1.O.x-K2.O.x,2)+
pow(K1.O.y-K2.O.y,2));
return ((d<K1.R+K2.R) &&
(d>fabs(K1.R-K2.R)));
}

void main()
{ int i,j,n;
Krug K[5];
scanf("%d",&n);
for(i=0; i<n; i++) CitajKrug(&K[i]);
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(Intersect(K[i],K[j])) printf("(%d,%d)\n",i+1,j+1);
}

195
Ivan P. Stanimirović Uvod u programiranje

Primer. Retka matrica se može predstaviti brojem ne-nula elemenata kao i sledećim informacijama za
svaki ne-nula element:
- redni broj vrste tog elementa,
- redni broj kolone tog elementa, i
- realan broj koji predstavlja vrednost tog elementa.
Predstaviti retku matricu brojem ne-nula elemenata i nizom slogova, u kome svaki slog sadrži redni
broj vrste i kolone kao i vrednost svakog ne-nula elementa.
Napisati procedure za formiranje niza slogova koji predstavljaju reprezentaciju retke matrice A.
Napisati proceduru za ispis matrice.
Napisati proceduru za formiranje sparse reprezentaciju predstavlja matricu AT.
Napisati funkciju koja za zadate vrednosti i, j preko tastature izračunava vrednost elementa A[i,j].
#include<stdio.h>

struct slog
{ int i,j;
float aij;
};

void pravimatricu(struct slog x[10], int *n)


{ int p,q,i;
float xpq;
printf("Broj ne-nula elemenata? "); scanf("%d", n);
printf("Pozicije i vrednosti ne-nula elemenata?\n");
for(i=1; i<=*n; i++)
{ scanf("%d%d%f", &p,&q,&xpq);
x[i].i=p; x[i].j=q; x[i].aij=xpq;
}
}

void transponuj(struct slog x[10], int n, struct slog y[10])


{ int i;
for(i=1; i<=n; i++)
{ y[i].i=x[i].j; y[i].j=x[i].i; y[i].aij=x[i].aij; }
}

void pisimatricu(struct slog y[10], int n)


{ int i;
printf("%d\n",n);
for(i=1; i<=n; i++)
printf("(%d %d): %10.3f\n",y[i].i, y[i].j,y[i].aij);
}

float vrednost(int n, struct slog x[10], int k, int l)


{ int i;
for(i=1; i<=n; i++)
if((x[i].i==k) && (x[i].j==l))
return(x[i].aij);
return(0);
}

void main()
{ int i,j,n;
struct slog p[10], q[10];
pravimatricu(p, &n);
printf("Matrica je: \n");
pisimatricu(p,n);
transponuj(p,n,q);
printf("Transponovana matrica: \n");

160
Ivan P. Stanimirović Uvod u programiranje

pisimatricu(q,n);
printf("i,j= ? "); scanf("%d%d", &i,&j);
printf("%10.3f\n",vrednost(n,p,i,j));
}
Primer. Modifikacija prethodnog primera. Matrica se zadaje brojem vrsta, brojem kolona, brojem ne-
nula elemenata kao i nizom slogova koji odgovaraju ne-nula elementima. Svaki takav slog je određen
sledećim informacijama za ne-nula element:
- redni broj vrste tog elementa,
- redni broj kolone tog elementa, i
- realan broj koji predstavlja vrednost tog elementa.
Napisati funkciju za formiranje retke matrice A.
Napisati funkciju za ispis nenula elemenata matrice.
Napisati funkciju za uobičajeni ispis matrice.
Napisati funkciju za formiranje sparse reprezentaciju matrice AT.
Napisati funkciju koja za zadate vrednosti i, j preko tastature izračunava vrednost elementa A[i,j].
#include<stdio.h>

struct slog
{ int i,j;
float aij;
};

struct matrica
{ int m,n,bn;
slog sp[10];
};

void pravimatricu(matrica *a)


{ int i;
printf("Dimenzije matrice: "); scanf("%d%d",&a->m,&a->n);
printf("Broj ne-nula elemenata? "); scanf("%d", &a->bn);
printf("Pozicije i vrednosti ne-nula elemenata?\n");
for(i=0; i<a->bn; i++)
scanf("%d%d%f", &a->sp[i].i,&a->sp[i].j,&a->sp[i].aij);
}

void transponuj(matrica x, matrica *y)


{ int i;
y->m=x.n; y->n=x.n;
y->bn=x.bn;
for(i=0; i<x.bn; i++)
{ y->sp[i].i=x.sp[i].j; y->sp[i].j=x.sp[i].i;
y->sp[i].aij=x.sp[i].aij; }
}

void pisimatricu(matrica x)
{ int i;
for(i=0; i<x.bn; i++)
printf("(%d %d): %10.3f\n",x.sp[i].i, x.sp[i].j,x.sp[i].aij);
}

float vrednost(matrica x, int k, int l)


{ int i;
for(i=0; i<x.bn; i++)
if((x.sp[i].i==k) && (x.sp[i].j==l))
return(x.sp[i].aij);
return(0);
}

161
Ivan P. Stanimirović Uvod u programiranje

void pisigusto(matrica x)
{ int i,j;
for(i=0;i<x.m; i++)
{ for(j=0; j<x.n; j++)
printf("%5.2f ",vrednost(x,i,j));
printf("\n");
}
}

void main()
{ int i,j;
matrica p, q;
pravimatricu(&p);
printf("Matrica je: \n"); pisimatricu(p); pisigusto(p);
transponuj(p,&q);
printf("Transponovana matrica: \n"); pisimatricu(q); pisigusto(q);
printf("i,j= ? "); scanf("%d%d", &i,&j);
printf("%10.3f\n",vrednost(p,i,j));
}
Primer. Definisana je struktura koja predstavlja datum:
type datum=record
dan:1..31;
mesec:1..12;
godina:0..maxint;
end;
Zatim je definisana je struktura koja sadrži jedno polje tipa datum i jedno polje tipa sting:
praznik=record
d:datum;
naziv:string[30];
end;
Ova struktura reprezentuje jedan praznik. U programu formirati niz datuma koji predstavljaju
praznike.
program Praznici;

type datum=record
dan:1..31;
mesec:1..12;
godina:0..maxint;
end;
praznik=record
d:datum;
naziv:string[30];
end;
procedure CitajPraznik(var p:praznik);
begin
with p do
begin
with d do
begin
write('Dan = ? '); readln(dan);
write('Mesec = ? '); readln(mesec);
write('Godina = ? '); readln(godina);
end;
write('Naziv praznika ? '); readln(naziv);
end; {with }
end;

procedure PisiPraznik(p:praznik);

162
Ivan P. Stanimirović Uvod u programiranje

begin
writeln(p.naziv); writeln;
writeln(p.d.dan,'.',p.d.mesec,'.',p.d.godina,'.'); writeln;
end;

var
i,n:integer;
a:array[1..30] of praznik;

begin
readln(n); writeln('Zadati podatke za ',n,' praznika:');
for i:= 1 to n do CitajPraznik(a[i]);
writeln; writeln;
for i:=1 to n do
begin
writeln(i,'. praznik:'); PisiPraznik(a[i]);
end;
end.
Rešenje u jeziku C:
#include<stdio.h>
#include<string.h>
typedef struct
{ int dan, mesec, godina; }datum;
typedef struct
{ char naziv[30];
datum d;
}praznik;

void CitajPraznik(praznik *p)


{ int d,m,g;
printf("Dan = ? "); scanf("%d", &d);
printf("Mesec = ? "); scanf("%d", &m);
printf("Godina = ? "); scanf("%d", &g);
p->d.dan=d; p->d.mesec=m; p->d.godina=g;
printf("Naziv praznika ? ");
gets(p->naziv); gets(p->naziv);
}
void PisiPraznik(praznik p)
{ puts(p.naziv);
printf("\n%d.%d.%d.\n\n",p.d.dan,p.d.mesec,p.d.godina);
}
void main()
{ int i,n;
praznik a[30];
scanf("%d",&n); printf("Zadati podatke za %d praznika:\n",n);
for(i=0;i<n;i++)CitajPraznik(a+i);
printf("\n\n");
for(i=0;i<n;i++)
{ printf("%d. praznik:\n",i+1); PisiPraznik(a[i]); }
}
Primer. Polinom se može predstaviti strukturom koja sadrži red polinoma i niz njegovih koeficijenata.
Napisati funkcije za izračunavanje zbira, razlike, proizvoda i količnika dva polinoma koji su zadati
odgovarajućim strukturama. Napisati program za testiranje napisanih funkcija.
#include<stdio.h>

typedef struct
{ double a[30]; int n; } Poli;

Poli zbir(Poli p1, Poli p2)


{ Poli p; int i;

163
Ivan P. Stanimirović Uvod u programiranje

p.n=(p1.n>p2.n)? p1.n : p2.n;


for(i=0;i<=p.n; i++)
if(i>p2.n)p.a[i]=p1.a[i];
else if(i>p1.n)p.a[i]=p2.a[i];
else p.a[i]=p1.a[i]+p2.a[i];
while(p.n>=0 && p.a[p.n]==0)p.n--;
return p;
}

Poli razlika(Poli p1, Poli p2)


{ Poli p; int i;
p.n=(p1.n>p2.n)? p1.n : p2.n;
for(i=0;i<=p.n; i++)
if(i>p2.n)p.a[i]=p1.a[i];
else if(i>p1.n)p.a[i]=-p2.a[i];
else p.a[i]=p1.a[i]-p2.a[i];
while(p.n>=0 && p.a[p.n]==0)p.n--;
return p;
}

Poli proizvod(Poli p1, Poli p2)


{ Poli p; int i,j;
p.n=p1.n+p2.n;
for(i=0;i<=p.n; p.a[i++]=0);
for(i=0; i<=p1.n; i++)
for(j=0; j<=p2.n; j++) p.a[i+j]+=p1.a[i]*p2.a[j];
return p;
}

Poli kolicnik(Poli p1, Poli p2, Poli *ostatak)


{ Poli p; int i,j;
p.n=p1.n-p2.n;
for(i=p.n; i>=0; i--)
{ p.a[i]=p1.a[p2.n+i]/p2.a[p2.n];
for(j=0; j<=p2.n; j++) p1.a[i+j]-= p.a[i]*p2.a[j];
}
while(p1.n>=0 && p1.a[p1.n]==0)p1.n--;
*ostatak=p1;
return p;
}

Poli citaj()
{ Poli p; int i;
printf("Stepen = ? "); scanf("%d", &p.n);
printf("Koeficijenti?\n"); for(i=p.n; i>=0; scanf("%lf", &p.a[i--]));
return p;
}

void pisi(Poli p)
{ int i;
putchar('{');
for(i=p.n; i>=0; i--){ printf("%.2lf", p.a[i]); if(i>0)putchar(','); }
putchar('}');
}
void main()
{ Poli p1, p2, p3;
while(1)
{ p1=citaj(); p2=citaj();
printf("P1 = "); pisi(p1); putchar('\n');
printf("P2 = "); pisi(p2); putchar('\n');
printf("P1+P2 = "); p3=zbir(p1,p2); pisi(p3); putchar('\n');
printf("P1-P2 = "); pisi(razlika(p1,p2)); putchar('\n');

164
Ivan P. Stanimirović Uvod u programiranje

printf("P1*P2 = "); pisi(proizvod(p1,p2)); putchar('\n');


printf("P1/P2 = "); pisi(kolicnik(p1,p2, &p3)); putchar('\n');
printf("P1%%P2 = "); pisi(p3); putchar('\n'); putchar('\n');
}
}

6.7.4. Unije
Unija je tip podataka koji može da sadrži (u raznim situacijama) objekte različitih tipova. Unije
određuju način manipulisanja različitim tipovima podataka u istoj memorijskoj oblasti. Svrha njihovog
postojanja je ušteda memorije. One su analogne slogovima promenljivog tipa u Pascal-u, a sintaksa im
je zasnovana na strukturama jezika C. Svrha unije je da postoji samo jedna promenljiva koja može da
sadrži bilo koju od vrednosti različitih tipova. Unije se razlikuju od struktura po tome što elementi
unije koriste isti memorijski prostor, i što se u svakom trenutku koristi samo jedan element unije.
Primer. Pretpostavimo da u tabeli simbola nekog kompajlera, konstanta može da bude int, float ili
char. Najveća ušteda memorije se postiže ako je vrednost ma kog elementa tabele memorisana na
istom mestu, bez obzira na tip. U našem slučaju je potrebna sledeća deklaracija
union tag
{ int ival;
float fval;
char *sval;
};
union tag u;

Ekvivalentna deklaracija je data kako sledi:


union tag
{ int ival;
float fval;
char *sval;
} u;

Promenljivoj koja je deklarisana kao unija prevodilac dodeljuje memorijski prostor dovoljan za
memorisanje onog člana unije koji zauzima najveći memorijski prostor. Programer mora da vodi
računa o tome koji tip se trenutno memoriše u uniji, jer je važeći tip onaj koji je najskorije memorisan.

Članovi unije se selektuju identično članovima strukture:


unija.clan

ili
pointer_unije->clan.
Ako je int tip tekućeg člana unije u, njegova vrednost se prikazuje izrazom
printf("%d\n",u.ival);
ako je aktivni član tipa float pišemo
printf("%f\n",u.fval);
a ako je tipa char
printf("%s\n",u.sval);
Elementima strukturne promenljive u vrednosti se mogu dodeliti, na primer, iskazima
u.ival=189; ili u.fval=0.3756; ili u.sval="string";

Primer. Jednostavna unija koja sadrži jedno celobrojno i jedno realno polje.
void main()
{ union { int i;
float f;
} x;

165
Ivan P. Stanimirović Uvod u programiranje

x.i=123; printf("x.i=%d x.f=%f\n",x.i,x.f);


x.f=12.803; printf("x.i=%d x.f=%f\n",x.i,x.f);
}

Unije mogu da se pojavljuju u strukturama i nizovima. Kombinacijom strukture i unije grade se


promenljive strukture.
Primer. Tablica simbola
struct { char*name;
int flags;
int utype;
union { int ival;
float fval;
char *sval;
} u;
} symtab[100];

Sada možemo pristupiti članu ival i-tog elementa tablice simbola pomoću izraza
symtab[i].u.ival;

Prvi znak stringa sval i-tog elementa tablice simbola se dobija jednim od sledeća dva ekvivalentna
izraza:
*symtab[i].u.sval;
symtab[i].u.sval[0];

Unija se može inicijalizovati samo pomoću vrednosti koja odgovara tipu njenog prvog člana. Stoga
se unija opisana u prethodnom primeru može inicijalizovati samo pomoću celobrojne vrednosti.
Primer. Osnovne geometrijske figure se mogu okarakterisati sledećom strukturom:
struct figura
{ float povrsina, obim; /* Zajednicki elementi */
int tip; /* Oznaka aktivnog elementa */
union
{ float r; /* Poluprecnik kruga */
float a[2]; /* Duzine strana pravougaonika */
float b[3]; /* Duzine strana trougla */
} geom_fig;
} fig;
Primer. Napisati program za izračunavanje rastojanja između dve tačke u ravni, pri čemu postoji
mogućnost da svaka od tačaka bude definisana u Dekartovom ili polarnom koordinatnom sistemu.
Obuhvaćeni su svi slučajevi: kada su obe tačke zadate Dekartovim koordinatama, jedna od tačaka
Dekartovim, a druga polarnim koordinatama i slučaj kada su obe tačke definisane polarnim
koordinatama.
#include<stdio.h>
#include<math.h>
typedef enum { Dekartove, Polarne }TipKor;

typedef struct
{ double x,y; } Dek;
typedef struct
{ double r,fi; } Pol;
typedef struct
{ TipKor tip;
union
{ Dek DK;
Pol PK;
};

166
Ivan P. Stanimirović Uvod u programiranje

} koordinate;

void ucitaj(koordinate *Q)


{ int ch;
double u,v;
printf("Tip koordinata? 1 za Dekartove, 2 za polarne: ");
scanf("%d", &ch);
printf("Koordinate? ");
switch (ch)
{ case 1: Q->tip=Dekartove; scanf("%lf%lf", &u, &v);
Q->DK.x=u; Q->DK.y=v;
break;
case 2: Q->tip=Dekartove; scanf("%lf%ld", &u,&v);
Q->PK.r=u, Q->PK.fi=v;
break;
}
}

void main()
{ koordinate A,B;
double d;
ucitaj(&A); ucitaj(&B);
switch(A.tip)
{
case Dekartove:
switch(B.tip)
{ case Dekartove:
d=sqrt(pow(A.DK.x-B.DK.x,2)+pow(A.DK.y-B.DK.y,2));
break;
case Polarne:
d=sqrt(pow(A.DK.x-B.PK.r*cos(B.PK.fi),2)+
pow(A.DK.y-B.PK.r*sin(B.PK.fi),2));
break;
}
break;
case Polarne:
switch(B.tip)
{case Dekartove:
d=sqrt(pow(A.PK.r*cos(A.PK.fi)-B.DK.x,2)+
pow(A.PK.r*sin(A.PK.fi)-B.DK.y,2));
break;
case Polarne:
d=sqrt(pow(A.PK.r*cos(A.PK.fi)-B.PK.r*cos(B.PK.fi),2)+
pow(A.PK.r*sin(A.PK.fi)-B.PK.r*sin(B.PK.fi),2));
break;
}
break;
}
printf("%.4lf\n",d);
}
Primer. Napisati program za sumiranje površina n geometrijskih figura. Figura može biti krug
(određen dužinom poluprečnika), pravougaonik (određen dužinama susednih stranica) ili trougao
(određen dužinama svojih stranica).
#include<stdio.h>
#include<math.h>
void main()
{ struct pravougaonik
{ double a,b;};
struct trougao
{ double a,b,c; };

167
Ivan P. Stanimirović Uvod u programiranje

struct figura
{ int tip;
union
{ double r;
struct pravougaonik p;
struct trougao t;
};
} figure[50];

int i,n;
double pov=0,s;
scanf("%d",&n);
for(i=0; i<n; i++)
{ printf("Tip figure (0 - krug, 1-pravougaonik, 2-trougao): ");
scanf("%d",&figure[i].tip);
switch(figure[i].tip)
{ case 0:
scanf("%lf",&figure[i].r);break;
case 1:
scanf("%lf%lf",&figure[i].p.a,&figure[i].p.b);break;
case 2:

scanf("%lf%lf%lf",&figure[i].t.a,&figure[i].t.b,&figure[i].t.c);
break;
}
}
for(i=0;i<n;i++)
{ switch(figure[i].tip)
{ case 0:
pov+=3.14*figure[i].r*figure[i].r;break;
case 1:
pov+=figure[i].p.a*figure[i].p.b;break;
case 2:
s=(figure[i].t.a+figure[i].t.b+figure[i].t.c)/2;
pov+=sqrt(s*(s-figure[i].t.a)*(s-figure[i].t.b)*(s-
figure[i].t.c));
}
}
printf("Povrsina svih figura je %lf\n",pov);
}

6.8. Nabrojivi tip podataka u c


Pomoću ključne reči enum deklarišu se nabrojivi (enumerisani) tipovi podataka. Promenljive
nabrojivog tipa mogu da imaju samo konačan skup vrednosti. Deklaracija promenljivih nabrojivog
tipa se sastoji od ključne reči enum, imena enumerisanog tipa, eventualno liste dozvoljenih vrednosti i
liste enumerisanih promenljivih koje se deklarišu.
Primer. Iskazom
enum flag{true,false};
definisan je nabrojivi tip enum flag. Promenljive ovog tipa mogu da imaju samo vrednosti true ili
false. Ključna reč enum označava da se radi o nabrojivom tipu podataka, a identifikator flag
predstavlja ime definisanog nabrojivog tipa. Između zagrada se nalazi lista vrednosti.
Sada se mogu deklarisati promenljive nabrojivog tipa enum flag:
enum flag file_end, input_end;
Ime nabrojivog tipa se može izostaviti, čime se dobija neimenovani nabrojivni tip. Na primer,
sledeća deklaracija je analogna prethodnoj:
enum {true,false} file_end, input_end;

168
Ivan P. Stanimirović Uvod u programiranje

Dodeljivanje vrednosti enumerisanoj promenljivoj je analogno dodeljivanju vrednosti


promenljivima ostalih tipova. Sledeći iskazi su legalni:
file_end=false;
if(input_end == true)

U sledećem primeru se definiše nabrojivi tip enum dani:


enum dani {pon,uto,sre,cet,pet,sub,ned};
Vrednosti nabrojivog tipa se tretiraju kao celobrojne konstante. Preciznije, C kompajler dodeljuje
sekvencijalne celobrojne vrednosti elementima liste vrednosti, startujući od prvog elementa liste,
kome se dodeljuje vrednost 0. Na primer, izrazom
ovaj_dan=sreda;
dodeljena je vrednost 2 (ne ime sreda) promenljivoj ovaj_dan (tipa enum dani).
Sekvencijalni način dodeljivanja celobrojnih vrednosti elementima iz liste imena može se promeniti
eksplicitnim dodeljivanjem željene celobrojne vrednosti nekom elementu iz liste imena. Pri tome se
mogu koristiti i negativni celi brojevi.
Primer. Možemo pisati
enum dani{pon,uto,sre=10,cet,pet,sub=100,ned} ;
Sada je
pon=0, uto=1, sre=10, cet=11, pet=12, sub=100, ned=101.
Ako se želi eksplicitno dodeljivanje celobrojne vrednosti nabrojivog promenljivoj, mora da se
koristi kast operator.
Na primer, izraz
ovaj_dan=pon
ekvivalentan je sa
ovaj dan=(enum dani)0;

Primer. Program određivanje sledećeg dana u nedelji


#include<stdio.h>
void main()
{ int k;
enum dani{pon,uto,sre,cet,pet,sub,ned} sledeci;
printf("unesite danasnji dan:\n"); scanf("%d",&k);
k+=1; k%=7;
sledeci=(enum dani)k;
printf("\nSledeci dan je %d.dan u nedelji\n", (int)sledeci);
}

Ista konstanta se ne može koristiti u deklaracijama različitih nabrojivih tipova podataka. Na primer,
definicije tipova
enum radnidani {pon,uto,sre,cet,pet};
enum vikend {pet,sub,ned};
su nekorektne, jer se konstanta pet pojavljuje u definiciji oba tipa. Nabrojivi tip se može definisati
koristeći operatore typedef i enum. Na primer, sledećim definicijama su uvedena dva nabrojiva tipa,
samoglasnik i dani:
typedef enum {A,E,I,O,U} samoglasnik;
typedef enum {pon,uto,sre,cet,pet,sub,ned} dani;

Posle definicije ovih tipova mogu se deklarisati promenljive uvedenih tipova:


samoglasnik slovo;
dani d1,d2;

169
Ivan P. Stanimirović Uvod u programiranje

Promenljivoj nabrojivog tipa se može dodeliti bilo koja vrednost koja je sadržana u definiciji
nabrojivog tipa:
slovo=U;
d1=sre;
Ako se vrednosti promenljivih nabrojivog tipa ispisuju pomoću funkcije printf(), ispisuju se
celobrojne vrednosti koje su dobile na osnovu definicije nabrojivog tipa.
Za razliku od Pascala, promenljive nabrojivog tipa se ne mogu koristiti kao brojačke promenljive u
operatorima FOR ciklusa.

6.9. Dinamičke matrice i strukture


Primer. Dinamička matrica se predstavlja strukturom koja sadrži dimenzije i pokazivač na elemente
matrice. Sastaviti na jeziku C paket funkcija za rad sa dinamičkim matricama realnih brojeva koji
sadrži funkcije za:
• dodeljivanje memorije matrici datih dimenzija,
• oslobađanje memorije koju zauzima matrica,
• kopiranje matrice,
• čitanje matrice preko glavnog ulaza,
• ispisivanje matrice preko glavnog izlaza,
• nalaženje transponovane matrice za datu matricu,
• nalaženje zbira, razlike i proizvoda dve matrice.
Sastaviti na jeziku C glavni program za proveru ispravnosti rada gornjih funkcija.
Rešenje:
#include <stdlib.h>
#include <stdio.h>

typedef enum {MEM, DIM} Greska; /* Šifre grešaka. */


typedef struct { float **a; int m, n; } Din_mat; /* Struktura matrice. */

Din_mat stvori (int m, int n); /* Dodela memorije. */


void unisti (Din_mat dm); /* Oslobadjanje memorije. */
Din_mat kopiraj (Din_mat dm) ; /* Kopiranje matrice. */
Din_mat citaj (int m, int n) ; /* Citanje matrice. */
void pisi (Din_mat dm, const char *frm, int max); /* Ispisivanje matrice.*/
Din_mat transpon (Din_mat dm); /* Transponovana matrica*/
Din_mat zbir (Din_mat dm1, Din_mat dm2); /* Zbir matrica. */
Din_mat razlika (Din_mat dm1, Din_mat dm2); /* Razlika matrica. */
Din_mat proizvod (Din_mat dm1, Din_mat dm2); /* Proizvod matrica. */

/* Definicije paketa za rad sa dinamickim matricama. */

const char *poruke[] = /* Poruke o greškama.*/


{ "Neuspela dodela memorije", "Neusaglasene dimenzije matrica" };

static void greska (Greska g) { /* Ispisivanje poruke grešci. */


printf("\n*** %s ! ***\n\a", poruke[g]);
exit(g+1);
}

Din_mat stvori (int m, int n) { /* Dodela memorije. */


int i; Din_mat dm;
dm.m = m; dm.n = n;
if((dm.a = (float **)malloc(m*sizeof(float*))) == NULL) greska (MEM);
for(i=0; i<m; i++)
if((dm.a[i] = (float *)malloc(n*sizeof(float))) == NULL) greska (MEM);

170
Ivan P. Stanimirović Uvod u programiranje

return dm;
}

void unisti (Din_mat dm) { /* Oslobadjanje memorije. */


int i;
for (i=0; i<dm.m; free(dm.a[i++]));
free (dm.a);
}

Din_mat kopiraj (Din_mat dm) { /* Kopiranje matrice. */


int i, j;
Din_mat dm2 = stvori (dm.m, dm.n);
for (i=0; i<dm.m; i++)
for (j=0; j<dm.n;j++)
dm2.a[i][j] = dm.a[i][j];
return dm2;
}

Din_mat citaj(int m, int n){ /* Citanje matrice. */


int i,j;
Din_mat dm = stvori(m,n);
for(i=0; i<m; i++)
for(j = 0; j<n; scanf("%f",&dm.a[i][j++]));
return dm;
}

void pisi(Din_mat dm, const char *frm, int max){ /* Ispis matrice. */
int i,j;
for(i=0; i<dm.m; i++) {
for(j=0; j<dm.n; j++) {
printf(frm,dm.a[i][j]);
putchar ((j%max==max-1 || j==dm.n-1) ? '\n' : ' ');
}
if(dm.n > max)putchar ('\n');
}
}

Din_mat transpon(Din_mat dm) { /* Transponovana matrica*/


int i, j;
Din_mat dm2 = stvori(dm.n, dm.m);
for (i=0; i<dm.m; i++)
for(j=0; j<dm.n; j++) dm2.a[j][i] = dm.a[i][j];
return dm2;
}

Din_mat zbir(Din_mat dm1, Din_mat dm2) { /* Zbir matrica. */


int i,j;
Din_mat dm3;
if(dm1.m!=dm2.m || dm1.n != dm2.n) greska(DIM);
dm3 = stvori(dm1.m, dm1.n);
for(i=0; i<dm3.m;i++)
for(j=0; j<dm3.n;j++)
dm3.a[i][j]= dm1.a[i][j] + dm2.a[i][j];
return dm3;
}

Din_mat razlika (Din_mat dm1, Din_mat dm2) { /* Razlika matrica.*/


int i,j; Din_mat dm3;
if(dm1.m!=dm2.m || dm1.n != dm2.n) greska (DIM);
dm3 = stvori (dm1.m, dm1.n);
for(i=0; i<dm3.m;i++)
for(j=0; j<dm3.n;j++)
dm3.a[i][j] = dm1.a[i][j] - dm2.a[i][j];

171
Ivan P. Stanimirović Uvod u programiranje

return dm3;
}

Din_mat proizvod (Din_mat dm1, Din_mat dm2) { /* Proizvod matrica. */


int i, j, k; Din_mat dm3;
if (dm1.n!=dm2.m) greska (DIM);
dm3 = stvori(dm1.m, dm2.n);
for(i=0; i<dm3.m; i++)
for(k=0; k<dm3.n; k++)
for(dm3.a[i][k]=j=0; j<dm2.m; j++)
dm3.a[i][k] +=dm1.a[i][j] * dm2.a[j][k];
return dm3;
}

int main() {
while (1) {
Din_mat dm1, dm2, dm3; int m, n;
printf ("m1, n1? "); scanf ("%d%d", &m, &n);
if (m<=0 || n<=0) break;
printf("Matrl?\n"); dm1 = citaj(m,n);
printf ("m2, n2? "); scanf ("%d%d", &m, &n);
if(m<=0 || n<=0) break;
printf ("Matr2?\n"); dm2 = citaj(m,n);
if(dm1.m==dm2.m && dm1.n==dm2.n) {
dm3 = zbir(dm1, dm2); printf ("ZBIR:\n");
pisi(dm3,"%8.2f", 8); unisti(dm3);
dm3 = razlika(dm1, dm2); printf ("RAZLIKA:\n");
pisi(dm3, "%8.2f", 8); unisti (dm3);
}
if(dm1.n == dm2.m) {
dm3 = proizvod(dm1,dm2); printf("PROIZVOD:\n");
pisi(dm3, "%8.2f", 8); unisti (dm3);
}
putchar('\n');
unisti(dm1); unisti(dm2);
}
return 0;
}

6.10. Datoteke
Programi koje smo do sada koristili imali su jedan ozbiljan nedostatak. Naime, rezultati obrade
ulaznih veličina prestankom izvršavanja programa su nepovratno nestajali. Jedan od načina da se
sačuvaju podaci bio bi da se posredstvom štampača ispišu na hartiji. Međutim, ako postoji potreba da
podaci budu pristupačni nekom programu, treba ih sačuvati na magnetnim nosiocima informacija, na
primer na disku ili traci. Na taj način, na disku ili traci se mogu čuvati datoteke sa podacima koje
možemo obrađivati koliko god hoćemo puta, a da ih ne moramo učitavati sa tastature.
Datoteke su sekvencijalne strukture jednorodnih zapisa čiji broj nije unapred poznat, i koje se
zapisuju na nekom od spoljašnjih memorijskih medijuma. Ovakvi strukturni tipovi opisuju se sa file i
postali su standardni u programskim jezicima posle pojave ovog koncepta u jeziku Pascal.
Datoteke su jednorodne strukture podataka, slično poljima ali za razliku od polja, broj elemenata
datoteke se ne definiše unapred i podrazumeva se da one fizički postoje van programa na nekom od
spoljašnjih memorijskih medijuma (disku, traci, disketi itd.).

6.10.1. Pristup datotekama u C


Datoteke omogućavaju da se ulazne veličine i rezultati obrade podataka trajno sačuvaju na disku.
Datoteka se tretira kao sekvencijalni niz karaktera. Datotekama se pristupa korišćenjem ukazatelja na
strukturu FILE, koja je definisana u biblioteci stdio.h. U datoteci stdio.h su definisane i konstante EOF

172
Ivan P. Stanimirović Uvod u programiranje

i NULL. Konstanta EOF označava kraj datoteke i ima vrednost -1. Konstanta NULL ima vrednost 0 i
vraća se kao rezultat neuspešnog poziva nekih funkcija za upravljanje datotekama.
Otvaranje i zatvaranje datoteka

Programski jezik C koristi dva osnovna tipa fajlova: tekstualni i binarni tip.
Rad sa fajlovima odvija se kroz nekoliko osnovnih aktivnosti: otvaranje fajla, čitanje i upis u fajl,
kretanje po fajlu, zatvaranje fajla.
Datoteka mora da bude otvorena pre bilo kakvog procesiranja. Prilikom otvaranja datoteke mora se
specificirati njeno ime i tip željene ulazno-izlazne operacije. Može se koristiti režim čitanja (read
mode), režim upisa (write mode), odnosno režim dodavanja (append mode). Za otvaranje datoteka
koristi se funkcija fopen iz C biblioteke. Zaglavlje ove funkcije je oblika
FILE *fopen(const char *filename, const char *mode);

Funkcija fopen() vraća pointer na otvoreni fajl. Vraćena vrednost NULL indicira grešku prilikom
otvaranja fajla. Parametar filename ime fajla, a parametar mode predstavlja način na koji se fajl otvara.
Mogući načini su opisani u nastavku:
"r" Otvara za čitanje. Ako fajl ne postoji ili ne može biti pronađen poziv ne uspeva.
"w" Otvara prazan fajl za pisanje. Ako dati fajl postoji njegov sadržaj se briše.
"a" Otvara fajl za pisanje na kraju fajla (appending) bez brisanja EOF markera pre pisanja novih
podataka na kraju postojećeg fajla. Ukoliko fajl ne postoji, kreira se novi.
"r+" Otavara fajl za čitanje i pisanje. Fajl mora da postoji.
"w+" Otvara prazan fajl za čitanje i pisanje. Ako dati fajl postoji, njegov sadržaj je obrisan.
"a+" Otvara fajl za čitanje i appednovanje. Operacija apendovanja uključuje brisanje EOF markera
pre nego se novi podaci upišu u fajl. Marker EOF se restaurira posle kompletiranja pisanja.
Ukoliko fajl sa specificiranim imenom ne postoji, on se prvo kreira.
Kad je fajl otvoren sa pristupom "a" ili "a+" sve opracije upisa se dešavaju na kraju fajla. Fajl
pointer može biti repozicioniran korišćenjem fseek ili rewind, ali se uvek vraća na kraj fajla pre bilo
koje operacije upisa u fajl. Na taj način se obezbeđuje da preko postojećih podataka nema upisa.
Mod "a" ne briše EOF marker pre dodavanja podataka u fajl. Ako se to desi MSDOS komanda
TYPE samo pokazuje podatke do originalnog EOF markera i ne pokazuje podatke dodate fajlu. Mod
"a+" briše EOF marker pre dodavanja fajlu. Posle dodavanja MSDOS komanda TYPE pokazuje sve
podatke dodate fajlu. Mod "a+" se zahteva za dodavanje stream fajlu koji je terminiran CTRL+Z EOF
markerom. Kad je specificiran neki od "r+", "w+" ili "a+" i čitanje i pisanje su dozvoljeni, a kaže se da
je fajl otovren za update. Potrebno je da se prilikom prebacivanja između čitanja i pisanja uradi
intervencija u obliku poziva fflush, fsetpos, fseek, ili rewind operacije. Tekuća pozicija može biti
specificirana fsetpos ili fseek operacijom.
Sledeći karakteri mogu biti uključeni u mod radi specifikacije prevođenja newline karaktera.
t Otvara fajl u tekstualnom modu. CTRL+Z se interpretira kao end-of-file karakter na ulazu. U
fajlu otvorenom za čitanje - pisanje sa "a+" fopen proverava CTRL+Z na kraju fajla i briše ga ako je
moguće. Ovo se radi jer korišćenje fseek i ftell za kretanje unutara fajla koji se završava sa CTRL+Z,
može da uslovi nekorektno ponašanje fseek blizu kraja fajla. Takođe, u tekstualnom modu carriage
return - line feed kombinacije na ulazu se prevode u jedan linefeeds na ulazu i obratno linefeed
karakter na izlazu se prevode u carriage return – line feed kombinacije.
b Otvara fajl u binarnom neprevedenom modu. Prevođenja koja uključuju carriage-return i
linefeed kraktere se ne vrše.
Ako je otvaranje neuspešno, tj. ako fopen() ne može da pronađe željenu datoteku, ona vraća
vrednost NULL.
Primer. Niz iskaza

173
Ivan P. Stanimirović Uvod u programiranje

#include<stdlib.h>
FILE *infile,*fopen();
infile=fopen("file","r"); }
otvara datoteku pod imenom file u režimu čitanja.
Funckija fopen() vraća ukazatelj na strukturu FILE, koja se dodeljuje promenljivoj infile istog tipa.
Neuspešno otvaranje datoteke infile se može ispitati izrazom oblika
if(infile==NULL)
printf("datoteka file ne moze se otvoriti\n");
Poziv funkcije fopen() i ispitivanje vraćenog rezultata se može ujediniti
if((infile=fopen("file","r"))==NULL)
printf("datoteka file ne moze biti otvorena\n");

Funkcijom fclose() zatvara se datoteka otvorena za čitanje ili upis. Zatvorenoj datoteci se ne može
pristupiti pre ponovnog otvaranja. Zaglavlje ove funkcije je
int fclose(FILE *file_pointer);
gde je file_pointer ukazatelj kojim se identifikuje datoteka.
Funkcija
fclose(file_pointer)
vraća vrednost EOF ako ukazatelj file_pointer nije povezan sa nekom datotekom.
Na primer, otvorena datoteka infile zatvara se izrazom
fclose(infile);

Primer.
/* FOPEN.C: This program opens files named "data"
and "data2".It uses fclose to close "data" and
_fcloseall to close all remaining files. */
#include <stdio.h>
FILE *stream, *stream2;
void main(void)
{ int numclosed;
/* Open for read (will fail if file "data" does not exist) */
if( (stream = fopen("data", "r")) == NULL )
printf("The file 'data' was not opened\n" );
else printf( "The file 'data' was opened\n" );
/* Open for write */
if( (stream2 = fopen( "data2", "w+")) == NULL )
printf("The file 'data2' was not opened\n");
else printf("The file 'data2’ was opened\n");
/* Close stream */
if(!fclose(stream))
printf( "The file 'data2' was not closed\n" );
/* All other files are closed: */
numclosed = _fcloseall();
printf("Number of files closed by _fcloseall: %u\n", numclosed);
}
Output
The file 'data' was opened
The file 'data' was opened
Number of files closed by _fcloseall : 1

174
Ivan P. Stanimirović Uvod u programiranje

Funkcije fgetc() i fputc()


Funkcija fgetc() učitava jedan po jedan karakter iz specificirane datoteke. Slična je funkciji getchar().
Ulazni argument funkcije fgetc() je ukazatelj na strukturu FILE, a rezultat je vrednost tipa int.
Zaglavlje ove funkcije je oblika:
int fgetc(FILE *infile)
Pretpostavimo da promenljiva infile dobija vrednost pomoću funkcije fopen(), koristeći opciju "r".
Ako je c promenljiva tipa int, tada se iskazom
c=fgetc(infile);
učitava jedan znak datoteke koja je povezana sa pointerom infile.
Ako je dostignut kraj datoteke, funkcija getc() vraća vrednost EOF.
Funkcija fputc() upisuje karakter u specificiranu datoteku. Poziva se izrazom oblika
int fputc(char c, FILE *outfile)

fputc

Zaglavlje ove funkcije je oblika


int fputc( int c, FILE *stream );
i piše karakter c u stream.
Vrednost koju ova funkcija vraća je karakter koji se upisuje, ako je upisivanje uspešno, ili EOF ako
je nesupešno upisivanje.
Primer. Izrazima
FILE *outfile;
outfile=fopen("file","w");
fputc('z', outfile);
u datoteku outfile upisuje se znak 'z'.
Primer. Napisati program kojim se sadržaj datoteke "ulaz" (formiran od velikih slova azbuke) šifrira i
upisuje u datoteku "izlaz". šifriranje se sastoji u tome da se svaki znak različit od 'Z' zamenjuje
sledećim ASCII znakom, dok se znak 'Z' zamenjuje znakom 'A'.
#include<stdio.h>
void main()
{ FILE *infile, *outfile;
int c;
infile = fopen("ulaz","r"); outfile= fopen("izlaz","w");
while((c=fgetc(infile)) != EOF)
{ if('A' <= c && c < 'Z')c++;
else c='A';
fputc(c,outfile);
}
fclose(infile); fclose(outfile);
}
Primer:
/* FGETC.C: This program uses getc to read the first
* 80 input characters (or until the end of input)
* and place them into a string named buffer.
*/
#include<stdio.h>
#include<stdlib.h>
void main(void)
{ FILE *stream;

175
Ivan P. Stanimirović Uvod u programiranje

char buffer[81];
int i, ch;
/* Open file to read line from: */
if( (stream = fopen("fgetc.c", "r")) == NULL ) exit(0);
/* Read in first 80 characters and place them in "buffer": */
ch = fgetc(stream);
for( i=0; (i<80) && (feof(stream)==0); i++)
{ buffer[i] = (char)ch; ch = fgetc( stream }; }
/* Add null to end string */
buffer [i] = '\0' ;
printf("%s\n", buffer); fclose(stream);
}

Primer. Kopiranje sadržaja ulazne datoteke u izlaznu datoteku. Imena datoteka data su kao parametri
funkcije main().
#include<stdio.h>
void main(int argc,char *argv[]);
{ int c; FILE *infile,*outfile;
if((infile=fopen(argv[1],"r"))==NULL)
printf("datoteka %s ne moze biti otvorena\n",argv[1]);
else if((outfile=fopen(argv[2],"w"))==NULL)
printf("datoteka %s ne moze biti otvorena\n",argv[2]);
else
{ while((c=getc(infile))!=EOF) putc(c,outfile);
printf("\n");
}
fclose(infile); fclose(outfile);
}
Primer.
/* FPUTC.C: This program uses fputc
* to send a character array to stdout.
*/
#include<stdio.h>
void main(void)
{ char strptrl[] = "This is a test of fputc!!\n";
char *p;
/* Print line to stream using fputc. */
p = strptrl;
while((*p != '\0') && fputc(*(p++), stdout)!= EOF);
}

Funkcije fprintf() i fscanf()


Ove funkcije obavljaju analogne operacije kao i funkcije printf() i scanf(), s tim što zahtevaju
dodatni argument za identifikaciju datoteke u koju se upisuju ili iz koje se čitaju podaci. Zaglavlje
ovih funkcija je sledećeg oblika:
fprintf(file_pointer,konverzioni_niz,lista_argumenata)
fscanf(file_pointer,konverzioni_niz,lista_argumenata)
pri čemu je:
file_pointer ukazatelj na tip FILE,
konverzioni_niz je lista formata po kojima se upisuju ili čitaju podaci, dok je lista_argumenata lista
vrednosti koje se upisuju u datoteku, odnosno čitaju iz datoteke koja je identifikovana pointerom
file_pointer.
Funkcije fprintf() i fscanf() imaju promenljivi broj argumenata, zavisno od broja vrednosti koje se
upisuju u datoteku, odnosno čitaju iz datoteke.

176
Ivan P. Stanimirović Uvod u programiranje

Na primer, izrazom
fprintf(outfile,"string u datoteku\n");
upisuje se string "string u datoteku\n" u datoteku koja je identifikovana pomoću pointera outfile.
Takođe, u istu datoteku se može upisati i sledeći sadržaj:
fprintf(outfile,"string sadrzaja %s u datoteku\n",x);
Primer. Izrazom oblika
fscanf(infile,"%f",&x);
iz datoteke koja je identifikovana sa infile učitava se vrednost u formatu %f i dodeljuje promenljivoj x.
Primer. Procedure za učitavanje celog broja iz datoteke "zad2.dat" i upis istog broja u datoteku
"zad2.res".
#include<stdio.h>
void citaj(long *n)
{ FILE *f;
f=fopen("d:\\zad2.dat","r"); fscanf(f,"%ld",n); fclose(f);
}

void upis(long n)
{ FILE *f;
f=fopen("d:\\zad2.res","w"); fprintf(f,"%ld",n); fclose(f);
}

void main()
{ void citaj(long *); void upis(long);
long n;
citaj(&n); upis(n);
}

Primer. Iz prvog reda datoteke učitati broj timova. U svakom od sledećih redova datoteke zadati
sledeće podatke za svaki tim:
- naziv tima,
- broj pobeda,
- broj nerešenih rezultata, i
- broj poraza.
Sortirati tabelu prema broju osvojenih bodova. Ako dva tima imaju isti broj osvojenih bodova, sortirati
ih prema broju pobeda.
#include<stdio.h>
#include<string.h>
#define broj 10
struct klub
{ char naziv[30];
int izgubljene;
int neresene;
int dobijene;
} tabela[broj];

void ucitaj(int *n, struct klub a[broj])


{ int i; FILE *f;
f=fopen("klubovi.dat","r");
fscanf(f,"%d",n); fgetc(f);
for(i=0; i<*n; i++)
{ fgets(a[i].naziv,30,f);

fscanf(f,"%d%d%d",&a[i].dobijene,&a[i].neresene,&a[i].izgubljene);
fgetc(f);
}

177
Ivan P. Stanimirović Uvod u programiranje

fclose(f);
}

void ispis(int n, struct klub a[broj])


{ int i;
for(i=0; i<n; i++)
{ printf("%-20s %d %d %d\n",a[i].naziv, a[i].dobijene,
a[i].neresene,a[i].izgubljene);
}
}

void main()
{ int i,j,n, bodovi[broj]; klub as; int pb;
ucitaj(&n,tabela);
for(i=0;i<n;i++)
tabela[i].naziv[(int)strlen(tabela[i].naziv)-1]='\0';

for(i=0;i<n;i++)
bodovi[i]=tabela[i].neresene+3*tabela[i].dobijene;
for(i=0; i<n-1;i++)
for(j=i+1;j<n;j++)
if((bodovi[i]<bodovi[j])||
((bodovi[i]==bodovi[j]) &&
(tabela[i].dobijene<tabela[j].dobijene))
)
{
as=tabela[i]; tabela[i]=tabela[j];tabela[j]=as;
pb=bodovi[i];bodovi[i]=bodovi[j];bodovi[j]=pb;
}
ispis(n,tabela);
}
Funkcija feof()
Ova funkcija ispituje da li je dostignut broj datoteke. Njen opšti oblik je
int feof(FILE *file pointer)
Funkcija feof() vraća nenultu vrednost ako je dostignut kraj datoteke.

Primer. Funkcija feof se koristi za ispitivanje kraja datoteke.


if(feof(infile)) printf("kraj datoteke\n");
Primer. Retka matrica se može predstaviti brojem ne-nula elemenata kao i sledećim informacijama za
svaki ne-nula element:
- redni broj vrste tog elementa,
- redni broj kolone tog elementa, i
- realan broj koji predstavlja vrednost tog elementa.
Predstaviti retku matricu brojem ne-nula elemenata i nizom slogova, u kome svaki slog sadrži redni
broj vrste i kolone kao i vrednost svakog ne-nula elementa.
Napisati procedure za formiranje niza slogova koji predstavljaju reprezentaciju retke matrice A.
Podaci za matricu A se učitavaju iz datoteke 'sparse.dat'.

Napisati proceduru za ispis matrice.


Napisati proceduru za formiranje sparse reprezentaciju predstavlja matricu AT.
Napisati funkciju koja za zadate vrednosti i, j preko tastature izračunava vrednost elementa A[i,j].
#include<stdio.h>

struct slog
{ int i,j;

178
Ivan P. Stanimirović Uvod u programiranje

float aij;
};

void pravimatricu(struct slog x[10], int *n)


{ int p,q,i;
float xpq;
FILE *infile;
infile=fopen("sparse.dat","r");
fscanf(infile,"%d", n);
for(i=1; i<=*n; i++)
{ fscanf(infile,"%d%d%f", &p,&q,&xpq);
x[i].i=p; x[i].j=q; x[i].aij=xpq;
}
fclose(infile);
}

void transponuj(struct slog x[10], int n, struct slog y[10])


{ int p,q,i;
float xpq;
for(i=1; i<=n; i++)
{ y[i].i=x[i].j; y[i].j=x[i].i; y[i].aij=x[i].aij;
}
}

void pisimatricu(struct slog y[10], int n)


{ int p,q,i;
float xpq;
printf("%d\n",n);
for(i=1; i<=n; i++)
printf("(%d %d): %10.3f\n",y[i].i, y[i].j,y[i].aij);
}

float vrednost(int n, struct slog x[10], int k, int l)


{ int i;
for(i=1; i<=n; i++)
if((x[i].i==k) && (x[i].j==l))
return(x[i].aij);
return(0);
}

void main()
{ int i,j,n;
struct slog p[10], q[10];
pravimatricu(p, &n);
printf("Matrica je : \n"); pisimatricu(p,n);
transponuj(p,n,q);
printf("Transponovana matrica: \n"); pisimatricu(q,n);
printf("i,j= ? "); scanf("%d%d", &i,&j);
printf("%10.3f\n",vrednost(n,p,i,j));
}

Funkcije fgets() i fputs()


Funkcija fgets() ima sledeće zaglavlje:
char *fgets(char *string, int maxl, FILE *infile);
Ovom funkcijom se, iz datoteke na koju ukazuje pointer infile, učitava string koji se završava
prelazom u novi red ili sadrži maxl-1 znakova. Prema tome, drugi argument, označen sa maxl,
predstavlja maksimalnu dužinu učitanog stringa. Na kraj učitanog stringa postavlja se znak '\0'. U
slučaju da linija iz koje se učitava sadrži više od maxl karaktera, linija se ne ignoriše, već se preostali
znakovi učitavaju sledećim pozivom funkcije fgets().

179
Ivan P. Stanimirović Uvod u programiranje

Razlika između funkcija gets() i fgets() je u tome da gets() zamenjuje znak za prelaz u novi red
null karakterom '\0', dok fgets() ostavlja znak za prelaz u novi red, pa tek onda postavlja znak '\0'.
Funkcija fgets() vraća vrednost NULL kada naiđe na znak EOF.
Funkcija fputs() poziva se izrazom
int fputs(char *string, FILE *outfile);
Pozivom ove funkcije upisuje se niz karaktera, sadržani u vrednosti parametra string, u datoteku na
koju ukazuje pointer outfile. U slučaju I/O greške ova funkcija vraća rezultat EOF. Funkcije puts() i
fputs() ne dopisuju karakter '\0' na kraj upisanog stringa. Za razliku od funkcije puts(), funkcija fputs()
ne dopisuje znak za prelaz u novi red na kraj stringa koji se upisuje.
fgets
Čita string iz fajla
char *fgets( char *string, int n, FILE *stream );
Vraća string inače NULL ako je greška ili je došlo do kraja fajla.
Koristiti feof ili ferror za određivanje da li je došlo do greške.
Parametri:
string Mesto za smeštanje podataka
n Maksimalni broj karaktera za čitanje
stream Pointer na FILE strukturu
Funkcija čita string sa ulaza zadatog argumentom stream i patmi ga u stringu. Čita karaktere od
tekuće pozicije u fajlu do i uključujući prvi newline karakter, do kraja fajla ili do broja karaktera
jednakog n-1, šta se prvo desi. Rezultat zapamćen u stringu je završen null karakterom. Newline
karakter ako je pročitan je uključen u string. Funkcija fgets je slična gets funkciji, mada gets zamenjuje
newline karakter sa NULL.
/* FGETS.C: This program uses fgets to display
* a line from a file on the screen.n*/
#include <stdio.h> void main( void )
{ FILE *stream;
char line[100];
if((stream = fopen("fgets.c", "r")) != NULL)
{ if(fgets(line, 100, stream) == NULL)
printf("fgets error\n");
else
printf("%s" , line);
fclose( stream );
}
}
fclose, _fcloseall
Zatvara fajl ili sve otvorene fajlove. int fclose( FILE *stream ); int _fcloseall( void );
feof

Testira end-of-file na streamu:


int feof( FILE *stream );
The feof routine (implemented both as a function and as a macro) determines whether the end
ofstream has been reached. When end of file is reached, read operations return an end-of-file indicator
until the stream is closed or until rewind, fsetpos, fseek, or clearerr is called against it.

180
Ivan P. Stanimirović Uvod u programiranje

6.10.2. Binarne datoteke

fread
Čita podatke iz streama.
size_t fread(void *buffer, size_t size, size_t count, FILE *stream );
Funkcija fread vraća broj zaista pročitanih itema, što može biti manje ili jednako parametru count ako
se desi greška ili se stigne do kraja fajla. Koristiti feof ili ferror da bi se razlikovao uzrok.
Parametri:
buffer Loakcija za podatke
size Veličina jednog itema u bajtovima
count Maximalni broj itema za čitanje stream pointer na FILE strukturu.
Funkcija čita do count itema a svaki je size bajtova sa ulaznog strima u buffer. File pointer povezan
sa streamom je povećan za broj bajtova koji je zaista pročitan. Ako je stream otvoren u tekstualnom
modu carriage return-linefeed par je zamenjen ejdnom linefeed characterom. File pointer nije određen
ako se desila greška.
fwrite
Upisuje podatke u stream.
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
fwrite vraća broj potopunih itema koji su upisani, a sve ostalo je slično funkciji fread.
Primer.
/* FREAD.C: This program opens a file named FREAD.OUT and
* writes 25 characters to the file. It then tries to open
* FREAD.OUT and read in 25 characters. If the attempt succeeds,
* the program displays the number of actual items read.
*/
#include <stdio.h>
void main()
{ FILE *stream;
char list[30];
int i, numread, numwritten;
/* Open file in text mode: */
if((stream = fopen("fread.out" , "w+t")) != NULL)
{ for ( i=0; i<25; i++ )
list[i] = (char)('z' - i);
/* Write 25 characters to stream */
numwritten = fwrite(list, sizeof(char), 25, stream);
printf("Wrote %d items\n", numwritten);
fclose(stream);
}
else printf("Problem opening the file\n");
if((stream = fopen("fread.out", "r+t" )) != NULL)
{ /* Attempt to read in 25 characters */
numread = fread(list, sizeof(char), 25, stream );
printf("Number of items read = %d\n", numread);
printf("Contents of buffer = %.25s\n", list);
fclose(stream);
}
else printf("File could not be opened\n");
}
fseek
Premešta file pointer na specificiranu lokaciju.

181
Ivan P. Stanimirović Uvod u programiranje

int fseek( FILE *stream, long offset, int origin );


Ako uspe fseek vraća inače vraća vrednost različitu od 0.
Parametri:
stream Pointer na strukturu FILE.
offset Broj bajtova od izvorišta (Number of bytes from origin).
origin Startna pozicija.
fseek funkcija pomera file pointer asociran sa streamom na novu lokaciju koja je offset bajtova od
ohgin.
Tako sledeća operacija na streamu uzima poyiciju od nove lokacije.
Argument origin mora biti jeadn od:
SEEK CUR Current position of file pointer
SEEK END End of file
SEEK_SET Beginning of file
ftell
Vraća tekuću poziciju fajl pointera. long ftell( FILE *stream );
Za rad sa tekstualnim fajlovima na raspolaganju su i funkcije pandani poznatim funkcijama prontf i
scanf.
int fprintf(
FILE *stream,
const char * format[,
argument ] . . .
)
int fscanf(
FILE *stream,
const char *format [,
argument ]...
)

Direktni pristup datotekama


Primer. U binarnoj datoteci je uređen niz od m celih brojeva, dodati prirodan broj n na
odgovarajuće mesto. Koristiti sekvencijalno pretraživanje.
#include <stdio.h>
#include <stdlib.h>

void main()
{ int niz[21], m,n,i;
FILE *f=fopen("file.txt", "w+b");
niz[0]=0;
printf("Koliko brojeva u nizu?\n"); scanf("%d",&m);
for(i=1; i<m; i++) niz[i]=niz[i-1]+2;
fwrite(niz, sizeof(int), m, f);
fclose(f);

printf("Formirana je sledeca datoteka:\n");


f=fopen("file.txt", "r+b");
fread(niz, sizeof(int), m, f);
for(i=0; i<m; i++) printf("%d ", niz[i]); printf("\n");
printf("Broj koji se umece? "); scanf("%d",&n);
i=0; while((niz[i]<n)&&(i<m)) i++;
fseek(f, i*sizeof(int), SEEK_SET);

fwrite(&n, sizeof(int), 1, f);


fwrite(niz+i, sizeof(int),m-i, f);

182
Ivan P. Stanimirović Uvod u programiranje

fclose(f); f=fopen("file.txt", "r+b");


printf("Datoteka sa umetnutim brojem %d:\n",n);
fread(niz, sizeof(int), m+1, f);
for(i=0; i<=m; i++) printf("%d ", niz[i]);
fclose(f);
}

Literatura

[1] Literatura sa predavanja.


[2] M. Čabarkapa, C, Osnovi programiranja, Biblioteka Algoritam, 2000.
[3] M. Čabarkapa, S. Matković, C/C++, Biblioteka Algoritam, Krug, Beograd, 2005.
[4] S. Stojković, Programski jezik C sa rešenim zadacima, Elektronski fakultet u Nišu, Edicija
pomoćni udžbenici, Niš, 2005.
[5] V. Vujičić, Uvod u C jezik, Univerzitet u Beogradu, Institut za nuklearne nauke “Boris Kidrič”,
Vinča, 1996.
[6] L. Kraus, Programski jezik C sa rešenim zadacima, Akademska Misao, Beograd, 2004.
[7] D. Urošević, Algoritmi u programskom jeziku C, Mikro Knjiga, Beograd, 1996.
[8] M. Vugdelija, Programiranje & Programiranje,
[9] M. Stanković, Programski jezici, Elektronski fakultet u Nišu, Edicija: osnovni udžbenici, 2000.
[10] J.J. Dujmović, Programski jezici i metode programiranja, Akademska misao, Beograd, 2003.
[11] Mike Grant, Christian Skalka, Scott Smith, Programming Languages, Version 1.01,
http://www.cs.jhu.edu/plbook, 2003.
[12] D.A. Watt, William Findlay, Programming language design concept, John Wiley & Sons Ltd.,
2004.

183
Darko Drakulić

Osnove programskog jezika C sa zbirkom zadataka


-skripta-
Rad u Code::Blocks okruženju

Da bi se napisao i izvršio program napisan na programskom jeziku C, potreban je tekst


editor u kojem će program biti napisan, kompajler i bilder koji će napisani kod kompajlirati i
prevesti u mašinski kod, razumljiv računaru. Postoji dosta aplikacija koji u sebi integrišu ove
alate i one nose zajedničko ime IDE (integrated development environment). One u sebi sadrže
pomenute alate – kod editor, kompajler ili interpreter, bilder i alat za testiranje programa
(debugger). Jedan od takvih alata je Code::Blocks IDE, open source alat koji je besplatan i
koji se može skinuti sa adrese http://www.codeblocks.org. Ovdje će ukratko biti opisano kako
napisati, kompajlirati i pokrenuti program u pomenutom alatu. Da bi se program mogao
kompajlirati i pokrenuti, sa pomenute adrese je potrebno skinuti instalaciju codeblocks-xxx-
mingw-setup koja u sebi sadrži GCC kompajler i GDB dibager. xxx predstavlja trenutnu
verziju alata.
Nakon uspješne istalacije i pokretanja programa Code::Blocks dobija se sljedeći izgled
ekrana

Slika 1

Da bi napisali i pokrenuli program u programskom jeziku C, potrebno je kreirati novi


projekat (File->ew->Project) zatim izabrati Console application (slika 2). U polju za izbor
jezika izabrati C (slika 3), i konačno dati ime projektu kao i lokaciju na koju će se kod
sačuvati (slika 4).

Slika 2.
Slika 3.

Slika 4.

Nakon ovih koraka, klikom na dugme Finish, u lijevom dijelu ekrana u dijelu Projects
pojaviće se projekat koji je kreiran, kao i datoteka (main.c) u kojoj se nalazi glavna (main)
funkcija kreiranog projekta.

Otvaranjem te datoteke, dobija se kod najprostijeg C-programa, koji na ekran ispisuje


tekst „Hello world“.
Osnove programskog jezika C

Struktura programa

Program koji Code::Blocks automatski kreira ima sljedeći kod


#include <stdio.h>
#include <stdlib.h>

int main()
{
printf("Hello world!\n");
return 0;
}

Na ovom primjeru će biti objašnjena struktura programa napisanog u programskom


jeziku C.
C je tzv. case-sensitive programski jezik, što znači da razlikuje mala i velika slova.
Naredbe return 0 i RETURN 0 su dvije različite naredbe.
Nakon svake naredbe u C-u mora se nalaziti karakter ;.
C ne poznaje razmake u kodu, tako da se prelazak u novi red nakon svake komande
vrši samo iz estetskih razloga, radi lakšeg čitanja koda.
Komentari se mogu pisati na dva načina: ukoliko se komentar nalazi u jednom redu,
dovoljno je na početak tog reda staviti karaktere //, a ukoliko se komentar nalazi u više
redova, potrebno je komentar ograničiti parovima karaktera /* i */. Primjeri komentara su

// Komentar u jednom redu


/* Komentar
u više redova */

Prva dva reda reda programa


#include <stdio.h>
#include <stdlib.h>
u postojeći kod uključuju datoteke za prevođenje, u kojma se nalaze funkcije koje su nam
potrebne za uspješno izvršavanje našeg programa. U datoteci stdio.h se nalaze funkcije za
ulaz/izlaz, a u datoteci stdlib.h se nalazi većina funkcija koje su u najčešćoj upotrebi. O
ovim funkcijama će kasnije biti više riječi.

Funkcija
int main()
je glavna funkcija programa i izvršavanje programa počinje od prve linije koda ove funkcije.
Svaki projekat mora u nekom od fajlova imati ovu funkciju. Ona može imati drugačiju
definiciju (može biti nekog drugog tipa, npr. void ili može imati listu argumenata).

Par vitičastih zagrada


{}
predstavlja granice bloka naredbi, kao begin i end u programskom jeziku PASCAL.
Posljednji red programa
return 0;
predstavlja izlaz iz glavnog programa, odnosno kraj glavnog programa. U ovom slučaju,
glavni program vraća vrijednost 0.

Red
printf("Hello world!\n");
štampa tekst „Hello world“ na ekran. Funkcija printf je definisana u datoteci stdio.h i
ona na standardni izlaz (ekran) ispisuje niz karaktera koji je njen argument. Nizovi karaktera
su ograničeni dvostrukim navodnim znacima (""). Karakter \n koji se nalazi na kraju ovog
niza je specijalni karakter koji označava novi red. Osim karaktera za novi red, postoje sljedeći
specijalni karakteri:
\t – tabulator,
\b – backspace,
\“ – dvostruki navodnici,
\\ - obrnuta kosa crta (backslash).

Promjenljive i konstante

Definisanje promjenljivih

Promjenljive su objekti koji imaju svoje ime i čija se vrijednost može mijenjati tokom
izvršenja programa.
Definisanje promjenljivih u C-u vrši se na sljedeći način:
tip_promjenljive ime_promjenljive;

Tip promjenljive mora biti neki od ugrađenih tipova u C jezik ili neki od korisnički
definisanih tipova.
Četiri osnovna tipa podataka su
int - cjelobrojni tip,
float - realni tip jednostruke tačnosti,
double - realni tip dvostruke tačnosti,
char - znakovni tip, karakter.
Iz osnovnog cjelobrojnog tipa se mogu dobiti izvedeni tipovi:
short int (short),
long int (long),
unsigned int (unsigned) – pozitivan cijeli broj.

Ime promjenljive je proizvoljan niz karaktera koji ispunjava sljedeće zahtjeve:


 ime se sastoji od karaktera, cifara i donje crte _,
 ime ne smije počinjati cifrom,
 ime ne može biti neka od rezervisanih riječi jezika C (tabela 1.)
Pravila koja važe za imena promjenljivih, važe i za imena konstanti, funkcija i korisničkih
tipova.

auto break case char const continue default do


double else enum extern float for goto if
int long register return short signed sizeof static
struct switch typedef union unsigned void volatile while
Tabela 1. Lista rezervisanih riječi programskog jezika C

Prema opisanom, sljedeće definicije promjenljivih su ispravne


int x;
char karakter;
float realni_broj1;
double realni_broj2;

Ukoliko je potrebno definisati više promjenljivih istog tipa, to se može učiniti u jednoj
naredbi. Naredba za definisanje cjelobrojnih promjenljivih x, y i z je
int x, y, z;

Definisanje alternativnih imena tipovima podataka

Da bi se definisalo alternativno ime postojećem tipu podatka koristi se ključna riječ


typedef. Sintaksa je sljedeća
typdef ime_tipa novo_ime_tipa;

Tako, npr. možemo definisati tip "cijeli_broj" i dvije promjenljive tog "novog" tipa na
sljedeći način
typedef int cijeli_broj;
cijeli_broj a;
cijeli_broj b;

Dodjela vrijednosti promjenljivima

Da bi se dodjelila neka vrijednost nekoj promjenljivoj, koristi se operator =. Naredba


za dodjelu ima oblik
ime_promjenljive = vrijednost;

Ukoliko se radi o cijelim brojevima (tip int), vrijednosti se mogu zadati u tri
različita brojna sistema. Ukoliko vrijednost počinje cifrom koja nije nula, broj se tretira kao
dekadni. Ukoliko počinje nulom, broj se tretira kao oktalni a ukoliko počinje sa 0x ili 0X broj
se tretira kao heksadekadni.
int x, y, z;
x = 123; // dekadni broj
y = 0123; // oktalni broj
z = 0x123; // heksadekadni broj

Ukoliko se radi o realnim brojevima, vrijednosti se mogu pisati samo u dekadnom


sistemu, a za decimalni zarez se koristi tačka (.). Vrijednosti se mogu i pisati u obliku oEk
(oek), gdje je o osnova a k eksponent.
float x, y, z;
x = 123;
y = 123.456;
z = 123E+2; // broj 12300

Ukoliko je promjenljiva tipa char, vrijednost mora biti jedan karakter, ograničen
jednostrukim navodnim znacima ('). Specijalni karakteri (\n, \t..) se tretiraju kao jedan
karakter, iako se, praktično sastoje od dva karaktera. Tip char je ustvari cjelobrojna
vrijednost ASCII koda karaktera.
char a, b, c, d;
a = 'a';
b = '\n';
c = '1';
d = '.';
Moguće je u istoj naredbi definisati promjenljivu i dodjeliti joj vrijednost
int x = 5;
float y = 1.2, z = 234e-1;
char c1, c2 = 'a';

Štampanje vrijednosti promjenljivih

Na početku je bilo riječi o funkciji printf koja štampa proizvoljan niz karaktera na
standardni izlaz. Ista funkcija se koristi za štampanje vrijednosti uz određene izmjene.
Funkcija ima sljedeći oblik
printf("niz_znakova_za_ispis", ime_promjenljive1, ...);

Niz znakova za ispis predstavlja niz karaktera, pri čemu se znakom % pokazuje mjesto
gdje treba da se upišu vrijednosti promjenljivih koje se nalaze iza niza znakova za ispis.
Nakon znaka % ide odgovarajuće slovo, koje zavisi od tipa promjenljive:
%d – cijelobrojni tip, zapisan u dekadnom sistemu,
%o – cijelobrojni tip, zapisan u oktalnom sistemu,
%x – cijelobrojni tip, zapisan u heksadekadnom sistemu,
%f – realni tip (float i double)
%c – karakter.

Primjeri naredbi za štampanje


printf(“%d“, x); // štampa promjenljive x u dekadnom sistemu
printf(“%f %f“, a, b); // štampa realnih promjenljivih a i b
printf(“%d %o %x“, x, x, x); /* štampa promjenljive x u
dekadnom, oktalnom i heksadekadnom sistemu */
printf(“%c“, c); // štampa vrijednosti promjenljive c tipa char

printf(“Vrijednost promjenljive x je %d“, x);

Opseg važenja promjenljivih


U jednom bloku naredbi nije dozvoljeno definisanje više promjenljivih istog imena.
Tako, na primjer, kompajliranje sljedećeg koda bi javilo grešku
{
int x;
char x;
}
dok je sljedeći kod ispravan
{
int i = 1;
{
int i = 2;
printf("Unutrasnje i = %d\n", i);
}
printf("Spoljasnje i = %d\n", i);
}
i njegovo izvršavanje daje rezultat
Unutrasnje i = 2
Spoljasnje i = 1

Veličina memorijskog prostora za promjenljive

Nakon svake definicije promjenljive, alocira se potrebna memorija za njeno čuvanje.


Veličina te memorije zavisi od tipa promjenljive, ali i sistema na kojem se program izvršava.
U C-u je ugrađen operator sizeof koji određuje veličinu promjenljive ili tipa u bajtovima.
Ukoliko se želi odštampati veličina (u bajtovima) tipa int, kod bi izgledao
int velicina = sizeof(int);
printf(“%d“, velicina);

Vrijednost se može odštampati i bez uvođenja nove promjenljive, izračunavanjem


veličine direktno u argumentu funkcije printf.
printf(“%d“, sizeof(int));

Cjelobrojne promjenljive se zapisuju u formatu potpunog komplementa, realne u


zapisu IEEE754 a karakteri u ASCII kodu. Za više informacija o ovim zapisima pogledati [?].

Primjer 1. Napisati program koji definiše dvije cjelobrojne promjenljive, dodjeljuje


im vrijednost i štampa njihov zbir.

Rješenje 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
int a, b;
a = 5;
b = 7;
int c = a+b;
printf("Zbir je %d\n", c);
return 0;
}
Rješenje 2
#include <stdio.h>
#include <stdlib.h>

int main()
{
int a = 5, b = 7;
printf("Zbir je %d\n", a+b);
return 0;
}

Primjer 2. Napisati program koji štampa veličine memorijskog prostora za osnovne


tipove podataka.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
printf("int: %d\n", sizeof(int));
printf("short: %d\n", sizeof(short));
printf("long: %d\n", sizeof(long));
printf("unsigned: %d\n", sizeof(unsigned));
printf("float: %d\n", sizeof(float));
printf("double: %d\n", sizeof(double));
printf("char: %d\n", sizeof(char));
return 0;
}

Izlaz ovog programa nam daje odgovor na veličinu osnovnih tipova u C-u
int: 4
short: 2
long: 4
unsigned: 4
float: 4
double: 8
char: 1

Konstante

Slično promjenljivima, konstante su objekti koji imaju svoje ime ali im se vrijednost
ne može mijenjati tokom izvršenja programa. Za definisanje konstanti koristi se ključna riječ
const ispred tipa i imena konstante.
const int x = 5;

Drugi način definisanja konstante je korišćenje preprocesorske direktive #define.


Ona ima oblik
#define ime_konstante vrijednost_konstante
Ova preprocesorska direktiva se piše na početku programa, ispod direktiva
#include a ove konstante se nazivaju simboličke konstante.

Učitavanje vrijednosti promjenljivih sa tastature

Jasno je da loše rješenje da se vrijednosti promjenljivim dodjeljuju u samom kodu.


Takav način dodjele zahtjeva promjenu koda svaki put kada se mijenja vrijednost
promjenljivih. Osnovna ideja je da se korisniku omogući dodjela vrijednosti promjenljivima u
toku izvršavanja programa. Za tu svrhu se koristi funkcija scanf oblika
scanf(“format“, lista_promjenljivih,...);

format i lista_promjenljivih predstavljaju argumente slične kao kod


funkcije printf. Prvi je niz karaktera koji u sebi sadrži oznaku tipa koji se unosi - % i
odgovarajuće slovo koje je identično kao kod funkcije printf. Što se tiče liste
promjenljivih, razlika u odnosu na funkcije printf je ta da se ispred svake promjenljive
mora napisati karakter &. Zašto baš on, biće objašnjeno u dijelu kada se bude govorilo o
pokazivačima i referencama.
Unos vrijednosti cjelobrojne promjenljive x i karaktera c se vrši na sljedeći način
scanf(“%d“, &x);
scanf(“%c“, &c);

Primjer 3. Napisati program koji sa tastature učitava dva cijela broja i štampa njihov
zbir.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int a, b;
scanf("%d", &a);
scanf("%d", &b);
printf("Zbir je %d\n", a+b);
return 0;
}

Operatori
Aritmetički operatori

Aritmetički operatori, kao što im samo ime govori, služe za izvršavanje aritmetičkih
operacija. Do sada je već korišćen operator sabiranja, a postoji ukupno pet aritmetičkih
operatora:
+ sabiranje,
- oduzimane,
* množenje,
/ dijeljenje,
% ostatak pri djeljenju (samo za cijele brojeve).
Svi ovi operatori su binarni, što znači da imaju dva argumenta i njihova svrha je jasna,
osim možda posljednjeg. Npr. izraz 8%3 daje ostatak pri dijeljenju broja 8 sa brojem 3, tj.
daje vrijednost 2.

Primjer 4. Napisati program koji sa tastature čita dva cijela broja i ispisuje njihov zbir,
razliku, proizvod i količnik.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int a, b;
scanf("%d", &a);
scanf("%d", &b);
printf("a + b = %d\n", a+b);
printf("a - b = %d\n", a-b);
printf("a * b = %d\n", a*b);
printf("a / b = %f\n", (float)a/b);
printf("a % b = %d\n", a%b);
return 0;
}
Svi redovi u kodu su poznati i jasni, osim
printf("a / b = %f\n", (float)a/b);
odnosno, izraza (float)a/b. U ovom izrazu se koristi tzv. cast operator.

Cast operator

U programskom jeziku C postoji ugrađena automatska konverzija tipova. To znači da


je moguće nekoj promjenljivoj dodijeliti vrijednost nekog drugog tipa. Npr. kod
int a = 5;
float b = a;
je ispravan, iako se u drugom redu promjenljivoj b tipa float dodjeljuje vrijednost
promjenljive a koja je tipa int. Tu dolazi do automatske konverzije tipa int u float. U
ovom slučaju ne postoji nikakav gubitak podataka, dok bi, recimo konverzija tipa float u
int dovela do gubitka podataka, i to cifara iza decimalnog zareza.
Moguća je i eksplicitna konverzija tipova, kada neki izraz želimo konvertovati u
odgovarajući tip. Takva konverzije je moguća korišćenjem unarnog operatora koji se naziva
cast a ima oblik
(tip) izraz;
Izraz (float)a/b je upravo konvarzija rezultata a/b u tip float. To je
neophodno jer su a i b tipa int i da nema eksplicitne konverzije, i rezultat a/b bi bio tipa
int i ne bi bio tačan.

Relacijski i logički operatori

Ovi operatori imaju isti smisao kao i u matematici. U ovu grupu operatora spadaju
> veće,
< manje,
<= veće ili jednako,
>= manje ili jednako,
== jednako (dvostruko jednako - jednostruko jednako je operator dodjele),
!= različito (! je znak negacije).
Osim ovih, u ovu grupu spadaju i logički vezinici.
&& logičko I,
|| logičko ILI.
Rezultat primjene ovih operatora je logička vrijednost koja može biti tačna ili netačna,
npr.
(x>4) && (x%2 == 0)
Ovaj izraz ispituje da li je x paran broj veći od 4.
O prioritetima operatora ovdje neće biti govora, za detaljnije pogledati [?].

Bitovni operatori

Bitovni operatori su operatori koji manipulišu sa cjelobronim tipovima podataka, na


nivou bitova. Za potpuno razumjevanje rada ovih operatora potrebno je poznavati način
zapisivanja cijelih brojeva u potpunom komplementu[?]. Postoji 6 operatora za rad s bitovima
& binarno I,
| binarno ILI,
^ binarno ekskluzivno ILI,
<< lijevi pomak (lijevi shift),
>> desni pomak (desni shift),
~ unarna negacija.

Primjer 5. Izračunati vrijednosti izraza 24&12, 17|12, 8^11, 17>>2, 21<<3,


~11.

Rješenje.
Zbog zapisa, veličina podataka će biti ograničena na 8 bitova.
00011000 = 24 00010001 = 17 00001000 = 8
00001100 = 12 00001100 = 12 00001011 = 11
&00001000 = 8 | 00011101 = 29 ^ 00000011 = 12

17 >> 2 = 00010001 >> 2 = (00)000100|01 = 00000100 = 4


21 << 3 = 00010101 << 3 = 000|10101(000) = 10101000 = 168
~11 = ~(00001011) = 11110100 = -12

Primjer 6. Napisati program koji izračunava vrijednosti izraza iz primjera 5.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
printf("24&12 = %d\n", 24&12);
printf("17|12 = %d\n", 17|12);
printf("8^11 = %d\n", 8^11);
printf("17>>2 = %d\n", 17>>2);
printf("21<<3 = %d\n", 21<<3);
printf("~11 = %d\n", ~11);
return 0;
}

Operatori uvećavanja i umanjivanja

U C-u postoje dva uobičajena operatora uvećavanja i umanjivanja za jedan. To su


operatori ++ i --. Operator inkrementiranja ++ uvećava svoj operand za jedan, dok operator
dekrementiranja -- umanjuje svoj operand za jedan.
To znači da izrazi a=a+1 i a++, odnosno a=a-1 i a-- imaju isto značenje.
Oba operatora se mogu koristiti i kao prefiksni (++a) i kao sufiksni (a++). Razlika je
što se u prefiksnom korišćenju vrijednost promjenljive a uveća prije njenog korišćenja, a u
sufiksnom obrnuto.

Operatori i izrazi dodjeljivanja vrijednosti

Slično kao kod operatora inkrementiranja i dekrementiranja, postoje skraćeni zapisi i


za operatore u kojima je promjenljiva na lijevoj strani a neki od operatora na desnoj, kakav je
i=i+2. Skraćeni zapis za ovaj izraz je i+=2.
Ovakvi skraćeni zapisi su mogući za operatore +, -, *, /, %, <<, >>, &, ^ i |.
Kontrola toka
if–else izraz

Uslovni if izraz ima sljedeći oblik


if(uslov)
naredba1;
else
naredba2;

uslov mora biti neki logički izraz. U slučaju da je uslov tačan, izvršava se
naredba1 a u suprotnom naredba2. if izraz se može pojaviti i bez else izraza. Ako je
potrebno da se izvrši više naredbi, tada je potrebno da se stave u blok, ograničen sa vitičastim
zagradama

if(uslov)
{
naredba1_1;
naredba1_2;
naredba1_3;
...
}
else
{
naredba2_1;
naredba2_2;
naredba2_3;
...
}

Primjer 7. Ispraviti rješenje primjera 4. tako da isključuje mogućnost dijeljenja nulom.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int a, b;
scanf("%d", &a);
scanf("%d", &b);
printf("a + b = %d\n", a+b);
printf("a - b = %d\n", a-b);
printf("a * b = %d\n", a*b);
if(b != 0)
printf("a / b = %f\n", (float)a/b);
else
printf("Greska! Dijeljenje nulom\n");
printf("a % b = %d\n", a%b);
return 0;
}

if–else if–else izraz

if–else naredba ima samo dvije grane – kada je uslov ispunjen i kada nije.
Međutim nekada je potrebno ispitati više uslova i u zavisnosti od njihovih vrijednosti
izvršavati određene naredbe. U tim slučajevima se koristi if-else if-else izraz, koji će
biti prikazan na sljedećem primjeru.

Primjer 8. Napisati program koji ispituje da li je uneseni broj pozitivan, negativan ili je
jednak nuli.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int x;
scanf("%d", &x);
if(x > 0)
printf("Broj je pozitivan\n");
else if(x < 0)
printf("Broj je negativan\n");
else
printf("Broj je jednak nuli\n");
return 0;
}

Operator ?

U programskom jeziku C postoji operator ? i to je jedini ternani operator, tj. ima tri
operanda. Izgled operatora je
(logicki_izraz) ? vrijednost1 : vrijednost2
Ovaj operatoj provjerava istinitost logičkog izraza i u slučaju njegove tačne vrijednosti
vraća vrijednost1 a u suprotnom vraća vrijednost2.

switch

Ovaj izraz je sličan izrazu if–else if–else i provjerava da li izraz odgovara


nekoj od konstantnih cjelobrojnih vrijednosti (ili karaktera). switch izraz ima sljedeći oblik
switch(izraz)
{
case vrijednost1:
naredbe1
break;
case vrijednost2:
naredbe2
break;
...
default:
naredbeN;
}

U slučaju da izraz ima vrijednost vrijednost1, tada se izvršavaju naredbe1, u


slučaju da ima vrijednost2 tada se izvršavaju naredbe2, a u slučaju da nema nijednu
od ponuđenih vrijednosti tada se izvršavaju naredbeN.

Primjer 9. Napisati program koji provjerava da li je uneseni karakter razmak, tačka ili
neki neki drugi znak.

#include <stdio.h>
#include <stdlib.h>

int main()
{
char c;
scanf("%c", &c);
switch(c)
{
case ' ':
printf("Uneseni karakter je razmak\n");
break;
case '.':
printf("Uneseni karakter je tacka\n");
break;
default:
printf("Uneseni karakter nije ni tacka ni
razmak\n");
}

return 0;
}

Petlje
for

Primjer 8. Napisati program koji štampa prvih 5 prirodnih brojeva.

Rješenje
U ovom programu je potrebno izvršiti 5 sličnih naredbi, tj. 5 poziva funkcije printf
sa različitim argumentima. U slučajevima kada se trebaju izvršiti slične naredbe koriste se
petlje. Jedan od načina da se riješi ovaj zadatak je sljedeći
#include <stdio.h>
#include <stdlib.h>

int main()
{
int i;
for(i=1; i<=5; i=i+1)
printf("%d\n", i);
return 0;
}

Ovdje je korišćen izraz for koji ima sljedeći oblik


for(inicijalizacija; uslov; korak)
inicijalizacija – izraz u kojem se promjenljivima dodjeljuju početne
vrijednosti,
uslov – logički izraz koji uslovljava izvršenje for petlje – petlja se izvršava sve dok
ovaj logički izraz tačan,
korak – izraz u kojem se vrši uvećavanje brojača. U prethodnom primjeru, u svakom
se izvršavanju for petlje vrijednost brojača i povećava za jedan.

Sva tri izraza u for petlji su opcioni, što znači da ne moraju postojati. Izraz
for( ; ; )
je ispravan izraz i predstavlja beskonačnu petlju.

Treba primjetiti da iza linije u kojoj se nalazi for petlja ne nalazi karakter ;. To je
zato što je kraj komande tek u sljedećem redu. Kao i kod if naredbe, ukoliko se for petlja
odnosi na više komandi, potrebno ih je ograničiti vitičastim zagradama {}.

while

while petlja ima iste osobine kao for petlja i sve što se može uraditi preko for
petlje može i preko while i obrnuto. while petlja ima sljedeći oblik
while(uslov)
{
komande...
}
Slično kao for petlja, samo što nema dijela za inicijalizaciju i korak, već se
inicijalizacija mora mora obaviti prije a korak u samoj petlji.

Primjer 9. Prethodni zadatak riješiti korišćenjem while petlje.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int i=1;
while(i<=5)
{
printf("%d\n", i);
i++;
}
return 0;
}

do-while

Kao i while petlja, samo što se kod do-while petlje prvo izvršavaju naredbe pa se
onda provjerava uslov. do-while petlja ima sljedeći oblik
do
{
komande...
} while(uslov);

Za razliku od while petlje, komande u do-while petlji će se izvršiti bar jednom.

Primjer 10. Prethodni zadatak riješiti korišćenjem do-while petlje.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int i=1;
do
{
printf("%d\n", i);
i++;
} while(i<=5);
return 0;
}

break i continue

Nekada postoji potreba izlaska iz petlje prije potpunog ispunjenja potrebnog uslova za
izlazak. Za to se koristi naredba break.

Primjer 11. Odštampati prvi broj (ako postoji) koji je manji od 500 a djeljiv sa brojevima 3, 4,
5 i 7.

Rješenje
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
for(i=1; i<=500; i++)
if(i%3 == 0 && i%4 == 0 && i%5 == 0 && i%7 == 0)
{
printf("%d\n", i);
break;
}
return 0;
}

Naredba continue je slična naredbi break, a njen poziv otpočinje sljedeću


iteraciju petlje.

Primjer 12. Odštampati sve brojeve manje od 20 koji nisu djeljivi sa brojem 3.

#include <stdio.h>
#include <stdlib.h>

int main()
{
int i;
for(i=1; i<=20; i++)
{
if(i%3 == 0)
continue;
printf("%d\n", i);
}
return 0;
}

goto i labele

C ima mogućnost rada sa labelama, ali se ne preporučuje njihovo korišćenje osim u


slučajevima kada je potrebno izaći iz više petlji odjednom, kao u sljedećem primjeru

for(...)
for(...)
{
if(...)
goto kraj;
}
...

kraj:
...
Rad sa karakterima

Kao što je već pomenuto, u programskom jeziku C tip char je ustvari cjelobrojna
vrijednost ASCII koda datog karaktera. To znači da se char može štampati i kao karakter i
kao cijeli broj
char c = 'A';
printf("%d\n", c); // štampa ASCII kod karaktera
printf("%c\n", c); // štampa izgled karaktera

Primjer 13. Napisati program koji štampa ASCII tabelu karaktera.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
char i;
for(i=1; i<127; i++)
printf("%d %c\t", i, i);

return 0;
}

Ako se pogleda ASCII tabela, vidi se da, recimo karakter 'A' ima vrijednost 65,
karakter 'B' vrijednost 66, karakter 'a' ima vrijednost 97, karakter 'b' ima vrijednost
98 itd. Tako da vrijednost izraza 'A' + 10 daje vrijednost 75 odnosno karakter 'K'.

Znakovni ulaz i izlaz

U standardnoj biblioteci, osim funkcija printf i scanf postoje funkcije koje služe
za ulaz odnosno izlaz znakovnog tipa podataka. To su funkcije getchar i putchar.
Funkcija getchar() čita jedan karakter sa standardnog ulaza (tastature) i kao
rezultat vraća njegovu ASCII vrijednost, npr. kod
char c = getchar();
čita jedan karakter sa tastature i njegovu vrijednost dodjeljuje promjenljivoj c.

Funkcija putchar(c) štampa vrijednost karaktera c na standardnom izlazu, npr


putchar(c);

Kod unosa teksta, kao indikator za kraj unosa se koristi znak za kraj datoteke, koji se
označava EOF (end of file). Ako je u pitanju unos sa tastature, znak EOF se dobija
kombinacijom tastera ctrl i z.
Primjer 14. Napisati program koji sa tastature čita karaktera sve dok se ne unese
karakter EOF i ispisuje ih na ekranu.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
char c;
int i;
while(c!=EOF)
{
c = getchar();
putchar(c);
}
return 0;
}
Riješeni zadaci

Zadatak 1. Napisati program koji za uneseno n štampa sumu prvih n prirodnih brojeva i n!

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, i, suma=0, fakt=1;
scanf("%d", &n);
for(i=1; i<=n; i++)
suma += i;
printf("Suma prvih %d je %d\n", n, suma);

for(i=1; i<=n; i++)


fakt *= i;
printf("%d! = %d\n", n, fakt);

return 0;
}

Zadatak 2. Odštampati sve djelioce unesenog broja.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, i;
scanf("%d", &n);

for(i=1; i<=n; i++)


if (n%i == 0)
printf("%d ", i);

return 0;
}

Zadatak 3. Odštampati sve savršene brojeve manje od 10000 (broj je savršen ako je jednak
zbiru svojih djelilaca, osim sebe samog).
Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, i,suma;

for(n=1; n<10000; n++)


{
suma = 0;
for (i=1; i<n; i++)
if (n%i == 0)
suma+=i;

if (suma==n)
printf("broj %d je savrsen\n", n);
}

return 0;
}

Zadatak 4. Napisati program koji za uneseni prirodni broj štampa zbir njegovih cifara.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, suma = 0;
scanf("%d", &n);
while(n > 0)
{
suma += n % 10; // sa n%10 se dobija posljednja cifra
n /= 10;
}
printf("%d", suma);
return 0;
}

Zadatak 5. Napisati program koji za uneseni prirodan broj ispisuje broj čije su cifre u
obrnutom redoslijedu.
Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, obrnuti = 0;
scanf("%d", &n);
while(n > 0)
{
obrnuti = obrnuti*10 + n % 10;
n /= 10;
}
printf("%d", obrnuti);
return 0;
}

Zadatak 6. Izračunati kvadratni korjen datog broja Njutnovom metodom sa zadatom tačnosti.

Rješenje
1 æç xö
Njutnova formula glasi yi +1 = y i + ÷ , gdje je x broj za koji se traži korjen, a
2è yi ø
početna iteracija y 0 = x + 1 . Za rješavanje ovog zadatka potrebna je funkcija koja računa
apsolutnu vrijednost datog broja. To je funkcija abs(float) koja je definisana u datoteci
math.h1.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
float x, y, z, eps;
scanf("Unesite broj i tacnost: ");
scanf("%f", &x);
scanf("%f", &eps);
y = x+1;
do
{
z = y;
y = .5 * (y + x/y);
} while(abs(z-y) > eps);
printf("Korjen iz %.2f je %f", x, y);
return 0;
}

1
Pregled načajnijih funkcija standardne biblioteke je prikazano u dodatku A
Zadatak 7. Napisati program koji simulira rad kalkulatora sa osnovnim operacijama +, -, *,
/. Izraz se unosi u obliku operator operand1 operand2.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
float op1,op2;
char op;
scanf ("%c", &op);
scanf ("%f", &op1);
scanf ("%f", &op2);
printf("izraz: %.2f %c %.2f\n",op1,op,op2);

switch(op)
{
case '+':
printf("vrijednost: %.2f\n", op1 + op2);
break;
case '-':
printf("vrijednost: %.2f\n", op1 - op2);
break;
case '*':
printf("vrijednost: %.2f\n", op1 * op2);
break;
case '/':
if (op2 == 0)
printf("Greska! Dijeljenje nulom\n");
else
printf("vrijednost: %.2f\n", op1 / op2);
break;
default:
printf("Greska! Pogresan operator\n");
}
return 0;
}

Zadatak 8. Napisati program koji pronalazi rješenja kvadratne jednačine ax 2 + bx + c = 0

Rješenje
Za rješavanje ovog zadatka potrebna je funkcija koja računa kvadratni korjen datog
broja, a to je funkcija sqrt(float) koja je definisana u datoteci math.h
Moguća su tri slučaja – jednačina nema realna rješenja (D<0), ima dvostruko rješenje
(D=0) i ima dva različita rješenja (D>0).
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
float a, b, c;
scanf("%f", &a);
scanf("%f", &b);
scanf("%f", &c);
printf("Jednacina: %.2f*x^2 + %.2f*x + %.2f\n", a, b, c);

float D = b*b - 4*a*c;


if(D < 0)
printf("Rjesenja nisu realna\n");
else if(D == 0)
{
float x = -b/(2*a);
printf("Jednacina ima jedno dvostruko rjesenje x =
%.2f\n", x);
}
else
{
float x1 = (-b + sqrt(D))/(2*a);
float x2 = (-b - sqrt(D))/(2*a);
printf("Rjesenja su x1=%.2f, x2=%.2f\n", x1, x2);
}

return 0;
}

Zadatak 9. Napisati program koji ispituje da li se dvije prave y=a1x+b1 i y=a2x+b2 sijeku.

Rješenje
Moguća su tri slučaja – prave su paralelne, prave se poklapaju ili se sijeku u jednoj
tački.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
float a1,a2,b1,b2;
scanf ("%f",&a1);
scanf ("%f",&b1);
scanf ("%f",&a2);
scanf ("%f",&b2);
printf("y =%5.2fx + %5.2f\n",a1,b1);
printf("y =%5.2fx + %5.2f\n",a2,b2);
if (a1 == a2 && b1== b2)
printf ("prave se poklapaju\n");
else if (a1 == a2 && b1 != b2 )
printf ("prave su paralelne\n");
else
{
float x=(b2-b1)/(a1-a2);
float y=a1*x+b1;
printf ("prave se sijeku u tacki
(%5.2f,%5.2f)\n",x,y);
}

return 0;
}

Zadatak 10. Podaci o krugovima se sastoje od koordinata centra i dužine poluprečnika.


Napisati program koji ispituje u kom su položaju dati krugovi.

Rješenje
Moguća su tri slučaja. Da se krugovi ne sijeku (udaljenost među centrima je veća od
zbira poluprečnika), da se dodiruju (udaljenost među centrima je jednaka zbiru poluprečnika)
i da se dijeku (udaljenost među centrima je manja od zbira poluprečnika).

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
int x1,x2,y1,y2,r1,r2;
scanf ("%d", &x1);
scanf ("%d", &y1);
scanf ("%d", &r1);
scanf ("%d", &x2);
scanf ("%d", &y2);
scanf ("%d", &r2);

float d = sqrt((x2-x1)*(x2-x1)+ (y2-y1)*(y2-y1));

if (d>r1+r2)
printf ("kruznice se ne sijeku");
else if (d<r1+r2)
printf ("kruznice se sijeku");
else
printf ("kruznice se dodiruju");

return 0;
}
Zadatak 11. Napisati program koji za uneseno n štampa romb čija je dužina stranice n, kao na
slici (na slici n=2)
*
* *
*

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, i, j, k;
scanf("%d", &n);
for(i=1; i<=n; i++)
{
for(k=n; k>i; k--)
printf(" ");
for(j=0; j<i; j++)
printf("* ");
printf("\n");
}
for(i=n-1; i>0; i--)
{
for(k=n; k>i; k--)
printf(" ");
for(j=0; j<i; j++)
printf("* ");
printf("\n");
}

return 0;
}

Zadatak 12. Napisati program koji štampa sve trocifrene brojeve kod kojih je druga cifra za
dva veća od prve a treća za jedan veća od druge.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int i, j, k;
for(i=1; i<=9; i++)
for(j=3; j<=9; j++)
for(k=4; k<=9; k++)
if(j == i+2 && k == j+1)
printf("%d%d%d\n", i, j, k);
return 0;
}

Zadatak 13. Napisati program koji uneseno mali slovo pretvara u veliko.

Rješenje
Ideja: vrijednost između malog slova i njemu odgovarajućeg velikoj je konstantna za
sva slova.
#include <stdio.h>
#include <stdlib.h>

int main()
{
char maliC;
scanf("%c", &maliC);

char velikiC = maliC - ('a' - 'A');


printf("%c", velikiC);

return 0;
}

Zadatak 14. Napisati program koji za uneseni karakter provjerava da li je malo slovo, veliko
slovo, cifra ili neki drugi karakter.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
char c;
scanf("%c", &c);

if(c >= 'A' && c <= 'Z')


printf("Uneseni karakter je veliko slovo\n");
else if(c >= 'a' && c <= 'z')
printf("Uneseni karakter je malo slovo\n");
else if(c >= '0' && c <= '9')
printf("Uneseni karakter je cifra\n");
else
printf("Uneseni karakter nije slovo ni cifra\n");

return 0;
}

Zadatak 15. Napisati program koji sa tastature čita karaktera sve dok se ne unese karakter
EOF i broji unesenie samoglasnike i suglasnike.
Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
char c;
int i, suglasnici=0, samoglasnici=0;
while(c!=EOF)
{
c = getchar();
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
if(c == 'a' || c == 'e' || c == 'i' || c == 'o'
|| c == 'u' || c == 'A' || c == 'E' || c == 'I' || c == 'O' ||
c == 'U')
samoglasnici++;
else
suglasnici++;
}
printf("Samoglasnika: %d, suglasnika: %d", samoglasnici,
suglasnici);

return 0;
}
Zadaci za vježbu

å2
n
k 2
1. Napisati program koji za uneseno n izračunava sumu
k =1
¥
2. Napisati program koji za zadatu tačnost eps izračunava broj e = å
1
k = 0 k!
m
3. Napisati program koji za unesene n i m računa broj n (bez korišćenja funkcije
pow) .
æ nö
4. Napisati program koji za uneseno n i m (n > m) računa ç ÷
è mø
5. Napisati program koji učitava n, zatim učitava n brojeva i izračunava njihovu
aritmetičku sredinu.
6. Napisati program koji određuje za koliko procenata je porasla cijena C1 ako ona
sad iznosi C2.
7. Napisati program koji izračunava sumu i proizvod dva kompleksna broja x1+iy1 i
x2+iy2
8. Napisati program koji računa zbir, razliku i proizvod razlomaka a/b i c/d.
9. Napisati program koji za uneseno n izračunava n-ti stepen kompleksnog broja,
korišćenjem De Moavrove formule3
10. Napisati program koji učitava brojeve m i n i pravi Dekartov proizvod skupova
{1,2,...,n} i {1,2,...,m}.
11. Napisati program koji za uneseno n ispisuje trougao kao na slici (na slici n=3)
1
22
333
12. Napisati program koji za uneseno n štampa kvadrate brojeva 1, 2, ... , n-1.
13. Napisati program koji za uneseno x izračunava vrijednost y po formuli
ì 1
,x > 0
ï x
y =í 0, x = 0
1
ï- , x < 0
î x
14. Napisati program koji izračunava aritmetičku sredinu cifara datog broja.
15. Napisati program koji u datom četverocifrenom broju izračunava razliku između
prve i poslednje cifre.
16. Napisati program koji za unesene n i m (m<n) izračunava sumu posljednjih m
cifara broja n.
17. Napisati program koji za unesene n i m učitava n brojeva i izračunava aritmetičku
sredinu brojeva koji su veći od m.
18. Napisati program koji učitava broj m i zatim učitava brojeve sve dok im suma ne
pređe m.
19. Napisati program koji za n unijeti cijelih brojeva računa zbir negativnih.
20. Napisati program koji za uneseno n računa n-ti član Fibonačijevog niza
21. Napisati program koji za unesena tri cijela broja ispisuje najveći.

2
Za funkciju stepenovanja pogledati dodatak A
3
Za funkcije sin i cos pogledati dodatak A
22. Napisati program koji za unesena tri cijela broja ispituje da li čine Pitagorinu
trojku.
23. *Napisati program koji nalazi NZD za dva broja korišćenjem Euklidovog
algoritma.
1 1
24. *Napisati program koji za uneseno n izračunava 1 + + ... +
2 n
25. Napisati program koji za uneseno n učitava n brojeva i određuje najveći i najmanji
među njima.
26. Napisati program koji rješava jednačinu ax+b=0.
27. Napisati program koji ispituje da li je prava y=kx+n tangenta parabole y2=2px
(vrijednosti k, n i p se unose sa tastature).
28. Napisati program koji ispituje da li se sijeku prava y=kx+n i kružnica x2+y2=r2
(vrijednosti k, n i r se unose sa tastature).
29. Napisati program koji ispituje da li je vrijednost polinoma 2x3+x2-2x+1 pozitivna
ili negativna u tački n koja se unosi sa tastature.
30. Napisati program koji ispituje da li je uneseni broj Armstrongov. Amrstrongov
broj je jednak zbiru kubova svojih cifara.
31. Napisati program koji ispituje da li je uneseni broj Nivenov. Nivenov broj je broj
koji je djeljiv sumom svojih cifara.
32. Napisati program koji učitava broj b i osnovu o < 10 i zatim ispisuje broj o u
dekadnom brojnom sistemu.
33. Napisati program koji izračunava površinu pravougaonika čije su stranice
paralelne koordinatnim osama, a zada je preko dijagonalnih tjemena (x1, y1) i (x2,
y2)
34. Napisati program koji ispituje da li tačke A(x1, y1), B(x2, y2), C(x3, y3) i D(x4, y4)
čine paralelogram ABCD.
35. Napisati program koji štampa kvadrant u kojem se nalazi tačka (x1, y1).
36. Napisati program koji učitava vrijednost n (n < 180) i ispituje da li je ugao od n
stepeni oštar, prav ili tup.
37. Napisati program koji računa maksimim za unesena četiri broja.
38. Napisati program koji ispituje da li tri unesene duži mogu da naprave trougao
(koristiti nejednakost trougla).
39. Napisati program koji računa površinu trougla datog preko svojih tjemena (x1, y1),
(x2, y2), (x3, y3) (koristiti Heronov obrazac).
40. Napisati program koji provjerava da li je uneseni karakter slovo, tačka ili razmak.
41. Napisati program koji za uneseni broj n ispisuje n-ti dan u nedjelji (npr. za 1 se
ispisuje „Ponedjeljak“.
42. Napisati program koji provjerava da li tri cijela broja koja se unose sa tastature h,
m i s čine ispravno vrijeme (h:m:s).
43. Napisati program koji provjerava da li tri cijela broja koja se unose sa tastature d,
m i g čine ispravan datum (d.m.g).
44. Napisati program koji za uneseni broj n ispisuje n-ti mjesec u godini.
45. Napisati program koji provjerava da li je unesena godina prestupna.
46. Napisati program koji ispisuje ocjenu koju je student dobio na ispitu na osnovu
osvojenih bodova (5 – od 0 do 50, 6 – od 51 do 60 itd).
Funkcije

Do sada je bilo riječi o funkcijama. Pominjane su funkcije za ulaz/izlaz (printf,


scanf, getchar, putchar...), matematičke funkcije (fabs, sqrt, sin, cos...) itd.
Moguće je da korisnici sami definišu funkcije koje su im neophodne za izvršavanje programa.
Deklaracija funkcije izgleda
tip_funkcije ime_funkcije(lista_argumenata...)

tip_funkcije predstavlja tip rezultata kojeg funkcija vraća. To može biti bilo koji
od standarnih ili korisnički definisanih tipova programskog jezika C ili tip void
ime_funkcije je proizvoljan identifikator funkcije za koje važe ista pravila kao i
za davanje imena promjenljivima
lista_argumenata je niz od nijednog, jednog ili više argumenata funkcije. Svaki
argument mora imati svoje ime i tip. U slučaju da postoji više argumenata svaki novi
je potrebno odvojiti zarezom od prethodnog.

Primjeri deklaracija funkcija


int funkcija();
float funkcija1(int x);
void funkcija2(intx, char y, float z);

Osim deklaracije funkcije potrebno je definisati šta ta funkcija radi. Definicija funkcije
se piše u bloku naredbi ograničenim {}. Npr. za prvu funkciju bi to izgledalo
int funkcija()
{
Tijelo funkcije
...
}

Deklaracija funkcije mora biti iznad main() funkcije, dok definicija može biti i
ispod, ali u prostijim programima je lakše napisati definiciju funkcije odmah iza deklaracije.

U definiciji funkcije mora postojati (osim eventualno u funkcijama tipa void)


naredba koja prekida izvršavanje funkcije i vraća njenu vrijednost. To je naredba return.

Funkcija za sabiranje dva realna broja bi izgledala


float saberi(float x, float y)
{
float rezultat = x+y;
return rezultat;
}

Pozivu ove funkcije je potrebno kao argumente zadati dva realna broja a ona kao
rezultat vraća njihov zbir
float rezultat = saberi(2.4, 3.5);

U slučaju da je funkcija tipa void, ona ne vraća nikakv rezultat. Ukoliko je potrebno
izaći iz te funkcije, može se pozvati komanda return bez vrijednosti iza nje.
Bitno je napomenuti da kod ovakvog definisanja funkcija argumenti ne mijenjaju
svoje vrijednosti nakon poziva funkcije, tj. njihova vrijednost ostaje nepromjenjena. U
sljedećem programu vrijednost promjenljive n ostaje nepromjenjena u nakon pozova funkcije
f, iako se u funkciji vrijednost argumenta uvećava za jedan.
void f(int n)
{
n++;
}

int main()
{
int n = 1;
f(n);
printf("%d\n", n);
return 0;
}

Primjer 15. Napisati funkciju koja izračunava faktorijel datog broja.

Rješenje
int faktorijel(unsigned int broj)
{
int i, fakt=1;

for(i=1; i<=broj; i++)


fakt *= i;
return fakt;
}

Primjer 16. Napisati funkciju koja ispituje da li je dati broj prost.

Rješenje
int prost(unsigned int broj)
{
int i;
for(i=2; i<broj; i++)
if(broj % i == 0)
return 0;

return 1;
}

Obzirom da u C-u ne postoji logički tip, ukoliko se radi o nekoj funkciji koja treba da
vrati vrijednost tačno/netačno, kao što je slučaj sa ovom, tada je ona tipa int i vraća 1 ako
treba da vrati tačno a 0 ako treba da vrati netačno.
Iz tog razloga ova funkcija je tipa int i u zavisnosti od (ne)ispunjenja uslova vraća se
vrijednost 0 ili vrijednost 1.
Primjer 17. Napisati program koji štampa sve proste brojeve manje od 1000.

Rješenje
Ovdje ćemo iskoristiti funkciju iz prethodnog primjera. Za svaki broj od 1000
pozivanjem funkcije iz prethodnog primjera ćemo ispitati da li je prost.

#include <stdio.h>
#include <stdlib.h>

int prost(unsigned int broj)


{
int i;
for(i=2; i<broj; i++)
if(broj % i == 0)
return 0;
return 1;
}

int main()
{
int i;
for(i=1; i<=1000; i++)
if(prost(i) == 1)
printf("%d\t", i);

return 0;
}

Primjer 18. Napisati program koji ispisuje sve brojeve manje od 500 koji su Nivenovi i
Armstrongovi.

Rješenje
Kod zadataka koji su kompleksniji, najlakše je problem razbiti na podprobleme i za
svaki od njih uvesti funkciju. Ovdje će biti uvedene četiri funkcije – za računanje sume cifara
datog broja, za računanje sume kubova cifara datog broja i funkcija koje ispituju da li je broj
Nivenov odnosno Armstrongov.

#include <stdio.h>
#include <stdlib.h>

int sumacifara(int n)
{ //
int suma = 0 ;
for ( ; n>0; n/=10)
suma += n%10;
return suma;
}

int sumakubova(int n)
{
int suma = 0 ;
for ( ; n>0; n/=10)
suma += pow(n%10, 3);
return suma;
}

int nivenov(int n)
{
if(n % sumacifara(n) == 0)
return 1;
return 0;
}

int armstrongov(int n)
{
if(n == sumakubova(n))
return 1;
return 0;
}

int main()
{
int i;
for(i=1; i<=500; i++)
if(armstrongov(i) && nivenov(i))
printf("%d\t", i);

return 0;
}

Rekurzija

U programskom jeziku C moguće je pisati rekurzivne funkcije. To znači da funkcija


može pozivati samu sebe, bilo direktno ili indirektno. Kod rekurzivnih funkcija bitno je
obezbijediti izlaz iz rekurzije, tj. uslov u kojem se rekurzija prekida.

Primjer 19. Napisati rekurzivnu funkciju koja izračunava faktorijel datog broja.

Rješenje
Funkcija faktorijela se rekurzivno može predstaviti kao f(n) = n*f(n-1) sa
početnim uslovom f(1) = 1.
int faktorijel(unsigned int n)
{
if(n == 1)
return 1;
return n*faktorijel(n-1);
}

Primjer 20. Napisati rekurzivnu funkciju koja štampa prvih n prirodnih brojeva u
obrnutom redoslijedu.

Rješenje
void stampa(unsigned int n)
{
if(n == 0)
return;
printf("%d\n", n);
stampa(n-1);
}

Nizovi

Deklaracija niza u programskom jeziku C ima sljedeći oblik


tip_niza ime_niza[maksimalna_veličina]
Sljedeće deklaracije nizova su ispravne
int niz_cijelih_brojeva[10];
int niz_realnih_brojeva[5];
char niz_karaktera_brojeva[15];
Elementima niza se pristupa preko njihovih indeksa koji se navode u uglastim
zagradama iza imena niza, s tim što prvi element niza ima indeks nula. Tako, prvom elementu
niza iz prošlog primjera ćemo dodijeliti neki vrijednost na sljedeći način
niz_cijelih_brojeva[0] = vrijednost;
Inicijalizacija elemenata niza može se izvršiti pri samoj deklaraciji niza tako što se
nakon deklaracije niza u uglu vitičastih zagrada navedu vrijednosti elementa niz. Izraz
int niz[5] = {1, 2, 3, 4, 5};
deklariše niz od pet elemenata čije su početne vrijednosti 1, 2, 3, 4 i 5, odnosno dobija se niz
promjenljivih
int niz[0] = 1;
int niz[1] = 2;
int niz[2] = 3;
int niz[3] = 4;
int niz[4] = 5;

U radu s nizovima, ondnosno njihovim indeksima prirodno se nameće korišćenje for


petlji, pri čemu se brojači petlje koriste za indekse u nizu. U takvim petljama brojači idu od 0
do duzina_niza–1.
Sljedeći primjer pokazuje kako deklarisati niz od 10 cijelih brojeva, učitati mu
vrijednosti elemenata sa tastature i odštampati ih
int niz[10], i;
for(i=0; i<10; i++)
scanf(“%d“, &niz[i]);
for(i=0; i<10; i++)
printf(“%d “, niz[i]);

U C se mogu na sličan način definisati i višedimenzioni nizovi, samo je potrebno pri


deklaraciji niza navesti veličine svake od dimenzija. Dovodimenzioni niz cijelih brojeva
dimenzija 2x2 bi definisali na sljedeći način
int dvo_niz[2][2];
Indeksi višedimenzionalnih nizova imaju iste osobine kao i kod jednodimenzionih.
Primjer 21. Učitati niz sa tastature i izračunati aritmetičku sredinu elemenata, i minimalni i
maksimalni element.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int a[10], i, suma=0, min, maks;
for(i=0; i<10; i++)
scanf("%d", &a[i]);
min = maks = a[0];

for(i=0; i<10; i++)


{
suma += a[i];
min = (a[i] < min) ? a[i] : min;
maks = (a[i] > maks) ? a[i] : maks;
}

printf("Artimeticka sredina je %.2f\n", (float)suma/10);


printf("Minimalni element %d\n", min);
printf("Maksimalni element %d\n", maks);

return 0;
}

Primjer 22. Učitati niz sa tastature dvije matrice 3x3 pronaći njihov zbir i odštampati ga na
ekranu.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int mat1[3][3], mat2[3][3], zbir[3][3];

int i, j;
printf("Unesite elemente matrice 1\n");
for(i=0; i<3; i++)
for(j=0; j<3; j++)
scanf("%d", &mat1[i][j]);

printf("Unesite elemente matrice 2\n");


for(i=0; i<3; i++)
for(j=0; j<3; j++)
scanf("%d", &mat2[i][j]);
printf("Zbir matrica je\n");
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
printf("%d ", mat1[i][j] + mat2[i][j]);
printf("\n");
}

return 0;
}

Primjer 23. Napisati rekurzivnu i iterativnu funkciju koja izračunava n-ti član (n < 20)
Fibonačijevog niza.

Rješenje:
n-ti član Fibonačijevog niza zadat je rekurentnom relacijom fn = fn-1 + fn-2.

int fib_rek(int n)
{
if(n > 20)
{
printf("Greska! n mora biti manje od 20\n");
return -1;
}
if(n == 1 || n == 2)
return 1;
return fib_rek(n-1) + fib_rek(n-2);
}

int fib_iter(int n)
{
if(n > 20)
{
printf("Greska! n mora biti manje od 20\n");
return -1;
}

int niz[20], i;
niz[0] = niz[1] = 1;
for(i=2; i<20; i++)
niz[i] = niz[i-1] + niz[i-2];
return niz[n];
}

Nizovi karaktera

U programskom jeziku C, nizovi karaktera se ponašaju drugačije od nizova brojeva.


Na kraju svakog niza karaktera se automatski dodaje karakter '\0' koji predstavlja kraj niza.
Tako niz karaktera “abcd“ u C se predstavlja kao [a,b,c,d,\0].
Ova činjenica nam omogućava da koristimo nizove karaktera, čak i kada ne znamo
njihovu dužinu, kretanjem kroz niz sve dok se ne dođe do karaktera '\0'.
Osim toga, niz karaktera se može unijeti i štampati u cjelini, a ne element po element
kao nizovi brojeva. Konverzija za niz karaktera je %s.
Sljedeći primjer pokazuje kako sa tastaure možemo učitati niz karaktera i odrediti mu
dužinu
char niz[10];
scanf(“%s“, &niz);
int i, duzina = 0;
for(i=0; niz[i] != '\0'; i++)
duzina++;
printf(“%d“, duzina);

Nizovi kao argumenti funkcija

Ukoliko želimo da definišemo funkciju koja za argument ima niz, niz kao argument
funkcije možemo prenijeti na jedan od sljedećih načina
tip_funkcije f1(tip_niza ime_niza[]);
tip_funkcije f2(tip_niza* ime_niza);

Funkcija koja računa dužinu niza karaktera izgledala bi


int duzina(char niz[])
{
int i, duzina = 0;
for(i=0; niz[i] != '\0'; i++)
duzina++;
return duzina;
}

Kada je niz argument funkcije, vrijednost elemenata se može promjeniti u funkciji, za


razliku od argumenata osnovnih tipova. Nakon izvršavanja sljedećeg programa vrijednost
elemenata niza postaju 2 i 3.
void f(int a[])
{
a[0]++;
a[1]++;
}

int main()
{
int niz[2] = {1, 2};
f(niz);
printf("%d\n%d", niz[0], niz[1]);
return 0;
}

Razlozi za ovo biće objašnjeni kada se bude govorilo o pokazivačima.

Primjer 24. Napisati funkciju koja dopisuje jedan niz karaktera na drugi.
Rješenje
#include <stdio.h>
#include <stdlib.h>

void prepis(char prvi[], char drugi[], char rezultat[])


{
int i, j=0;
for(i=0; prvi[i] != '\0'; i++)
rezultat[j++] = prvi[i];
for(i=0; drugi[i] != '\0'; i++)
rezultat[j++] = drugi[i];
rezultat[j] = '\0';
}

int main()
{
char prvi[10], drugi[10], rezultat[20];
scanf("%s", &prvi);
scanf("%s", &drugi);
prepis(prvi, drugi, rezultat);
printf("%s", rezultat);
return 0;
}
Riješeni zadaci

Zadatak 16. Napisati funkciju koja provjerava da li dat niz karaktera predstavlja ispravan
hekdasecimalni broj u obliku #broj i funkciju koja pretvara dati niz karaktera koji predstavlja
heksadekadni broj u dekadni.
Rješenje:
Radi lakšeg rješavanja ovog zadatka, uvešćemo pomoćne funkcije koje ispituju da li
dati karakter predstavlja cifru, slovo između a i f i slovo između A i F. U rješenju se koristi
funkcija strlen(char s[]) biblioteke string.h4 koja vraća duzinu niza karaktera s i
koja je analogna funkciji int duzina(char s[]).
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

int cifra(char c)
{
if(c >= '0' && c <= '9')
return 1;
return 0;
}

int slovoa_f(char c)
{
if(c >= 'a' && c <= 'f')
return 1;
return 0;
}

int slovoA_F(char c)
{
if(c >= 'A' && c <= 'F')
return 1;
return 0;
}

int ispravan(char hex[])


{
if(hex[0] != '#')
return 0;
int i;
for(i=1; hex[i] != '\0'; i++)
if(cifra(hex[i]) == 0 && slovoa_f(hex[i]) == 0 &&
slovoA_F(hex[i]) == 0)
return 0;
return 1;
}

4
Opis datoteke string.h dat je u dodatku A
int hexudek(char hex[])
{
int i, rez = 0;
int d = strlen(hex);
for(i=1; hex[i] != '\0'; i++)
{
if(cifra(hex[i]) == 1)
rez += (hex[i] - '0') * (int) pow(16, d-i-1);
else if(slovoa_f(hex[i]) == 1)
rez += (hex[i] - 'a' + 10) *
(int) pow(16, d-i-1);
else
rez += (hex[i] - 'A' + 10) *
(int) pow(16, d-i-1);
}
return rez;
}

int main()
{
char niz[10];
scanf("%s", &niz);
if(ispravan(niz) == 0)
printf("Broj nije ispravan\n");
else
printf("%s = %d", niz, hexudek(niz));
return 0;
}

Zadatak 17. Sa tasture se unosi niz karaktera oblika <broj1><operator><broj2>, pri


čemu su broj1 i broj2 dvocifreni brojevi a operator +, -, * ili /. Napisati program koji učitava
niz karaktera, ispituje da li je ispravan izraz i izračunava vrijednost unesenog izraza.

Rješenje
U programu ćemo koristiti ugrađenu funkciju isdigit(char c) koja je definisana
u datoteci ctype.h5 koja ispituje da li je dati karakter cifra i analogna je funkciji
cifra(char c) iz prethodnoh zadatka.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int ispravan(char izraz[])


{
if(!isdigit(izraz[0]) || !isdigit(izraz[1])
|| !isdigit(izraz[3]) || !isdigit(izraz[4]))
return 0;
if(izraz[2] != '+' && izraz[2] != '-'
&& izraz[2] != '*' && izraz[2] != '/')
return 0;

5
Opis datoteke ctype.h dat je u dodatku A
return 1;
}

int main()
{
char izraz[5];
scanf("%s", &izraz);
if(ispravan(izraz) == 0)
{
printf("Izraz nije ispravan!\n");
return -1;
}

int broj1 = (izraz[0] - '0') * 10 + (izraz[1] - '0');


int broj2 = (izraz[3] - '0') * 10 + (izraz[4] - '0');

printf("%s = ", izraz);


switch(izraz[2])
{
case '+':
printf("%d", broj1 + broj2);
break;
case '-':
printf("%d", broj1 - broj2);
break;
case '*':
printf("%d", broj1 * broj2);
break;
case '/':
printf("%.2f", (double)broj1 / broj2);
break;
}
return 0;
}

Zadatak 18. Napisati program koji sa tastature učitava polinom (stepen < 10 i koeficijente),
štampa ga na ekran, učitava vrijednost v i štampati vrijednost polinoma u tački v.
Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
float koef[11];
int stepen, i;
printf("Unesite stepen polinoma:");
scanf("%d", &stepen);

for(i=0; i<=stepen; i++)


{
printf("Unesite koeficijent a[%d]: ", i);
scanf("%f", &koef[i]);
}

printf("P(x) = ");
for(i=0; i<=stepen; i++)
printf("%.2f*x^%d + ", koef[i], i);
printf("\n");

float v, vr = 0;
printf("Unesite vrijednost v: ");
scanf("%f", &v);

for(i=0; i<=stepen; i++)


vr += koef[i] * pow(v,i);

printf("P(%.2f) = %.2f\n", v, vr);

return 0;
}

Zadaci za vježbu

1. Sa ulaza se unosi osnova <= 10 i broj. Provjeriti da li je taj broj ispravan broj za datu
osnovu i ako jeste izračunati njegovu vrijednost u osnovi 10.
2. Sa ulaza se unosi broj u osnovi deset i osnova <= 10. Odštampati vrijednost datog
broja u datoj osnovi
3. Napisati program koji sa tastature čita broj n (najviše 100), niz od n cijelih brojeva i
vrijednost n a zatim provjerava da li je v u nizu, na kom je mjestu i koliko u nizu ima
brojeva manjih od n
4. Za dati niz realnih brojeva ispitati da li je „testerast“ (niz je testarast ako važi
x1<x2>x3<x4>... ili x1>x2<x3>x4<...)
5. Napisati program koji ispisuje sve proste brojeve manje od 10000 koristeći
Eratostenovo sito.
6. Zadatu matricu ispisati spiralno, u smjeru kazaljke na satu, počevši od A11.*
7. Napisati program koji učitava dvije realne kvadratne matrice (prvo dimenzije pa
elemente, najviše 10x10) i ispisuje njihov proizvod.
8. Napisati program koji učitava dva polinoma i ispiruje nihov proizvod.
9. Napirati program koji izračunava n-ti stepen datog polinoma.
10. Napirati program koji izračunava n-ti izvod datog polinoma.
11. Napisati rekurzivnu funkciju koja ispisuje romb čija je dužina stranice n, kao na slici
(na slici n=2)
*
* *
*
12. Napisati program koji sa tastature učitava broj n i štampa sve permutacije tih n
elemenata.
13. Napisati funkciju koja dati realni broj prevodi u odgovarajući niz karaktera, npr.
123.123 u „123,123“
14. Napisati funkcije koje ispituju da li su sva niza karaktera jednaka i da li su jednaki na
prvih n mjesta (ne koristiti datoteku string.h)
15. Napisati funkciju koja koja dati niz karaktera razbija na dva niza karaktera date
dužine.
16. Data su dva niza karaktera. Ispitati da li je drugi niz karaktera podniz prvog.
17. Data su dva niza karaktera. Napisati program koji pravi novi niz karaktera koji se
sastoji od karaktera koji se pojavljuju u oba niza.
18. Data su dva niza karaktera. Napisati program koji pravi novi niz karaktera koji se
sastoji od karaktera koji se pojavljuju u prvom, a ne pojavljuju se u drugom nizu.
19. Napisati program koji vrši šifrovanje ulaznog teksta: svako slovo sa ulaza zamjenjuje
se sa slovom koje je na tri mjesta udaljeno od njega u abecedi.
20. Napisati funkciju koja na osnovu date reči formira šifru koja se dobija tako što se
svako slovo u riječi zameni sa naredna tri slova koja su mu susedna u abecedi. Na
primer, reč "tamo" treba da bude zamenjena sa "uvwbcdnoppqr".
21. Napisati program koji u datom tekstu uklanja sve višestruke razmake.
22. Napisati program koji iz datog teksta štampa riječi (neprekidne nizove karaktera).
Svaka riječ treba da se nalazi u novom redu.
23. Napisati funkcije koje dati niz slova pretvara u mala, odnosno u velika slova.
24. Napisati program koji radi s dvodimenzionim matricama koristeći nizove (učitavanje,
štampa i sabiranje)
25. Napisati funkciju koja provjerava da li je data matrica simetrična
26. Napisati funkciju koja provjerava da li je data matrica magični kvadrat (magični
kvadrat je kadratna matrica kod koje je suma brojeva u svakom redu i koloni jednaka)
27.
a. Napisati funkciju koja za datu matricu računa transponovanu matricu
b. Napisati funkciju koja provjerava da li je data matrica jedinična
28. Za datu matricu ispitati da li je ortogonalna (matrica je ortogonalna ako važi
A·AT = E)
Pokazivači

Osnovni tipovi koji su do sada korišćeni sadrže vrijednosti promjenljivih. Pokazivači


su promjenljive koja sadrže memorijsku adresu promjenljive. Za razumjevanje principa rada
pokazivača potrebno je poznavati osnovne principe organizacije memorije računara.
Memorija je, ustvari, niz lokacija u koje možemo upisivati vrijednosti ili iz kojih možemo
čitati vrijednosti. Svaka lokacija predstavlja prostor u koji se može zapisati jedan bajt (osam
binarnih cifara) ima svoju adresu. Tako se tip char može zapisati na jednu memorijsku
lokaciju, int na četiri i double na osam lokacija (o veličini osnovnih tipova je bilo govora
u dijelu o tipovima podataka).
Da bi se dobila adresa nekog objekta koristi se unarni operator &.

Sljedeći kod prikazuje kako odštampati adresu neke promjenljive x.


int x;
printf("Adresa promjenljive: %x", &x);

U principu, vrijednost same adrese nas i ne zanima, ali pomoću ovoga možemo
provjeriti jednu važnu činjenicu vezanu za alokaciju memorije za nizove.

Primjer 24. Napisati program koji štampa memorijske lokacije članova niza od 10 cijelih
brojeva.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int niz[10], i;
for(i=0; i<5; i++)
printf("Adresa clana %d: %d\n", i, &niz[i]);

return 0;
}

Rezultat izvršavanja ovog programa izgleda ovako6:


Adresa clana 0: 2293520
Adresa clana 1: 2293524
Adresa clana 2: 2293528
Adresa clana 3: 2293532
Adresa clana 4: 2293536
Adresa clana 5: 2293540
Adresa clana 6: 2293544
Adresa clana 7: 2293548
Adresa clana 8: 2293552
Adresa clana 9: 2293556

Ovo nam pokazuje da se elementi niza u memoriji nalaze na susjednim lokacijama, tj.
drugi element se nalazi iza lokacije na kojoj se nalazi prvi itd.
6
Rezultat ovog programa neće biti uvijek isti, moguće je da se razlikuju vrijednosti adresa.
Ako u kodu pokušamo odštampati vrijednost promjenljive „niz“, tj.
printf("Vrijednost promjenljive \"niz\": %d\n", niz);
dobićemo
Vrijednost promjenljive "niz": 2293520
Ovim je pokazano, da je promjenljiva koja označava niz, ustvari pokazivač koji
pokazuje na prvi element niza.

Da bi se definisala promjenljiva koja sadrži pokazivač na neki tip, potrebno je iza tipa
promjenljive dodati znak *. Tako dobijamo četiri tipa pokazivača, na svaki od osnovnih
tipova:
char*
int*
float*
double*

Potrebno je napomenuti da ako u jednom redu definišemo više pokazivača, potrebno je


ispred imena svakog od njih dodati *. Tako, npr. kod
int *a, *b;
definiše dva pokazivača tipa int, a kod
int *a, b;
definiše promjenljivu a koja je pokazivač tipa int i promjenljivu b koja je tipa int.

Kada definišemo pokazivač (promjenljivu pokazivačkog tipa) u nju možemo smjestiti


adresu neke promjenljive. Sljedeći kod pokazuje kako se pokazivaču p može dodjeliti adresa
objekta x.
int x = 5;
int* p = &x;

Izrazom p=&x promjenljivoj p se dodjeljuje adresa promjenljive x i ukoliko


pristupamo promjenljivoj p mi ustvari pristupamo adresi na kojoj se nalazi promjenljiva x,
odnosno adresi gdje se nalazi njena vrijednost. Ukoliko želimo da pristupimo vrijednosti na
koju pokazuje pokazivač p, moramo koristiti unarni operator dereferenciranja *. U kodu
printf("%d\n", p);
printf("%d\n", *p);
prvi red štampa adresu na koju p pokazuje, a drugi red štampa vrijednost koja se
nalazi u memoriji na koju pokazuje p (tj. vrijednost 5).

Nakon ovoga, postaje jasno šta je karakter & ispred imena promjenljive u funkciji
scanf - funkcija za argument ima adresu promjenljive a ne njenu vrijednost. Razlozi za to
biće detaljno objašnjeni u dijelu u kojem će se govoriti o pokazivačima kao argumentima
funkcija.

Dinamička alokacija memorije


Kada se pokazivač definiše, on ne sadrži adresu lokacije kojoj možemo pristupiti i da
bi radili sa njim neophodno je dodjeliti mu adresu neke lokacije. Pokazivaču može biti
dodjeljena adresa neke već postojeće promjenljive ili mu se može dodjeliti adresa neke
lokacije u memoriji. Da bi mogli pristupati toj adresi neophodno je alocirati memoriju na toj
lokaciji, tj. "reći" operativnom sistemu tu memorijsku lokacija dodjeljuje programu koji se
izvršava. Ova operacija se naziva dinamička alokacija memorije, i ona se vrši u vrijeme
izvršavanja programa. Kod korišćenja "nepokazivačkih" tipova se ne vrši dinamička
alokacija, tj. automatski se alocira potreban prostor za memorisanje promjenljivih i nakon
završetka izvršavanja program se taj prostor oslobađa.
Da bi se memorija dinamički alocirala, koristi se funkcija
void *malloc(size_t size);

Ova funkcija ima jedan argument, a to je veličina memorijskog prostora koji se


alocira, u bajtima. Rezultat funkcije je pokazivač na alociranu memoriju ili NULL pokazivač
ukoliko je alokacija nemoguća. Obzirom da se ovom funkcijom alokacija vrši za sve tipove
pokazivača, njen rezultat je tipa void*, pa ja potrebno da se uradi cast-ovanje rezultata u
potreban tip.
Definisanje pokazivača na cijeli broj i alokacija memorije na koju on pokazuje
izgledaće
int *p = (int*) malloc(sizeof(int));

Obzirom da veličina tipova nije ista na svim sistemima, dobra praksa je da se pri
alokaciji koristi operator sizeof o kojem je ranije bilo govora.
U opštem slučaju, definisanje pokazivača i alokacija memorije za proizvoljan tip
podataka izgleda
TIP *p = (TIP*) malloc(sizeof(TIP));
pri čemu TIP može biti bilo koji od osnovnih ili korišnički-definisanih tipova.

Nakon izvršenja programa koji koristi dinamičku alokaciju memorije ta memorija se


ne oslobađa automatski. Da bi program bio potpuno ispravan, potrebno je tu memoriju ručno
osloboditi. Ukoliko se to ne učini, program će raditi bez grešaka, ali će nakon izvršavanja
programa dinamički alocirana memorija ostati zauzeta. Ovaj problem je poznat kao "curenje
memorije" ili ne engleskom "memory leak". Da bi se dealocirala memorija na koju pokazuje
neki pokazivač koristi se funkcija
void free(void *pointer);
pri čemi je pointer pokazivač na memorijsku alokaciju koju želimo dealocirati.
Funkcije malloc i free se uvijek trebaju pojavljivati u paru, tj. koliko imamo fukncija
malloc, moramo imati toliko i funkcija free.

Primjer 25. Napisati program koji sa tastature čita dva broja i ispisuje njihov zbir na ekranu.
Memoriju za brojeve alocirati dinamički.
Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int *p1, *p2;
p1 = (int*) malloc(sizeof(int));
p2 = (int*) malloc(sizeof(int));
scanf("%d", p1);
scanf("%d", p2);
printf("%d + %d = %d", *p1, *p2, *p1 + *p2);
free(p1);
free(p2);
return 0;
}
U ovom primjeru u funkciji scanf ne postoji karakter & ispred imena promjenljivih,
jer su promjenljive p1 i p2 pokazivači, pa oni u sebi sadrže adrese - a to je upravo ono šta
funkcija scanf očekuje za argument.

Nizovi i pokazivači

Dosadašnje korišćenje pokazivača i nije bilo tako efektno, tj. za svaku promjenljivu
smo morali definisati pokazivač i alocirati potrebnu memoriju a to se automatski dešava kada
ne koristimo pokazivače. Pokazivači pokazuju svoju snagu i svrsishodnost korišćenja kada je
potrebno alocirati memoriju za nizove. Do sada je svaki niz imao ograničenu veličinu - pri
definisanju niza smo navodili maksimalnu veličinu koliku niz može da ima. Ovo je loše iz dva
razloga. Prvi od njih je postojanje mogućnosti da je korisniku potreban veći niz, a drugi
razlog je da postoje memorijske lokacije koje alociramo bez potrebe. Nrp. ako definišemo niz
od maksimalno 100 elemenata, našem korisniku može zatrebati niz od više elemenata, ili pak,
korisniku je možda potreban niz od samo nekoliko elemenata pri čemu svi ostali elementi
zazumaju memoriju bez potrebe.
Pokazivači omogućavaju i dinamičku alokaciju nizova, tačnije omogućavaju alokaciju
memorije za proizvoljan niz u toku izvršavanja programa. Osobina niza da mu se svi elementi
nalaze jedan za drugim i da je ime promjenljive koja označava niz ustvari pokazivač na prvi
element omogućava vrlo laku alokaciju memorije za nizove.
Dovoljno je definisati pokazivač određenog tipa i alocirati onoliko memorije koliko je
potrebno za smještanje cijelog niza. U opštem slučaju, alokacija memorije za niz od n
elemenata niza proizvoljnog tipa izgleda
TIP* niz = (TIP*) malloc(sizeof(TIP)*n);
pri čemu TIP može biti bilo koji od osnovnih ili definisanih tipova.

Sa ovako definisanim nizom se radi kao i sa "običnim" nizovima - moguće je


indeksiranje članova niza pri čemu prvi element niza ima indeks nula.

Primjer 26. Napisati program koji sa tastature čita proizvoljan broj n, zatim definiše niz od n
cijelih, učitava elemente niza i pronalazi im aritmetičku sredinu.
Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, i;
scanf("%d", &n);
int *niz = (int*) malloc(sizeof(int)*n);
for(i=0; i<n; i++)
scanf("%d", &niz[i]);

double zbir=0.0;
for(i=0; i<n; i++)
zbir += niz[i];

printf("%3.2f", zbir/n);
free(niz);
return 0;
}

Članovima niza je moguće pristupati i drugačiji način - preko operatora +. Ukoliko


imamo neku promjenljivu p koja je pokazivačkog tipa i na nju primjenimo operator + sa
argumentom n, kao rezultat dobićemo memorijsku lokaciju koja se nalazi na
(n*veličina_tipa) mjesta od mjesta na koje pokazuje pokazivač p. Prostije, ako imamo
pokazivač koji pokazuje na neki niz, elementi niza se nalaze na memorijskim lokacijama
niz+1, niz+2, ...
a vrijednosti elemenata niza na lokacijama
*(niz+1), *(niz+2), ...

Primjer 27. Napisati program koji sa tastature čita proizvoljan broj n, zatim definiše niz od n
realnih brojeva, učitava i štampa elemente niza pristupajući im preko njihovih adresa.
Rješenje
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n, i;
scanf("%d", &n);
float *niz = (float*) malloc(sizeof(float)*n);
for(i=0; i<n; i++)
scanf("%f", niz+i);

for(i=0; i<n; i++)


printf("%.2f ", *(niz+i));

free(niz);
return 0;
}

Pokazivači kao argumenti funkcija

Do sada je bilo govora da funkcija scanf za argument zahtjeva adresu promjenljive,


a ne njeno ime (odnosno vrijednost), dok recimo funkcija printf zahtjeva ime (vrijednost) a
ne adresu. Koja je razlika?

Funkciji se argumenti mogu proslijediti na dva načina - po vrijednosti i po adresi.

U prvom slučaju se kao argument funkcije zadaje ime promjenljive a funkciji se


prosljeđuje vrijednost te promjenljive. Funkcija radi sa vrijednosću promjenljive i ne postoji
način da izmjeni stvarnu vrijednost promjenljive. Sljedeći kod
int x = 5;
f(x);
se tumači kao:
- promjenljiva x ima vrijednost 5
- funkcija f se poziva sa argumentom 5, tj. f(5) i daje rezultat.
Pri prenosu adrumenata po adresi funkciji se prosljeđuje adresa promjenljive i funkcija
barata sa adresom na kojoj se nalazi promjenljiva. U tom slučaju stvarna vrijednost
promjenljive se može promjeniti nakon izvršavanja funkcije.

Sljedeći primjer to najbolje ilustruje:


#include <stdio.h>
#include <stdlib.h>

void fv(int x)
{
x++;
}

void fa(int* x)
{
(*x)++;
}

int main()
{
int x = 5;

fv(x);
printf("%d\n", x);

fa(&x);
printf("%d\n", x);

return 0;
}
Funkcija fv za argument dobija vrijednost promjenljive x, tj. broj 5 i ona ustvari samo
tu vrijednost povećava za jedan dok vrijednost promjenljive x ostaje 5 i nakon izvršavanja
funkcije fv. Funkcija fa za argument dobija adresu promjenljive x i komandom (*x)++ se
povećava za jedan vrijednost koja se nalazi na lokaciji x, tj. mijenja se stvarna vrijednost
promjenljive x.
Poziv prve funkcije ne mjenja vrijednost promjenljive x, a poziv druge je mijenja.
Rezultat izvršavanja ovog programa je
5
6

Ova osobina se naziva bočni efekat ili side-effect jer omogućava mjenjanje vrijednosti
promjenljivih kroz pozivanje funkcija. Ova osobina omogućava da funkcija vrati više od
jedne vrijednosti. Potrebno je u glavnom programu definisati promjenljive, proslijediti
funkciji njihove adrese i nakon izvršavanja programa u tim promjenljivima dobijamo
određene rezultate.

Primjer 27. Napisati funkciju koja za dati niz nalazi minimum, maksimum i aritmetičku
sredinu.
Rješenje
#include <stdio.h>
#include <stdlib.h>

void mmas(int* niz, int d, int* min, int* max, float* as)
{
int i, suma = 0;
int mi=niz[0], ma=niz[0];
for(i=0; i<d; i++)
{
if(mi > niz[i])
mi = niz[i];
if(ma < niz[i])
ma = niz[i];
suma += niz[i];
}
*as = (float) suma / d;
*min = mi;
*max = ma;
}

int main()
{
int niz[5] = {4, 2, 8, 6, 1};
int min, max;
float as;

mmas(niz, 5, &min, &max, &as);

printf("Minimalni elemenat: %d\n", min);


printf("Maksimalni elemenat: %d\n", max);
printf("Aritmeticka sredina: %f\n", as);

return 0;
}

Kada su opisivani nizovi kao argumenti funkcija rečeno je da kada je niz argument
funkcije, vrijednost elemenata niza se može promjeniti u funkciji. Sada je jasno i zašto - ime
niza je, ustvari, pokazivač na prvi elemenat niza, pa je argument ustvari adresa prvog
elementa a to omogućava i mijenjanje vrijednosti niza.

Strukture

Struktura je skup jedne ili više promjenljivih koje su grupisane radi lakše manipulacije
sa njima. Sintaksa definisanja strukture je
struct ime_strukture
{
tip1 ime1;
tip2 ime2;
...
};
Definicijom strukture se, ustvari, definiše tip imena struct ime_strukture i u
programu se mogu praviti promjenljive ovoga tipa. Svaka promjenljiva ovog tipa se sastoji od
skupa promjenljivih koje su definisane u strukturi. Tim promjenljivim se pristupa preko
operatora tačka (.) i sa njima se radi kao sa običnim promjenljivim.

Primjer 28. Napisati strukturu za čuvanje podataka o tačkama u ravni, funkciju za štampanje
tačke i funkciju za izračunavanje udaljenosti između dvije tačke.
Rješenje
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct tacka
{
float x;
float y;
};

double udaljenost(struct tacka t1, struct tacka t2)


{
return sqrt((t1.x-t2.x)*(t1.x-t2.x) + (t1.y-t2.y)*(t1.y-
t2.y));
}

void odstampaj(struct tacka t)


{
printf("(%.2f, %.2f)\n", t.x, t.y);
}

int main(int argc, char *argv[])


{
struct tacka t1, t2;

scanf("%f", &t1.x);
scanf("%f", &t1.y);
scanf("%f", &t2.x);
scanf("%f", &t2.y);

odstampaj(t1);
odstampaj(t2);

printf("d = %.2f\n", udaljenost(t1, t2));

system("PAUSE");
return 0;
}

U praksi se najčešće definiše tip koji predstavlja tip strukture, da se ne bi svaki put
morala navoditi ključna riječ struct. Tako bi npr. u prošlom primjeru mogli definisati tip
Tacka pomoću ključne riječi typedef:
typedef struct tacka Tacka;
i onda bi koristili tip Tacka umjesto struct tacka. Korišćenjem ovog novog
naziva tipa možemo definisati dvije promjenljive tipa tačka na sljedeći način:
Tacka t1, t2;

Još kraći zapis je da se pri definiciji strukture definiše i tip, u prošlom primjeru bi to
izgledalo
typedef struct tacka
{
float x;
float y;
} Tacka;

Pokazivači na strukture

Kao i na svaki drugi tip, možemo definisati pokazivač i na strukturu. Sintaksa je


identična kao sa ostalim tipovima, jedina razlika je u načinu pristupanja članovima strukture.
Kod običnih promjenljivih operator pristupa članovima je tačka (.) a kod pokazivača
članovima se pristupa preko operatora minus veće (->). Korišćenje strukture iz prošlog
primjera preko pokazivača izgledalo bi
Tacka *p = (Tacka*) malloc(sizeof(Tacka));
p->x = 10.0;
p->y = 5.0;
odstampaj(*p);
free(p);

Zadaci za vježbu
Algoritmi sortiranja i pretrage
Binarna pretraga
Primjer 29. Napisati funkciju koja pretražuje dati neopadajući niz pomoću algoritma binarne
pretrage
Rješenje
int BinPretraga(int* niz, int d, int x)
{ // Iterativna binarna pretraga
int lijevi = 0;
int desni = d-1;
while(lijevi <= desni)
{
int m = (lijevi+desni) / 2;
if(x == niz[m])
return m;
else if(x < niz[m])
desni = m-1;
else
lijevi = m+1;
}
return -1;
}

int BinPretragaR(int* niz, int lijevi, int desni, int x)


{ // Rekurzivna binarna pretraga
if(lijevi >= desni)
return -1;
int m = (lijevi + desni) / 2;
if(x < niz[m])
return BinPretragaR(niz, lijevi, m, x);
else if(x > niz[m])
return BinPretragaR(niz, m, desni, x);
else
return m;
}

Bubble sort
Primjer 30. Napisati funkciju koja dati niz sortira pomoću algoritma Bubble sort
Rješenje
void SortBubble(int* niz, int duzina)
{
int i, j;
for(i=0; i<duzina; i++)
for(j=i; j<duzina; j++)
if(niz[i] > niz[j])
{
int x = niz[i];
niz[i] = niz[j];
niz[j] = x;
}
}

Sortiranje umetanjem
Primjer 31. Napisati funkciju koja dati niz sortira pomoću algoritma sortiranja umetanjem.
Rješenje
void SortUmetanje(int* a, int d)
{ // Osnovna varijanta sortiranja umetanjem
int i, j;
for(i=1; i<d; i++)
{
int x = a[i];
j = i-1;
while(j>0 && x > a[j])
{
a[j+1] = a[j];
j = j-1;
}
a[j+1] = x;
}
}

void SortBinUmetanje(int* a, int d)


{ // Poboljsana varijanta, pri cemu se binarnom pretraga
pronalazi mjesto na koje se umece elemenat
int i, j;
for(i=1; i<d; i++)
{
int x = a[i];
int lijevi = 0;
int desni = i-1;
while(lijevi <= desni)
{
int m = (lijevi+desni) / 2;
if(x < a[m])
desni = m-1;
else
lijevi = m+1;
}
for(j=i-1; j>=lijevi; j--)
a[j+1] = a[j];
a[lijevi] = x;
}
}

Sortiranje izborom
Primjer 32. Napisati funkciju koja dati niz sortira pomoću algoritma sortiranja izborom.
Rješenje
void SortIzborom(int* a, int d)
{ // Varijanta 1
int i, j, indexNajmanjeg;
for(i=0; i<d-1; i++)
{
indexNajmanjeg = i;
int najmanji = a[i];
for(j=i+1; j<d; j++)
{

if(a[j] < najmanji)


{
indexNajmanjeg = j;
najmanji = a[j];
}
}
a[indexNajmanjeg] = a[i];
a[i] = najmanji;
}
}

void SortIzborom1(int* a, int d)


{ // Varijanta 2
int i, j, indexNajmanjeg;
for(i=0; i<d-1; i++)
{
indexNajmanjeg = i;
for(j=i+1; j<d; j++)
if(a[j] < a[indexNajmanjeg])
indexNajmanjeg = j;
int najmanji = a[indexNajmanjeg];
a[indexNajmanjeg] = a[i];
a[i] = najmanji;
}
}

QuickSort
Primjer 33. Napisati funkciju koja dati niz sortira pomoću algoritma QuickSort.
Rješenje
void swap(int v[], int i, int j)
{
int temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}

void QuickSort(int v[], int lijevi, int desni)


{
int i, zadnji;

if (lijevi >= desni)


return;
swap(v, lijevi, (lijevi + desni)/2);
zadnji = lijevi;
for (i = lijevi + 1; i <= desni; i++)
if (v[i] < v[lijevi])
swap(v, ++zadnji, i);
swap(v, lijevi, zadnji);
QuickSort(v, lijevi, zadnji-1);
QuickSort(v, zadnji+1, desni);
}

MergeSort
Primjer 34. Napisati funkciju koja dati niz sortira pomoću algoritma MergeSort.
Rješenje
void Merge(int* a, int d1, int d2)
{ // Funkcija koja spaja dva podniza tako da se dobije
sortirani niz
int* novi = (int*) malloc(sizeof(int) * (d1+d2));
int i=0, j1=0, j2=0;

while(j1 < d1 && j2 < d2)


novi[i++] = (a[j1] <= a[d1+j2]) ? a[j1++] :
a[d1+j2++];
while(j1 < d1)
novi[i++] = a[j1++];
while(j2 < d2)
novi[i++] = a[d1+j2++];

for(i=0; i<d1+d2; i++)


a[i] = novi[i];

free(novi);
}

void SortMerge(int* a, int d)


{ // Funkcija koja sortira niz
if(d>1)
{
int d1 = d/2;
int d2 = d - d1;
SortMerge(a, d1);
SortMerge(a+d1, d2);
Merge(a, d1, d2);
}
}

U svakom algoritmu sortiranja niz koji se sortira može biti proizvoljan: niz cijelih
brojeva, niz realnih brojeva, niz karaktera ili pak niz promjenljivih nekog korisnički
definisanog tipa. Jedini uslov je da postoji kriterijum po kojem se elementi niza mogu
upoređivati.
Primjer 35. Podaci o vektoru se sastoje od koordinata x, y i z. Napisati strukturu za čuvanje
podataka o vektoru. Sa tastature učitati broj n a zatim učitati n vektora i sortirati ih po
intenzitetu korišćenjem sortiranja umetanjem.

#include <stdio.h>
#include <stdlib.h>

typedef struct v
{ float x;
float y;
float z;
}vektor;

void ucitaj(vektor *niz,int d)


{
int i;

for(i=0;i<d; i++)
{
scanf("%f", &niz[i].x);
scanf("%f", &niz[i].y);
scanf("%f", &niz[i].z);
}
}

void ispisi(vektor *niz,int d)


{
int i;
for(i=0;i<d; i++)
printf("(%.2f, %.2f, %.2f) ", niz[i].x, niz[i].y,
niz[i].z);
}

float intenzitet(vektor v)
{
return (float) sqrt(v.x*v.x+v.y*v.y+v.z*v.z);
}

void sort(vektor* a, int d)


{
int i, j;
for(i=1; i<d; i++)
{
vektor x = a[i];
j = i-1;
while(j>0 && intenzitet(x) < intenzitet(a[j]))
{
a[j+1] = a[j];
j = j-1;
}
a[j+1] = x;
}
}

int main()
{
int n;
scanf("%d", &n);
vektor *niz=(vektor*)malloc(sizeof (vektor)*n);
ucitaj(niz,n);

sort(niz,n);

ispisi(niz,n);

free(niz);
return 0;
}
Stek i red

Stek je struktura podataka koja predstavlja kontejner promjenljivih istog tipa. Nad
stekom su definisane dvije operacije: push (dodaj) i pop (ukloni). Osobina steka je da se
posljednje dodat elemenat prvi uklanja sa steka. Zato se stek naziva LIFO (last-in-first-out)
struktura podataka.
Ovdje će biti prikazana dva načina implementacije steka - statički, preko niza
unaprijed definisane maksimalne dužine i dinamički - preko pokazivača na strukturu koja
predstavlja jedan elemenat steka. Stek se sastoji od elemenata koji međusobno čine povezanu
listu, kao na slici.

El1 El2 El3 NULL

Svaki član liste se sastoji od nekog podatka i pokazivača na sljedeći član liste.
Posljednji član pokazuje na NULL

Primjer 36. Napisati program koji omogućava rad sa stekom cijelih brojeva.

Rješenje - statičko, preko niza


#include <stdio.h>
#include <stdlib.h>
#define MAXVALUE 100

int stek[MAXVALUE];
int brElem = 0;

void Push(int v)
{
if(brElem == MAXVALUE)
{
printf("Stek je pun\n");
return;
}
stek[brElem++] = v;
printf("Dodaje se element %d\n", v);
}

void Pop()
{
if(brElem == 0)
{
printf("Stek je prazan\n");
return;
}
printf("Uklanja se element %d\n", stek[brElem--]);
}

void Print()
{
int i;
printf("Stek: ");
for(i=0; i<brElem; i++)
printf("%d ", stek[i]);
printf("\n");
}

int main()
{
Push(5);
Push(10);
Push(0);
Print();
Pop();
Print();
return 0;
}

Rješenje - dinamičko, preko pokazivača na strukturu


#include <stdio.h>
#include <stdlib.h>

typedef struct el
{
int v;
struct el* sljedeci;
} Elem;

Elem* stek;

void Push(int v)
{
Elem* novi = (Elem*) malloc(sizeof(Elem));
novi->v = v;
novi->sljedeci = stek;
stek = novi;
printf("Dodaje se element %d\n", v);
}

void Pop()
{
if(stek == NULL)
{
printf("Stek je prazan\n");
return;
}
int v = stek->v;
Elem* prvi = stek;
stek = stek->sljedeci;
free(prvi);
printf("Uklanja se element %d\n", v);
}
void Print()
{
Elem* t = stek;
printf("Stek: ");
while(t != NULL)
{
printf("%d ", t->v);
t = t->sljedeci;
}
putchar('\n');
}

int main()
{
Push(5);
Push(7);
Push(6);
Print();
Pop();
Print();
Push(1);
Print();
return 0;
}

Primjer 37. Napisati program koji omogućava rad sa redom cijelih brojeva.
Red je slična struktura steku, s tim da se iz reda uklanja onaj element koji je prvi došao
u red, zato se red naziva FIFO (first-in-first-out) struktura. Red će se implementirati na dva
načina kao i stek.

Rješenje - statičko, preko niza


#include <stdio.h>
#include <stdlib.h>
#define MAXVALUE 100

int red[MAXVALUE];
int brElem = 0;

int Push(int v)
{
if(brElem == MAXVALUE)
{
printf("Red je pun\n");
return;
}
red[brElem] = v;
brElem++;
printf("Dodaje se element %d\n", v);
}
void Pop()
{
if(brElem == 0)
{
printf("Red je prazan\n");
return -1;
}
int v = red[0];
int i;
for(i=0; i<brElem; i++)
red[i] =red[i+1];
brElem--;
printf("Uklanja se element %d\n", v);
}

void Print()
{
int i;
printf("Red: ");
for(i=0; i<brElem; i++)
printf("%d ", red[i]);
printf("\n");
}

int main(int argc, char *argv[])


{
Push(3);
Push(6);
Push(4);
Print();
Pop();
Print();
return 0;
}

Rješenje - dinamičko, preko pokazivača na strukturu


#include <stdio.h>
#include <stdlib.h>

typedef struct el
{
int v;
struct el* sljedeci;
} Elem;

Elem* red;

void Push(int v)
{
Elem* novi = (Elem*) malloc(sizeof(Elem));
novi->v = v;
novi->sljedeci = red;
red = novi;
printf("Dodaje se element %d\n", v);
}

void Pop()
{
if(red == NULL)
printf("Red je prazan\n");
else if(red->sljedeci == NULL)
{
int v = red->v;
free(red->sljedeci);
red = NULL;
}
else
{
Elem *e = red;
while(e->sljedeci->sljedeci != NULL)
e = e->sljedeci;
int v = e->sljedeci->v;
free(e->sljedeci);
e->sljedeci = NULL;
printf("Uklanja se element %d\n", v);
}
}

void Print()
{
Elem* t = red;
printf("Red: ");
while(t != NULL)
{
printf("%d ", t->v);
t = t->sljedeci;
}
putchar('\n');
}

int main()
{
Push(5);
Push(7);
Push(6);
Print();
Pop();
Print();

return 0;
}
Jednostruko povezane liste

Implementacija steka i reda preko pokazivača na strukture predstavljaju jedno


koriščenje jednostruko povezane liste. Jednostruko povezana lista može imati mnogo više
operacija osim dodavanja elementa i uklanjanja elementa s vrha (kod steka), odnosno sa dna
(kod reda). U jednostruko povezanoj listi se može uklanjati elemenat s proizvoljne pozicije u
listi, može se vršiti pretraga liste, vršiti ubacivanje elemenata tako da lista bude sortirana po
nekom kriterijumu itd. Ovdje će biti prikazane implementacije nekih od ovih operacija.

Primjer 38. Napisati program koji omogućava rad sa jednostruko povezanim listama čiji su
elementi parovi (kljuc, vrijednost). Implementirati funkcije za dodavanje elementa u listu (na
proizvoljno mjesto), pretragu liste po ključu i štampu elemenata liste.
Rješenje
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct el
{
int kljuc;
char vrijednost[10];
struct el* sljedeci;
} Elem;

Elem* lista = NULL;

void dodaj(Elem* e, int k, char* v)


{
Elem *novi = (Elem*) malloc(sizeof(Elem));
novi->kljuc = k;
strcpy(novi->vrijednost, v);
novi->sljedeci = lista;
lista = novi;
}

void pronadji(Elem* e, int k)


{
if(e == NULL)
{
printf("Ne postoji element sa kljucem %d\n", k);
return;
}
else if(k == e->kljuc)
{
printf("Vrijednost s kljucem %d: %s\n", k,
e->vrijednost);
return;
}
else
pronadji(e->sljedeci, k);
}

void odstampaj(Elem* e)
{
if(e == NULL)
{
printf("---Kraj liste---\n");
return;
}
printf("%d %s\n", e->kljuc, e->vrijednost);
odstampaj(e->sljedeci);
}

void oslobodi_memoriju(Elem* e)
{
if(e == NULL)
return;
Elem *n = e->sljedeci;
free(e);
oslobodi_memoriju(n);
}

int main()
{
dodaj(lista, 3, "tri");
dodaj(lista, 2, "dva");
dodaj(lista, 6, "sest");
dodaj(lista, 4, "cetiri");
odstampaj(lista);

pronadji(lista, 6);
pronadji(lista, 12);

oslobodi_memoriju(lista);

return 0;
}

Primjer 39. Napisati program koji omogućava rad sa jednostruko povezanim listama čiji su
elementi parovi (kljuc, string). Implementirati funkcije za dodavanje elementa u listu tako da
lista bude sortirana po ključu i funkciju za izbacivanje elementa iz liste sa zadatim ključem
kao i štampu elemenata liste.
Rješenje
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct el
{
int kljuc;
char string[10];
struct el* sljedeci;
} Elem;

Elem* lista = NULL;

void dodaj(Elem* e, int k, char* s)


{
if(lista == NULL)
{ // lista je prazna
Elem* novi = (Elem*) malloc(sizeof(Elem));
novi->kljuc = k;
strcpy(novi->string, s);
novi->sljedeci = NULL;
lista = novi;
return;
}
else if(k < lista->kljuc)
{ // element koji se dodaje ide na prvo mjesto
Elem* novi = (Elem*) malloc(sizeof(Elem));
novi->kljuc = k;
strcpy(novi->string, s);
lista = novi;
novi->sljedeci = e;
return;
}
else if(e->sljedeci == NULL)
{ // dodaje se na posljednje mjesto u listi
Elem* novi = (Elem*) malloc(sizeof(Elem));
novi->kljuc = k;
strcpy(novi->string, s);
novi->sljedeci = NULL;
e->sljedeci = novi;
return;
}
else if(k < e->sljedeci->kljuc)
{
Elem* novi = (Elem*) malloc(sizeof(Elem));
novi->kljuc = k;
strcpy(novi->string, s);
novi->sljedeci = e->sljedeci;
e->sljedeci = novi;
return;
}
else
dodaj(e->sljedeci, k, s);
}

void izbaci(Elem* e, Elem* p, int k)


{
if(e == NULL)
{
printf("Lista je prazna!\n");
return;
}
else if(k == lista->kljuc)
{
Elem* e = lista;
lista = lista->sljedeci;
free(e);
return;
}
else if(k == e->kljuc)
{
p->sljedeci = e->sljedeci;
free(e);
return;
}
else if(e == NULL)
{
printf("Ne postoji element sa zadatim kljucem!\n");
return;
}
else
izbaci(e->sljedeci, e, k);
}

void odstampaj(Elem* e)
{
if(e == NULL)
{
printf("---Kraj liste---\n");
return;
}
printf("%d %s\n", e->kljuc, e->string);
odstampaj(e->sljedeci);
}

void oslobodi_memoriju(Elem* e)
{
if(e == NULL)
return;
Elem *n = e->sljedeci;
free(e);
oslobodi_memoriju(n);
}

int main()
{
dodaj(lista, 3, "tri");
dodaj(lista, 2, "dva");
dodaj(lista, 6, "sest");
dodaj(lista, 4, "cetiri");
dodaj(lista, 1, "jedan");
dodaj(lista, 8, "osam");
dodaj(lista, 9, "devet");
dodaj(lista, 7, "sedam");
dodaj(lista, 5, "pet");
odstampaj(lista);
izbaci(lista, NULL, 6);
odstampaj(lista);
izbaci(lista, NULL, 1);
odstampaj(lista);
izbaci(lista, NULL, 9);
odstampaj(lista);
oslobodi_memoriju(lista);

return 0;
}

Grafovi

Graf se definiše kao uređeni par G=(V,E), gde je V konačan, neprazan skup čvorova, a
E je skup grana (veza između čvorova).
Osnovni pomjovi vezani za graf su:
Stepen čvora grafa je broj grana koje uparuju taj čvor.
Dve grane su susjedne ako imaju isti čvor.
Grana koja spaja čvor sa samim sobom naziva se petljom.
Graf koji nema nijednu petlju nazivaju se prostim grafom.
Graf je regularan ako su svi čvorovi istog stepena.
Graf je usmjeren ukoliko su mu grane usmjerene, odnosno ukoliko se zna koji čvor je
početak a koji čvor je kraj grane.

Svaki graf se može grafički prikazati kao crtež koji se sastoji od tačaka i linija koje
predstavljaju čvorove i grane grafa.
Na slici ... je prikazan jedan neusmjeren graf a na slici ... usmjeren graf.

1 2
1 2
3
3
4
4 5
5
6
6
Postoje dva načina da se predstavi graf - preko matrica povezanosti i preko lista
povezanosti.
Matrica povezanosti za graf G koji ima n čvorova je matrica dimenzija nxn pri čemu je
element aij = 1 akko postoji grana između čvorova ci i cj, a aij=0 ako ne postoji grana između
tih čvorova. Jasno je da su matrice povezanosti neusmjerenih grafova simetrične.
Matrice povezanosti grafova sa slika ... i ... su
é0 0 0 1 1 0ù é0 1 0 1 1 0ù
ê0 0 1 1 0 1úú ê0 0 1 0 0 0úú
ê ê
ê0 1 0 0 0 0ú ê0 1 0 0 1 0ú
ê ú ê ú
ê1 1 0 0 0 0ú ê1 0 0 0 0 1ú
ê1 0 0 0 0 1ú ê0 0 0 0 0 1ú
ê ú ê ú
êë0 1 0 0 1 0úû êë1 0 0 0 1 0úû

Primjer 40. Implementirati graf preko matrice povezanosti.

Rješenje
#include <stdio.h>
#include <stdlib.h>

int **matp;

void OdstampajMatricu(int **m, int stepen)


{
int i, j;
for(i=0; i<stepen; i++)
{
for(j=0; j<stepen; j++)
printf("%d\t", m[i][j]);
printf("\n");
}
}

void UcitajMatricu(int stepen)


{
int i, j, pov;
matp = (int **) malloc(stepen*sizeof(int*));
for(i=0; i<stepen; i++)
matp[i] = (int*) malloc(stepen*sizeof(int));

for(i=0; i<stepen; i++)


for(j=0; j<stepen; j++)
matp[i][j] = 0;

for(i=0; i<stepen; i++)


{
printf("Unesite cvorove koji su povezani sa %d.
cvorom:\n", i);
for(; ;)
{
scanf("%d", &pov);
if(pov < 0 || pov >= stepen)
break;
matp[i][pov] = 1;
matp[pov][i] = 1;
}
}
}

int main(int argc, char *argv[])


{
int stepen, i;
printf("Unesite broj cvorova grafa: ");
scanf("%d", &stepen);

UcitajMatricu(stepen);
OdstampajMatricu(matp, stepen);

for(i=0; i<stepen; i++)


free(matp[i]);
free(matp);

return 0;
}

Drugi način predstavljanja grafa je preko liste povezanosti. U takvoj implementaciji se


pravi lista čvorova pri čemo svaki čvor pokazuje na čvorove sa kojima je povezan. Tako npr,
lista povezanosti za graf na slici ... izgleda

1 2 4 5 NULL
2 3 NULL
3 2 5 NULL
4 1 6 NULL
5 6 NULL
6 1 5 NULL

Primjer 41. Implementirati graf preko liste povezanosti.


Rješenje
#include <stdio.h>
#include <stdlib.h>

typedef struct c
{
int v;
struct c* s;
} Cvor;

Cvor* UcitajGraf(int brCvorova)


{
Cvor *graf;
int i, j, pov;
for(i=0; i<brCvorova; i++)
graf = (Cvor*) malloc(brCvorova*sizeof(Cvor));
for(i=0; i<brCvorova; i++)
{
graf[i].v = i;
graf[i].s = NULL;
Cvor* p = &graf[i];
printf("Unesite cvorove koji su povezani sa %d.
cvorom:\n", i);
for( ; ;)
{
scanf("%d", &pov);
if(pov < 0 || pov >= brCvorova)
break;
Cvor* c = (Cvor*) malloc(sizeof(Cvor));
c->v = pov;
c->s = NULL;
p->s = c;
p = c;
}
}
return graf;
}

void OdstampajGraf(Cvor* graf, int brCvorova)


{
int i, j;
for(i=0; i<brCvorova; i++)
{
Cvor* c = &graf[i];
printf("%d->", graf[i].v);
while(c->s != NULL)
{
c = c->s;
printf("%d, ", c->v);
}
printf("\n");
}
}

int main(int argc, char *argv[])


{
Cvor *graf;
int brCvorova, i;
printf("Unesite broj cvorova grafa: ");
scanf("%d", &brCvorova);
graf = UcitajGraf(brCvorova);
OdstampajGraf(graf, brCvorova);
return 0;
}

Stabla
Zadaci za vježbu

1. Podaci o procesu se sastoje od naziva procesa i vremena izvršavanja. Implementirati


stek koji čuva podatke o procesima.
2. Napisati program koji učitava jednostruko povezanu listu i iz nje uklanja najveći
element.
3. Napisati program koji učitava jednostruko povezanu listu i pronalazi aritmetičku
sredinu pozitivnih elemenata te liste.
4. Napisati program koji učitava jednostruko povezanu listu i od pozitivnih elemenata te
liste pravi novu listu.
5. Napisati program koji učitava jednostruko povezanu listu i ispisuje njene elemente u
obrnutom redoslijedu.
6. Napisati program koji učitava dvije jednostruko povezane liste i provjerava da li su te
dvije date liste identične.
7. Napisati program koji učitava i štampa jednostruko povezanu listu. Lista ne smije
sadržavati jednake elemente.
8. Napisati program koji učitava jednostruko povezanu listu i štampa elemente koji se
nalaze na neparnim mjestima.
9. Napisati program koji učitava jednostruko povezanu listu i od nje pravi dvije
jednostruko povezane liste tako da se u prvoj nalazi polovina elemenata a druga
polovina u drugoj listi.
10. Napisati program koji učitava i štampa cikličnu jednostruko povezanu listu.
11. Napisati program koji učitava dva grafa i ispituje da li su identični.
12. Napisati program koji učitava graf i ispituje da li je usmjeren.
13. Napisati program koji učitava graf i ispituje da
14. Napisati program koji učitava uređeno binarno stabla i izračunava koliko njegovih
čvorova ima tačno dva podčvora.
15. Dodatak A

Pregled važnijih funkcija biblioteke math.h


Ime funkcije Opis
acos Inverzni kosinus
acosh Inverzni hiperbolički kosinus
asin Inverzni sinus
asinh Inverzni hiperbolički sinus
atan Inverzni tangens
atanh Inverzni hiperbolički tangens
cbrt Kubni korjen
cos Kosinus
cosh Hiperbolički kosinus
exp Eksponencijalna funkcija
exp2(x) 2x
fabs Apsolutna vrijednost realnog broja
fmax(x,y) Vraća veću vrijednost od x i y
fmin(x,y) Vraća manju vrijednost od x i y
hypot(x,y) Hipotenuza - sqrt(x2 + y2)
log Prirodni logaritam
log2 Logaritam po bazi 2
log10 Lograitam po bazi 10
pow(x,y) xy
round Zaokruživanje realnog broja
sin Sinus
sinh Hiperbolički sinus
sqrt Kvadratni korjen
tan Tangens
tanh Hiperbolički tangens

Pregled važnijih funkcija biblioteke string.h

Pregled važnijih funkcija biblioteke ctype.h


00 – UVOD

PLAN VEŽBI

1. UVOD
2. TIPOVI PODATAKA
3. GRANANJA, CIKLUSI UVOD
4. CIKLUSI NASTAVAK
5. FUNKCIJE
6. NIZOVI
7. NIZOVI NASTAVAK
8. I KOLOKVIJUM
9. MATRICE
10. MATRICE NASTAVAK
11. STRINGOVI
12. STRUKTURE
13. STRUKTURE NASTAVAK
14. II KOLOKVIJUM

NAČIN POLAGANJA

I KOL II KOL
UL ZA UL ZA DOL+AKT UKUPNO
MAX 10 35 10 35 10 100
MIN 5 20 5 20 5 55

• ISPIT SE MOŽE POLOŽITI PREKO KOLOKVIJUMA SA MINIMUM 55 BODOVA.

• ZA DOBIJANJE POTPISA NEOPHODNO JE OSTVARITI MINIMUM PO 5 BODOVA NA


ULAZNIM TESTOVIMA

POMOĆNI MATERIJAL KAO I MATERIJAL SA VEŽBI BIĆE DOSTUPAN NA FORUMU


LABORATORIJE ZA RAČUNARSKU TEHNIKU (Computer Science Laboratory)
csl.ftn.kg.ac.rs/forum u okviru nastavnih predmeta pa pod predmetom Uvod u programiranje.

http://csl.ftn.kg.ac.rs/forum/index.php/board,23.0.html

1
RAZVOJNO OKRUŽENJE Code::Blocks
Preuzeti sa sledećeg linka:
http://www.codeblocks.org/downloads/26
odabrati veću verziju sa uključenim MinGW GCC kompajlerom (codeblocks-12.11mingw-setup.exe)

Za lično vežbanje moguće je koristiti i druga dostupna razvojna okruženja.

KREIRANJE PROJEKTA

ODABRATI Console application

2
ODABRATI C JEZIK I NAKON TOGA UPISATI IME PROJEKTA I ODABRATI LOKACIJU

NA SLEDEĆEM PROZORU NE MENJATI PODEŠAVANJA I KLIKNUTI FINISH

3
NAKON TOGA DOBIJAMO FAJL main.c SA UPISANIM „HELLO WORLD“ PROGRAMOM

REZULTAT IZVRŠENJA PROGRAMA

4
U SLUČAJU NE PREPOZNAVANJA MinGW KOMPAJLERA U OKVIRU
Settings=>Compiler and debugger, TAB Tolchain Executables

Odabrati Auto detect ili podesiti putanju do MinGW kompajlera

5
UVOD U ALGORITME

Simboli koji se koriste u algoritamskim šemama:

Povezivanjem simbola usmerenim strelicama, koje označavaju tokove obrade, dobijaju se


algoritamske šeme.

Primer 1. Nacrtati algoritam za sabiranje brojeva x i y.

6
Primer 2. Nacrtati algoritam za izračunavanje sledeće funkcije:

7
01 - Tipovi podataka
Podaci u programu mogu da se predstave pomoću vrednosti ili pomoću identifikatora. Podaci predstavljeni
pomoću vrednosti ne mogu da promene svoje vrednosti u toku izvršavanja programa i nazivaju se konstantama.
Podacima koji su smešteni u memoriji računara, obično, mogu da se promene vrednosti u toku izvršavanja
programa. Takvi podaci nazivaju se promenljivim podacima ili kraće promenljivama. Podaci mogu da budu
prosti ili složeni.
Prosti podaci ne mogu da se rastave na manje elemente koji bi mogli nezavisno da se obrađuju. Zato se kaže da
oni nemaju strukturu. Nazivaju se i nestrukturiranim podacima ili skalarnim podacima.
Složeni podaci se sastoje od nekoliko elemenata koji mogu da se nezavisno obrađuju. Elementi složenih podataka
mogu da budu prosti, ali i sami mogu da budu složeni. Na taj način broj različitih složenih tipova podataka, koji
mogu da se izvode polazeći od prostih tipova podataka, je neograničen. Pošto složeni podaci imaju imaju određenu
strukturu, nazivaju se i strukturiranim podacima.

Dužina [bit] Opseg vrednosti


Oznaka tipa
standard tipično standard tipično
signed char -128÷127
char 8 -128÷127 ili 0÷255
unsigned char 0÷255
short int 2i-1÷2i-1-1 -32768÷32767
unsigned short int
i (i ≥ 16) 16 0÷2i-1 0÷65535
int 2j-1÷2j-1-1
j (k ≥ j ≥ i) 16 ili 32
unsigned int 0÷2j-1
long int -2147483648÷
2k-1÷2k-1-1
k (k ≥ 32) 32 2147483648
unsigned long int 0÷2k-1 0÷4294967295

Tabela 1. – Osobine celobrojnih podataka


Dužina Značajne Prošireni opseg
Oznaka tipa Opseg vrednosti Relativna greška
[bit] cifre (smanjena tačnost)
float 32 1,17*10-38<|x|<3,40*10+38 ε<1,19*10 -7 6÷7 1,39*10-45<|x|
double 64 2,22*10-308<|x|<1,79*10+308 ε<2,22*10-16 15÷16 4,93*10-324<|x|
Tabela 2. – Osobine realnih podataka
Logički podaci
U jeziku C za predstavljanje logičkih vrednosti koriste se celobrojni podaci tipa int, s tim da se vrednost 0 tumači
kao logička neistina (false), a bilo koja nenulta vrednost kao logička istina (true).

Simboličke konstante
Simbolička konstanta je konstanta kojoj je dodeljen identifikator. Kasnije se u programu koristi identifikator, a ne
vrednost konstante. Simbolička konstanta se definiše direktivom define čiji je opšti oblik:

#define IME_KONSTANTE vrednost_konstante

IME_KONSTANTE je identifikator koji u nastavku programa predstavlja navedenu konstantnu vrednost. Direktiva
define mora da se piše u zasebnom redu. Jednom direktivom može da se definiše samo jedna konstanta. Komentar
na kraju reda je dozvoljen. Evo nekoliko primera definisanja simboličkih konstanti:

#define MIN 0
#define MAX 1000
#define PI 3.14159

1
Bibliotečke funkcije
Ako žele da se koriste neke od bibliotečkih funkcija, potrebno je na početku programa to saopštiti prevodiocu
jezika C ime odgovarajućeg zaglavlja direktivom include čiji je opšti oblik:
#include <naziv_datoteke>
Primer:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

Konverzioni karakteri
Konverzioni Opis konverzije
karakter (q)
d decimalna koncerzija označenih brojeva (tip int)
c Konverzija jednog karaktera (tip char)
s Konverzija niza karaktera (tip char[])
f konverzija realnih decimalnih brojeva u jednostrukoj tačnosti
(tip float)
lf konverzija realnih decimalnih brojeva u dvostrukoj tačnosti
(tip double)

Ulazna konverzija
Ulazna konverzija podataka vrši se pozivanjem bibliotečke funkcije scanf pomoću naredbe čiji je opšti oblik:

scanf(“format“ , &podatak, ... , &podatak);


scanf(“%f“ , &a);
scanf(“%d%d“ , &a, &b);

Prvi argument funkcije scanf je format kojim se određuju konverzije koje treba da se izvršavaju u toku unosa
podataka. Svaki podatak predstavlja identifikator numeričke promenljive u koju će biti smešten rezultat konverzije
pojednog unetog podatka. Operator & ispred identifikatora promenljive označava da se funkciji scanf dostavlja
adresa navedene promenljive. Format je tekstualni podatak (niz znakova) oblika “tekst”. Pojedinačne konverzije se
iskazuju podnizovima opšteg oblika:
%nq
koji počinju znakom % i završavaju se oznakom za vrstu konverzije (q). Između njih može da bude i izvestan broj
dopunskih parametara konverzije (n).

Izlazna konverzija
Izlazna konvrzija podataka vrši se pozivanjem bibliotečke funkcije printf pomoću naredbe čiji je opšti oblik:

printf(“format“ , izraz, ... , izraz);


printf(“Pozdrav svima!!!“);
printf(“Suma je %d a kolicnik je %f“, suma, kolicnik);

Prvi argument funkcije printf je format kojim se određuju konverzije koje treba da se izvršavaju u toku ispisivanja
podataka. Svaki izraz predstavlja numerički izraz čija će vrednost da se ispisuje. Treba da se skrene pažnja da
skalarna promenljiva i numerička konstanta predstavljaju specijalne slučajeve numeričkih izraza. Format je
tekstualni podatak (niz znakova) oblika “tekst”.

2
ZADATAK 1: Napisati program koji na standardnom izlazu ispisuje pozdravnu poruku.

#include <stdio.h>
main () {
printf ("Pozdrav svima!");
return 0;
}

ZADATAK 2: Napisati program koji učitava dva cela broja i ispisuje njihov zbir na standardnom izlazu..

#include <stdio.h>
main () {
int a, b, c;
printf ("Uneti dva cela broja:");
scanf ("%d%d", &a, &b);
c=a+b;
printf ("Zbir unetih brojeva je: %d\n", c);
return 0;

MATEMATIČKE FUNKCIJE ( #include <math.h> )


Mat.simbol C simbol
cos (x) cos (x)
sin (x) sin (x)
tan (x) tan (x)
ln (x) log (x)
ex exp (x)
xy pow (x,y)
koren (x) sqrt (x)
|x| abs (x) za int, fabs(x) za float i double
Prvi veci ceo broj ceil(x), ceil(2.2)=3, ceil(2.8)=3
Prvi manji ceo broj floor(x), floor(2.2)=2, floor(2.8)=2
Zaokruzivanje round (x), round(2.2)=2, round(2.8)=3

ZADATAK 3: Napisati program koji učitava stranicu kvadrata i izračunava obim, površinu, dijagonalu kvadrata i
ispisuje rezultat na standardnom izlazu..

#include <stdio.h>
#include <math.h>
main () {
double a, o, p, d;
printf ("Unesi stranicu: ");
scanf ("%lf", &a);
o=4*a;
p=pow (a, 2);
d=(sqrt (2))*a;
printf ("Obim je: %.2lf\n Povrsina je: %.2lf\n Dijagonala je: %.2lf\n", o, p, d);
return 0;
}

3
ZADATAK 4. Написати програм који учитава странице квадра и израчунава: главну дијагоналу D,
површину и запремину квадра. Напомена: резултат штампати са две децимале.

#include <stdio.h>
#include <math.h>
main(){
float a, b, c; //stranice kvadra
float P, V; //povrsina, zapremina
double D; //glavna dijagonala
printf("Unesi stranice kvadra: ");
scanf("%f%f%f", &a, &b, &c);

D = sqrt(a*a + b*b + c*c);


P = 2*(a*b + b*c + a*c);
V = a*b*c;

printf("Glavna dijagonala je: %.2lf\nPovrsina je: %.2f\nZapremina je: %.2f\n", D, P, V);


return 0;
}
DELJENJA U C programskom jeziku

U C jeziku postoje dva simbola za deljenje pomoću kojih se mogu postići 3 tipa deljenja.
• Celobrojno (int a)/(int b) = 5 / 3 = 1, daje ceo deo realnog broja
• Po modulu (int a)%(int b) = 5 % 3 = 2, daje celobrojni ostatak pri deljenju
• Realno (int a)/(int b) = (float) 5 / 3 = 1.67, daje realan rezultat pri deljenju celih brojeva, mora se uraditi
kastovanje u željeni tip rezultata pored jedne od celobrojnih promenljivih (float)

ZADATAK 5: Napisati program koji ucitava dva cela broja a ispisuje zadnju cifru prvog broja, rezultat
celobrojnog deljenja, ostatak pri deljenju kao i realan rezultat na standardnom izlazu.

#include <stdio.h>
main () {
int a, b, c, d, e;
float f;
printf ("Unesi dva cela broja: ");
scanf ("%d%d", &a, &b);
c = a%10;
printf ("Zadnja cifra unetog broja %d je: %d\n", a, c);
d = a / b;
e = a % b;
f = (float) a / b;
printf ("d = %d, e = %d, f = %f \n", d, e, f);
return 0;
}

4
02 - Grananja
Osnovna selekcija: if – else

Osnovnom selekcijom se vrši uslovno izvršavanje jedne od dve moguće naredbe. Standardni i strukturirani
dijagrami toka ove upravljačke strukture prikazani su na slikama 2a i 2b, respektivno. Ukoliko logički izraz uslov
ima vrednost logičke istine (≠0), izvršava se naredba 1. Ako je vrednost uslova logička neistina (=0), izvršava se
naredba 2.
LOGIČKE OPERACIJE
== provera identičnosti
!= ne identično
<= manje ili jednako
>= vece ili jednako
! negacija
&& i
|| ili

Načini pisanja naredbe if

if (uslov) if (uslov){
naredba_1; naredba_1;
else naredba_2;
naredba_2; } // nema else
if (uslov){ if(uslov_1)
naredba_11; naredba_1;
naredba_12; else if(uslov_2)
... naredba_2;
naredba_1M; else if( ... )
}else{ ...
naredba_21; else if(uslov_N)
naredba_22; naredba_N-1;
... else
naredba_2N; naredba_N;
}

1
ZADATAK 6: Napisati algoritam i program koji učitava dva cela broja i na standardnom izlazu ispisuje koji je
veći od ta dva broja.

#include <stdio.h>
main (){
int a, b;
printf ("Uneti dva cela broja:");
scanf ("%d%d", &a, &b);
if (a>b)
printf("Veci je broj %d\n", a);
else if(b>a)
printf("Veci je broj %d\n", b);
else
printf("Brojevi su jednaki\n”);
return 0;
}

2
ZADATAK 7: Napisati program koji učitava ceo broj, proverava da li je učitani broj paran ili neparan i ispisuje
odgovarajuću poruku na standardnom izlazu.

#include <stdio.h>
main (){
int a;
printf ("Unesi ceo broj: ");
scanf ("%d", &a);
if (a%2 == 0)
printf ("Broj je paran\n");
else
printf ("Broj je neparan\n");
return 0;
}

ZADATAK 8: Napisati C program koji učitava ceo broj c i realan broj x pri čemu je x > 0 . Zatim izračunava i
štampa vrednost funkcije f i to na sledeći način
- ukoliko je c < 0 računa se i štampa f = sin x 2 − x 5 + x − 2
- ukoliko je 0 ≤ c ≤ 8 računa se i štampa f =| sin 31x − x 3 | + | x 2 − 3 x | +1
- ukoliko je c > 8 računa se i štampa f = log 2 x + e −3 x
NAPOMENA: abs(x) za int, fabs(x) za float i double
#include <stdio.h>
#include <math.h>

int main(){
int C;
float X;
double f;

printf("Uneti ceo broj C!\n");


scanf("%d", &C);

printf("Uneti realan broj X, veci od 0!\n");


scanf("%f", &X);

if (C<0) {
f = sin( pow( X, 2 )) - pow( X, 5 ) + X - 2;
}else if (C<=8) {
f = fabs(sin( 31 * X) - pow( X, 3 )) + sqrt( fabs( pow( X, 2 ) - 3*X )) + 1;
}else {
f = log( 2*X ) + exp( -3*X );
}
printf("\nVrednost funkcije je %lf \n", f);
return 0;
}

3
ZADATAK 9: Napisati program koji ucitava 3 cela broja a ispisuje na standardnom izlazu najmanji od njih.

#include <stdio.h> //standardni nacin // skraceni uslov


main (){ if (a<b)
int a, b, c; (a<c) ? printf ( " Najmanji je: %d\n", a):
printf("Uneti tri cela broja: "); printf ( " Najmanji je: %d\n", c);
scanf ("%d%d%d", &a, &b, &c); else
if(a<b){ (b<c) ? printf ( " Najmanji je: %d\n", b):
if(a<c) printf ( " Najmanji je: %d\n", c);
printf("Najmanji broj je: %d\n", a);
else // najbolji nacin za bilo koji broj elemenata
printf("Najmanji broj je: %d\n", c); min = a; /* min je prvi element iz skupa u kojem se
}else{ trazi resenje*/
if(b<c) if (b < min) /* proci kroz ostale elemente i pitati da li
printf("Najmanji broj je: %d\n", b); ima ko manji*/
else min = b; /*ako ima onda on postaje najmanji*/
printf("Najmanji broj je: %d\n", c); if (c < min)
} min = c;
return 0; printf (“Minimalni je %d \n”, min);
}
Selekcija pomoću skretnice: switch
Selekcija pomoću skretnice se sastoji od niza naredbi i celobrojnog izraza čija vrednost određuje prvu naredbu u
nizu odakle počinje izvršavanje. Mogu se switch-ovati samo celobrojne promenljive ili izrazi ili znakovi.
Celokupan niz naredbi je razbijen u podnizove niz_naredbi_1,niz_naredbi_2, …,niz_naredbi_N. Opšti oblik:
switch (izraz) {
case konstanta1: operator1
break;
case konstanta2: operator2
break;
default : operatorn
break;
}

4
Primer 2. Nacrtati algoritam za izračunavanje sledeće funkcije:

ZADATAK 10: Napisati program koji unosi dva cela broja a i b i jedan ceo broj n na osnovu koga se izvrsava
odredjena operacija nad brojevima a i b i to ako je:
• n=1, c=a+b
• n=2, c=a-b
• n=3, c=a/b
• n=4, c=a%b
• n=6, c=a*b

#include<stdio.h>
int main(){
int n;
int a, b, c;

printf("Uneti cele brojeve a i b\n");


scanf("%d %d",&a,&b);
printf("Uneti ceo broj n\n");
scanf("%d",&n);
switch(n){
case 1:

5
c=a+b;
printf("\nZbir je %d \n", c);
break;
case 2:
c=a-b;
printf("\nRazlika %d\n", c);
break;
case 3:
c=a/b; // 2=5/2
printf("\nCelobrojno deljenje %d\n", c);
break;
case 4:
c=a%b; //1=5/2
printf("\nDeljenje po modulu %d\n", c);
break;
case 6: //brojevi ne mora da idu po redu
c=a*b;
printf("\nMonozenje %d\n", c);
break;
default: printf("Nekorektna operacija\n");
}
return 0;
}

ZADATAK 11: Napisati program koji za uneti broj meseca (na primer, 1=Januar, 2=Februar, itd.) ispisuje njegov
broj dana. U slučaju unete vrednosti 2 pitati korisnika da li je godina prestupna.

#include<stdio.h>
int main(){
int mesec, ch;
printf("Uneti redni broj meseca\n");
scanf("%d",&mesec);
switch(mesec){
case 1:case
1 case 3:case
3 case 5:case
5 case 7:case
7 case 8:case
8 case 10:
10 case 12:
12 printf("31 dan\n"); break;
break
case 4:
4 case 6:
6 case 9:
9 case 11:
11 printf("30 dana\n"); break;
break
case 2:
2 printf("Da li je godina prestupna (d-1/n-0)?\n");
scanf("%d",&ch);
if(ch == 1)
printf("29 dana\n");
else
printf("28 dana\n");
break;
break
default:
default printf("Nekorektan broj meseca\n");
break;
break
}
return 0;
}

6
CIKLUSI UVOD
Ciklusi
Ciklusi su upravljačke strukture koje omogućavaju ponovljeno izvršavanje neke naredbe. Broj ponavaljanja može
biti poznat a može i zavisiti od ispunjenja određenog logičkog uslova.

Generalizovani ciklus sa izlazom na vrhu: FOR


U praksi su vrlo česti ciklusi sa sledećom strukturom:
• postavljanje početne vrednosti jedne ili više promenljivih pre ulaska u ciklus,
• ispitivanje da li treba izvršavati sadržaj ciklusa pre svakog prolaska kroz ciklus,
• menjanje vrednosti jedne ili više promenljivih na kraju svakog prolaska kroz ciklus.
Standardni i strukturirani dijagrami toka osnovnog ciklusa sa izlazom na vrhu kao i programska sintaksa prikazani
su na slici.

for(izraz_1; uslov_2; izraz_3){


naredba_1;
naredba_2;
...
naredba_N;
}

IZRAZ 1 predstavlja predstavlja pripremu za ulazak u ciklus (može da obuhvata i više radnji razdvojenih
zarezom). Služi za postavljanje potrebnih početnih vrednosti.
USLOV 2 je logički izraz koji predstavlja uslov za nastavljanje ciklusa.
IZRAZ 3 predstavlja završne radnje na kraju svakog prolaska kroz ciklus, tj. pripremne radnje za naredni prolazak
kroz ciklus. Te radnje, najčešće, predstavljaju menjanje brojača koji kontroliše broj prolazaka kroz ciklus.

NAPOMENA: idealna je kada je poznat broj ponavaljanja nekog skupa naredbi

Primeri for iteracije:

for (i = 0; i< 5; i++) KORAK I


1 0
2 1
3 2
4 3
5 4
6 5 ( i<5 = false)

for (i = 0, j = 10; i< 50 && j<200; i+=3, j*=2) KORAK I j


1 0 10
2 3 20
3 6 40
4 9 80
5 12 160
6 15 320 (j<200 = false)

7
Ciklus sa izlaskom na vrhu: WHILE
Standardni i strukturirani dijagrami toka osnovnog ciklusa sa izlazom na vrhu kao i programska sintaksa prikazani
su na slici.

while (uslov){
naredba_1;
naredba_2;
...
naredba_N;
}

Na početku svakog prolaska kroz ciklus izračunava se vrednost logičkog izraza uslov, i ako se dobija logička istina
(≠0), izvršava se naredba. Ciklus se završava kada vrednost uslova postane logička neistina (=0). Treba da se uoči,
može se desiti da naredba ne bude ni jednom izvršavana.

NAPOMENA: idealna je kada je nepoznat broj ponavaljanja nekog skupa naredbi


Ciklus sa izlazom na dnu: DO - WHILE
Standardni i strukturiran dijagram toka ciklusa sa izlazom na dnu prikazan je na slici

do{
naredba_1;
naredba_2;
...
naredba_N;
}while(uslov);

Kod ciklusa sa izlazom na dnu prvo se izvršava naredba koja čini sadržaj ciklusa pa se proverava vrednost
logičkog izraza uslov, i ako se dobija logička istina (≠0), skoči se na ponovno izvršavanje naredbe. Ciklus se
završava kada vrednost uslova postane logička neistina (=0). Naredba se uvek izvršava bar jednom.

NAPOMENA: idealan kada je potrebno prvo izvršiti naredbu pa proveriti da li je ispunje uslov, to treba raditi
sve dok se ne ispuni uslov

PRIMER 1 : Ispisati sve brojeve od 1 do n pomoću svih petlji osiguravajući da je n minimum 4.


#include <stdio.h>
#include <stdlib.h>

int main(){
int n;
int i; // iterator kroz petlje

do{
printf("Unesi n!\n");
scanf("%d",&n);
}while(n<4);

8
printf("\nPOMOCU FOR PETLJE!\n");
for(i=1; i<=n; i++)
printf("%d ", i);

printf("\nPOMOCU WHILE PETLJE!\n");


i = 1;
while(i<=n) { // uslov
printf("%d ", i);
i++; // promena iteratora
}

printf("\nPOMOCU DO - WHILE PETLJE!\n");


i = 1;
do{
printf("%d ", i);
i++; // promena iteratora
} while(i<=n); // uslov

return 0;
}
Primer 2. Nacrtati algoritam za množenje dva prirodna broja koristeći operaciju sabiranja.

9
VEŽBE 03
CIKLUSI

ZADATAK 11: Program za izračunavanje faktorijela

#include<stdio.h>
int main(){
int i,n;
int fakt=1; /*obavezno postavljanje promenljive na vrednost
koja ne utice na operaciju koja se nad njom obavlja*/
printf("Izracunavanje n!\nUkucajte broj (<33)?");
scanf("%d",&n);
for(i=1; i<=n; i++)
fakt*=i;
printf("%d!=%d\n",n,fak);
return 0;
}

1
ZADATAK 12: Napisati program kojim se na ekranu dobijaju permutovane cifre unetog celog broja.

#include<stdio.h>
int main(){
int broj, cifra;
printf("Ukucajte ceo broj?\n");
scanf("%d",&broj);
printf("Permutovan broj je\n");

while(broj != 0){ // ili while(broj);


cifra = broj%10;
broj /= 10;
printf("%d", cifra);
}
return 0;
}

ZADATAK 13: Napisati program za određivanje srednje vrednosti n celih brojeva

#include<stdio.h>
int main() {
int n, i;
float suma=0; /*obavezno postavljanje promenljive na vrednost
koja ne utice na operaciju koja se nad njom obavlja*/
float x;
printf("Ukupno brojeva?\n");
scanf("%d",&n);
for (i=0; i<n; i++){
printf("Ukucajte %d. broj?", i+1);
scanf("%f",&x);
suma+=x;
}

printf("Srednja vrednost ovih brojeva je %f\n",suma/n);


return 0;

2
}

ZADATAK 14: Napisati program kojim se unosi jedan ceo broj sa tastature i ukoliko je broj veći od 10 zahteva se
ponovni unos sve dok se ne unese odgovarajući broj.

#include<stdio.h>
int main(){
int broj;
do {
printf ("Ukucajte ceo broj?\n");
scanf ("%d",&broj);
}
while(broj>10);
printf("\nKonacno je unet broj %d", broj);
return 0;
}

ZADATAK 15: Napisati program koji ucitava cele brojeve dok se ne ucita nula i koji prikazuje njihov zbir na
standardnom izlazu.

#include <stdio.h> /*Ucitavanje brojeva razlicitih od nule i izracunavanje njihovog zbira*/


int main (){
int a, zbir=0; /*obavezno postavljanje promenljive na vrednost
koja ne utice na operaciju koja se nad njom obavlja*/
do{
printf ("Unesi broj: ");
scanf ("%d", &a);
zbir += a;
}while (a!=0);
printf("Zbir je: %d\n", zbir);
return 0;
}

3
Upravljačke stukture ciklusa: break i continue

Iskakanje iz upravljačke strukture izvršava se naredbom:


break;
Korišćenjem naredbe break se postiže:
• prevremeni završetak ciklusa (while,for,do) skakanjem na prvu naredbu neposredno iza ciklusa, ili
• preskakanje preostalih naredbi unutar selekcije pomoću skretnice (switch) skakanjem na prvu naredbu
neposredno iza selekcije.
U slučaju uklopljenih upravljačkih struktura, izlazi se samo iz najdublje strukture, tj. iz strukture koja neposredno
obuhvata datu naredbu break.

Naredba continue prosleđuje tok kontrole na sledeću iteraciju najbliže do, for ili while naredbe u kojoj se
pojavljuje, čime se preskaču preostale naredbe u telu petlje.

Korišćenjem naredbe continue se postiže:


- Unutar do ili while petlje, sledeća iteracija počinje proveravanjem uslova u do ili while naredbi;
- U for petlji, continue naredba uzrokuje da se proveri uslov u for naredbi. Potom kompajler ponovo
proverava uslov i u zavisnosti od rezultata provere, ili prekida izvršavanje petlje ili nastavlja njeno
izvršavanje.

4
ZADATAK 16a: Napisati program koji ucitava ceo pozitivan broj a ispituje da li je on prost ili ne i rezultat
ispisuje na standardnom izlazu.
#include <stdio.h>
main (){
int a, i=2, prost = 1; // 1 je logicki tačan izraz, 0 je logicki netačan
printf("Unesi ceo pozitivan broj: ");
scanf("%d", &a);

while(i<a) for (i=2; i<a; i++)


if(a % i == 0){ if(a% i == 0){
prost = 0; prost = 0;
break; break;
}else }
i ++;

if( prost )
printf("Broj %d je prost\n", a);
else
printf("Broj %d je slozen\n", a);
return 0;
}

5
ZADATAK 16b: Napisati program koji nalazi proizvod 4 cela broja koja unosi korisnik. U slučaju da korisnik
unese nulu, preskočiti je.

#include <stdio.h>
int main(){
int i,broj,proizvod;
for(i=1,proizvod=1;i<=4;++i){
printf("Unesite broj %d:",i);
scanf("%d",&broj);
if(broj==0)
continue; / *Kada je broj jednak nuli, preskače se sledeća naredba proizvod*=broj i nastavlja se ciklus. */
proizvod*=broj;
}
printf("Proizvod iznosi %d",proizvod);
return 0;
}

ZADATAK 17: Napisati program koji ucitava cele brojeve a, b, c i prebrojava i ispisuje na standardnom izlazu
cele brojeve iz intervala [a,b] koji su deljivi sa c. Demonstrirati rešenje pomoću while i for cikljusa.

#include <stdio.h> #include <stdio.h>


main (){ main (){
int a, b, c, i; int a, b, c, i;
int br = 0; // pocetna vrednost int br = 0; // pocetna vrednost
printf("Uneti brojeve: "); printf("Uneti brojeve: ");
scanf("%d%d%d", &a, &b, &c); scanf("%d%d%d", &a, &b, &c);
i=a; // startna vrednost for(i=a; i<=b; i++){
while(i<=b){ if(i%c==0){
if(i%c==0){ printf("%d,", i);
printf("%d,", i); br++;
br++; }
} }
i++; // korak printf(“br= %d”, br);
} }
printf(“br= %d”, br);
}
Domaći : Prepraviti kod da broj b mora biti veći od a a da broj c mora biti manji od b i da c ne sme biti 0.

ZADATAK 18: Napisati program koji ucitava cele brojeve dok se ne ucita pozitivan broj deljiv sa 4 a da nije
manji od 10 a prikazuje na standardnom izlazu srednju vrednost svih brojeva koji su neparni ili deljivi sa 3 i 6.

#include <stdio.h>
#include <math.h>
int main () {
int a, broj=0;
float srvr=0;

printf("Unesi broj: ");


scanf("%d", &a);

6
do{
printf("Unesi broj: ");
scanf("%d", &a);

if (a%2==1 || (a%3==0 && a%6==0)){


srvr+=a;
broj++;
}
} while(!(a>0 && a%4==0 && a>10));

printf("Srednja vrednost je: %.2f\n", (srvr/broj));


return 0;
}

ZADATAK 19: Napisati program koji za zadati prirodan pozitivan broj n ispisuje najpre da li je deljiv i sa 6 i sa 7.
Ako je deljiv izračunava se suma oblika , ako nije a paran je računa se suma oblika
S=sin(1)-sin(2)+…+sin(n). Za sve ostale računa se suma oblika S=
#include <stdio.h>
#include <math.h>
int main(){
int n,i,z; // z predstavlja operaciju (+ , -) koja ce u svakom ciklusu menjati (z=-z)
double s=0;

int j; //za stepen za poslednji else


printf("Uneti prirodan broj n");
scanf("%d",&n);
if (n%6==0 && n%7==0){
for (i=1; i<=n; i++)
s+= pow(i,4);
}else if (n%2==0){
z=1;
for(i=1; i<=n; i++){
s+=z*sin(i);
z=-z; // promena znaka
}
}else {
for (i=2, j=2; i<=n; i+=2, j++) //for petlja sa vise iteratora koji zajedno menjaju vrednost
s+= pow(i,j)/pow(i+1,j);
}
printf("Suma je %lf\n",s);
return 0;
}

Domaci: Napisati program koji izračunava sumu S3 koja samo umesto sume razlomaka ima jednu razlomačku crtu

7
04 – FUNKCIJE

Kada je reč o funkcijama prvo treba objasniti funkciju Main(). Ova funkcija kao rezultat vraća void ili
int, a može se uključiti string[] args parametar, pa su moguće sledeće verzije ove funkcije:
void main(){}

void main(int argc, char* argv){}

int main(){ ... return 0;}

int main(int argc, char* argv) { ... return 0;}

NAPOMENA:
int argc – broj ulaznih argumenata od kojih je ime programa uvek jedan
char* argv – niz stringova prosledjenih prilikom poziva programa

Funkcije su programske celine koje imaju ulogu da odrade jedan deo ili eventualno ceo problem koji
se traži u zadatku. Definicija funkcije sastoji se od zaglavlja i tela funkcije. Zaglavlje funkcije sadrži
identifikator (ime funkcije), par zagrada ‘(‘ i ‘)’ između kojih se opcionalno nalazi lista argumenata
funkcije sa definicijama argumenata funkcije. Telo funkcije je skup izvršnih iskaza i deklaracija
promenljivih korišćenih u funkciji.

tipRezultata imeFunkcije(argumenti){ //primer funkcije koja sabira dva broja


Definicija lokalnih promenljivih; int zbir (int a, int b){
Naredba1; int c;
… c = a + b;
NaredbaN; return c;
return rezultat; }
}
Funkcija koje prenose parametre preko vrednosti mogu da vrate maksimalno jedan rezultat a takodje
funkcija može i da ne vrati rezultat što se vidi na sledećem primeru funkcije koja samo ispisuje
pozdravnu poruku;

void poruka(){ /*Zaglavlje funkcije*/


printf(“Zdravo!\n”); /*Telo funkcije su svi iskazi izmedju { i }*/
}

• Preporuka je da se funkcije definišu pre glavnog dela programa (funkcije main).


• U glavnom delu programa FUNKCIJE SE POZIVAJU POMOCU IMENA FUNKCIJE SA
ISTIM BROJEM, TIPOM I REDOSLEDOM STVARNIH ARGUMENATA.
Definicija funkcije void test(int a){…} int test2(int a, int b){…}
Main funkcija i poziv pomoćne main(){ main(){
funkcije int a = 5; int a = 5, b = 6, c = 7, d;
test (5); d = test2 (a, b); // ok
test(a); d = test2 (b, c); // ok
test(a+5) a = test2(a+5, c); // ok
} }

1
ZADATAK 18: Napisati program koji računa hipotenuzu pravouglog trougla pomoću funkcije.

#include <stdio.h>
#include <math.h>
double hipotenuza (float a, float b){
double c;
c = sqrt ( pow(a, 2) + pow (b, 2));
return c;
}

int main(){
float a, b;
printf(“Uneti stranice pravouglog trugla \n”);
scanf(“%f%f”, &a, &b);
printf (“Hipotenuza je: %lf \n”, hipotenuza(a, b));
return 0;
}
ZADATAK 19. Napisati program za izračunavanje sume kvadrata od 1 do n za dva cela broja.

Rešenje: Funkcija int suma_kvadrata(int n) je deklaracija funkcije, koja kao rezultat vraća int i zove se
suma_kvadrata. Int n predstavljaju formalne ulazne argument funkcije. To znači da funkciuja prihvata
jedan int a ali se on pri pozivu ne mora zvati n. Kada funkcija vraća neki rezultat (nije void) unutar
funkcije (najčešće na kraju) mora da postoji komanda return kojom se vraća vrednost rezultata; gde se kao
rezultat funkcije vraća vrednost promenljive. Funkcija se poziva tako što se u glavnom programu napiše
ime funkcije sa odgovarajućim argumentima funkcije. Kada se pozove funkcija, u zagradi stoje stvarni
argumenti.

#include<stdio.h>
int suma_kvadrata(int n){
int i;
int suma = 0;
for(i=1; i <= n; i++){
suma += i*i;
}
return suma;
}
int main(){
int n, m, rezN, rezM;
printf(“Uneti dva cela broja \n”);
scanf(“%d%d”, &n,&m);
rezN = suma_kvadrata (n); // funkcije se mogu neograniceno puta pozivati
printf("Suma kvadrata od 1 do %d : %d\n", n, rezN);
rezM = suma_kvadrata (m);
printf("Suma kvadrata od 1 do %d : %d\n", m, rezM);

printf("Suma kvadrata od 1 do %d : %ld\n", 15, suma_kvadrata(15));


printf("Suma kvadrata od 1 do %d : %ld\n", 10, suma_kvadrata(10));
return 0;

2
}

ZADATAK 20. Napisati program u kome se definiše funkcija prost() koja ispituje da li je broj prost i
funkcija main() koja njenim korišćenjem štampa sve proste brojeve do datog prirodnog broja n.

#include<stdio.h>
#include<math.h>
int prost(int n){
int i;
for (i=2; i<=sqrt(n); i++) //dovoljno je ici do koren iz 3
if(n%i == 0)
return 0; //nije prost = 0
return 1; //jeste prost = 1
}
int main() {
int i, n;
printf("Uneti broj\n");
scanf("%d", &n);
printf("Prosti brojevi su\n");
for( i=2; i <= n; i++)
if(prost(i) == 1) //isto kao i if(prost(i)),
if(prost(i)) ne mora da se stavi ==1,
printf("%d\n", i);
return 0;
}

ZADATAK 21: Napisati funkciju koja izracunava faktorijel datog prirodnog broja a potom glavni
program koji ucitava brojeve a i b a ispisuje (a!/b!.)2. Napomena: faktorijal negativnih brojeva je 0,
faktorijal od 0 i 1 je 1.

#include <stdio.h>
#include <math.h>

int Faktorijel(int n) {
if(n<0)
return 0;
else if(n==0 || n==1)
return 1;
else{
int f=1, i=2;
for(i=2; i<=n; i++){
f *= i;
}
return f;
}
}
main(){

3
int a, b;
double c;
printf("Unesi dva cela broja: ");
scanf("%d %d", &a, &b);
c = pow((double)Faktorijel(a)/Faktorijel(b), 2);
printf("Vrednost je %.4lf \n", c);
return 0;
}
VEŽBA: Izračunati sledeći izraz: r= (a!+b!)/(a+b)!

ZADATAK 22: Napisati funkciju koja izračunava površinu trougla. Poznate su koordinate temena
trougla u X-Y koordinatnom sistemu. Funkcija treba da ima jedan argument, a koordinate se zadaju
pre poziva funkcije kao celi brojevi.
gde je S poluobim trougla tj.
#include<stdio.h>
#include<math.h>

double povrsinaTrougla (int x1, int y1, int x2, int y2, int x3, int y3 ){
double a, b, c, s;
a = sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2));
b = sqrt(pow((x2 - x3), 2) + pow((y2 - y3), 2));
c = sqrt(pow((x3 - x1), 2) + pow((y3 - y1), 2));
s = (a + b + c)/2;
return sqrt(s * (s-a) * (s-b) * (s-c));
}
int main (){
int x1, y1, x2, y2, x3, y3;

printf ("Uneti koordinate prve tacke: \n");


scanf ("%d%d", &x1, &y1);
printf ("Uneti koordinate druge tacke: \n");
scanf ("%d%d", &x2, &y2);
printf ("Uneti koordinate trece tacke: \n");
scanf ("%d%d", &x3, &y3);

printf("\nPovrsina trogla je :%.2lf \n", povrsinaTrougla(x1, y1, x2, y2, x3, y3));
return 0;
}
ZADATAK 23: Napisati program kojim se stampaju svi petocifreni brojevi(ako ih ima) koji su
jednaki sumi faktorijala svojih cifara. U programu koristiti funkcije.
#include <stdio.h>
int fakt(int n){
int i, f=1;
for ( i=1; i <= n; i++ )
f *= i;
return f;

4
}
int sumaFakt(int n){
int suma = 0, zadCifra;
while(n!=0){
zadCifra = fakt(n % 10);
suma += zadCifra;
n /= 10;
}
return suma;
}
int main(){
int i;
for(i=10000; i <= 99999; i++)
if (i == sumaFakt(i))
printf("%d ", i);
return 0;}

5
VEŽBE 05 – NIZOVI

Podatak nizovnog tipa predstavlja niz podataka međusobno ISTIH tipova. Oni se nazivaju elemetima niza i
identifikuju se pomoću rednog broja (indeksa) elemenata niza. Prvi element niza u jeziku C obavezno ima indeks
0, drugi 1 itd.
Definisanje nizova vrši se pomoću sledeće naredbe:

TIP ime_niza [Max broj elemenata]

Max broj elemenata mora da bude konstantan izraz.


Evo nekoliko primera za definisanje nizova:
float vekt[50];
int niz[100];

Inicijalizacija početne vrednosti pri definisanju pišu u obliku niza vrednosti međusobno razdvojenih zarezima
stavljenih između para vitičastih zagrada ({}). To treba da su konstante koje po tipu odgovaraju osnovnom tipu
navedenom u opisu tipa na početku naredbe za definisanje podataka.
Evo nekoliko primera za definisanje jednodimenzionalnih nizova sa inicijalizatorima:

int dani1[12] = {31,28,31,30,31,30,31,31,30,31,30,31};


int dani1[] = {31,28,31,30,31,30,31,31,30,31,30,31};
long a1[5] = {1,2,3};
long a2[5] = {1,2,3,0,0};
long a3[5] = {1,2,3,4,5,6}; /* GRESKA! */
const int tablica[] = {1,5,3,4,2};

Indeksi u jeziku C su celi brojevi od 0 do n–1, gde je n broj elemenata (tj. dužina) niza. Pristup elementima niza
naziva se indeksiranjem. Indeksiranje u jeziku C smatra se binarnim operatorom i obeležava se sa [].

int a1[3] = {4,2,8}; pa je a[1]=2

a [i] – je vrednost elementa koji se nalazi u nizu a na poziciji i

1
ZADATAK 20: Napisati program kojim se ucitava niz n celih brojeva n<=20 i ispisuje ga na standardnom
izlazu uz sumu svih elemenata niza. (a – bez funkcija, b – preko funkcija)

Unos dimenzije niza (n)

Proci kroz niz

Unos a[i] elementa niza

Pocetak problematike sume

Proci kroz niz

Dodati vrednost svakog elementa a[i] na sumu

Ispis izracunate sume

Proci kroz niz

ispis a[i] elementa niza

2
A) Bez funkcija
#include <stdio.h>
#include <stdlib.h>
#define DIM 20
main (){
int a[DIM], suma;
int i, n;

printf ("\nDuzina niza (najvise %d)je: ", DIM);


scanf ("%d", &n);

if (n<=0 || n>DIM) // provera dimenzije niza


exit (1); // prekid u slucaju netacne dimenzije. Nije lose ali bolje sa do while !!!

//unos elemenata niza


printf ("Unesite clanove niza: \n");
for (i=0;i<n;i++){
printf(“\n a[%d]=”, i);
scanf ("%d", &a[i]);
}

// sumiranje elemenata niza


suma = 0;
for (i=0;i<n;i++)
suma += a[i];

printf ("Zbir svih elemenata niza je: %.d\n ", suma);

// ispis elemenata niza


printf ("\nElementi niza: \n");
for (i=0;i<n;i++)
printf(“%d ”, a[i]);
return 0;
}
B) Preko funkcija

#include <stdio.h>
#include <stdlib.h>
#define DIM 20

void unos(int a[], int n){


int i;
printf ("Unesite clanove niza: \n");
for (i=0; i<n; i++){
printf(“\n a[%d]=”, i);
scanf ("%d", &a[i]);
}
} // treba je pozvati u main-u

3
void ispis(int a[], int n){
int i;
printf ("\nElementi niza: \n");
for (i=0; i<n; i++)
printf(“%d ”,a[i]);
} // treba je pozvati u main-u

int suma(int a[], int n){


int i, s;
s = 0;
for (i=0; i<n; i++)
s += a[i];
return s;
} // treba je pozvati u main-u

main (){
int a[DIM], s;
int i, n;

do{
printf ("\nDuzina niza (najvise %d)je: ", DIM);
scanf ("%d", &n);
}while (n<=0 || n>DIM); // unos odgovarajuce dimenzije niza preko do while

unos(a, n);

s = suma(a, n);

printf ("Zbir svih elemenata niza je: %.d\n ", s);

ispis (a, n);

return 0;
}

ZADATAK 20a : Napisati program kojim se ucitava niz n realnih brojeva n<=20 a ispisuje na standardnom
izlazu zbir i srednju vrednost svih pozitivnih elemenata.

#include <stdio.h>
#include <stdlib.h>
#define DIM 20
main (){
double a[DIM], zbir;
int i, n, poz;

printf ("\nDuzina niza (najvise %d)je: ", DIM);


scanf ("%d", &n);

4
if (n<=0 || n>DIM) // provera dimenzije niza
exit (1); // prekid u slucaju netacne dimenzije. Nije lose ali bolje sa do while !!!

//unos elemenata niza void unos(double a[], int n){ // pre main-a
int i;
printf ("Unesite clanove niza: \n"); printf ("Unesite clanove niza: \n");
for (i=0;i<n;i++){ for (i=0; i<n; i++){
printf(“\n a[%d]=”, i); printf(“\n a[%d]=”, i);
scanf ("%lf", &a[i]); scanf ("%lf", &a[i]);
} }
} // treba je pozvati u main-u
// sumiranje elemenata niza double srvr(double a[], int n){ // pre main-a
zbir = 0; poz = 0; int i, zbir = 0, poz = 0;
for (i=0;i<n;i++){ for (i=0; i<n; i++){
if (a[i]>0){ if (a[i]>0){
zbir += a[i]; zbir += a[i];
poz++; poz++;
} }
} }
return zbir/poz;
} // treba je pozvati u main-u
printf ("Zbir pozitivnih elemenata je: %.2lf\nSrednja vrednost pozitivnih je: %.2lf\n", zbir, zbir/poz);
return 0;
}

ZADATAK 21: Napisati program koji ucitava niz n realnih brojeva n<=20 a ispisuje na standardnom izlazu
najveci clan niza.

#include <stdio.h>
#include <stdlib.h>
#define DIM 20
main (){
double a[DIM], max;
int i, n;

printf("\nDuzina niza (najvise %d)je: ", DIM);


scanf("%d", &n);

if(n<=0 || n>DIM)
exit(1);

printf("Unesite clanove niza: ");

for (i=0;i<n;i++){//unos elemenata niza


printf(“\na[%d]=”, i);
scanf ("%lf", &a[i]);
}

5
//max obavezno postaviti na PRVI element iz double maxf(double a[], int n){ // pre main-a
skupa u kojem se trazi resenje. int i;
max = a[0];
max=a[0]; for (i=1; i<n; i++)
for (i=1; i<n; i++){ if(a[i]>max)
if(a[i]>max) max=a[i];
max=a[i]; return max;
} }
printf("Najveci element je: %.2f\n", max); printf("Najveci element je: %.2f\n", maxf(a,n));
return 0;
}
ZADATAK 22: Napisati program koji ucitava niz n realnih brojeva n<=20 a ispisuje na standardnom izlazu
elemente niza sortirane u neopadajućem poretku.

NAPOMENA: diskutovanje petlji

int n = 6; KORAK I j
1 0 1
for (i = 0, j = i+1; i< n-1; i++, j++) 2 1 2
3 2 3
4 3 4
5 4 5
6 5(i<n-1 = false) 6

int n = 6; KORAK I j
1 0 1
for (i = 0; i< n-1; i++) 2 0 2
for (j = i+1; j<n; j++) 3 0 3
4 0 4
j uvek vece od i 5 0 5
6 0 6 (j<6 = false)
zavrsi se cela unutrasnja petlja (j) pa se tek 7 1 2
8 1 3
onda spoljna (i) uveca za 1
9 1 4
10 1 5
11 1 6 (j<6 = false)
12 2 3
13 2 4
14 2 5
15 2 6 (j<6 = false)
16 3 4
17 3 5
18 3 6 (j<6 = false)
19 4 5
20 4 6 (j<6 = false)
21 5 6 (j<6 = false)

6
#include <stdio.h>
#include <stdlib.h>
#define DIM 20
void unos(int a[], int n){
int i;
printf ("Unesite clanove niza: \n");
for (i=0; i<n; i++){
printf(“\n a[%d]=”, i);
scanf ("%d", &a[i]);
}
}
void ispis (int a[], int n){
inti;
for (i=0;i<n;i++)
printf(“%d, ”,a[i]);
}
main (){
int a[DIM], max;
int i, j, n, tmp;

// provera dimenzije niza


do{
printf("\nDuzina niza (najvise %d)je: ", DIM);
scanf("%d", &n);
}while (n<=0 || n>DIM);
unos(a, n); // unos preko funkcije
// sortiranje elemenata niza void sort(int a[], int n){ // pre main-a
// I uvek levo od J jer J krece od I+1 int i, j, tmp;
for (i=0; i<n-1 i++)
for (i=0; i<n-1; i++) for (j=i+1; j<n; j++)
for (j=i+1;j<n; j++) if(a[i] > a[j]){
if(a[i] > a[j]){ tmp = a[i];
tmp = a[i]; a[i] = a[j];
a[i] = a[j]; a[j] = tmp;
a[j] = tmp; }
} } // treba je pozvati u main-u
ispis(a,n); // ispis preko funkcije
return 0;
}

ZADATAK 23: Napisati program koji učitava 2 niza od n elemenata n<=20 a ispisuje na standardnom
izlazu skalarni proizvod odgovarajućih članova datih nizova.
#include <stdio.h>
#include <stdlib.h>
#define DIM 20

7
void unos(int a[], int n){
int i;
printf ("Unesite clanove niza: \n");
for (i=0; i<n; i++){
printf(“\n a[%d]=”, i);
scanf ("%d", &a[i]);
}
}
main (){
int a[DIM], b[DIM], sp=0;
int i, n;

printf("Uneti broj clanova niza (najvise je %d): ", DIM);


scanf("%d", &n);

unos(a, n);
unos(b, n);

for(i=0; i<n; i++)


sp+=a[i]*b[i];

printf("Skalarni proizvod je: %d", sp);


return 0;
}

ZADATAK 24: Napisati C program koji formira niz A[8] od celih brojeva koji se učitavaju jedan po jedan sa
tastature. Program treba da sve elmente niza A koji su izmedju 5 I 10 a nalaze se na neparnim pozicijama prekopira
u niz B.

#include <stdio.h>
#include <stdlib.h>
#define DIM 20
main (){
int n, a[DIM], b[DIM], i, k;

printf("\nDuzina niza (max %d): ", DIM);


scanf("%d", &n);

printf("\nPocetni niz:\n");
for(i=0; i<n; i++){
printf("\na[%d]=", i);
scanf("%d", &a[i]);
}

k = 0; // na pocetku nema prebacenih elemenata


for(i=0; i<n; i++)
if(a[i]>5 && a[i]<10 && i%2==1)
b[k++] = a[i]; // po prebacivanju se k uvecava za 1 (k++)

printf("\nElementi niza B su:\n");

8
for(i=0; i<k; i++) // dimenzija niza B je K
printf("%d ", b[i]);
}

DOPUNA: funkcija prebaci


int prebaci(int a[], int n, int b[]){ // vraca broj prebacenih elemenata, to ce biti i dimenzija niza B
k = 0; // na pocetku nema prebacenih elemenata
for(i=0; i<n; i++) // proci kroz sve elemente niza
if(a[i]>5 && a[i]<10 && i%2==1) // pitati
b[k++] = a[i]; // po prebacivanju se k uvecava za 1
return k;
}

9
VEŽBE 06

NASTAVAK NIZOVI

ZADATAK 25: Napisati program koji učitava niz od n elemenata n<=20 i cele brojeve K i X a
ispisuje niz koji nastaje kada se na K-to mesto datog niza umetne broj X.

#include <stdio.h>
#include <stdlib.h>
#define DIM 20
main (){
int a[DIM],k ,x;
int i, n;

printf("\nDuzina niza (najvise %d)je: ", DIM);


scanf("%d", &n);

printf("Uneti elemente niza: ");


for(i=0;i<n;i++)
scanf("%d", &a[i]);

printf("Unesi dva cela broja: ");


scanf("%d %d", &k, &x);

k--; /*smanjivanje za 1 jer indeks niza krece od nule*/


for(i=n-1; i>=k; i--) /*Pomeranie elemenata niza u desno za jedno mesto da bi se
ubacio X*/
a[i+1]=a[i];
a[k] = x; /*ubacivanje elementa u niz*/

for(i=0; i<n+1; i++)


printf(" %d", a[i]);

return 0;
}

ZADATAK 25 :a: Napisati program koji učitava niz od n elemenata n<=20 i ceo broj K. Iz niza
treba izbaciti element na K-toj poziciji i prikazati dobijeni niz.

k--; /*smanjivanje za 1 jer indeks niza krece od nule*/


for(i=k+1; i<n; i++) /*Pomeranie elemenata niza u levo za jedno mesto da bi se izbacio a[k]*/
a[i-1] = a[i];
n--; /*smanjivanje dimenzije niza za 1 jer smo izbacili jedan element.
NAPOMENA: poslednji element u nizu a[n-1] i dalje postoji
*/

1
ZADATAK 26: Napisati program koji učitava niz od n elemenata n<=50, obrće ga i ispisuje
novodobijeni niz na standardnom izlazu.

#include <stdio.h>
#include <stdlib.h>
#define DIM 50
main(){

int a[DIM], n, i, j;
printf("\nDuzina niza (max %d): ", DIM);
scanf("%d", &n);
if(n <= 0 || n > DIM) exit(1);

printf("Uneti elemente niza: ");


for(i=0;i<n;i++)
scanf("%d", &a[i]);

for(i=0,j=n-1; i<j; i++,j--){ // ici do pola niza i menjati prvi sa poslednjim


int tmp = a[i];
a[i]= a[j];
a[j]= tmp;
}

for(i=0;i<n;i++)
printf(" %d", a[i]);

printf("\n");
}

ZADATAK 27: Napisati program koji stvara i ispisuje slučajan celobrojni niz zadate dužine koji
se sastoji od jednocifrenih decimalnih brojeva, izvrši uređivanje niza po neopadajućem redosledu
vrednosti brojeva i ispisuje rezultujući niz.

#include <stdio.h>
#include <stdlib.h>
#define DIM 500

main (){
int n, a[DIM], i, j;

printf("\nRAND_MAX = %d, RAND= %d", RAND_MAX, rand());


//ispis u konzoli: RAND_MAX = 32767, RAND= 41 (bilo koja vrednosti od 0 do MAX)

printf("\nDuzina niza (max %d): ", DIM);


scanf("%d", &n);

2
printf("\nPocetni niz:\n\n");
for(i=0; i<n; i++)
a[i] = rand() / ((double)RAND_MAX + 1) * 10;

/*Sortiranje niza*/
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i] > a[j]){
int b = a[i];
a[i] = a[j];
a[j] = b;
}

printf("\nSortirani niz:\n\n");
for(i=0; i<n; i++)
printf("%d ", a[i]);

return 0;
}
VEZBA : NAPRAVITI LOTO IZVLACENJE (6 od 39, da se ne ponavljaju)
A[i]=(rand()%39)+1

ZADATAK 28: Napisati C program koji formira niz C[8] od celih brojeva koji se učitavaju
jedan po jedan sa tastature. Program treba da nađe sumu svih parnih elemenata DO PRVE
NULE U NIZU.

#include <stdio.h>

int main(){
int C[8];
int i, s;

printf ("\nUneti elemente niza ! \n");


for(i=0; i<8; i++){
printf("\nC[%d]= ",i);
scanf("%d", &C[i]);
}
// umesto for koristiti while
i=0;
s=0;
while(i<8 && a[i]!=0){
if (a[i]%2==0) //ovde se moze resavati bilo koja problematika
s += a[i]; //koja ide dok je neki uslov tacan a ne do kraja niza

i++;
}

3
printf("Suma = %d \n", s);

return 0;
}
ZADATAK 29: Iz niza a u niz B prebaciti sve PROSTE brojeve koji se nalaze ISPRED
PRVOG PARNOG BROJA U NIZU.

#include <stdio.h>
#include <stdlib.h>
#define DIM 20

void unos(int a[], int n){


int i;
printf ("Unesite clanove niza: \n");
for (i=0; i<n; i++){
printf("\n a[%d]=", i);
scanf ("%d", &a[i]);
}
}
void ispis(int a[], int n){
int i;
printf("\n Elemenni niza su :\n");
for(i=0; i<n; i++)
printf("%d ", a[i]);
}

int prost(int n){


int i;
for(i=2; i<=sqrt(n); i++)
if(n%i==0) // ako je n deljivo sa bilo kojim i
return 0; // vrati 0, nije prost
return 1; // ako se to nikad ne desi, vrati 1, jeste prost
}

int prebaci(int a[], int n, int b[]){


int i, k;
k=0;
i=0;

while(i<n && a[i]%2!=0){ // do provog parnog elementa = dok nisu parni


if(prost(a[i])) // ako je a[i] prost => prebaciti ga u niz b
b[k++] = a[i];
i++;
}
return k;
}

4
main (){
int a[DIM], b[DIM];
int i, n;

printf("Uneti broj clanova niza ");


scanf("%d", &n);

unos(a, n);

int k;
k= prebaci(a,n,b);

ispis(b,k);

return 0;
}

5
VEŽBE 07
MATRICE

Matrice predstavljaju dvodimenzionalne nizove (nizove nizova) koje pored stadardnih nizova karakteriše i još
jedna dimenzija. Definicija matrica izvšava se u sledećem formatu:
TIP naziv_matrice [BR_VRSTA][BR_KOLONA]
gde su BR_VRSTA i BR_KOLONA maksimalno dozvoljene dimenzije koje se mogu koristiti u programu za rad.
Anotacija je ista kao i kod nizova i kreće od 0. Kvadratne matrice ( BR_VRSTA = BR_KOLONA ) imaju dve
dijagonale, glavnu i sporednu.

VRSTE => for(i=0; i<n; i++)//po vrsti Dve petlje za matricu.


Prvo se izmenjaju svi elementi unutrasnje petlje, pa
KOLONE =>

for(j=0; j<n; j++)


A00 A01 A02 ….. se tek onda uveća iterator spoljasnje petlje za 1 tj.:
for(j=0; j<n; j++)//po koloni A00, A01, A02, i fiksno, uvećava se j
A10 A11 A12 for(i=0; i<n; i++) A10, A11, A12 uveća se i,ponovo se uvećava j
A[i][j] vrednost elementa u vrsti i i koloni j
A20 A21 A22 Elementi u istoj vrsti imaju isto i a elementi u istoj koloni imaju isto j

ZADATAK 29. Napisati program za sabiranje matrica a i b dimenzije n i štampanje rezultujuće matrice c.

#include <stdio.h> int main(){


void unos(int
unos a[][10],int n, int m){ int a[10][10], b[10][10], c[10][10];
int i, j; int n, m;
for(i=0; i<n; i++)
for(j=0; j<m; j++){ printf("Uneti broj vrsta i kolona\n");
printf("\n a[%d][%d]=", i,j); scanf("%d %d", &n, &m);
scanf("%d", &a[i][j]);
} printf("Uneti elemente matrice a\n");
} unos(a, n, m);

void ispis(int
ispis a[][10],int n, int m){ printf("Uneti elemente matrice b\n");
int i,j; unos(b, n, m);
for(i=0; i<n; i++){
for(j=0; j<m; j++) printf("Zbir matrica a i b je:\n");
printf("%d\t", a[i][j]); zbir(a, b, c, n, m);
printf("\n");
} ispis(c, n, m);
} return 0;
}
void zbir(int a[][10], int b[][10], int c[][10], int n, int m){
int i, j;
for(i=0; i<n; i++){
for(j=0; j<m; j++){
c[i][j] = a[i][j] + b[i][j];
}
}
}

1
ZADATAK 29. Napisati C program koji učitava jedan po jedan realan broj i formira matricu A[5][5]. Zatim
program treba da odredi sumu svih elemenata prve kolone i sumu druge vrste ove matrice i da ispita koja je suma
veća. Zatim odštampati poruku o tome koja je suma veća.

#include <stdio.h>
int main(){
float a[5][5];
int i,j;
float spk, sdv;

printf("Uneti elemente matrice A\n");


for(i=0;i<5;i++)
for(j=0; j<5; j++)
scanf("%f",&a[i][j]);

spk=0.0;
for(i=0; i<5; i++) // i se menja a j = 0 (fiksno pa ne treba petlja)
spk+=a[i][0];
sdv=0.0;
for(j=0; j<5; j++) // j se menja a i = 1 (fiksno pa ne treba petlja)
sdv+=a[1][j];
printf("Suma elemenata prve kolone je: %f\n\n", spk);
printf("Suma elemenata druge kolone je: %f\n\n", sdv);

if (spk > sdv)


printf("Veca je suma prve kolone i iznosi: %f\n\n",spk);
else if (sdv > spk)
printf("Veca je suma druge vrste i iznosi: %f\n\n",sdv);
else
printf("Sume kolona su iste i iznose %f",spk);
return 0;
}

2
ZADATAK 30. Napisati C program koji učitava jedan po jedan realan broj i formira matricu A[7][5]. Program
treba da izračuna u kojoj koloni je najmanji element (pretpostavka da ima samo jedan najmanji element u celoj
matrici), da odštampa tu najmanju vrednost i da odštampa tu kolonu.

#include <stdio.h>
int main(){
float a[7][5];
int i, j, k, v;

printf("Uneti elemente matrice A\n");


for(i=0; i<7; i++)
for(j=0; j<5; j++)
scanf("%f", &a[i][j]);

float min=a[0][0];
v=0;
k=0;
for(i=0; i<7; i++)
for(j=0; j<5; j++)
if(min>a[i][j]) {
min=a[i][j];
v=i;
k=j;
}

printf("Minimalni element je %f a nalazi se u koloni %d i vrsti %d \n", min, k, v);

printf("Izgled kolone %d ",k);


for (i=0;i<7;i++) // i se menja a j = k (fiksno pa ne treba petlja)
printf("%f ",a[i][k]);
printf("\n");

printf("Ispis matrice \n ");


for (i=0; i<7; i++){
for (j=0; j<5; j++)
printf("%f ", a[i][j]);
printf("\n");
}
return 0;
}

Primer: vise vrsta ili kolona odjednom


for(i=0; i<n; i++) //proci kroz matricu
for(j=0; j<m; j++)
if (i ==1 || i==3) //odbrati samo potrebne vrste ili kolone

3
ZADATAK 31. Napisati program kojim se za random generisanu matricu sumu elemenata i-te vrste upisuje na i-tu
poziciju niza b, a srednja vrednost pozitivnih elemenata i-te kolone se upisuje na i-tu pozciju niza c.
#include <stdio.h>
A00 A01 A02 B0
#include <math.h> A10 A11
A11 A12 B1
#define DIM 20
void ispisMat (int a[][DIM], int n, int m){ C0 C1 C2
printf ("Elementi matrice su \n");
for (int i =0;i<n;i++){
for (int j=0;j<m;j++)
printf("%d\t", a[i][j]);
printf("\n"); for(i=0; i<m; i++){ //po vrstama
} s=0;
} for(j=0; j<n; j++)
s+=a[i][j];
void ispisNiz (int a[], int n){
b[i]=s;
printf ("Elementi niza su \n");
}
for (int i =0;i<n;i++)
printf("%d\t",a[i]);
for(j=0; j<n; j++){ //po kolonama
printf("\n");
sr=0;
}
br=0;
for(i=0; i<m; i++)
int main(){
if (a[i][j]>0){
int a[DIM][DIM], int b[DIM], int c[DIM];
sr+=a[i][j];
int i, j, m, n, s, sr, br;
br++;
}
printf("Uneti dimenzije matrice A\n");
c[j]=sr/br;
scanf(“%d %d”, &m, &n);
}
// unos elemenata pomocu rand
ispisNiz(b,m);
for(i=0; i<m; i++)
ispisNiz(c,n);
for(j=0; j<n; j++)
a[i][j]=rand();
ispisMat(a,n,m);
return 0;
}

4
ZADATAK 32. Napisati program kojim se nakon što se unesu elementi matrice unose i indeksi dve vrste čiji
elementi treba da se zamene.

#include<stdio.h> void zamena(int a[][5], int m, int v1, int v2){


int j, pom;
void unos(int a[][5], int n, int m){ for(j=0; j<m; j++){ // po kolonama
int i, j; pom = a[v1][j];
for(i=0;i<n;i++) a[v1][j] = a[v2][j];
for(j=0;j<m;j++){ a[v2][j] = pom;
printf("a[%d][%d]= ", i, j); }
scanf("%d", &a[i][j]); }
} int main(){
} int a[5][5], n, m, v1, v2;
printf("Unesi dimenziju matrice: \n");
void ispis(int a[][5], int n, int m){ scanf("%d%d", &n, &m);
int i,j; unos(a, n, m);
for(i=0; i<n; i++){ printf("Unesi dve vrste koje menjas: \n");
for(j=0; j<m; j++) scanf("%d%d", &v1, &v2);
printf("%d\t", a[i][j]); zamena(a, m, v1, v2);
printf("\n"); ispis(a, n, m);
} return 0;
} }
VEŽBA: Prebaciti proste brojeve iz matrice a u niz b.
#include <stdio.h> #include <stdlib.h> int prebaci(int a[][10], int n, int m, int b[]){
#define DIM 20 int i,j,k;
void unos (int a[][10], int n, int m){
int i, j; k=0;
printf("Uneti elemente matrice\n"); for(i=0;i<n;i++)
for(i=0;i<n;i++) for(j=0;j<m;j++)
for(j=0;j<m;j++){ if(prost(a[i][j]))
printf("a[%d][%d]=", i,j); b[k++] = a[i][j];
scanf("%d", &a[i][j]); return k;
} }
} void ispisNiz (int a[], int n){a
void ispis (int a[][10], int n, int m){ int i;
int i, j; printf("element niza su\n");
printf("element matrice su\n"); for(i=0;i<n;i++)
for(i=0;i<n;i++){ printf("%d\t", a[i]);
for(j=0;j<m;j++) }
printf("%d\t", a[i][j]); main (){
printf("\n"); int a[10][10],n,m, k, b[100];
}
} printf("Uneti dimenizje\n");
int prost(int n){ scanf("%d%d",&n,&m);
int i; unos(a,n,m);
for(i=2;i<=sqrt(n);i++)
if(n%i==0) ispis(a,n,m);
return 0; k = prebaci(a,n,m,b);
return 1; ispisNiz(b, k);
} }

5
VEŽBE 08
MATRICE - DIJAGONALE

VRSTE =>
GLAVNA DIJAGONALA SPOREDNA DIJAGONALA
KOLONE =>

A00 A01 A02 1. Na ( i == j), max = a[0][0] 1. Na ( i + j == n-1 ) , max = a[0][n-1]


2. Iznad ( i < j ) , max = a[0][1] 2. Iznad ( i + j < n-1 ) , max = a[0][0]
A10 A11 A12 3. Ispod ( i > j ) , max = a[1][0] 3. Ispod ( i + j > n-1 ) , max = a[1][n-1]
Pozicionirati se na pravi deo matrice sa dve for petlje i sa jednim if uslovom od
A20 A21 A22 prethodnih 6 ili nekom njihovom kombinacijom.

ZADATAK 32: Napisati program koji učitava n (vrsta) i m (kolona) matrice a potom učitava elemente matrice,
ispisuje zbir elemenata na glavnoj i sporednoj dijagonali te matrice.
#include <stdio.h>
#include <stdlib.h>
#define N 5

void unos (int a[][4], int n){


int i,j;
printf ("Uneti elemente matrice\n");
for (i=0; i<n; i++){
for (j=0; j<n; j++){
printf("a[%d][%d]= ", i, j);
scanf ("%d", &a[i][j]);
}
}
}

void ispis (int a[][4], int n){


int i,j;
printf ("Elementi matrice su \n");
for (i =0; i<n; i++){
for (j=0; j<n; j++)
printf("%d\t", a[i][j]);
printf("\n");
}
}
main (){
int a[N][N];
int i, j, m, n, glavnadija, sporedna;
printf("Unesi dimenziju matrice \n");
scanf("%d%d", &n, &m);
unos(a, n, m);
glavnadija=0;
sporedna=0;
//prvi nacin //drugi EFIKASNIJI nacin
for (i=0; i<n; i++)
for (j=0; j<m; j++) for (i=0; i<n; i++)
if(i==j) glavnadija+=a[i][i];
glavnadija+=a[i][j];
//prvi nacin //drugi EFIKASNIJI nacin
for (i=0; i<n; i++) for(i=0, j=n-1; i<n; i++, j--)
for (j=0; j<m; j++) sporedna+=a[i][j];
if(i+j==n-1)
sporedna +=a[i][j];

printf("Zbir na glavnoj dijagonali je: %d\nZbir na sporednoj dijagonali je: %d\n", glavnadija, sporedna);
}

ZADATAK 33: Napisati program kojim se učitava matrica nxm. Naći aritmetičku sredinu svih elemenata matrice,
naći maksimalni element ISPOD sporedne dijagonale matrice, aritmetičku sredinu elemenata na sporednoj
dijagonali i najmanji element na glavnoj dijagonali.
#include <stdio.h> main (){
#include <stdlib.h>
#define N 5 int a[N][N], max, min;
void unos (int a[][4], int n){ … } int i, j, n, zbir, sp;
void ispis (int a[][4], int n){ … }
int maxis (int a[][4], int n){ printf("Unesi dimenzije matrice ");
/* max ispod sporedne dijagonale*/ scanf("%d %d", &n);
/*vazno je postaviti max na prvi iz skupa u kojem
se trazi maksimalni*/ unos(a, n);
int i, j,, max=a[1][n-
max=a[1][n-1]; ispis(a, n);

for(i=0; i<m; i++) zbir=0; // zbir svih elemenata


for(j=0; j<n; j++) for (i =0; i<n; i++)
if( i+j > n-1) for (j=0; j<n; j++)
if ( a[i][j] > max) zbir += a[i][j];
max = a[i][j]; printf("Ar. sr. je: %.2lf", zbir/(double)(m*n));
return max;
max
}
int mingd (int a[][4], int n){ printf("\nMAX ispod SD = %d\n", maxis
maxis(a,n));
is
//minimalni na glavnoj dijagonali
int min = a[0][0], i, j; printf("MIN na GD = %d\n", mingd(a,n);
mingd
//kraci i efikasniji nacin
for(i=0; i<n; i++) printf("Ar. sr. na sp = %.2lf\n", arsd(a,n);
arsd
if(a[i][i]<min)
min = a[i][i];
return min; return 0;
} }
double arsd (int a[][4], int n){
//aritmeticka sredina na sporednoj dijagonali
int i, j;
double sp = 0;
for(i=0; i<m; i++)
for(j=0; j<n; j++)
if( i+j == n-1)
sp += a[i][j];
return sp/n;
}
ZADATAK 34: Napisati program koji u kvadratnoj matrici vrsi izdvajanje elemenata ispod glavne dijagonale
uključujući i elemente na glavnoj dijagonali u niz B. Ispisati novo dobijeni niz.

#include <stdio.h>
#include <stdlib.h>
#define N 20

main (){
int a[N][N], b[N];
int i, j, n, k;
printf("Unesi dimenziju matrice \n");
scanf("%d", &n);

printf("Unesi elemente matrice \n");


for(i=0; i<n; i++)
for(j=0; j<n; j++){
printf("Element a[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}

//premestanje elemenata u niz B


k=0; //indeks prvog elementa u nizu B, na kraju dimenzija niza B
for(i=0; i<n; i++)
for(j=0; j<n; j++)
if(i>j || i==j) // || za uniju a && za presek
b[k++] = a[i][j];
printf ("Elementi matrice su \n");
for (i=0; i<n; i++){
for (j=0; j<n; j++)
printf("%d\t", a[i][j]);
printf("\n");
}

printf("Elementi niza su\n");


for(i=0; i<k; i++)
printf("%d, ",b[i]);
return 0;
}

ZADATAK 32: Napisati funkcije za transponovanje matrice a dimenzije n I kreiranje jedinicne matrice.
void transponovanje(int a[][DIM], int n){ void jedinicna(int a[][DIM],int n ){
for(i = 0; i < n; i++) int i,j;
for(j = i; j < n; j++) { for(i=0;i<n;i++)
int p = a[i][j]; for(j=0;j<n;j++)
a[i][j] = a[j][i]; if (i==j)
a[j][i] = p; a[i][j]=1;
} else
} a[i][j]=0;
}

3
4
VEŽBE 09
STRINGOVI ( nizovi karaktera )

Nizovi karaktera su jednodimenzionalni nizovi tipa char.

U standardnom zaglavlju stdio.h definisane su sledeće funkcije:


• a = getchar() - čita sledeći znak, uključujući i bele znakove, i simboličku konstantu EOF (end of file)
ukoliko je pročitan signal za kraj datoteke kao i u slučaju greške u toku čitanja.
• putchar(c) - funkcija za ispisivanje znaka c na ekranu.
• gets(s) - funkcija za čitanje jednog reda teksta i smeštanje u string s
• puts(s) - funkcija za ispisivanja jednog reda teksta
• a = getc(c) - čitanje jednog karaktera sa ulaza c, to može biti stdin (tastatura) ili neki fajl
• putc(c, izlaz) - ispis karaktera C na izlaz, to može biti stdout (tastatura) ili neki fajl
• stdin - standardni ulazni tok
• stdout - standardni izlazni tok
• stderr - standardne greške
• EOF - end of file
sprintf(s,“format”, arg1,...)-štampanje u string s
sscanf(s,“format”, &ime1,...)-unos iz stringa s

U standardnom zaglavlju string.h definisane su sledeće funkcije:


• n = strlen(s) - vraća duzinu s-a.
• strcpy(s, c) - kopira niz c u niz s.
• strncpy(s, c,n) - kopira niz c u niz s prvih n karaktera.
• strcat(s, c) - povezuje niz karaktera c iza niza s
• strncat(s, c, n) - povezuje niz karaktera c iza niza s počevši od n-tog karaktera
• strcmp(s, st) - upoređuje niz s sa nizom st; vraća <0 za s<st, 0 za s=st ili >0 ako je s>st.
• srtncmp(s, c, n) - upoređuje prvih n karaktera niza s sa nizom c
• strchr(s, c) - pokazivač na prvi karakter niza c u nizu s
• strrchr(s, c) - pokazivač na poslednji karakter niza c u nizu s
• strstr(s, c) – vraća pokazivač na prvo pojavljivanje stringa c u stringu s
• strtok(s, c) – razbija string s na tokene sa delimiterom c
• memcpy(s, c, n) - kopira n karaktera iz niza c u niz s
• memmove(s, c, n) - kopira n karaktera iz niza c u niz s sa mogućnošću preklapanja
• memchr(s, c, n) - pozakizvač na prvi c u privih n karaktera u nizu s
• memset(s, c, n) - smešta c u prvih n karaktera niza s

U standardnom zaglavlju ctype.h definisane su sledeće funkcije:


• isalnum(c) - ispituje da li je c alfanumerički karakter
• isalpha(c) - ispituje da li je c alfabetski karakter
• iscntrl(c) - ispituje da li je c kontrolni karakter
• isdigit(c) - ispituje da li je c cifra
• isgraph(c) - ispituje da li je c štampani karakter (ne uključuje prazninu)
• islower(c) - ispituje da li je c malo slovo
• isupper(c) - ispituje da li je c veliko slovo
• isspace(c) - ispituje da li je c praznina, formfeed, nova linija, vertikalni, horizontalni karaker
• isprint(c) - ispituje da li je c karakter (samo da nije praznina)
• ispunct (c) - ispituje da li je c izuzimajući praznine, slovo ili broj
• isxdigit(c) - ispituje da li je c heksadecimalni broj
• tolower(c) - pretvara c u malo slovo
• toupper(c) - pretvara c u veliko slovo

1
ZADATAK 58. Napisati program koji učitava jedan znak sa tastature i proverava da li je slovo ili cifra.

#include <stdio.h> #include <stdio.h>


void main(){ #include <ctype
ctype.h>
ctype
char a; void main(){
printf("Unesi jedan znak: "); char a;
scanf(“%c”, &a); printf("Unesi jedan znak: ");
a = getchar();
getchar
if(a>='0' && a<='9') if(isdigit
isdigit(a))
isdigit
printf("Znak %c je cifra!\n", a); printf("Znak %c je cifra!\n", a);
else else
printf("Znak %c nije cifra!\n", a); printf("Znak %c nije cifra!\n", a);
if((a>='a' && a<='z') || (a>='A' && a<='Z')) if(isalpha
isalpha(a))
isalpha
printf("Znak %c je slovo!\n", a); printf("Znak %c je slovo!\n", a);
else else
printf ("Znak %c nije slovo!\n", a); printf("Znak %c nije slovo!\n", a);
} }

ZADATAK 59: Napisati program koji učitava jedan znak i ispituje li je on malo slovo, veliko slovo,
samoglasnik ili suglasnik.
#include <stdio.h>
#include <ctype.h>
void main (){
char a, b;
printf("Unesi jedan znak: ");
a = getchar();
getchar
if(isalpha(a)) {
if(isupper
isupper(a))
isupper
printf("Znak %c je veliko slovo!\n", a);
else if(islower
islower(a))
islower
printf("Znak %c je malo slovo!\n", a);
b = tolower(a);
tolower
if(b=='a' || b=='e' || b=='i' || b=='o' || b=='u')
printf("Znak %c je samoglasnik!\n", a);
else printf("Znak %c je suglasnik!\n", a);
}
}
ZADATAK 60 : Napisati program koji učitava string (niz karaktera) ne duži od 40 karaktera. Ispisati
koliko ima karaktera (tj. koliko je dugačak string), cifara, slova i praznih mesta u tom stringu.

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define DIM 40
void main (){
char a[DIM];
int n, i=0, s=0, c=0, b=0;
printf("Unesi string ne duzi od 40 karaktera: ");
gets(a);
gets
n = strlen(a);
strlen

2
printf("U nizu '%s' ima %d karaktera!\n", a, n);
for(i=0; i<n; i++) {
if(isalpha
isalpha(a[i]))
isalpha
s++;
else if(isdigit
isdigit(a[i]))
isdigit
c++;
else if(isspace
isspace(a[i]))
isspace
b++;
}
printf("U nizu '%s' ima %d slova, %d cifara i %d praznih mesta!\n", a, s, c, b);
}

ZADATAK 61: Napisati program koji učitava string (niz karaktera) ne duži od 80 karaktera. Ispisati isti
string samo sva mala slova u njemu zameniti velikim.

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define DIM 80
int main (){
char a[DIM];
int i = 0;
printf("Unesi string ne duzi od %d: ", DIM);
gets(a);
gets

for(i=0; i< strlen(a);


strlen i++)
a[i] = toupper(a[i]);
toupper

printf("Posle izmene string je: '%s'!\n", a);

return 0;
}

ZADATAK 62: Napisati program koji učitava string (niz karaktera) ne duži od 80 karaktera i još jedan
karakter. Ispisati string koji nastaje izbacivanjem učitanog karaktera.

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define DIM 80
void main (){
char a[DIM], b;
int i=0;
printf("Unesi string ne duzi od %d znakova: ", DIM);
gets(a);
gets
printf("Unesi znak koji treba izbaciti iz stringa: ");

3
b = getchar();
getchar
for(i=0; i< strlen(a);
strlen i++) {
if(a[i] != b)
putchar(a[i]);
putchar
}
putchar('\n');
}

Mnogo tačniji način sa promenom dimenzije niza


#include <stdio.h> for(i=0; i< strlen(a);
strlen i++) {
#include <ctype.h> if(a[i] != b){
#include <string.h> a[k] = a[i];
#define DIM 80 k++;
}
int main (){ }
char a[DIM], b,k = 0;
unsigned int i = 0; a[k] = '\
'\0';//obavezno
0';//obavezno zatvoriti string

printf("Unesi string \n”); printf("Duzina novog stringa je %d \n",


gets(a); strlen(a));

printf("Duzina stringa je %d \n", strlen(a)); printf("Novi string je \n\n");


puts(a);
printf("Unesi znak koji treba izbaciti: \n");
b = getchar(); printf("\n");
return 0;
}

ZADATAK 63. Prikazivanje tablice ASCII kodova sa po 19 znakova u jednoj koloni.

#include<stdio.h>
int main() {
char c;
int i;
printf("\t\t Tablica ASCII kodova\n\n");
for(c=' ';c<' '+19;++c){
for(i=0;i<95;i+=19)
printf("%3d %c ",c+i,c+i);
putchar('\n');
}
return 0;
}
// moze I prostije
// for(i=0;i<127;i++)
// printf("%d = %c ", i, i);

4
VEŽBE 10
STRUKTURE

Struktura je skup jedne ili više promenljivih, koje mogu biti različitih tipova, grupisanh zajedno radi lakše
manipulacije. Strukture pomažu pri organizaciji kompleksnih podataka, posebno u velikim programima, jer one
omogućuju obradu grupe međusobno povezanih promeljivi kao jedne cjeline. Primer strukture Tacka vidi se na
slici. Tačka je definirana uređenim parom koordinata, pravougaonik se može definisati parom tačaka i sl.

Te dve komponente mogu se smestiti u strukturu koja je ovako deklarisana


struct IME_STRUKTURE{ struct Tacka {
tip IME_CLANA1; int x;
tip IME_CLANA2; int y;
}; };
typedef struct Tacka TACKA;
//dalje umesto struct Tacka => TACKA
struct Tacka A; //deklaracija promenljive
TACKA A; //ako je koriscen typedef struct Tacka TACKA;

typedef komandom se definiše da se u daljem delu koda umesto struct Tacka koristi skraćeno TACKA kao i bilo
koji drugi standardan tip promenljive.
• Članu određene strukture pristupa se sledećim izrazom
IME_STRUKTURE. IME_ CLANA // pristup preko operatora “.”
• Operatorom "." povezujemo ime strukture i ime člana. Ispis koordinata za sturkturu TACKA A, npr.,
printf("%d, %d", A.x, A.y);

Takođe moguća je kombinacija typedef i deklaracije structure u jednom koraku kao u sledećem primeru:

typedef struct Tacka{


double x, y;
}TACKA;

main(){
TACKA t1, t2, t3;
}

Strukture možemo ugnjezditi. Pravougaonik možemo predstaviti parom tačaka koje označavaju dijagonalno
suprotne tačke.
typedef struct rect{
struct point pt1;
struct point pt2;
}RECT;
main{
rect a;
printf(“%d”, a.p1.x)
}
//ispisuje X koordinatu tacke p1 pravougaonika a

1
ZADATAK 64: Definisati strukturu za teme trougla a zatim izracunati povrsinu trougla ako su date koordinate
temena trougla.

#include <stdio.h>
#include <math.h>

struct Tacka{
double x, y;
};

typedef struct Tacka TACKA;

main(){
TACKA t1, t2, t3;
double povrsina, a, b, c, s;
printf("Unesi kordinate prve tacke: ");
scanf("%lf %lf", &t1.x, &t1.y);
printf("Unesi kordinate druge tacke: ");
scanf("%lf %lf", &t2.x, &t2.y);
printf("Unesi kordinate trece tacke: ");
scanf("%lf %lf", &t3.x, &t3.y);
a=sqrt(pow(t1.x-t2.x,2)+pow(t1.y-t2.y,2));
b=sqrt(pow(t1.x-t3.x,2)+pow(t1.y-t3.y,2));
c=sqrt(pow(t2.x-t3.x,2)+pow(t2.y-t3.y,2));
s=(a+b+c)/2;
povrsina=sqrt(s*(s-a)*(s-b)*(s-c));
printf("Povrsina trougla je: %.2lf!\n", povrsina);
}

ZADATAK 65: Definisati strukturu za rad sa kompleksnim brojevima a potom napisati program koji ucitava 2
kompleksna broja a prikazuje njihov zbir, razliku, proizvod, kolicnik, moduo prvog i konjugovano kompleksan
drugom. VEZBA

#include <stdio.h>
#include <math.h>

struct Kb{
double x, y;
};

main(){
struct Kb z1, z2, zbir, razlika, pr, ko, kk;
double mo;
printf("Unesi prvi kompleksan broj: ");
scanf("%lf %lf", &z1.x, &z1.y);
printf("Unesi drugi kompleksan broj: ");
scanf("%lf %lf", &z2.x, &z2.y);
zbir.x=z1.x+z2.x;
zbir.y=z1.y+z2.y;

2
razlika.x=z1.x-z2.x;
razlika.y=z1.y-z2.y;
pr.x=z1.x*z2.x-z1.y*z2.y;
pr.y=z1.y*z2.x+z1.x*z2.y;
ko.x=(z1.x*z2.x+z1.y*z2.y)/(pow(z2.x, 2)+pow(z2.y, 2)) ;
ko.y=(z1.y*z2.x-z1.x*z2.y)/(pow(z2.x, 2)+pow(z2.y, 2)) ;
mo=sqrt(pow(z1.x, 2)+pow(z1.y, 2));
kk.x=z2.x;
kk.y=-z2.y;
printf("Zbir je (%.2lf,%.2lf)\nRazlika je (%.2lf,%.2lf)\n", zbir.x, zbir.y, razlika.x, razlika.y);
printf("Proizvod je (%.2lf,%.2lf)\nKolicnik je (%.2lf,%.2lf)\n", pr.x, pr.y, ko.x, ko.y);
printf("Moduo prvog broja je: %.2lf\nKonjugovano kompleksan sa drugim je (%.2lf,%.2lf)\n", mo, kk.x,
kk.y);
}

ZADATAK 66: Deklarisati strukturu za rad sa razlomcima a potom napisati program koji ucitava 3 razlomka a, b,
c i prikazuje razlomak a2-b/c. VEZBA

#include <stdio.h>
#include <math.h>

struct Razlomak{
int br, im;
};

main() {
struct Razlomak a, b, c, d, e, f;
printf("Unesi brojilac i imenilac prvog razlomka: ");
scanf("%d %d", &a.br, &a.im);
printf("Unesi brojilac i imenilac drugog razlomka: ");
scanf("%d %d", &b.br, &b.im);
printf("Unesi brojilac i imenilac treceg razlomka: ");
scanf("%d %d", &c.br, &c.im);
d.br=pow(a.br, 2);
d.im=pow(a.im, 2);
e.br=b.br*c.im;
e.im=b.im*c.br;
f.br=d.br*e.im-e.br*d.im;
f.im=d.im*e.im;
printf("Rezultat izraza a*a-b/c=%d/%d!\n", f.br, f.im);
}

ZADATAK 67: Deklarisati strukturu tacka a potom strukturu pravougaonik (opisuje se pomocu 2 tacke, gornjeg
levog i donjeg desnog temena), pretpostavlja se da su stranice paralelne koordinatnim osama a potom napisati
program koji ucitava 2 pravougaonika a prikazuje njihove povrsine.

#include <stdio.h>

typedef struct Tacka {


double x, y;

3
}TACKA;

typedef struct Pravougaonik{


TACKA gl, dd;
}PRAVOUGAONIK;

main(){
PRAVOUGAONIK p1, p2;
double p;
printf("Unesi temena prvog pravougaonika: ");
scanf("%lf %lf %lf %lf", &p1.gl.x, &p1.gl.y, &p1.dd.x, &p1.dd.y);
printf("Unesi temena drugog pravougaonika: ");
scanf("%lf %lf %lf %lf", &p2.gl.x, &p2.gl.y, &p2.dd.x, &p2.dd.y);
p=(p1.gl.y-p1.dd.y)*(p1.dd.x-p1.gl.x);

printf("Povrsina prvog pravougaonika je: %.2lf\n", p);


p= (p2.gl.y-p2.dd.y)*(p2.dd.x-p2.gl.x);

printf("Povrsina drugog pravougaonika je: %.2lf\n", p);


}

ZADATAK 68. Napisati program koji za zadato tekuće vreme određuje naredno vreme.
#include<stdio.h>

typedef struct vreme{


int sat;
int minut;
int sekund;
}VREME;

int main(){
VREME tekuce, naredno;

printf("Unesite tekuce vreme?[hh:mm:ss]\n");


scanf("%d:%d:%d",&tekuce.sat,&tekuce.minut,&tekuce.sekund);

naredno = tekuce;

if(++naredno.sekund==60){
naredno.sekund=0;
if(++naredno.minut==60){
naredno.minut=0;
if(++naredno.sat==24)
naredno.sat=0;
}
}

printf("Naredno vreme je %02d:%02d:%02d\n", naredno.sat, naredno.minut, naredno.sekund);


return 0;
}

4
ZADATAK 69. Napisati program koji za dva studenta opisana preko imena, i proseka ispisuje podatke o onom sa
boljim prosekom sa napomenom o duzini imena (strlen).

#include <stdio.h>
#include <string.h>
#define DIM 20

typedef struct Student{


char ime[DIM];
float prosek;
}STUD;

main(){
STUD a, b;

printf("\nUnesite podatke o prvom studentu:\n");

printf("Ime studenta: ");


scanf("%s", a.ime);

printf("Srednja ocena studenta: ");


scanf("%f", &a.prosek);

printf("\nUnesite podatke o drugom studentu:\n");

printf("Ime studenta: ");


scanf("%s", b.ime);

printf("Srednja ocena studenta: ");


scanf("%f", &b.prosek);

if (a.prosek > b.prosek)


printf("PODACI: %s %.2f, duzina imena= %d\n",a.ime, a.prosek, strlen(a.ime));
else if (b.prosek > a.prosek)
printf("PODACI: %s %.2f, duzina imena= %d\n",b.ime, b.prosek, strlen(b.ime));
else
printf ("\n Studenti imaju iste proseke %d\n", a.prosek);

5
VEŽBE 11
Nastavak struktura

ZADATAK 46. Napisati program za formiranje strukture student sa karakteristikama: Ime, Prezime, broj indeksa,
srednja ocena. Za uneti broj studenata n, sortirati studente prema srednjoj oceni i ispisati na ekranu.

#include <stdio.h>
#define DIM 20

struct Student{
char ime[DIM];
char prezime[DIM];
int br_indeksa;
float sred_ocena;
};

typedef struct Student STUD;

void unos (STUD a[], int n){


int i;
printf("Unesite podatke o studentima:\n\n");

for(i=0; i<n; i++) {


printf("Ime studenta: ");
scanf("%s", a[i].ime);
printf("Prezime studenta: ");
scanf("%s", a[i].prezime);
printf("Broj indeksa: ");
scanf("%d", &a[i].br_indeksa);
printf("Srednja ocena studenta: ");
scanf("%f", &a[i].sred_ocena);
}
}

void ispis (STUD a[], int n){


int i;

for(i=0; i<n; i++)


printf("[%d]. %s %s,\t%d,\t%3.2f\n",i+1, a[i].ime, a[i].prezime, a[i].br_indeksa, a[i].sred_ocena);
}
void sort(STUD a[], int n){
int i,j;
STUD pom;

for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(a[i].sred_ocena < a[j].sred_ocena) {
pom = a[i];
a[i] = a[j];
a[j] = pom;

1
}
}
main(){
int n, i, j;
STUD a[DIM];
printf("Unesite broj studenata: ");
scanf("%d", &n);

unos(a,n);

sort(a,n);

ispis(a,n);
}

2
ZADATAK 47. Definisati strukturu GRAD sa podacima članovima: ime, broj stanovnika, prosečan dohodak
radnika. Napisati program kojim se unose podaci o gradovima u Srbiji i štampati na ekranu ime grada sa najvećim
brojem stanovnika. Izračunati ukupan dohodak svih unetih gradova.

#include <stdio.h>
#define DIM 10
#define N 20

typedef struct Grad{


char ime[N];
int br_stan;
float dohodak;
}GRAD;

main(){
GRAD NizGradova[DIM];
int i, n, max, max_index = 0;
float uk_dohodak = 0.0;
printf("Unesi broj gradova(max %d): ", DIM);
scanf("%d", &n);

printf("Unesi podatke o gradovima:\n");


for(i=0;i<n;i++) {
printf("Ime grada: ");
scanf("%s", NizGradova[i].ime);
printf("Broj stanovnika: ");
scanf("%d", &NizGradova[i].br_stan);
printf("Dohodak grada: ");
scanf("%f", &NizGradova[i].dohodak);

uk_dohodak += NizGradova[i].dohodak;
}

max = NizGradova[0].br_stan;
for(i=0;i<n;i++)
if(NizGradova[i].br_stan > max) {
max = NizGradova[i].br_stan;
max_index = i;
}

printf("Grad sa najvise stanovnika je: %s.\n",NizGradova[max_index].ime);


printf("Ukupan dohodak svih gradova je: %5.3f.\n", uk_dohodak);
}

3
ZADATAK 48. Napisati program koji ispisuje podatke o najskupljem mercedesu iz niza auta opisanih preko
marke i cene.
#include <stdio.h>
#define DIM 20

struct Auto{
char marka[DIM];
int cena;
};

typedef struct Auto AUTO;

void unos (AUTO a[], int n){


int i;
printf("Unesite podatke o automobilima:\n\n");

for(i=0; i<n; i++) {


printf("Marka: ");
scanf("%s", a[i].marka);
printf("Cena: ");
scanf("%d", &a[i].cena);
}
}

int maxMerc(AUTO a[], int n){ // vraca poziciju najveceg mercedesa ako postoji ili -1 ako ne postoji
int i,j, poz;
AUTO max;

poz = -1; // nema mercedesa


i = 0; // trazimo prvi mercedes, idemo sve dok nije mercedes
while(i<n && strcmp(a[i].marka,"mercedes")!=0){
i++;
}

if (i<n){ // ima mercedesa u nizu


poz = i; // i je stalo na prvom mercedesu
max = a[poz]; // moramo da postavimo max na prvog mercedesa
for(i=0; i<n; i++)
if(a[i].cena > max.cena && strcmp(a[i].marka,"mercedes")==0) {
max = a[i];
poz = i;
}
}
return poz;
}
main(){
int n, poz;
AUTO a[DIM];
printf("Unesite broj Auta: ");
scanf("%d", &n);

4
unos(a,n);

poz = maxMerc(a,n);

if(poz != -1)
printf("\n Cena najskupljeg mercedesa je %d \n", a[poz].cena);
else
printf("\n Nema mercedesa u nizu !!! \n");
}

5
Zadaci sa vežbi iz
Programskog jezika „C“
Tehnički Fakultet Čačak, školska 2007/2008 godina

Vežbe održao: Vlade Maksimović


VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
Zadatak 1. Napisati program koji ispisuje sve trocifrene Amstrongove brojeve, Amstrongovi 
brojevi su oni brojevi koji su jednaki zbiru kubova svojih cifara.

#include<stdio.h>

int main(int argc, char *argv[])


{
int c1,c2,c3,n;
for(n=100;n<=999;n++){
c1=n%10;
c2=n/10%10;
c3=n/100;
if(c1*c1*c1+c2*c2*c2+c3*c3*c3==n)
printf("%d\n",n);
}
return 0;
}

Zadatak 2. Objašnjenje rada switch-a, šta ispisuje sledeci program.

#include<stdio.h>

int main(int argc, char *argv[])


{
int x = 0,i;
for(i=0;i<8;i++)
{
switch(i)
{
case 1: x++;
case 2: x+=2; break;
case 3: x+=1; break;
default: x-=1;
}
}
printf("x=%d",x);
return 0;
}

Zadatak 3. Napisati program koji za uneti mesec ispisuje broj dana u mesecu.

#include<stdio.h>

int main(int argc, char *argv[])


{
int mesec;
char ch;

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
printf("Uneti redni broj meseca\n");
scanf("%d",&mesec);

switch(mesec)
{
case 1:case 3:case 5:case 7:case 8:case 10: case 12: printf("31 dan\n"); break;
case 4: case 6: case 9: case 11: printf("30 dana\n"); break;
case 2: printf("Da li je godina prestupna (d/n)?\n"); scanf("%c",&ch); scanf("%c",&ch);
if((ch=='d')||(ch=='D'))
printf("29 dana\n");
else
printf("28 dana\n"); break;
default: printf("Nekorektan broj meseca\n");
}
return 0;
}

Zadatak 4. Napisati program koji za uneti datum ispisuje datum sledećeg dana.

#include<stdio.h>

int main(int argc, char *argv[])


{
int d, m, g, p=0, brdana;
printf("Unesi datum(d m g): ");
scanf("%d%d%d",&d,&m,&g);

if ((g%100 !=0 && g%4==0) || (g%400 == 0))


p++;

switch (m) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12: brdana=31; break;
case 4: case 6: case 9: case 11: brdana=30; break;
case 2: brdana=28+p; break;
}

if ( d < brdana )
d++;
else if (m!=12) {
d=1;
m++;
}
else {
d=1;
m=1;
g++;
}
printf("Datum sledeceg dana je: %d/%d/%d\n",d,m,g);

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
return 0;
}

Zadatak 5. Nalaženje korena kvadratne jednačine.

#include<stdio.h>
#include<math.h>

int main(int argc, char *argv[])


{
double a,b,c,d,x1,x2,y1,y2;
typedef enum {Realni,Kompleksni,Dvostruki,Linearna,Pogresna} Vrsta;
Vrsta vrsta;

printf("Unesi koeficijente kvdratne jednacine:" );


scanf("%lf%lf%lf",&a,&b,&c);

if(a){
d=b*b-4*a*c;
if(d>0){
vrsta=Realni;
x1=(-b+sqrt(d))/(2*a);
x2=(-b-sqrt(d))/(2*a);
}
else if (d==0){
vrsta=Dvostruki;
x1=(-b/(2*a));
}
else {
vrsta=Kompleksni;
x1=(-b/(2*a));
x2=x1;
y1=sqrt(-d)/(2*a);
y2=-y1;
}
}
else if(b){
vrsta=Linearna;
x1=-c/b;
}
else
vrsta = Pogresna;

switch(vrsta){
case Realni: printf("Realni koreni su %lf i %lf\n",x1,x2);break;
case Dvostruki: printf("Dvostruki realni koren je: %lf",x1);break;
case Kompleksni: printf("Kompleksni koreni su:(%lf + %lf) i (%lf - %lf)",x1,y1,x2,y2);
break;

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
case Linearna: printf("Resenje linearne jednacine je: %lf",x1);break;
case Pogresna: printf("Podaci nemaju smisla!!!");break;
}
printf("\n");
return 0;
}

Zadatak 6. Mnozenje broja sa 2 bez upotrebe operacija sabiranja i mnozenja.

#include<stdio.h>

int main(int argc, char *argv[])


{
int d;
printf("Unesi broj: "); scanf("%d",&d);
d= d<<1;
printf("Novi broj je: %d\n",d);
return 0;
}

Zadatak 7. Predsavljanje brojeva u binarnom brojnom sistemu.

#include<stdio.h>

int main(int argc, char *argv[])


{
int broj,i;
printf("Unesi decimalni broj: ");
scanf("%d",&broj);
for (i=1;i<=8;i++)
{
if ((broj & 0x80) != 0) {
broj <<= 1;
printf("1");
}
else {
broj <<= 1;
printf("0");
}
if (i%4 == 0)
printf(" ");
}
printf("\n");
return 0;
}

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
Zadatak 8. Permutovanje cifara broja.

#include<stdio.h>

int main(int argc, char *argv[])


{
int broj;
printf("Ukucajte ceo broj?\n");
scanf("%d",&broj);
printf("Permutovan broj je\n");
do
{
printf("%d",broj%10);
broj/=10;
}
while(broj);
printf("\n");
return 0;
}

Zadatak 9. Ispisivanje slučajnih brojeva pritiskom na taster SPACE.

#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <time.h>
#include <stdlib.h>

int main(int argc, char *argv[])


{
int ch;
ch = -1;

srand( (unsigned)time(NULL) );

while ( ch != 0x1B )
{
if ( kbhit() )
{
ch = getch();
switch ( ch )
{
case 0x20: printf( "%d\n",rand()%100 ); break;
default: printf( "Greska!\n" ); break;
}
}
}

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
return 0;
}

Zadatak 10. Napisati program u kome se definiše funkcija prost() koja ispituje da li je broj
prost i funkcija main() koja njenim korišćenjem štampa sve proste brojeve do datog prirodnog
broja n.

#include<stdio.h>
#include<math.h>

int prost(int n)
{
int i;
for (i=2;i<=sqrt(n);i=i+1)
if(n%i==0)
return 0;
return i;
}

int main(int argc, char *argv[])


{
int i,n;
printf("Uneti broj\n");
scanf("%d",&n);
printf("Prosti brojevi su\n");
for(i=2;i<=n;i=i+1)
if(prost(i)) printf("%d\n",i);
return 0;
}

Zadatak 11. Napisati program kojim se štampaju svi trocifreni brojevi (ako ih ima) koji su
jednaki sumi faktorijela svojih cifara.

#include<stdio.h>

int fakt(int n)
{
int p=1,i;
for(i=2;i<=n;i++)
p*=i;
return p;
}

int main(int argc, char *argv[])


{
int n,a,b,c;

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
printf("Trocifreni brojevi jednaki sumi faktorijela svojih cifara su:\n");
for(n=100;n<1000;n++)
{
a=n%10;
b=n/10%10;
c=n/100;
if(n==fakt(a)+fakt(b)+fakt(c)) printf("%d\n",n);
}
return 0;
}

Zadatak 12. Pomeranje elemenata niza za jedno mesto u levo.

#include<stdio.h>

void upis(int a[], int n)


{
int i;

for(i=0;i<n;i++)
{
printf("a[%d]= ",i+1);
scanf("%d",&a[i]);
}
}

void ispis(int a[], int n)


{
int i;

for(i=0;i<n;i++)

printf(" a[%d]= %d",i+1,a[i]);


}

void pomerilevo(int a[], int n)


{
int i,pom;
pom = a[0];
for(i=1;i<n;i++)
a[i-1]=a[i];
a[n-1]=pom;
}

int main(int argc, char *argv[])


{
int a[25],n;
n=5;
upis(a,n);

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
pomerilevo(a,n);
ispis(a,n);
printf("\n");
return 0;
}

Zadatak 13. Izdvajanje niza iz k-te paralele dijagonale kvadratne matrice, i njegovo sortiranje.

#include<stdio.h>

void upis(int a[][25],int n)


{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf("a[%d][%d]=",i+1,j+1);
scanf("%d",&a[i][j]);
}
}

void ispis(int a[],int n)


{
int i;

for(i=0;i<n;i++)
printf("%d\n",a[i]);
}

int izdvoj (int a[][25],int b[],int n,int k)


{
int i,j,p=0;
/*za k-tu paralelu iznad sporedne dijagonale */
for(i=0;i<=n-1-k;i++)
for(j=0;j<=n-1-k;j++)
if(i+j==n-1-k)
b[p++]=a[i][j];

/*za k-tu paralelu ispod sporedne dijagonale


for(i=k;i<=n-1;i++)
for(j=k;j<=n-1;j++)
if(i+j==n-1+k)
b[p++]=a[i][j]; */

/*za k-tu paralelu iznad glavne dijagonale


for(i=0;i<=n-1-k;i++)
for(j=k;j<=n-1;j++)

 

VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
if(j-i == k)
b[p++]=a[i][j];*/

/*za k-tu paralelu ispod glavne dijagonale


for(i=k;i<=n-1;i++)
for(j=0;j<=n-1-k;j++)
if(i-j == k)
b[p++]=a[i][j];*/
return p;
}

void sort(int b[],int n)


{
int i,j,pom;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(b[i]>b[j])
{
pom=b[i];
b[i]=b[j];
b[j]=pom;
}
}

int main(int argc, char *argv[])


{
int a[25][25],b[25],n,k,br;
n=4;
k=1;
upis(a,n);
br=izdvoj(a,b,n,k);
sort(b,br);
ispis(b,br);
return 0;
}

Zadatak 14. Napisati program koji od unete matrice formira niz na taj način što od
maksimalnog elementa oduzme minimalan u svakoj vrsti matrice.

#include<stdio.h>

void unos(int a[][25], int v, int k)


{
int i,j;
for(i=0;i<v;i++)
for(j=0;j<k;j++)
{
printf("a[%d,%d]= ",i+1,j+1);

 
10 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
scanf("%d",&a[i][j]);
}
}

void ispis(int a[], int v)


{
int i;
for(i=0;i<v;i++)
printf("%d ",a[i]);

void razlika(int a[][25], int v, int k, int b[])


{
int i,j, max[25], min[25];
for(i=0;i<v;i++)
{
max[i]=a[i][0];

for(j=0;j<k;j++)
if(a[i][j]>max[i])
max[i]=a[i][j];
}

for(i=0;i<v;i++)
{
min[i]=a[i][0];
for(j=0;j<k;j++)
if(a[i][j]<min[i])
min[i]=a[i][j];
}

for(i=0;i<v;i++)
b[i]= max[i]-min[i];
}

int main(int argc, char *argv[])


{
int a[25][25],k,v,b[25];
printf("Unesi dimenziju matrice(npr: 3x4): ");
scanf("%d%d",&v,&k);
unos(a,v,k);
razlika(a,v,k,b);
ispis(b,v);
return 0;
}

Zadatak 15. Napisati program koji menja elemente iz dve vrste matrice.

 
11 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
#include<stdio.h>

void unos(int a[][25], int v, int k)


{
int i,j;
for(i=0;i<v;i++)
for(j=0;j<k;j++)
{
printf("a[%d,%d]= ",i+1,j+1);
scanf("%d",&a[i][j]);
}
}

void ispis(int a[][25], int v, int k)


{
int i,j;
for(i=0;i<v;i++)
{
for(j=0;j<k;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}

void zamena(int a[][25], int k, int m, int n)


{
int i,pom;
for(i=0;i<k;i++)
{
pom = a[m][i];
a[m][i] = a[n][i];
a[n][i] = pom;
}
}

int main(int argc, char *argv[])


{
int a[25][25],k,m,n,v;
printf("Unesi dimenziju matrice(npr: 3x4): ");
scanf("%d%d",&v,&k);
unos(a,v,k);
printf("Unesi dve vrste koje menjas: ");
scanf("%d%d",&m,&n);
zamena(a,k,m,n);
ispis(a,v,k);
return 0;
}

 
12 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
Zadatak 16. Napisati program koji za uneti niz brojeva određuje koliko ih ima do prvog
negativnog.

#include<stdio.h>

void upis(int a[], int n)


{
int i;
for(i=0;i<n;i++)
scanf(“%d”,&a[i]);
}

void ispis(int a[], int n)


{
int i;
for(i=0;i<n;i++)
printf(“%d”,a[i]);
}

int brojpozitivnih(int a[], int n)


{
int k=0,i;
for(i=0;i<n && a[i]>=0;i++)
if(a[i]>0)
k++;
return k;
}

int main(int argc, char *argv[])


{
int a[100],n;
printf(“Unesite dimenziju niza: “);
scanf(“%d”,&n);
printf(“Unesite clanove niza: ”);
upis(a,n);
printf(“Broj pozitivnih do prvog negativnog je: %d”, brojpozitivnih(a,n));
return 0;
}

Zadatak 17. Napisati program koji sve negativne elemente niza stavlja na kraj tog niza.

#include <stdio.h>

void citaj(float a[],int n)


{
int i;
printf("Uneti niz \n");
for(i=0;i<n;i++)

 
13 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
{
printf("a[%d]=",i);
scanf("%f",&a[i]);
}
}

void uredi(float a[],int n)


{
float pom;
int i,j;
i=0; j=n-1;
while(i<j)
if(a[i]>0) i++;
else
{
if(a[j]>0)
{
pom=a[i];
a[i]=a[j];
a[j]=pom; }
j--;
}
}

void pisi(float a[],int n)


{
int i;
printf("Formirani niz\n");
for(i=0;i<n;i++)
printf("a[%d]=%5.2f\n",i,a[i]);
}
int main(int argc, char *argv[])
{
float a[100];
int n;
printf("Uneti broj elemenata niza\n");
scanf("%d",&n);
citaj(a,n);
uredi(a,n);
pisi(a,n);
}

Zadatak 18. Napisati program koji za slučajno uneti niz brojeva, sažima niz na taj način što
sve iste elemente koji su jedan za drugim sabira i postavlja na prvo mesto pojavljivanja tog
broja u nizu.

 
14 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

void upis (int a[], int n)


{
int i;
srand((unsigned)time(NULL));
for(i=0;i<n;i++)
{
a[i]=rand()%10;
}
}

void ispis (int a[], int n)


{
int i;
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
}

int sazimanje(int a[], int b[], int n)


{
int i,j,k,p=0,pom;

for(i=0;i<n;i++)
{
k=i;
j=i+1;
pom=a[k];

while(a[k] == a[j])
{
pom=pom+a[j];
j++;
i++;
}
b[p++]=pom;
}
return p;
}

int main(int argc, char *argv[])


{
int n,a[50],b[50],br;
printf("Unesi dimenziju niza: ");
scanf("%d",&n);

 
15 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
printf("\nUnesi elemente niza");
upis(a,n);
br = sazimanje(a,b,n);
printf("\n");
ispis(a,n);
printf("\n");
ispis(b,br);
printf("\n");
}

Zadatak 19. Napisati program koji na početak niza stavlja one elemente koji se pojavljuju
samo jedanput u nizu, a zatim ostale elemente po redosledu po kome su učitani u niz.

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

void upis (int a[], int n)


{
int i;
srand((unsigned)time(NULL));
for(i=0;i<n;i++)
{
a[i]=rand()%10;
}
}

void ispis (int a[], int n)


{
int i;
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
}

int brponavljanja(int a[], int n, int w)


{
int i,k=0;
for(i=0;i<n;i++)
{
if (a[i] == w)
k++;
}

return k;
}

 
16 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
int main(int argc, char *argv[])
{
int n,a[50],b[50],c[50],k=0,e=0,i;

printf("Unesi dimenziju niza: ");


scanf("%d",&n);
printf("\nUnesi elemente niza");
upis(a,n);

for(i=0;i<n;i++)
{
if (brponavljanja(a,n,a[i]) == 1)
b[k++]=a[i];
else
c[e++]=a[i];
}

printf("\n");
ispis(a,n);
printf("\n");
ispis(b,k);
printf(" ");
ispis(c,e);
}

Zadatak 20. Šta nedostaje u sledećem opisu, da bi predstavljao opis stringa?

char ime[]={F, A, L, S, E};

Rešenje: Nedostaje null znak na kraju stringa.

Zadatak 21. Šta ispisuje sledći program?

#include<stdio.h>
int main(int argc, char *argv[])
{
char film[]=”Tango argentino”;
char *pok;
pok=film;
puts(pok);
puts(++pok);
film[5]=’\0’;
puts(film);
puts(++pok);
}

Rešenje:
Tango argentino
ango argentino

 
17 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
Tango
ngo

Zadatak 22. Šta ispisuje sledeći program?

#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
char ime[]=”Bingo”;
char *pok;
pok=ime+strlen(ime);
while(--pok >= ime)
puts(pok);
}

Rešenje:
o
go
ngo
ingo
Bingo

Zadatak 23. Šta ispisuje sledeći program?

#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
char s1[28]=”ani ceo”;
char s2[40]=”Ko rano r”;
char *s3=”dan zeva.”;
strcat(s1,s3);
strcat(s2,s1);
puts(s2);
}

Rešenje: Ko rano rani ceo dan zeva.

Zadatak 24. Napisati funkciju koja:


a) kopira string s1 u s2;
b) proverava da li je string s2 palindrom;
c) vraća pokazivač na prvo pojavljivanje znaka c u stringu s
d) brise svako pojavljivanje znaka c;
e) vraća poziciju prvog pojavljivanja stinga s2 u stringu s1, ako string s2 nije prisutan
u stringu s1 funkcija treba da vrati -1.

 
18 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
a)
void kopi(char *s1, char *s2)
{
while (*s2=*s1)
{
s1++;
s2++;
}
}

b)
int palindrom(char *s)
{
char *p=s+strlen(s)-1;
while(s<p && *s==*p)
{s++; p--;}
return (s>=p);
}

c)
char *nadji_prvi(char *s, char c)
{
while(*s && *s!=c) s++;
if(*s) return s
}

d)
void brisi_znak(char *s, char c)
{
char *p=s;
while(*p)
{
if(*p!=c) *s++=*p;
p++;
}
*s=’\0’;
}

e)
int pos(char *s1, char *s2)
{
if(strstr(s1,s2)!=NULL) return strstr(s1,s2) – s1;
else return -1;
}

Zadatak 25. Napisati funkciju kojom se iz stringa s briše d znakova počev od pozicije p, pri
čemu počev od pozicije p u stringu s ima barem d znakova.

 
19 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

#include< stdio.h >


#include<string.h>
void brisi(char *s, int d, int p)
{
char *q;
for(q=s+p;*(q+d);q++) *q=*(q+d);
*q=’\0’;
}

Zadatak 26. Napisati program koji za uneti string i neki broj ispisuje samo one karaktere sa
pozicija gde se u broju u njegovom binarnom zapisu javlja broj 1.

#include <stdio.h>

int main(int argc, char *argv[])


{
short int M, maska;
char S1[17], *s1, S2[17], *s2;
printf("%Unesi string S1 i broj M:\n");
scanf("%s%d", &S1, &M);
s1 = S1;
s2 = S2;
maska = 1;
while (maska)
{
if (M & maska) {*s2 = *s1; s2++; };
s1++; maska<<=1;
}
*s2 = '\0';
printf("Novi string S2: %s\n", S2);
}

Zadatak 27. Objašnjenje nizovia i pokazivača.

/*Nizovi i pokazivaci*/
#include<stdio.h>
int main(int argc, char *argv[])
{
float a,b,c,fniz[5]={0.01,0.1,0.5,1.0,10.0};
float *p_fniz;
char tekst[]={"Ovo je znakovni niz\n"};
char *p_tekst;
int i;

 
20 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
p_fniz=fniz;
a=*p_fniz; // a=fniz[0]
b=*(p_fniz+2); // b=fniz[2]
p_fniz=&fniz[2];
c=*(p_fniz+2); // c=fniz[4]
printf("a=%f b=%f c=%f\n",a,b,c);

//ispis stinga
for(i=0;tekst[i]!='\0';++i)putchar(tekst[i]);
// ispis stringa na drugi nacin
for(p_tekst=tekst;*p_tekst!='\0';++p_tekst)putchar(*p_tekst);

return 0;
}

Zadatak 28. Stranice a i b pravougaonika su prirodni brojevi. Odrediti, na koliko se kvadrata


maksimalne površine može iseći dati pravougaonik. Ispisati dimenzije kvadrata. Na primer za
a=12 i b=7 se ispisuje:
1 kvadrata stranice: 7
1 kvadrata stranice: 5
2 kvadrata stranice: 2
2 kvadrata stranice: 1

#include<stdio.h>

void razmeni(int *a, int *b)


{
int t;
t=*a;
*a=*b;
*b=t;
}

int main(int argc, char *argv[])


{
int a,b;
printf("Uneti stranice pravougaonika\n");
scanf("%d%d",&a,&b);
if(a==b)
printf("Jedan kvadrat stranice %d\n",a);
else
while(a)
{
if(a<b) razmeni(&a,&b);
printf("%d kvadrata stranice: %d\n",a/b,b);
a=a%b;
}
return 0;
}

 
21 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

Zadatak 29. Napisati program kojim se iz stringa s brise svaki znak koji odgovara bilo kom
znaku stringa t.

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])


{
char s[50], t[50];
int i,j;
gets(s);
gets(t);
for(i=j=0;*(s+i);i++)
if(!strchr(t,*(s+i)))
{
*(s+j)=*(s+i);
j++;
}
*(s+j)='\0';
puts(s);
}

Zadatak 30. Program za odredjivanje dužine stringa koji se učitava sa komnadne linije.

#include<stdio.h>

int duzina(char *p_string);

int main(int argc,char *argv[])


{
int i;
for(i=1;i<argc;i++)
printf("argument%d %s\n",i,argv[i]);
i=duzina(argv[2]);
printf("duzina stringa je %d\n",i);
return 0;
}

// funkcija koja kao rezultat vraca duzinu stringa


int duzina(char *p_string)
{
int l=0;
char *p;
p=p_string;
while(*p!='\0')
{

 
22 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
++l;
++p;
}
return l;
}

Zadatak 31. Napisati program koji iz datog stringa s izbacuje sve komentare, s tim što u
komentaru nema komentara.

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])


{
char s[100], *p,*q;
gets(s);
while(p=strstr(s,"/*"))
{
q=strstr(s,"*/");
strcpy(p,q+2);
}
puts(s);
}

Zadatak 32. Napisati program koji odredjuje broj reči u stringu s i dužinu najduže reči, reci su
razdvojene blanko simbolima.

#include<stdio.h>

int main(int argc, char *argv[])


{
char s[80];
int i,brojreci,brojslovaureci,maksimalnarec;
gets(s);
maksimalnarec=brojslovaureci=brojreci=0;

for(i=0;*(s+i);i++)
if(*(s+i)==' ')
{
if(brojslovaureci>maksimalnarec) maksimalnarec=brojslovaureci;
brojslovaureci=0;
}

 
23 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
else
{
if(!brojslovaureci)brojreci++;
brojslovaureci++;
}

if(brojslovaureci>maksimalnarec) maksimalnarec=brojslovaureci;
printf("%d %d\n",brojreci,maksimalnarec);
return 0;
}

Zadatak 33. Napisati program koji odredjuje prosečan broj slova u rečima parne dužine.

#include<stdio.h>

int main(int argc, char *argv[])


{
char s[80];
// br broj reci parne duzine,
// q broj smibola u recima parne duzine
int k,br=0,q=0,i;
gets(s);
k=0;
for(i=0;*(s+i);i++)
if(*(s+i)!=' ')
k++;
else
if(k>0)
{
if(k%2==0)
{
br++;
q+=k;
}
k=0;
}

if(k>0)
if(k%2==0)
{
br++;
q+=k;
}

printf("Prosecan broj simbola u recima parne duzine je %2.0f\n",(float)q/br);


return 0;
}

 
24 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

Zadatak 34. Nalaženje unije dva skupa.

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[])


{

int n1,n2,n3,i,j;
double *s1, *s2, *s3;

printf("Unesi broj elemenata skupova: ");


scanf("%d%d",&n1,&n2);

s1=malloc(n1*sizeof(double));
printf("Elementi prvog skupa su: ");
for(i=0;i<n1;scanf("%lf",&s1[i++]));
if (n1==0) putchar('\n');

s2=malloc(n2*sizeof(double));
printf("Elementi drugog skupa: ");
for(i=0;i<n2;scanf("%lf",&s2[i++]));
if (n2==0) putchar('\n');

s3=malloc((n1+n2)*sizeof(double));
for(n3=0;n3<n1;n3++)
s3[n3]=s1[n3];
for(j=0;j<n2;j++){
for(i=0;i<n1;i++)
if(s2[j]==s1[i]) break;
if(i==n1) s3[n3++]=s2[j];
}

s3=realloc(s3,n3*sizeof(double));

printf("Unija pocetnih skupova: ");


for(i=0;i<n3;i++)
printf("%lf ",s3[i]);

free(s1);
free(s2);
free(s3);
}

Zadatak 35. Sortiranje imena smeštenih u dinamičku matricu.

#include<stdio.h>

 
25 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
#include<string.h>
#include<stdlib.h>

#define MAX_IME 100


#define MAX_DUZ 30

int main(int argc, char *argv[])


{

char **imena, *ime;


int br_imena=0,duz,i;

printf("\nNeuredjeni niz imena: \n");


imena = malloc(MAX_IME*sizeof(char *));

do {

ime=malloc(MAX_DUZ*sizeof(char));
gets(ime);

if((duz=strlen(ime))==0)
{
free(ime);
break;
}

for(i=br_imena-1;i>=0;i--)
if( strcmp(imena[i],ime) > 0 )
imena[i+1]=imena[i];
else break;
imena[i+1]=ime;

}
while(++br_imena<MAX_IME);

imena = realloc(imena, br_imena*sizeof(char *));


printf("Uredjeni niz imena:\n");
for(i=0;i<br_imena;i++)
puts(imena[i]);
free(imena);
}

Zadatak 36. Odrediti broj linija u tekstualnom fajlu sa imenom knjiga.txt.

#include<stdio.h>

int main(int argc, char *argv[])


{
int k=0;

 
26 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
FILE *fp;
char s[256];
if((fp=fopen("knjiga.txt","r"))==NULL)
{
perror("Greska");
return;
}
while(fgets(s,256,fp)!=NULL)k++;
printf("Fajl ima %d linija\n",k);
fclose(fp);
}

Zadatak 37. Napisati program kojim se sadržaj fajla test.dat formiran od velikih slova alfabeta
šifriran šalje u fajl sifra.dat. Znak se šifrira tako što se zamenjuje sledećim ASCII znakom, a
znak Z zamenjuje sa A.

#include<stdio.h>

int main(int argc, char *argv[])


{
int c;
FILE *inf,*outf;
inf=fopen("test.dat","r");
outf=fopen("sifra.dat","w");
while((c=fgetc(inf))!=EOF)
{
if('A'<=c&&c<'Z')
c++;
else c='A';
putc(c,outf);
}
fclose(inf);
fclose(outf);
}

Zadatak 38. U tekstualnom fajlu odrediti najdužu liniju. Ako ima više linija najveće dužine
odrediti prvu među njima.

#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[])


{
unsigned k=0,maxl;
42
char s[256],maxs[256];
FILE *fp;

 
27 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
if((fp=fopen("test.txt","r"))==NULL)
{
printf("Greska\n ");
return;
}
maxl=0;
while(fgets(s,256,fp)!=NULL)
if(strlen(s)>maxl)
{
maxl=strlen(s);
strcpy(maxs,s);
}
printf("Najduza linija\n%s\n ima duzinu %d\n",maxs,maxl);
fclose(fp);
}

Zadatak 39. Napisati program za učitavanje datoteke pod imenom ulaz.dat i formiranje
datoteke sa nazivom izlaz.dat koja sadrži samo one redove ulazne datoteke ulaz.dat u kojima
se nalazi reč “fakultet”.

#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[])


{
FILE *ulaz;
FILE *izlaz;
char buffer[80];
char trazenaRec[]="fakultet";
if((ulaz=fopen("ulaz.dat","r"))==NULL)
printf("Datoteka ulaz.dat nije otvorena.");
if((izlaz=fopen("izlaz.dat","w"))==NULL)
printf("Datoteka izlaz.dat nije otvorena.");
while(!feof(ulaz)){
fgets(buffer,80,ulaz);
if(strstr(buffer,trazenaRec)!=NULL){
printf("%s",buffer); /*stamanje na ekranu*/
fprintf(izlaz,"%s",buffer);
}
}
fclose(ulaz);
fclose(izlaz);
}

 
28 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
Zadatak 40. Napisati program koji čita podatke iz datoteke ULAZ.TXT (ime studenta, broj
bodova na prijemnom ispitu), broji sve studente koji imaju broj bodova veći od proseka i
upisuje podatke o takvim studentima u datoteku IZLAZ.TXT.

#include<stdio.h>

#define DIM 10
typedef struct student{
char ime[20];
int brBodova;
};

int main(int argc, char *argv[])


{
struct student nizStudenata[DIM];
int i;
int brojStudenata=0;
int suma=0;
float prosek;
FILE *ulaz;
FILE *izlaz;
ulaz=fopen("ulaz.txt", "r");
if(ulaz==NULL){
printf("Ulazna datoteka nije otvorena!\n");
return 1;
}
izlaz=fopen("izlaz.txt", "w");
if(izlaz==NULL){
printf("Izlazna datoteka nije kreirana!\n");
return 1;
}
while(!feof(ulaz)){
fscanf(ulaz, "%s%d", &nizStudenata[brojStudenata].ime,
&nizStudenata[brojStudenata].brBodova);
suma+=nizStudenata[brojStudenata].brBodova;
brojStudenata++;
}
prosek=(float)suma/brojStudenata;
for(i=0; i<brojStudenata; i++)
if(nizStudenata[i].brBodova>prosek)
fprintf(izlaz, "%s\t%d\n", nizStudenata[i].ime, nizStudenata[i].brBodova);
fclose(ulaz);
fclose(izlaz);
return 0;
}

 
29 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
Zadatak 41. U datoteci IMENIK.TXT nalaze se sledeci podaci: ime, prezime i broj telefona
telefonskog pretplatnika. Napisati program koji vrsi sortiranje imenika prema prezimenu
pretplatnika i za zadato prezime prikazuje telefonski broj pretplatnika na standardnom izlazu.

#include<stdio.h>
#include<string.h>
#define DIM 10

typedef struct telefonski_imenik{


char ime[10];
char prezime[20];
char broj[10];
};
void razmeni(struct telefonski_imenik *a, struct telefonski_imenik *b){
struct telefonski_imenik tmp;
tmp=*a;
*a=*b;
*b=tmp;
}

void sort(struct telefonski_imenik niz[], int n){


int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(niz[i].prezime<niz[j].prezime)
razmeni(&niz[i], &niz[j]);
}

int main(int argc, char *argv[])


{
struct telefonski_imenik nizImenik[DIM];
int n, i;
FILE *in;
char trazi[20];
in=fopen("imenik.txt", "r");
if(in==NULL){
printf("Ulazni fajl nije otvoren!");
return 1;
}
i=0;
while(!feof(in)){
fscanf(in, "%s%s%s", &nizImenik[i].ime, &nizImenik[i].prezime, &nizImenik[i].broj);
i++;
}
fflush(in);
n=i+1;
sort(nizImenik, n);
printf("\nTelefonski imenik sortiran po prezimenu pretplatnika je:\n\n");
for(i=0; i<n; i++)

 
30 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
printf("%s\t%s\t%s\n", nizImenik[i].prezime, nizImenik[i].ime, nizImenik[i].broj);
printf("Ukupan broj telefonskih pretplatnika je: %d\n",n);
printf("Zadati prezime pretplatnika: ");
scanf("%s", &trazi);
for(i=0; i<n; i++){
if(strcmp(nizImenik[i].prezime,trazi)==0){
printf("Broj telefoma trazenog pretplatnika je:\n");
printf("%s\t%s\t%s\n", nizImenik[i].prezime, nizImenik[i].ime, nizImenik[i].broj);
}
}
fclose(in);
return 0;
}

 
31 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
REŠENI ZADACI SA PRVOG KOLOKVIJUMA IZ PROGRAMSKIH JEZIKA

Zadatak 1. Napisati program koji za uneti broj ispisuje koliko ima jedinica u njegovom
binarnom zapisu.

#include<stdio.h>

int brjedinica(int broj)


{
int i,br=0;
for(i=0;i<8;i++)
{
if(broj & 128)
br++;
broj<<=1;
}
return br;
}
int main(int argc, char *argv[])
{
int broj;
printf("Unesi broj: ");
scanf("%d",&broj);
printf("Broj jedinica je %d\n",brjedinica(broj));
return 0;
}

Zadatak 2. Napisati program koji uneti niz pomera za n cifara u desno. Zadatak rešiti preko
funkcija.

#include<stdio.h>
void unosniza(int a[],int n)
{
int i;
for(i=0;i<n;i++)
{
printf("a[%d]=",i+1);
scanf("%d",&a[i]);
}
}
void ispisniza(int a[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",a[i]);
printf("\n");
}
void pomeri(int a[], int n, int koliko)

 
32 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
{
int i,pom,j;
for(j=0;j<=koliko;j++)
{
pom=a[n-1];
for(i=n-1;i>=0;i--)
a[i]=a[i-1];
a[0]=pom;
}
}
int main(int argc, char *argv[])
{
int a[25],n,k;
printf("Unesi broj elemenata niza: ");
scanf("%d",&n);
unosniza(a,n);
printf("Unesi broj za koji pomeras niz u desno: ");
scanf("%d",&k);
printf("Niz posle pomeranja u desno je:\n");
pomeri(a,n,k);
ispisniza(a,n);
return 0;
}

Zadatak 3. Napisati program koji za unetu matricu vrši razmenu elemenata po vrstama na taj
način što negativne elemente stavlja na kraj svake vrste.

#include<stdio.h>
void unosmatrice(int a[][20],int v,int k)
{
int i,j;
for(i=0;i<v;i++)
for(j=0;j<k;j++)
{
printf("a[%d][%d]=",i+1,j+1);
scanf("%d",&a[i][j]);
}
}
void ispismatrice(int a[][20],int v,int k)
{
int i,j;
for(i=0;i<v;i++)
{
for(j=0;j<k;j++)
printf("%d ",a[i][j]);
printf("\n");
}

 
33 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
}
void uredimatricu(int a[][20], int v, int k)
{
int i,j,pom,vrsta;
for (vrsta=0;vrsta<v;vrsta++)
{
i=0;
j=k-1;
while(i<j)
{
if(a[vrsta][i]>0)
i++;
else
if(a[vrsta][j]>0)
{
pom=a[vrsta][i];
a[vrsta][i]=a[vrsta][j];
a[vrsta][j]=pom;
j--;
}
}
}
}
int main(int argc, char *argv[])
{
int a[20][20],v,k;
printf("Unesi broj vrsta i kolona matrice: ");
scanf("%d %d",&v,&k);
unosmatrice(a,v,k);
uredimatricu(a,v,k);
ispismatrice(a,v,k);
return 0;
}

Zadatak 4. Napisati program koji za uneti broj ispisuje koliko ima nula u njegovom binarnom
zapisu.

#include<stdio.h>
int brnula(int broj)
{
int i,br=0;
for(i=0;i<8;i++)
{
if((broj & 128)==0)
br++;
broj<<=1;
}
return br;
}

 
34 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
int main(int argc, char *argv[])
{
int broj;
printf("Unesi broj: ");
scanf("%d",&broj);
printf("Broj nula je %d\n",brnula(broj));
return 0;
}

Zadatak 5. Napisati program koji uneti niz pomera za 2. cifre u desno, pa za 3. cifre u levo.
Zadatak raditi prko funkcija.

#include<stdio.h>
void unosniza(int a[],int n)
{
int i;
for(i=0;i<n;i++)
{
printf("a[%d]=",i+1);
scanf("%d",&a[i]);
}
}
void ispisniza(int a[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",a[i]);
printf("\n");
}
void pomeri(int a[], int n, int smer, int koliko)
{
int i,pom,j;
switch(smer)
{
/*pomeranje u levo */
case 1:{
for(j=0;j<koliko;j++)
{
pom=a[0];
for(i=0;i<n-1;i++)
a[i]=a[i+1];
a[n-1]=pom;
}
} break;
/*pomeranje u desno */
case 2: {
for(j=0;j<koliko;j++)
{
pom=a[n-1];

 
35 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
for(i=n-1;i>=0;i--)
a[i]=a[i-1];
a[0]=pom;
}
} break;
}
}
int main(int argc, char *argv[])
{
int a[25],n;
printf("Unesi broj elemenata niza: ");
scanf("%d",&n);
unosniza(a,n);
pomeri(a,n,2,2);
printf("Niz posle pomeranja u desno za dve pozicije:\n");
ispisniza(a,n);
pomeri(a,n,1,3);;
printf("Niz posle pomeranja u levo za tri pozicije:\n");
ispisniza(a,n);
return 0;
}

Zadatak 6. Napisati program koji za unetu matricu vrši razmenu elemenata po kolonama na taj
način što negativne elemente stavlja na kraj svake kolone.

#include<stdio.h>
void unosmatrice(int a[][20],int v,int k)
{
int i,j;
for(i=0;i<v;i++)
for(j=0;j<k;j++)
{
printf("a[%d][%d]=",i+1,j+1);
scanf("%d",&a[i][j]);
}
}
void ispismatrice(int a[][20],int v,int k)
{
int i,j;
for(i=0;i<v;i++)
{
for(j=0;j<k;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}

void uredimatricu(int a[][20], int v, int k)


{

 
36 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
int i,j,pom,kolona;
for (kolona=0;kolona<k;kolona++)
{
i=0;
j=v-1;
while(i<j)
{
if(a[i][kolona]>0)
i++;
else
if(a[j][kolona]>0)
{
pom=a[i][kolona];
a[i][kolona]=a[j][kolona];
a[j][kolona]=pom;
j--;
}
}
}
}

int main(int argc, char *argv[])


{
int a[20][20],v,k;
printf("Unesi broj vrsta i kolona matrice: ");
scanf("%d %d",&v,&k);
unosmatrice(a,v,k);
uredimatricu(a,v,k);
ispismatrice(a,v,k);
return 0;
}

Zadatak 7. Марку је једне преступне године на часу из програмских језика било


досадно. Насумице је окренуо роковник који је показивао датум(d.m.g.). Не знајући
шта да ради, Марко је почео редом да исписује датуме почев од показаног датума, без
водећих нула, са тачком иза дана, месеца и године. После исписаних n знакова, оловка
је престала да пише. Написати програм који, за учитани датум исписује код ког датума
је Марку престала оловка да пише.

#include<stdio.h>

int broj_cifara(int n)

int s=0;

while(n)

 
37 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
{

s++;

n=n/10;

return s;

int main(int argc, char *argv[])

int dan,mesec,godina,n,s,brdana;

printf("Unesite dan, mesec i godinu: ");

scanf("%d%d%d",&dan,&mesec,&godina);

printf("Unesite broj cifara n: ");

scanf("%d",&n);

s=broj_cifara(dan)+broj_cifara(mesec)+broj_cifara(godina)+3;

do

switch(mesec)

case 1: case 3: case 5: case 7: case 8: case 10: case 12: brdana=31;break;

case 4: case 6: case 9: case 11: brdana=30; break;

case 2: brdana=29; break;

if ( dan < brdana )

dan++;

else if (mesec!=12) {

dan=1;

mesec++;

 
38 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
}

else {

dan=1;

mesec=1;

godina++;

s = s+ broj_cifara(dan) + broj_cifara(mesec) + broj_cifara(godina) + 3;

while( s < n );

printf("Olovka je prestala da pise kod datuma: %d %d %d\n",dan,mesec,godina);

return 0;

 
39 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
REŠEI ZADACI SA DRUGOG KOLOKVIJUMA IZ PROGRAMSKIH JEZIKA

Zadatak 1. На пријему је n особа, нумерисаних бројевима 0, 1, 2... , n-1. Свака особа има
највише два непријатеља. Дата је матрица Аnxn тако да а[i][j]=1 ако је особи i
непријатељ особа ј, иначе a[i][j]=0. Матрица А је симетрична у односу на главну
дијагоналу (a[i][j]=a[j][i]). Написати функцију којом се особе распоређују у три групе
тако да су у свакој групи само пријатељи.

#include <stdio.h>
#include <stdlib.h>

int provera(int m[][6],int a[],int x[],int k,int i, int n)


{
int brneprijatelja=0,s,t;
for(s=0;s<k;s++){
for(t=0;t<n;t++)
if(a[s]==x[t])
if(m[t][i]==1)
brneprijatelja++;
}
return brneprijatelja;
}

int main(int argc, char*argv[])


{
int x[6]={2,8,4,7,5,10};
int m[6][6]= { 0,1,1,0,0,1,
1,0,1,0,1,0,
1,1,0,1,0,0,
0,0,1,0,0,0,
0,1,0,0,0,1,
1,0,0,0,1,0};
int a[6],b[6],c[6];
int i,j=0,k=0,l=0,n=6;

 
40 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

for (i=0;i<n;i++) {
if (provera(m,a,x,j,i,n)==0)
a[j++]=x[i];
else
if (provera(m,b,x,k,i,n)==0)
b[k++]=x[i];
else
c[l++]=x[i];
}

printf("Prvi niz je:\n");


for(i=0;i<j;i++)
printf("%d ",a[i]);
printf("\nDrugi niz je:\n");
for(i=0;i<k;i++)
printf("%d ",b[i]);
printf("\nTreci niz je:\n");
for(i=0;i<l;i++)
printf("%d ",c[i]);
printf("\n");
system("PAUSE");
}

Zadatak 2. У датотеци magacin.txt се налази списак са подацима о n роба (шифра,


назив, количина и јединична цена). У датотеци може да постоји више записа са истом
шифром робе, који се налазе један за другим. Формирати датотеку sredjeno.txt у којој
су сви записи са истом шифром сажети у један запис у коме је количина робе једнака
збиру количина у свим записима са истом шифром.

#include<stdio.h>
#include<string.h>

struct Roba{

 
41 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
int sifra;
char naziv[20];
int kolicina;
float cena;
};

void sredi(struct Roba roba[], int n)


{
int i,j,k,p=0,pom;
FILE *out;
out=fopen("sredjeno.txt","w");

for(i=0;i<n;i++)
{
k=i;
j=i+1;

pom=roba[k].kolicina;

while(roba[k].sifra == roba[j].sifra) {
pom=pom+roba[j].kolicina;
j++;
i++;
}
fprintf(out,"%d %s %d %.2fdin\n",roba[k].sifra,roba[k].naziv,pom,roba[k].cena);
}
}

int main(int argc, char *argv[]){

int i,n,p; FILE *in;


struct Roba roba[20];
printf("Unesi broj zapisa koje citas: "); scanf("%d",&n);

 
42 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
in=fopen("magacin.txt", "r");

for(i=0;i<n;i++){

fscanf(in,"%d%s%d%f",&roba[i].sifra,&roba[i].naziv,&roba[i].kolicina,&roba[i].cena
);
}
sredi(roba,n);
}

Zadatak 3. Написати програм на програмском језику C који учитава један занковни низ
(стринг) S1 и један цео број М, а затим формира нови знаковни низ S2 само од оних
знакова на чијим су позицијама одговарајући битови броја М једнаки нули. Сматрати
да се цео број представља у 8-битној локацији, а да знаковни низ може имати највише 8
знакова. На крају, програм исписује нови знаковни низ S2.

#include <stdio.h>

int main(int argc,char *argv[])


{
short int M, maska;
char S1[9], *s1, S2[9], *s2;
printf("%Unesi string S1 i broj M:\n");
scanf("%s%d", &S1, &M);
s1 = S1;
s2 = S2;
maska = 1;
while (maska)
{
if (M & maska == 0) {*s2 = *s1; s2++; };
s1++; maska<<=1;
}
*s2 = '\0';

 
43 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
printf("Novi string S2: %s\n", S2);
}

, .
Zadatak 4. Izračunati i ispisati vrednost z po formuli: , 16.8 2 ,
ako se x menja od x1 do x2 sa korakom 1. Ako nije ispunjen uslov definisanosti, uzeti da je
vrednost promenljive z jednaka 1. Koristiti funkcije kod kojih se vrši prenošenje parametara
po referenci.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define min 19.2
#define max 16.8

void min3(float x, float *k)


{
if (x<min) *k=pow(x,3);
else *k=pow(min,3);
}

void max2(float x, float *k)


{
if (x<max) *k=pow(max,2);
else *k=pow(x,2);
}
void koren(float x, float *k)
{
float p;
max2(x,&p);
*k=sqrt(p-2);
}

void razl(float x, float *k)


{
float p;
min3(x,&p);
*k=p/(1+pow(x,3));
}

void ispis(float a[],int n)


{
int i;
for(i=0;i<n;i++)
printf("%f\n",a[i]);
}

int main(int argc, char *argv[])


{

 
44 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
float x1,x2,h,d1,d2,z[30];
int j=0;
printf("Unesi granice x1, x2 i korak h: ");
scanf("%f%f%f",&x1,&x2,&h);
while( x1 <= x2 )
{
if (x1==-1)
z[j]=1;
else
{
koren(x1,&d1);
razl(x1,&d2);
z[j]=d1*d2;
}
j++;
x1=x1+h;
}
ispis(z,j);
system("PAUSE");
}

Zadatak 5. Написати програм на програмском језику C који учитава један занковни низ
(стринг) S1 и један цео број m, а затим формира нови знаковни низ S2 тако што од низа
S1 узме све елементе од p-тог до q-тог, уклони све карактере “a” уколико постоје и
нађе суму квадрата од броја k(број елемената низа S2) до m. Уколико је та сума већа од
41*m решење исписати на стандардном излазу, у супротном решење запамтити у
датотеци. Задтак решити коришћењем функција које своје параметре преносе преко
референци.

#include<stdio.h>
#include<string.h>

void seci(char *s,int p,int q)


{
char *t;
t=s;
while( p<q )
{
*s=*(t+p);
s++;
p++;
}
*s='\0';
}

 
45 
VEŽBE IZ PROGRAMSKOG JEZIKA „C“  2007/2008 

 
void sredi(char *s)
{
char *t;
t=s;
while(*s && *s!='a')
{
*s=*t;
t++;
s++;
}
*s='\0';
}

void kv(char *s, int m,float *k,int dim)


{
int i;
for(i=0;i<dim;i++)
*k=*k + *(s+i);
}

int main(int argc,char *argv[])


{
char s1[50];
int m,p,q,dim;
float kvadrat=0;
FILE *out;
out=fopen("sredjeno.txt","w");

printf("Unesite string:");
gets(s1);
printf("unesite p,q i m:");
scanf("%d%d%d",&p,&q,&m);
seci(s1,p,q);
sredi(s1);
dim=strlen(s1);
kv(s1,m,&kvadrat,dim);
if (kvadrat>41*m)
fprintf(out,"%f je vece od %d",kvadrat,41*m);
else
fprintf(out,"%f nije vece od %d",kvadrat,41*m);

 
46 
Увод у програмски језик C

Задаци за вежбу

1
1. Програм за демонстрацију операције инкремента (++) пре и после имена променљиве

/* Upotreba operatora inkrementa */

#include <stdio.h>

/* funkcija main, mesto pocetka izvrsenja programa */


int main()
{
int c=5; /* definisanje promenljive */
int x;

/* demonstracija operatora inkrementa NAKON imena promenljive (postincrement) */


printf( "Vrednost promenljive c je %d\n", c );

x=c; /* dodela vrednosti */

/* ispis vrednosti promenljive x */


printf( "\nNakon naredbe x=c, vrednost promenljive x je %d\n", x );

x=c++;
printf( "\nNakon naredbe x=c++\n");
printf("\tvrednost promenljive x je %d\n", x );
printf("\tvrednost promenljive c je %d\n\n", c );

/* demonstracija operatora inkrementa PRE imena promenljive (preincrement) */


c = 5; /* dodela vrednosti */
printf( "\nVrednost promenljive c je %d\n", c );

x=++c;
printf( "\nNakon naredbe x=++c\n");
printf("\tvrednost promenljive x je %d\n", x );
printf("\tvrednost promenljive c je %d\n\n", c );

return 0;

} /* kraj funkcije main */

2
2. Програм за демонстрацију операције декремента (--) пре и после имена променљиве

/* Upotreba operatora dekrementa */

#include <stdio.h>

/* funkcija main, mesto pocetka izvrsenja programa */


int main()
{
int c=5; /* definisanje promenljive */
int x;

/* demonstracija operatora dekrementa NAKON imena promenljive (postdecrement) */


printf( "Vrednost promenljive c je %d\n", c );

x=c; /* dodela vrednosti */


printf( "\nNakon naredbe x=c, vrednost promenljive x je %d\n", x );

x=c--;
printf( "\nNakon naredbe x=c--\n");
printf("\tvrednost promenljive x je %d\n", x );
printf("\tvrednost promenljive c je %d\n\n", c );

/* demonstracija operatora dekrementa PRE imena promenljive (predecrement) */


c = 5; /* dodela vrednosti */
printf( "\nVrednost promenljive c je %d\n", c );

x= --c;
printf( "\nNakon naredbe x= --c\n");
printf("\tvrednost promenljive x je %d\n", x );
printf("\tvrednost promenljive c je %d\n\n", c );

return 0;

} /* kraj funkcije main */

3
3. Написати програм који наизменично исписује знак + или знак -. Укупан број појављивања знакова је 10.
Сваки знак треба да се налази у посебном реду.

Решење 1:

/* Upotreba while petlje i operatora "?" */


#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int brojac = 1; /* inicijalizacija promenljive brojac */
char znak; /* definisanje promenljive znak */

while ( brojac <= 10 ) /* sve dok je brojac manji ili jednak 10, radi */
{
znak = (brojac % 2) ? ('-') : ('+'); /* parne vrednosti +, neparne - */

/* Ispis na ekran */
printf( "%c \n", znak );

brojac++; /* inkrement brojaca, isto sto i brojac=brojac+1 */


} /* kraj while petlje */

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

Решење 2. (He мора се уводити променљива znak)

/* Upotreba while petlje i operatora "?" */


#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int brojac = 1; /* inicijalizacija promenljive brojac */

while ( brojac <= 10 ) /* sve dok je brojac manji ili jednak 10, radi */
{
/* Ispisi na ekran */
printf("%c\n",(brojac % 2) ? ('-'):('+')); /* parni +, neparni - */

brojac++; /* inkrement brojaca, isto sto i brojac=brojac+1 */


}/* kraj while petlje */

return 0; /* povratna vrednost uspesnog zavrsetka programa */

}/* kraj funkcije main*/

4
4. Написати програм који захтева од корисника да унесе два цела броја а потом исписује њихову суму

Решење 1

/* Sabiranje dva broja */


#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int integer1; /* prvi broj koji unosi korisnik */
int integer2; /* drugi broj koji unosi korisnik */
int sum; /* promenljiva u kojoj ce biti smesten rezultat */

printf( "Unesite prvi broj\n" ); /* Prikazivanje poruke */


scanf( "%d", &integer1 ); /* ucitavanje unetog broja u promen. integer1 */

printf( "Unesite drugi broj\n" ); /* Prikazivanje poruke */


scanf( "%d", &integer2 ); /* ucitavanje unetog broja u prom. integer2 */

sum = integer1 + integer2; /* racunanje zbira i dodelа vrednosti prom. sum */

printf( "Zbir je %d\n", sum ); /* Prikazi vrednost zbira (sum) */

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

Решење 2. (He мора се уводити променљива sum)

/* Sabiranje dva broja */


#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int integer1; /* prvi broj koji unosi korisnik */
int integer2; /* drugi broj koji unosi korisnik */

printf( "Unesite prvi broj\n" ); /* Prikazivanje poruke */


scanf( "%d", &integer1 ); /* ucitavanje unetog broja u promen. integer1 */

printf( "Unesite drugi broj\n" ); /* Prikazivanje poruke */


scanf( "%d", &integer2 ); /* ucitavanje unetog broja u prom. integer2 */

/* racunanje zbira i dodelа vrednosti prom. integer1 */


integer1 = integer1 + integer2;

printf( "Zbir je %d\n", integer1 ); /* Prikazi vrednost zbira */

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

5
Решење 3. (He мора се уводити променљива sum)
/* Sabiranje dva broja */
#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int integer1; /* prvi broj koji unosi korisnik */
int integer2; /* drugi broj koji unosi korisnik */

printf( "Unesite prvi broj\n" ); /* Prikazivanje poruke */


scanf( "%d", &integer1 ); /* ucitavanje unetog broja u promen. integer1 */

printf( "Unesite drugi broj\n" ); /* Prikazivanje poruke */


scanf( "%d", &integer2 ); /* ucitavanje unetog broja u prom. integer2 */

/* racunanje zbira i prikaz vrednosti */


printf( "Zbir je %d\n", integer1 + integer2); /* Prikazi vrednost zbira */

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

6
5. Написати програм који очекује од корисника да унесе два цела броја а потом употребом релационих
оператора (==, !=, <,<=, >, >=) исписује однос унетих бројева.

Решење 1.
/* Upotreba if naredbe, relacionih operatora i operatora dodele */
#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


main()
{
int num1; /* prvi broj koji unosi korisnik */
int num2; /* drugi broj koji unosi korisnik */

printf( "Unesite dva cela broja a ja cu Vam reci\n" );


printf( "u kom su oni odnosu: " );

scanf( "%d%d", &num1, &num2 ); /* citanje dva cela broja */

if( num1 == num2 )


{
printf( "%d je jednako sa to %d\n", num1, num2 );
} /* kraj if naredbe */

if( num1 != num2 )


{
printf( "%d nije jednako sa %d\n", num1, num2 );
} /* kraj if naredbe */

if( num1 < num2 )


{
printf( "%d je manje od %d\n", num1, num2 );
} /* kraj if naredbe */

if( num1 > num2 )


{
printf( "%d je vece od %d\n", num1, num2 );
} /* kraj if naredbe */

if( num1 <= num2 )


{
printf( "%d je manje ili jednako sa %d\n", num1, num2 );
} /* kraj if naredbe */

if( num1 >= num2 )


{
printf( "%d je vece ili jednako sa %d\n", num1, num2 );
} /* kraj if naredbe */

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

7
Решење 2. (Обзиром да if наредбе обухватају само једну наредбу витичасте заграде нису неопходне)
/* Upotreba if naredbe, relacionih operatora i operatora dodele */
#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


main()
{
int num1; /* prvi broj koji unosi korisnik */
int num2; /* drugi broj koji unosi korisnik */

printf( "Unesite dva cela broja a ja cu Vam reci\n" );


printf( "u kom su oni odnosu: " );

scanf( "%d%d", &num1, &num2 ); /* citanje dva cela broja */

if( num1 == num2 )


printf( "%d je jednako sa to %d\n", num1, num2 );

if( num1 != num2 )


printf( "%d nije jednako sa %d\n", num1, num2 );

if( num1 < num2 )


printf( "%d je manje od %d\n", num1, num2 );

if( num1 > num2 )


printf( "%d je vece od %d\n", num1, num2 );

if( num1 <= num2 )


printf( "%d je manje ili jednako sa %d\n", num1, num2 );

if( num1 >= num2 )


printf( "%d je vece ili jednako sa %d\n", num1, num2 );

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

8
6. Применом while петље и оператора ++ и – – написати програм који исписује табелу димензија десет
врста и пет колона и то тако да су парне врсте попуњене знацима $ $ $ $ $, а непарне знацима # # # # #.

/* upotreba while petlje, operatora "?", ++ i -- operatora */

#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int vrsta = 10; /* definisanje i inicijalizacija promenljive vrsta */
int kolona; /* definisanje promenljive kolona */

while ( vrsta >= 1 ) /* kruzi u while petlji dve dok vrsta ne bude < 1 */
{
kolona =1; /* postavi prom. kolona na 1 pri ulasku u while petlju */
while ( kolona <= 5 ) /* sve dok je kolona manje i jednako 5... */
{
printf( "%c", (vrsta % 2) ? ('$'): ('#') ); /* Ispis na ekran */
kolona++; /* isto sto i kolona = kolona + 1 ili kolona += 1*/
} /* kraj unutrasnje while petlje */

vrsta--; /* isto sto i vrsta = vrsta – 1 ili vrsta -= 1 */


printf( "\n" ); /* prelazak u novi red */
} /* kraj spoljsnje while petlje*/

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

9
7. Напишите програм који очекује од корисника да унесе тачно 5 целих бројева а потом израчунава њихову
средњу вредност. Све дефинисане променљиве морају бити целобројне.

Решење 1 (Приметите ефекте целобројног дељења)

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int brojac; /* Broj vrednosti koje treba uneti */
int vrednost; /* vrednost koja se unosi */
int zbir; /* suma unetih vrednosti */
int srednja_vred; /* srednja vrednost */

/* inicijalizacija */
zbir = 0; /* inicijalizacija promenljive zbir */
brojac = 1; /* inicijalizacija promenljive brojac */

/* faza obrade */
while ( brojac <= 5 ) /* sve dok je brojac manji ili jednak 5... */
{
printf( "Unesite vrednost: " ); /* Ispis poruke na ekran */
scanf( "%d", &vrednost ); /* ucitaj unetu vrednost */
zbir = zbir + vrednost ; /* dodaj unetu vrenost prom. zbir */
brojac = brojac + 1; /* inkrement promenljive brojac */
} /* kraj while petlje */

/* zavrsna faza */
srednja_vred = zbir / 5; /* celobrojno deljenje, odbacivanje decimalnog dela */

printf( "Srednja vrednost je %d\n", srednja_vred ); /* prikaz rezultata */

return 0; /* povratna vrednost uspesnog kraja programa */

} /* kraj funkcije main */

Напомена:
Променљива zbir и променљива srednja_vred су целобројне променљиве (типа int ) па је
резултат дељења srednja_vred = zbir / 5 цео број тј. одбацује се децимални део

10
Решење 2 (Превазилажење проблема целобројног дељења)

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int brojac; /* Broj vrednosti koje treba uneti */
int vrednost; /* vrednost koja se unosi */
int zbir; /* suma unetih vrednosti */
float srednja_vred; /* srednja vrednost */

/* inicijalizacija */
zbir = 0; /* inicijalizacija promenljive zbir */
brojac = 1; /* inicijalizacija promenljive brojac */

/* faza obrade */
while ( brojac <= 5 ) /* sve dok je brojac manji ili jednak 10... */
{
printf( "Unesite vrednost: " ); /* Ispis poruke na ekran */
scanf( "%d", &vrednost ); /* ucitaj unetu vrednost */
zbir = zbir + vrednost ; /* dodaj unetu vrenost prom. zbir */
brojac = brojac + 1; /* inkrement promenljive brojac */
} /* kraj while petlje */

/* privremena promena tipa prom. zbir iz int u float, */


srednja_vred = (float)zbir / 5;

printf( "Srednja vrednost je %f\n", srednja_vred ); /* format %f */

return 0; /* povratna vrednost uspesnog kraja programa */

} /* kraj funkcije main */

Напомена:
Променљива zbir типа int а променљива srednja_vred је типа float. Без обзира на то
резултат дељења zbir/5 је цео број. Да би се превазишао овај проблем довољно је да бар
један операнд буде типа float или double. У овом примеру је извршена привремена
конверзија типа променљиве zbir из типа int у тип float наредбом (float)zbir.

11
Решење 3 (Претходно решење без променљиве srednja_vred )

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int brojac; /* Broj vrednosti koje treba uneti */
int vrednost; /* vrednost koja se unosi */
int zbir; /* suma unetih vrednosti */

/* inicijalizacija */
zbir = 0; /* inicijalizacija promenljive zbir */
brojac = 1; /* inicijalizacija promenljive brojac */

/* faza obrade */
while ( brojac <= 5 ) /* sve dok je brojac manji ili jednak 10... */
{
printf( "Unesite vrednost: " ); /* Ispis poruke na ekran */
scanf( "%d", &vrednost ); /* ucitaj unetu vrednost */
zbir = zbir + vrednost ; /* dodaj unetu vrenost prom. zbir */
brojac = brojac + 1; /* inkrement promenljive brojac */
} /* kraj while petlje */

/* privremena promena tipa prom. zbir iz int u float, */


printf( "Srednja vrednost je %f\n", (float)zbir / 5 ); /* format %f */

return 0; /* povratna vrednost uspesnog kraja programa */

} /* kraj funkcije main */

12
8. Напишите програм који очекује од корисника да унесе произвољан број целих бројева а потом
израчунава њихову средњу вредност. Крајем уноса се сматра унос броја -1.

#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
int brojac; /* broj unetih vrednosti */
int vrednost; /* uneta vrednost */
int zbir; /* zbir unetih vrednosti */

float srednja_vred; /* srednja vrednost definisana kao realan broj */

/* inicijalizacija */
zbir = 0; /* inicijalizacija promenljive zbir */
brojac = 0; /* inicijalizacija promenljive brojac */

/* Obrada */
/* Procitaj prvu vrednost od korisnika */
printf( "Unesite vrednost, -1 za prekid: " ); /* Prikaz na ekran */
scanf( "%d", &vrednost ); /* Ucitaj unetu vrednost */

/* Kruzi u while petlji dok korisnik ne unese vrednost -1 */


while ( vrednost != -1 )
{
zbir = zbir + vrednost; /* dodaj unetu vrednost promenljivoj zbir */
brojac = brojac + 1; /* inkrement brojaca */

/* ucitaj sledecu vrednost od korisnika */


printf( "Unesite vrednost, -1 za prekid: " ); /* Prikaz na ekran */
scanf("%d", &vrednost); /* Ucitaj sledecu unetu vrednost */
} /* kraj while petlje */

/* zavrsna faza */
/* Ako je uneta bar jedna vrednost */
if ( brojac != 0 )
{
/* izracunaj srednju vrednost svih unetih vrednosti */
srednja_vred = ( float )zbir / brojac; /* privremena promena tipa */

/* prikazi srednju vrednost sa dve decimalne vrednosti */


printf( "Srednja vrednost je %.2f\n", srednja_vred );
} /* kraj if naredbe */
else /* Ako nije uneta ni jedna vrednost, ispis poruke */
{
printf( "Nije unesena ni jedna vrednost\n" );
} /* kraj else naredbe */

return 0; /* povratna vrednost uspesnog kraja programa */

} /* kraj funkcije main */

13
9. Демонстрација рада са битским операторима

#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int a = 0x0003; /* a= 03h = 0000 0011b = 3d */
int b = 0x0022; /* b= 22h = 0010 0010b= 34d */
int c = 5;
int d;
int e;
int f = 0x0100; /* f=100h = 0001 0000 0000b = 256d */

printf("a=%d, b=%d, c=%d, f=%d\n",a, b, c, f);


printf("-------------------------\n");

printf("a bitsko AND b = %xh \n",a & b);


printf("a logicko AND b = %d \n",a && b);
printf("a bitsko OR b = %xh \n",a | b);
printf("a logicko OR b = %d \n",a || b);
printf("a bitsko EXOR b = %xh \n\n",a ^ b);

d = (a < b) && (b > c); /* logicko i (AND) */


printf("Vrednost logicke operacije (a < b) && (b > c) je %d \n\n",d);
e = a << 3; /* shift a za 3 u levo */
printf("Vrednost a je %x, vrednost a << 3 je %xh\n",a,e);
printf("Vrednost f je %d ili %xh\n",f,f);
f =f^(1 << 4); /* shift jedinice za 4 mesta u levo */
/* 1<<4= 0000 0001b << 4 = 0001 0000b = 10h = 16d */
/* f EXOR 16 = 100h EXOR 10h = 0001 0000 0000b EXOR 0000 0001
0000b */
printf("Vrednost f je 100h a f^(1 << 4) je %d ili %xh \n",f,f);

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

14
10. Напишите програм који на основу унетих података исписује број студената који су положили испит
односно број студената који нису положили испит.
Корисник за сваког студента који је положио испит уноси вредност 1, а за сваког студента који није
положио испит уноси вредност 2.
Корисник уносом вредности било ког целог броја изузев 1 или 2 покреће процедуру обраде унетих
података и испис жељених вредности

Pешење 1

/* Upotreba do while petlje i if elseif else naredbe */


#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
/* definisanje i inicijalizacija promenljivih */
int polozilo = 0; /* broj studenata koji su polozili ispit */
int palo = 0; /* broj studenata koji nisu polozili ispit */
int rezultat; /* uneta vrednost */
int izlaz=0;

do
{
printf( "Unesite rezultat ( 1=polozio, 2=pao ): " ); /* Ispis na ekran */
scanf( "%d", &rezultat );

/* Ako je rezultat 1, povecaj vrednost promenljive polozilo za 1 */


if ( rezultat == 1 )
{
polozilo = polozilo + 1;
} /* kraj if naredbe */
else if(rezultat==2)/* inace inkrementiraj vrednost promenljive palo */
{
palo = palo + 1;
} /* kraj else if*/
else
{
izlaz = 1;
}

} while ( izlaz == 0 ); /* kraj do while petlje */

/* zavrsna faza */
printf( "Broj studenata koji su polozili ispit %d\n", polozilo );
printf( "Broj studenata koji nisu polozili ispit %d\n", palo );

/* Ako je polozilo vise od 8 studenata ispisi Odlican uspeh" */


if ( polozilo > 8 )
{
printf( "Odlican uspeh\n" );
} /* kraj if */

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

15
Pешење 2

/* Upotreba do while petlje i if elseif else naredbe */


#include <stdio.h>

/* funkcija main, odavde pocinje izvrsavanje programa */


int main()
{
/* definisanje i inicijalizacija promenljivih */
int polozilo = 0; /* broj studenata koji su polozili ispit */
int palo = 0; /* broj studenata koji nisu polozili ispit */
int rezultat; /* uneta vrednost */

do
{
printf( "Unesite rezultat ( 1=polozio, 2=pao ): " ); /* Ispis na ekran */
scanf( "%d", &rezultat );

/* Ako je rezultat 1, povecaj vrednost promenljive polozilo za 1 */


if ( rezultat == 1 )
polozilo++;
else if(rezultat==2)/* inace inkrementiraj vrednost promenljive palo */
palo++;
else
break;

} while (1); /* kraj do while petlje, BESKONAČNA petlja */

/* zavrsna faza */
printf( "Broj studenata koji su polozili ispit %d\n", polozilo );
printf( "Broj studenata koji nisu polozili ispit %d\n", palo );

/* Ako je polozilo vise od 8 studenata ispisi Odlican uspeh" */


if ( polozilo > 8 )
printf( "Odlican uspeh\n" );

return 0; /* povratna vrednost uspesnog zavrsetka programa */

} /* kraj funkcije main */

Напомена:
У другом решењу је примењена бесконачна do while петља, услов је увек испуњен
while(1). Напуштање петље је омогућено наредбом break.

16
11. Применом for петље табеларно испишите вредности куба бројева од 1 до 10.

/* primena for petlje */


#include<stdio.h>

/* funkcija main, program pocinje da se izvrsava odavde */


int main(void)
{
int num;

printf("\tk\tk na treci stepen\n");


for(num=1; num <= 10 ;num++ )
{
printf("%5d %5d\n", num , num*num*num);
}

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

12. Пример декремента for петље

/* primena for petlje, dekrement; if else if else grananje */


#include<stdio.h>

/* funkcija main, program pocinje da se izvrsava odavde */


int main(void)
{
int num;

printf("\nPreostalo je:\n");

for(num=10; num >= 1 ;num-- )


{
if( num >=5 )
printf("%2d sekundi\n", num);
else if(num > 1)
printf("%2d sekunde \n", num);
else
printf("%2d sekunda \n", num);
}
printf("\nVreme isteklo\n");
return 0; /* oznacava uspesan zavrsetak programa */
} /* kraj funkcije main */

17
13. Применом for петље и оператора ++ и – – написати програм који исписује табелу произвољних
димензија и то тако да је табела попуњена знацима #.

/* Upotreba for petlje */


#include <stdio.h>

/* funkcija main, program pocinje da se izvrsava odavde */


int main()
{
int x;
int y;
int i;
int j;

/* Prikaz na ekran */
printf( "Unesite dva cela broja: " );
scanf( "%d%d", &x, &y ); /* procitaj vrednosti za x i y */

for ( i = 1; i <= y; i++ ) /* broj od 1 do y */


{
for ( j = 1; j <= x; j++ ) /* broj od 1 do x */
{
printf( "#" ); /* ispisi # */
} /* kraj unutrasnje for petlje */

printf( "\n" ); /* predji u novu liniju */


} /* kraj spoljasnje for petlje */

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

18
14. Употребом while петље испишите вредности од 1 до 10 тако да свака буде у новом реду

/* Upotreba while petlje */


#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int brojac = 1; /* inicijalizacija */

while ( brojac <= 10 ) /* uslov ponavljanja */


{
printf ( "%d\n", brojac ); /* ispis vrednosti brojaca */
brojac++; /* povecaj vrednost brojaca za 1 */
} /* kraj while petlje */

return 0; /* oznacava uspesan kraj programa */

} /* kraj funkcije main */

15. Употребом fоr петље испишите вредности од 1 до 10 тако да свака буде у новом реду

Pешење 1
#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i;

for(i = 1; i < 11; i++) /* uslov ponavljanja */


{
printf ( "%d\n", i ); /* ispis vrednosti brojaca */
} /* kraj for petlje */

return 0; /* oznacava uspesan kraj programa */

} /* kraj funkcije main */

19
Pешење 2

/* Upotreba for petlje */


#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i;

i = 1;
for( ; i < 11; i++) /* uslov ponavljanja */
{
printf ( "%d\n", i ); /* ispis vrednosti brojaca */
} /* kraj for petlje */

return 0; /* oznacava uspesan kraj programa */

} /* kraj funkcije main */

Напомена:
Сваки од три елемента унутар округлих заграда for петље може да се изостави (напише на другом
месту). Приметите да је иницијализација променљиве i (i=0) обављена пре почетка for петље.

Pешење 3
/* Upotreba while petlje */
#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i;

i = 1;
for( ; i < 11; ) /* uslov ponavljanja */
{
printf ( "%d\n", i ); /* ispis vrednosti brojaca */
i++;
} /* kraj for petlje */

return 0; /* oznacava uspesan kraj programa */

} /* kraj funkcije main */

Напомена:
Сваки од три елемента унутар округлих заграда for петље може да се изостави (напише на другом
месту). Приметите да је: иницијализација променљиве i (i=0) обављена пре почетка for петље и
операција инкремента променљиве i (i++) обављена унутар тела for петље.

20
Решење 4
/* Upotreba for petlje */
#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i;

i = 1;
for( ; ; ) /* uslov ponavljanja */
{
printf ( "%d\n", i ); /* ispis vrednosti brojaca */
i++;
if(i > 10)
break;
} /* kraj for petlje */

return 0; /* oznacava uspesan kraj programa */

} /* kraj funkcije main */

Напомена:
Сваки од три елемента унутар округлих заграда for петље може да се изостави (напише на другом
месту). Приметите да је: иницијализација променљиве i (i=0) обављена пре почетка for петље,
услов напуштања for петље је реализован унутар тела петље ( if(i > 10)break; ) и операција
инкремента променљиве i (i++) обављена унутар тела for петље.

16. Употребом fоr петље испишите парне бројеве од 1 до 20.

#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int broj; /* definisanje promenljive */

for ( broj = 2; broj < 21; broj += 2 )


{
printf("%2d\n", broj); /* ispis vrednosti */
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

21
17. Употребом fоr петље испишите непарне бројеве од 1 до 20.

#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int broj; /* definisanje promenljive */

for ( broj = 1; broj < 21; broj += 2 )


{
printf("%2d\n", broj); /* ispis vrednosti */
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

18. Употребом fоr петље израчунајте збир свих парних бројева од 1 до 100.

/* Sumiranje sa for petljom 2+4+6+8+...+100 */


#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int zbir= 0; /* inicijalizacija promenljive zbir */
int broj; /* broj koji se dodaje zbiru */

for ( broj = 2; broj <= 100; broj += 2 )


{
zbir += broj; /* dodaj broj zbiru */
} /* kraj for */

printf( "Suma je %d\n", zbir ); /* Ispisi zbir */

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

22
19. Демострација примене наредбе break за напуштање for петље

/* Upotreba naredbe break */


#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i; /* brojac */

/* 10 puta uradi sledece naredbe... */


for ( i = 1; i <= 10; i++ )
{
/* Ako je i jednako 5, napusti for petlju */
if ( i == 5 )
{
printf( "\nNapustam for petlju naredbom break\n");
break; /* prekid for petlje */
} /* kraj if */

printf( "%d ", i ); /* prikazi vrednost promenljive i x */


} /* kraj for */
printf( "\nNakon izlaska iz for petlje vrednost brojaca je: %d\n", i );

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

20. Демострација примене наредбе break за напуштање while петље


/* Upotreba naredbe break */
#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i=0; /* brojac */

/* 10 puta uradi sledece naredbe... */


while ( i <= 10)
{
i++;
/* Ako je i jednako 5, napusti for petlju */
if ( i == 5 )
{
printf( "\nNapustam while petlju naredbom break\n");
break; /* prekid for petlje */
} /* kraj if */

printf( "%d ", i ); /* prikazi vrednost promenljive i x */


} /* kraj for */
printf( "\nNakon izlaska iz while petlje vrednost brojaca je: %d\n", i );

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

23
21. Демострација примене наредбе continue за “прескакање” једног корака унутар for петље

/* Upotreba naredbe continue */


#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i; /* brojac */

for ( i = 1; i <= 10; i++ ) /* 10 puta uradi sledece naredbe... */


{
/* Ako je i jednako 5, napusti preskoci naredbe do kraja for petlje */
if ( i == 5 )
{
printf( "\n\n Ne napustam for petlju, samo preskacem jednu vrednost\n\n");
continue; /* preskoci naredbe do kraja for petlje */
} /* kraj if */

printf( "%d\n", i ); /* prikazi vrednost promenljive i */


} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

24
22. Демострација примене наредбе continue за “прескакање” једног корака унутар while петље

/* Upotreba naredbe continue */


#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int i; /* brojac */

while( i <= 10) /* radi sve dok je ... */


{
/* Ako je i jednako 5, preskoci naredbe do kraja while petlje */
if ( i == 5 )
{
printf( "\n\n Ne napustam while petlju, preskacem jednu vrednost\n\n");
continue; /* preskoci naredbe do kraja while petlje */
} /* kraj if */

printf( "%d\n", i ); /* prikazi vrednost promenljive i */


} /* kraj while */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

25
Увод у програмски језик C
Карактери и стрингови

Задаци за вежбу

1
Програм за демонстрацију функција isdigit, isalpha, isalnum, и isxdigit

/* funkcije: isdigit, isalpha, isalnum, isxdigit */


#include <stdio.h>
#include <ctype.h>

int main()
{
printf( "%s\n%s%s\n%s%s\n\n", "Prema funkciji isdigit: ",
isdigit('8') ? ("8 je ") : ("8 nije "), "cifra",
isdigit('#') ? ("# je ") : ("# nije "), "cifra" );

printf( "%s\n%s%s\n%s%s\n%s%s\n%s%s\n\n", "Prema funkciji isalpha:",


isalpha( 'A' ) ? "A je " : "A nije ", "slovo",
isalpha( 'b' ) ? "b je " : "b nije ", "slovo",
isalpha( '&' ) ? "& je " : "& nije ", " slovo",
isalpha( '4' ) ? "4 je " : "4 nije ", "slovo" );

printf( "%s\n%s%s\n%s%s\n%s%s\n\n", "Prema funkciji isalnum:",


isalnum( 'A' ) ? "A je " : "A nije ", "cifra ili broj",
isalnum( '8' ) ? "8 je " : "8 nije ", "cifra ili broj",
isalnum( '#' ) ? "# je " : "# nije ", "cifra ili broj" );

printf( "%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n", "Prema funkciji isxdigit:",


isxdigit( 'F' ) ? "F je " : "F nije ", "heksadecimalna cifra",
isxdigit( 'J' ) ? "J je " : "J nije ", "heksadecimalna cifra",
isxdigit( '7' ) ? "7 je " : "7 nije ", "heksadecimalna cifra",
isxdigit( '$' ) ? "$ je " : "$ nije ", "heksadecimalna cifra",
isxdigit( 'f' ) ? "f je " : "f nije ", "heksadecimalna cifra" );

return 0; /* uspesan zavrsetak programa */

} /* kraj funkcije main */

2
Програм за демонстрацију функција islower, isupper, tolower, toupper

#include <stdio.h>
#include <ctype.h>

int main()
{
printf( "%s\n%s%s\n%s%s\n%s%s\n%s%s\n\n", "Prema funkciji islower:",
islower( 'p' ) ? "p je " : "p nije ", "malo slovo",
islower( 'P' ) ? "P je " : "P nije ", "malo slovo",
islower( '5' ) ? "5 je " : "5 nije ", "malo slovo",
islower( '!' ) ? "! je " : "! nije ", "malo slovo" );

printf( "%s\n%s%s\n%s%s\n%s%s\n%s%s\n\n", "Prema fukciji isupper:",


isupper( 'D' ) ? "D je " : "D nije ", "veliko slovo",
isupper( 'd' ) ? "d je " : "d nije ", "veliko slovo",
isupper( '8' ) ? "8 je " : "8 nije ", "veliko slovo",
isupper( '$' ) ? "$ je " : "$ nije ", "veliko slovo" );

printf( "%s%c\n%s%c\n%s%c\n%s%c\n",
"m konvertovano u veliko slovo je ", toupper( 'm' ),
"7 konvertovano u veliko slovo je ", toupper( '7' ),
"$ konvertovano u veliko slovo je ", toupper( '$' ),
"K konvertovano u malo slovo je ", tolower( 'K' ) );

return 0; /* oznacava uspesan zavrsetak */

} /* kraj funkcije main */

3
Програм за демонстрацију функција isspace, isgraph

#include <stdio.h>
#include <ctype.h>

int main()
{
printf( "%s\n%s%s%s\n%s%s%s\n%s%s\n\n", "Prema funkciji isspace:",
"Novi red", isspace('\n') ? " je " : " nije ", "beli znak",
"Tab", isspace('\t') ? " je " : " nije ", "beli znak",
isspace( '%' ) ? "% je " : "% nije ", "beli znak" );

printf( "%s\n%s%s\n%s%s%s\n", "Prema funkciji isgraph:",


isgraph( 'Q' ) ? "Q je " : "Q nije ", "stampajuci znak ",
"Space", isgraph( ' ' ) ? " je " : " nije ", "stampajuci znak " );

return 0; /* uspesan zavrsetak programa */

} /* kraj funkcije main */

Напишите програм који конвертује стринг "99.50" у поменљиву типа double и потом поменљиву типа
double дели са 3 и исписује резултат.

#include <stdlib.h>

int main()
{
char str_a[]="99.50";
double nova; /* promenljiva koja cuva konvertovani string */

nova = atof(str_a);

printf("String \"%s\" konvertovan u double je %.2f\n", str_a, nova);


printf("Konvertovana vrednost podeljena sa 3 je %.2f\n",nova/3 );

return 0; /* uspesan zavrsetak programa */

} /* kraj funkcije main */

Напомена: Да пи исписали знаке навода унутар наредбе printf морате користити ескејп
секвенцу ( printf("String \"%s\"...)

4
Напишите програм који конвертује стринг "3245" у поменљиву типа int и потом од поменљиве типа int
одузима 245 и исписује резултат.

#include <stdio.h>
#include <stdlib.h>

int main()
{
char str_a[]="3245";
int celo; /* promenljiva koja cuva konvertovani string */

celo = atoi(str_a);

printf("String \"%s\" konvertovan u integer je %d\n", str_a, celo);


printf("Konvertovana vrednost minus 245 je %d\n",celo -245 );

return 0; /* uspesan zavrsetak programa */


} /* kraj funkcije main */

Напишите програм који од корисника захтева да унесе једну линију текста а потом исписује унети текст
уназад

Решење 1:

#include<stdio.h>
#include<string.h>

int main()
{
char linija_teksta[80]; /* definisanje niza od 80 elemenata */
char *ptr; /* pokazivac na char promenljivu */
int indeks_poklapanja;
int i;

printf( "Unesite jednu liniju teksta:\n" );

/* Primena funkcije gets da se u zadati niz ucita jedna linija teksta */


gets(linija_teksta);

/* Primena funkcije strchr da se u zadatom nizu pronadje pozicija (indeks) prvog


pojavljivanja zadatog karaktera, ovde trazimo kraj stringa ili karakter '\0' */
ptr=strchr(linija_teksta, '\0');

indeks_poklapanja=ptr - linija_teksta - 1;
/* moze i ovako: indeks_poklapanja=ptr-&linija_teksta[0] - 1; ili
indeks_poklapanja=ptr-&linija_teksta - 1; */

printf( "\nLinija odstampana unazad je:\n" );

for(i=indeks_poklapanja;i>=0;i--)
{
printf("%c", linija_teksta[i]);
}

printf("\n");
return 0; /* oznacava uspesan kraj programa */
} /* kraj funkcije main */

5
Решење 2:

#include<stdio.h>
#include<string.h>

int main()
{
char linija_teksta_a[80]; /* definisanje niza od 80 elemenata */
char linija_teksta_b[80]; /* definisanje niza od 80 elemenata */
char *ptr; /* pokazivac na char promenljivu */
int indeks_poklapanja;
int i;

printf( "Unesite jednu liniju teksta:\n" );

/* Primena funkcije gets da se u zadati niz ucita jedna linija teksta */


gets(linija_teksta_a);

/* trazimo kraj stringa ili ADRESU na kojoj se nalazi karakter '\0' */


ptr=strchr(linija_teksta_a, '\0');

/* indeks se dobija kao razlika adresa */


indeks_poklapanja=ptr - linija_teksta_a - 1;

printf( "\nLinija odstampana unazad je:\n" );

/* u niz linija_teksta_b upisi unazad sadrzaj niza linija teksta_a */


/* for petlja ima samo jednu naredbu, moze i bez { } */
for(i=0;i<=indeks_poklapanja;i++)
linija_teksta_b[i]=linija_teksta_a[indeks_poklapanja-i];

/* string mora da se zavrsi nul karakterom! */


linija_teksta_b[i]='\0';

/* Primenom funkcije puts ispisujemo sadrzaj stringa */


/* puts zamenjuje '\0' sa '\n' pa automatski imamo novi red! */
puts(linija_teksta_b);

return 0; /* oznacava uspesan kraj programa */

} /* kraj funkcije main */

6
Напишите програм који од корисника захтева да унесе једну линију текста а потом исписује унети текст. За
прихват унетог текста користити функцију а за испис функцију

Решење 1

/* Primena funkcija getchar i puts */


#include <stdio.h>

int main()
{
char znak; /* promen. u koju se upisuje znak koji unese korisnik */
char recenica[80]; /* niz od 80 elemenata */
int i = 0; /* brojac inicijalizovan na 0 */

/* Ispis poruke na monitor */


puts( "Unesite jednu liniju teksta:" );

/* Inicijalizacija promenljive znak */


znak=' ';

/* Primena funkcije getchar da se procita svaki uneti znak (character) */


while (znak != '\n') /* radi sve dok se ne pritisne ENTER */
{
znak = getchar(); /* ucitaj jedan znak */
recenica[i] = znak; /* upisi ucitani znak u niz*/
i++;
} /* kraj while petlje */

recenica[i] = '\0'; /* string se mora zavrsit ovim znakom */

/* funkcija puts ispisuje sadrzaj stringa na monitor */


puts( "\nUneli ste sledeci tekst:" );
puts(recenica);

return 0; /* oznacava uspesan zavrsetak programa */


} /* karaj funkcije main */

7
Решење 2
#include <stdio.h>

int main()
{
char znak; /* promen. u koju se upisuje znak koji unese korisnik */
char recenica[80]; /* niz od 80 elemenata */
int i = 0; /* brojac inicijalizovan na 0 */

/* Ispis poruke na monitor */


puts( "Unesite jednu liniju teksta:" );

/* Primena funkcije getchar da se procita svaki uneti znak (character) */


while ( ( znak = getchar() ) != '\n')
{
recenica[i++] = znak;
} /* kraj while petlje */

recenica[i] = '\0'; /* string se mora zavrsit ovim znakom */

/* funkcija puts ispisuje sadrzaj stringa na monitor */


puts( "\nUneli ste sledeci tekst:" );
puts(recenica);

return 0; /* oznacava uspesan zavrsetak programa */


} /* karaj funkcije main */

Дефинишите стринг Happy Birthday to You и запишите га у низ x . Дефинишите још двс низа: y и z.
Применом наредбе strcpy ископирајте садржај стринга x у стринг y, а потом првих 14 знакова низа y
ископирајте у низ z. Прикажите садржај сва три стринга.

Решење 1
/* Primena funkcija strcpy i strncpy */
#include <stdio.h>
#include <string.h>

int main()
{
char x[] = "Happy Birthday to You"; /* inicijalizacija niza x */
char y[ 25 ]; /* definisanje niza y */
char z[ 15 ]; /* definisanje niza z */

printf( "%s %s\n", "Sadrzaj stringa x je:", x);

strcpy( y, x ); /* kopiraj sadrzaj stringa x u string y */

printf( "%s %s\n","Sadrzaj stringa y je:", y);

/* Kopiraj prvih 14 karaktera iz x u z. Ne kopira se null character! */


strncpy( z, x, 14 );

z[14] = '\0'; /* dodaj nul karakter stringu z */


printf( "String u nizu z je: %s\n", z );

return 0; /* oznacava uspesan zavrsetaka programa */


} /* kraj fukcije main */

8
Решење 2

#include <stdio.h>
#include <string.h>

int main()
{
char x[] = "Happy Birthday to You"; /* inicijalizacija niza x */
char y[ 25 ]; /* definisanje niza y */
char z[ 15 ]; /* definisanje niza z */

puts("Sadrzaj stringa x je:");


puts(x);

/* kopiraj sadrzaj stringa x u string y */


strcpy( y, x );

puts("\nSadrzaj stringa y je:");


puts(y);

/* Kopiraj prvih 14 karaktera iz x u z. Ne kopira se null character! */


strncpy( z, y, 14 );

z[14] = '\0'; /* dodaj nul karakter stringu z */


puts( "\nString u nizu z je:");
puts(z);

return 0; /* oznacava uspesan zavrsetaka programa */

} /* kraj fukcije main */

9
Дефинишите низ (стринг) s1 од 20 елемената и иницијализујте га на вредност "Srecna ",
дефинишите низ (стринг) s2 и иницијализујте га на вредност "Nova godina " и дефинишите стринг s3 од
40 елемената та тако да буде "празан". Применом функције strcat спојте садржаје стринга s1 и s2,
испишите вредност новодобијеног стринга. Дописите првих 7 знакова новодобијеног стринга s1 на стринг s3
и исписите садржај стринга s3. На садржај стринга s3 допишите садржај стринга s1 и испишите садржај
стринга s3.

/*strcat, strncat */
#include <stdio.h>
#include <string.h>

int main()
{
char s1[20] = "Srecna "; /* inicijalizacija niza s1 */
char s2[] = "Nova godina "; /* inicijalizacija niza s2 */
char s3[40] = ""; /* inicijalizacija niza s3 као "prazаn" niz */

/* Ispis sadrzaja stringova s1 i s2*/


printf( "s1 = %s \ns2 = %s \n", s1, s2 );

/* na sadrzaj stringa s1 dopisi sadrzaj stringa s2 */


strcat( s1, s2 );

/* ispisi sadrzaj stringa s1 */


printf( "Nakon naredbe strcat(s1, s2),\t sadrzaj stringa s1 je: %s\n", s1 );

/* dopisi prvih 7 karaktera stringa s1 u string s3.*/


strncat( s3, s1, 7);
printf( "Nakon naredbe strncat(s3,s1,7),\t sadrzaj stringa s3 je: %s\n",s3);

/* na sadrzaj stringa s3 dopisi sadrzaj stringa s1 */


strcat( s3, s1);
printf( "Nakon naredbe strcat(s3, s1),\t sadrzaj stringa s3 je: %s\n",s3);

return 0; /* Oynacava uspesan zavrsetak programa */

} /* kraj funkcije main */

10
Дефинишите низ (стринг) s1 и иницијализујте га на вредност "Happy New Year". Дефинишите низ
(стринг) s2 и иницијализујте га на вредност "Happy New Year". Дефинишите низ (стринг) s3 и
иницијализујте га на вредност " Happy Holidays". Применом наредбе strcmp поредите њихоове
мођусобне односе.

#include <stdio.h>
#include <string.h>

int main()
{
const char s1[] = "Happy New Year"; /* inicijalizacija stringa */
const char s2[] = "Happy New Year"; /* inicijalizacija stringa */
const char s3[] = "Happy Holidays"; /* inicijalizacija stringa */

printf("%s %s\n","Sadrzaj stringa s1 je:", s1);


printf("%s %s\n","Sadrzaj stringa s2 je:", s2);
printf("%s %s\n","Sadrzaj stringa s3 je:", s3);

printf("\nRezultat funkcije %s je: %2d","strcmp(s1, s2) = ", strcmp( s1, s2 ) );


printf("\nRezultat funkcije %s je: %2d","strcmp(s1, s3) = ", strcmp( s1, s3 ) );
printf("\nRezultat funkcije %s je: %2d\n","strcmp(s3, s1) = ", strcmp( s3, s1 ) );

return 0;

} /* kraj funkcije main */

Употребом функције strchr одредите да ли се знаци 'n' и 'z' налазе у стрингу "Ovo je jedan test"

/* strchr */
#include <stdio.h>
#include <string.h>

int main()
{
const char niz_znakova[] = "Ovo je jedan test"; /* inicijalizacija niza */
char znak1 = 'n';
char znak2 = 'z';

/* Ako je znak1 (karakter) pronadjen u stringu... */


if ( strchr( niz_znakova, znak1 ) != NULL )
printf( "Znak \'%c\' je pronadjen u stringu \"%s\".\n", znak1, niz_znakova);
else /* ako znak1 nije pronadjen */
printf( "Znak \'%c\' nije pronadjen u stringu \"%s\".\n",znak1,niz_znakova);

/* Ako je znak2 (karakter) pronadjen u stringu... */


if ( strchr( niz_znakova, znak2 ) != NULL )
printf( "znak \'%c\' je pronadjen u stringu \"%s\".\n", znak2, niz_znakova);
else /* ako znak2 nije pronadjen */
printf( "Znak \'%c\' nije pronadjen u stringu \"%s\".\n",znak2,niz_znakova);

return 0;
} /* kraj funkcije main */

11
Употребом функције strstr одредите да ли се и на којим местима стринг "def" појављује у стрингу
"abcdefabcdef"

/* strstr */
#include <stdio.h>
#include <string.h>

int main()
{
char str1[] = "abcdefabcdef"; /* string koji se pretrazuje */
char str2[] = "def"; /* string koji se trazi */
char *pch;

printf( "%s \"%s\"\n", "string1 = ", str1);


printf( "%s \"%s\"\n", "string2 = ", str2);

pch=str1; /* pch=&str1[0] ili pch=&str1; ; */

do
{
pch=strstr(pch, str2);
if(pch != NULL)
{
printf("String \"%s\" se nalazi u stringu \"%s\" na poziciji %2d\n",
str2, str1, pch-str1+1);
pch++;
} /* kraj if naredbe */
}while(pch != NULL);

return 0;
} /* kraj funkcije main */

Употребом функције strlen одредите дужину стрингова: "abcdefghijklmnopqrstuvwxyz", "tri" и


"Kikinda"

/* strlen */
#include <stdio.h>
#include <string.h>

int main()
{
/* initialize 3 char pointers */
const char str1[] = "abcdefghijklmnopqrstuvwxyz";
const char str2[] = "tri";
const char str3[] = "Kikinda";

printf("%s \"%s\" %s %d\n","Duzina stringa", str1, "je", strlen(str1));


printf("%s \"%s\" %s %d\n","Duzina stringa", str2, "je", strlen(str2));
printf("%s \"%s\" %s %d\n","Duzina stringa", str3, "je", strlen(str3));

return 0; /* oznacava uspesan zavrsetak */

} /* kraj funkcije main */

12
Увод у програмски језик C
Функције

Задаци за вежбу
1. Написати програм који исписује квадрате вредности од 1 до 10. Рачунање квадрата реализовати у
посебној функцији.

Решење:

/* Kreiranje i primena funkcije */


#include <stdio.h>

int kvadrat( int y ); /* deklaracija ili prototip funkcije */

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int x; /* brojac */

/* 10 pita izracunaj i ispisi kvadrat x */


for (x = 1; x <= 10; x++)
{
printf( "%d ", kvadrat(x) ); /* poziv funkcije */
} /* kraj for petlje */

printf( "\n" );

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj main */

/* funkcija kvadrat, definicija */


int kvadrat(int y) /* u y se kopira vrednost x */
{
return y*y; /* vraca kvadrat y kao int */
} /* kraj funkcije kvadrat */
2. Написати програм који од три унета цела броја проналази највећи.

Решење:

/* Pronalazenje maksimuma od tri broja */

#include <stdio.h>

int maximum( int x, int y, int z ); /* prototip funkcije */

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int number1; /* prvi broj */
int number2; /* drugi broj */
int number3; /* treci broj */

printf( "Unesite tri cela broja: " );


scanf( "%d%d%d", &number1, &number2, &number3 );

/* number1, number2 i number3 su argumenti pri pozivu funk. maximum */


printf( "Maksimalna vrednost je: %d\n", maximum( number1, number2, number3 ) );

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

/* Funkcija maximum, definicija */


/* x, y z su formalni argumenti */
int maximum( int x, int y, int z )
{
int max = x; /* pretpostavimo da je x najveci broj */

if(y > max) /* ako je y veci onda je max jednak y */


{
max = y;
} /* kraj if */

if(z > max) /* ako je z vece od max, onda je max jednak z */


{
max = z;
} /* kraj if*/

return max; /* max je najveca vrednost */

} /* kraj funkcije maximum */


3. Написати програм који исписује следеће вредности:

1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
Испис вредности реализовати у потпрограму (функцији) broji_unazad( int x) са једним улазним
аргументом.

Решење:

/* prenos argumenta po vrednosti*/


#include <stdio.h>

void broji_unazad(int x); /* prototip funkcije */

int main()
{
int br;

for (br=1; br <= 10; br++)


{
broji_unazad(br);
}

return 0;
} /* kraj funkcije main */

void broji_unazad(int x) /* definicija funkcije */


{
int i;

for (i = x; i > 0; i--)


{
printf("%d", x);
x--;
}

putchar('\n'); /* novi red */


} /* kraj funkcije broji_unazad */
4. Демонстрација прослеђивања аргумената по адреси у функцију

void zameni(int *a, int *b); /* prototip funkcije */

#include <stdio.h>

int main()
{
int x=6, y=10;

printf("Pre poziva funkcije, x = %d i y = %d\n\n", x, y);

zameni(&x, &y); /* Poziv funkcije i prosledjivanje promen. po adresi */

printf("Nakon povratka iz funkcije x = %d i y = %d\n\n", x, y);

return 0;
} /* kraj funkcije main */

/* definicija funkcije */
void zameni(int *a, int *b) /* funkcija nema povratnu vrednost, tip void */
{
/* u promenljivu a je preslikana adresa promen. x */
/* u promenljivu b je preslikana adresa promen. y */

int temp;

temp= *a; /* u promen. temp upisi vrednost na koju pokazuje pointer a, tj.
vrednost prom. x */
*a = *b; /* na adresu na koju ukazuje pointer a upisi vrednost sa adrese
na koju ukazuje pointer b */
*b = temp; /* na adresu na koju ukazuje pointer b upisi vrednost promen. temp*/
} /* kraj funkcije zameni */
5. Написати програм који у четири реда исписује по пет случајних вредности између 1 и 6.
(Симулација бацања коцке). Користити функцију rand().

rand
Генерише псеудослучајан број.
декларација (прототип)
int rand( void );
Пвратна (Return) вредност
Враћа псеудослучајан број у распону од 0 до вредности дефинисане константом RAND_MAX.
(32767), <stdlib.h>.
Уколико желите да се псеудослучајне вредности не понављају користите функцију srand пре
позива функције rand.
Решење:

#include <stdio.h>
#include <stdlib.h>

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int i; /* brojac */

/* ponovi 20 puta */
for ( i = 1; i <= 20; i++ )
{
/* uzmi slucajan (random) broj izmedju 1 i 6 i ispisi ga */
printf( "%10d", 1 + ( rand() % 6 ) ); /* moduo po 6 daje vrednosti od 0 do 5 */

/* ako je brojac deljiv sa 5, predji u novi red */


if(i % 5 == 0)
{
printf( "\n" );
} /* kraj if */
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

Сваки пут када покренете овај програм добићете исте вредности. Каква је то функција rand?
Проучите наредна два примера
6. Испитајте фреквенцију појављивања бројева од 1 до 6 применом функције rand() на узорку од 6000
покушаја.
Решење:

#include <stdio.h>
#include <stdlib.h>

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int frekvencija1 = 0; /* brojac pojavljivanja broja 1 */
int frekvencija2 = 0; /* brojac pojavljivanja broja 2 */
int frekvencija3 = 0; /* brojac pojavljivanja broja 3 */
int frekvencija4 = 0; /* brojac pojavljivanja broja 4 */
int frekvencija5 = 0; /* brojac pojavljivanja broja 5 */
int frekvencija6 = 0; /* brojac pojavljivanja broja 6 */

int i;
int vrednost; /* dobijena vrednost od generatora pseudoslucajnih brojeva 6 */

/* ponovi 6000 puta i daj rezultat */


for (i = 1; i<=6000; i++ )
{
vrednost = 1 + rand() % 6; /* pseudosl. broj od 1 do 6 */
/* odredi vrednost i povecaj odgovarajuci brojac */
switch ( vrednost )
{
case 1: /* dobijena jedinica */
++frekvencija1;
break;
case 2: /* dobijena dvojka */
++frekvencija2;
break;
case 3: /* dobijena trojka */
++frekvencija3;
break;
case 4: /* dobijena cetvorka */
++frekvencija4;
break;
case 5: /* dobijena petica */
++frekvencija5;
break;
case 6: /* dobijena sestica */
++frekvencija6;
break;
} /* kraj switch */
} /* kraj for */

/* prikazi rezultat u tabelarnom formatu */


printf( "%s%13s\n", "Vrednost", "Frekvencija" );
printf( " 1%13d\n", frekvencija1 );
printf( " 2%13d\n", frekvencija2 );
printf( " 3%13d\n", frekvencija3 );
printf( " 4%13d\n", frekvencija4 );
printf( " 5%13d\n", frekvencija5 );
printf( " 6%13d\n", frekvencija6 );
return 0;/* oznacava uspesan zavrsetak programa */
} /* kraj funkcije main */
7. Потпуно исто решење, реализовано употребом низа, уместо шест променљивих дато је у наставку
#include <stdio.h>
#include <stdlib.h>

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int frekvencija[7] = {0,0,0,0,0,0,0}; /* brojac pojavljivanja brojеva 1 do 6 */

int i;
int vrednost; /* dobijena vrednost od generatora pseudoslucajnih brojeva 6 */

/* ponovi 6000 puta i daj rezultat */


for (i = 1; i<=6000; i++ )
{
vrednost = 1 + rand() % 6; /* pseudosl. broj od 1 do 6 */
/* odredi dobijenu vrednost i povecaj odgovarajuci brojac */
++frekvencija[vrednost];
} /* kraj for */

/* prikazi rezultat u tabelarnom formatu */


printf( "%s%13s\n", " Vrednost", "Frekvencija" );

for(i=1;i<7;i++)
printf( "\t%d%13d\n", i,frekvencija[i] );

return 0;/* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */
8. Претходни пример показује да се бројеви појављују са подједнаком вероватноћом. Суштински
проблем је што функција rand представља псеудослучјни а не случајни генератор. То значи да
бројеви које она генерише статистички гледано задовољавају потребна својства али је то (довољно
дугачак) низ бројева који је периодичан (понавља се), и увек креће од истог места. Да би функција
rand не би генерисала бројеве од истог места потребно је пре њеног позивања позвати функцију
srand(unsigned int), која има unsigned int као аргумент и поставља место почетка функције
rand. У наредном примеру је демонстрирана употреба функције srand(unsigned int)

#include <stdlib.h>
#include <stdio.h>

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int i; /* brojac */
unsigned int seed; /* broj koji odredjuje mesto pocetka rada rand generatora */

printf( "Unesite vrednost parametra za rand generator: " );


scanf( "%u", &seed ); /* primetite %u za unsigned int */

srand( seed ); /* postavi pocetnu vrednost rand generatora */

/* petlja 10 puta */
for ( i = 1; i <= 10; i++ )
{
/* uzmi slucajnu vrednost od 1 do 6 i ispisi je */
printf( "%10d", 1 + ( rand() % 6 ) );

/* ako je brojac deljiv sa 5 predji u novi red */


if ( i % 5 == 0 )
{
printf( "\n" );
} /* kraj if */
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj main */
9. Сваки пут када унесете исту вредност добићете исте бројеве.
Како обезбедити да функција rand увек почне од друге почетне вредности. Потребно је да се сваки
пут функцији srand постави другачији аргумент. Један од начина је да се као аргумент постави излаз
функције time(NULL) која враћа текуће време дефинисано у рачунару. Ова функција враћа време
(број секунди) протекао од поноћи (00:00:00), 1. Јануара 1970. године. Aргумент NULL је потребан да
би функција time враћала вредност у бројчаном формату.
Претходни пример је сада могуће написати на следећи начин

#include <stdlib.h>
#include <stdio.h>
#include <time.h> /* sadrzi prototip funkcije time */

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int i; /* brojac */

srand(time(NULL)); /* postavi pocetnu vrednost rand generatora svaki put kad se


pokrene program na drugu vrednost*/

/* petlja 10 puta */
for(i = 1; i <= 10; i++)
{
/* uzmi slucajnu vrednost od 1 do 6 i ispisi je */
printf( "%10d", 1 + ( rand() % 6 ) );

/* ako je brojac deljiv sa 5 predji u novi red */


if( i % 5 == 0 )
{
printf( "\n" );
} /* kraj if */
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj main */
10. Унутар функције се не може дефинисати нова функција али функција може позивати другу функцију
па и сама себе. Појава када функција позива саму себе се назива рекурзија.
Размотримо проблем рачунања факторијела. Факторијел не негативног броја n које се обележава
као n! је производ:
n! =n*(n-1)*(n-2)*(n-3)*...*1
стим да је 1! = 1
0! = 1
На пример:
5! = 5*4*3*2*1= 120

Факторијел броја broj се може израчунати применом for петље:

faktorijel = 1;
for(i=broj; i>=1; i--)
{
faktorijel *= i; /* faktorijel = faktorijel * i; */
}

али се може добити и применом рекурзивне функције:


Рекурзивна дефиниција факторијела се може извести из следећих релација:
5! = 5*4*3*2*1= 5*(4*3*2*1) = 5*(4!)
4!= 4*3*2*1=4*(3*2*1) = 4*(3!)
3! = 3*2*1=3*(2*1) = 3*(2!)
2! = 2*1=2*(1) = 2*(1!)
1! = 1
...
#include <stdio.h>

long faktorijel(long broj); /* prototip funkcije */

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
int i; /* brojac */

/* 11 puta ponovi naredbe, svaki put izracunaj faktorijel(i) i ispisi rezultat */


for ( i = 0; i <= 10; i++ )
{
printf("%2d! = %ld\n", i, faktorijel(i) ); /* poziv funkcije faktorijel i */
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

/* Definicija rekurzivne funkcije faktorijel */


long faktorijel(long broj)
{
/* ako je broj 0 ili 1, 0!=1 i 1!=1 */
if( broj <= 1 )
{
return 1; /* vrati 1 i zavrsi rada sa funkcijom */
} /* kraj if */
else /* jedan korak rekurzije */
{
return (broj * faktorijel(broj - 1) ); /* rekurzivni poziv funkcije */
} /* kraj else */

} /* kraj funkcije faktorijel */

Функција faktorijel користи рекурзију да би одштампала факторијеле бројева од 0 до 10. Ова рекурзивна
функција прво тестира broj да би видела да ли је он различит од 1 и 0, и у том случају враћа вредност 1
што је уједно и прекид рекурзије односно напуштанје функције faktorijel.
Ако је улазни аргумент (broj) већи од 1 наредба return(broj*faktorijel(broj-1)); у ствари
позива функцију faktorijel са аргументом кој је за један мањи (broj-1)
11. Напишите програм који рачина Фибоначијеву вредност од унетог броја.

Fibonacci-јев низ почиње бројем 0 и 1 а има својство да је сваки наредни елемент низа једнак збиру
претходна два елемента низа, тј.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

У сврху писања програма дефинишимо функцију са једним аргументом fibonacci( i ) каја ће


враћати вредности
fibonacci(0)=0,
fibonacci(1)=1,
fibonacci(n) = fibonacci(n-1) + fibonacci(n-2)
Решење1

#include <stdio.h>

long fibonacci( long broj ); /* prototip funkcije */

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
long rezultat; /* fibonacci vrednost */
long indeks; /* broj koji unosi korisnik */

/* Uzmi broj od korisnika */


printf( "Unesite celi broj: " );
scanf( "%ld", &indeks );

/* Izracunaj fibonacci vrednost ya uneti broj */


rezultat = fibonacci(indeks);

/* prikazi rezltat */
printf( "Fibonacci( %ld ) = %ld\n", indeks, rezultat );

return 0; /* oznacava uspesan zavrsetak programa */

} /* kraj funkcije main */

/* definicija rekurzivne funkcije fibonacci */


long fibonacci(long broj)
{
long i;
long n_minus1=1, n_minus2=0, n;

if (broj==0 || broj==1)
return broj;

for(i=1;i<broj;i++)
{
n=n_minus1+n_minus2;
n_minus2=n_minus1;
n_minus1=n;
}
return n;
} /* kraj funkcije fibonacci */
Решење2

#include <stdio.h>

long fibonacci(long broj); /* prototip funkcije */

/* funkcija main, mesto pocetka izvrsavanja programa */


int main()
{
long rezultat; /* fibonacci vrednost */
long indeks; /* broj koji unosi korisnik */

/* Uzmi broj od korisnikao */


printf( "Unesite celi broj: " );
scanf( "%ld", &indeks );

/* Izracunaj fibonacci vrednost ya uneti broj */


rezultat = fibonacci( indeks );

/* prikazi rezltat */
printf( "Fibonacci( %ld ) = %ld\n", indeks, rezultat );

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

/* definicija rekurzivne funkcije fibonacci */


long fibonacci(long n)
{
/* osnovni slucaj */
if(n == 0 || n == 1)
{
return n;
} /* kraj if */
else
{ /* rekurzija */
return fibonacci(n - 1) + fibonacci(n - 2);
} /* kraj else */
} /* kraj funkcije fibonacci */
12. Написти програм који проверава исправност унетог датума.

#include <stdio.h>
#include <string.h> /* potrebno zbog funkcije strchr() */
#include<stdlib.h> /* potrebno zbog funkcije atoi() */
#include <ctype.h> /* potrebno zbog funkcije isdigit() */

int ucitaj_datum(int *d, int *m, int *g ); /* prototip funkcije*/


int proveri_datum( int xd, int ym, int yg ); /* prototip funkcije*/

int main()
{
int dan;
int mesec;
int godina;
int pom;

pom=ucitaj_datum(&dan, &mesec, &godina); /* poziv funkcije, unos podataka */

/* ako je po formatu korektno unet datum poroveri da li je moguc */


if(!pom) /* funkcija vraca vrednost u pom */
pom =proveri_datum(dan, mesec, godina); /* poziv funkcije, provera unosa */

switch(pom) /* i druga funkcija vraca vrednost u pom */


{
case 1:
printf("\n");
break;
case 2:
printf("Niste uneli odgovarajuci mesec\n\b");
break;
case 3:
printf("Niste uneli odgovarajuci dan u mesecu\n\b");
break;
default:
printf("Uneti datum je korektan!\n");
break;
}
return 0;
} /* kraj funkcije main*/
/* definicija funkcije ucitaj_datum */
int ucitaj_datum(int *d, int *m, int *g )
{
char niz[80];
char podniz[5];
int kontrola;
int duzina;
int i;
char *ptr;

kontrola=1;

do
{
printf("\nUnesite datum u formatu dd.mm.gggg ili dd.mm.gg, x za prekid\n" );
gets(niz); /* ucitaj unos korisnika */
duzina=strlen(niz); /* odredi broj unetih karaktera */

/* zahtev korisnika za prekid programa*/


if(niz[0]=='x' || niz[0]=='X')
return 1;

/* da li je broj unetih karaktera odgovarajuci? */


if(duzina != 10 )
printf("Broj unetih vrednosti nije odgovarajuci\n", duzina);
else
kontrola=0; /* ok */

/* Ako je broj unetih karaktera odgovarajuci... */


if(!kontrola)
{
/* da li je pozicija delimitera na pravom mestu (3. i 6.) */
ptr=strchr(niz, '.'); /* pozicija prvog delimitera */
if((ptr - niz+1) != 3)
{
printf("Pozicija delimitera ('.') nije odgovarajuca");
kontrola=1; /* greska u formatu */
}

if(!kontrola)
{
ptr=strchr(ptr+1, '.'); /* pozicija drugog delimitera */
if((ptr - niz+1) != 6)
{
printf("Pozicija delimitera ('.') nije odgovarajuca");
kontrola=1;
}
}
}
if(kontrola)
continue;

for(i=0; i<10;i++) /* da li su na svim pozicijama (sem 3 i 6) brojevi */


{
if(i==2 || i==5)
continue;

if( !( isdigit(niz[i]) ) )
{
printf("datum moze sadrzati samo brojeve\n");
kontrola =1;
break;
}
}

/* ako je format odgovarajuci, izdvoj podtke o danu mesecu i godini */


if(!kontrola)
{
strncpy( podniz, niz ,2);
podniz[2]='\0';
*d=atoi(podniz);
strncpy( podniz, niz+3 ,2);
podniz[2]='\0';
*m=atoi(podniz);
strncpy( podniz, niz+6 ,4);
podniz[4]='\0';
*g=atoi(podniz);

/* ukoliko je bar jedna od vrednosti 0 (uneto 00 ili slovo).. */


if( !(*d && *m && *g ) )
{
printf("Unete vrednosti moraju bit brojevi razliciti od 00 odnosno 0000\n");
kontrola =1;
}
}

}while(kontrola);

return 0;
}
int proveri_datum( int xd, int ym, int yg )
{

int max_dana;
int prestupna=0;

/* proveri da li je godnia prestupna */


if((yg % 4)==0)
prestupna =1;

/* utvrdi maks broj dana u mesecu */


if(ym>12)
return 2; /* mesec nije odgovarajuci*/

switch(ym)
{
case 4:
case 6:
case 9:
case 11:
max_dana = 30;
break;
case 2:
if (prestupna)
max_dana=29;
else
max_dana=28;
break;
default:
max_dana=31;
break;
}
if(xd>max_dana)
return 3; /* broj dana u mesecu nije odgovarajuci */

return 0;
}
Увод у програмски језик C

Задаци за вежбу
НИЗОВИ
1. Иницијализујете низ од 10 елемената на вредност 50 применом for петље, испишите вредности низа
у облику табеле.

/* Inicijalizacija niza */
#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int n[10]; /* n je niz od 10 celih brojeva */
int i; /* brojac */

/* inicijalizacija elementa niza na vrednost 50 */


for ( i = 0; i < 10; i++ )
{
n[ i ] = 50; /* dodeli vrednost e0 elementu niza sa indeksom i */
} /* kraj for petlje */

printf( "%s %11s \n\n", "Niz n", "Vrednost" ); /* %s je format za string */


printf("-----------------\n"); /* ispis crtica */

/* ispis vrednosti elemenata niza u obliku tabele */


for ( i = 0; i < 10; i++ )
{
printf( "n[%d] %6d\n", i, n[ i ] );
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

2. Иницијализујте дводимензионални низ димензија 2x5 на вредности 1, 2, 3, 4, 5 и 2, 4, 6,


8, 10, па испишите вредности низа.

#include <stdio.h>
int main()
{
/* Deklarisanje niza dimenzija 2 x 5 */
int x[2][5] = { {1, 2, 3, 4, 5},
{2, 4, 6, 8, 10} };

int red, kolona;

/* Prikaz elemenata niza po redovima */


for (red=0; red<2; red++)
{
/* Prikaz elemenata niza po kolonama */
for (kolona=0; kolona<5; kolona++)
{
printf("%2d\t", x[red][kolona]);
} /* kraj unutrasnje for petlje */
printf("\n"); /* putchar('\n');*/
} /* kraj spoljasnje for petlje */
return 0;
}/* kraj funkcije main */
3. Демонстрација иницијализације низа и исписа вредности по елементима

/* Inicijalizacija niza */
#include <stdio.h>

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int n[ 10 ] = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37 };
int i; /* brojac */

printf( "%s%13s\n\n", "Niz n", "Vrednost" );

/* ispis vrednosti elemenata niza u obliku tabele */


for ( i = 0; i < 10; i++ )
{
printf( "n[%d] %6d\n", i, n[ i ] );
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

4. Иницијализујте низ парним бројевима од 2 до 20

/* Inicijalizacija niza parnim brojevima od 2 do 20 */


#include <stdio.h>
#define SIZE 10

int main()/* funkcija main, pocetak izvrsavanja programa */


{
int s[ SIZE ];
int i; /* brojac */

for(i = 0; i < SIZE; i++) /* dodela pocetnih vrednosti */


{
s[i] = 2 + 2 * i;
} /* kraj for */

printf( "%s%13s\n\n", "Niz s", "Vrednost" );

/* ispis vrednosti elemenata niza u obliku tabele */


for(i = 0; i < 10; i++)
{
printf( "s[%d] %6d\n", i, s[ i ] );
} /* kraj for */

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */
5. Напишите програм који рачуна суму елемената низа. Нека низ има 12 елемената са произвољно
иницијализованим вредноситма.

/* Izracunavanje sume elemenata niza */


#include <stdio.h>
#define SIZE 12

/* funkcija main, pocetak izvrsavanja programa */


int main()
{
int a[ SIZE ] = { 1, 3, 5, 4, 7, 2, 99, 16, 45, 67, 89, 45 };
int i; /* brojac */
int suma = 0; /* zbir vrednosti elemenata niza */

for ( i = 0; i < SIZE; i++ ) /* dodela pocetnih vrednosti */


{
suma += a[ i ];
} /* kraj for */

printf( "Zbir svih vrednosti elemenata niza je %d\n", suma );

return 0; /* oznacava uspesan zavrsetak programa */


} /* kraj funkcije main */

6. Напишите програм који из низа од 10 елемената типа float, произвољно иницијализованог, издваја
елемент који садржи највећу вредност.

/* Izdvajanje elementa niza koji ima najvecu vrednost*/


#include<stdio.h>

int main()
{
#define BR_ELEMENATA 10

double niz[BR_ELEMENATA] = {117.0, 129.95, 276.22, 201.10,106.31,


358.11, 31.85, 256.45, 269.09, 197.81};
double max;
int i;

max = niz[0];
for (i = 1; i < BR_ELEMENATA; i++)
{
if (niz[i] > max) max = niz[i];
/* Primetite da i pocinje od 1 */
}

printf("\nMaksimalna vrednost niza je %f\n", max);

return 0;
}
7. Анкетирано је четрдесет студената о квалитету хране у мензи. Сваки студент је дао оцену од 1 до 10.
Написати програм који који ће одредити и исписати фреквенцију (број) појављивања сваке оцене.
(Нпр. две јединице, три четворке....)

#include <stdio.h>

#define BROJ_STUDENATA 40 /* definisi velicinu nizova */


#define FREKV_VELICINA 11 /* 10 ocena, 11 zbog zanemarivanja indeksa 0*/

/* funkcija main pocetak izvrsavanja programa */


int main()
{
int i; /* brojac koji kruzi od 1. do 40. odgovora */

/* inicijaliacija niza sa brojem dobijenih ocena na 0 */


int frekvOcena[FREKV_VELICINA] = { 0 };

/* inicijalizacija niza odgovor studenata, proizvoljno */


int odgovor[ BROJ_STUDENATA ] = { 1, 2, 6, 4, 8, 5, 9, 7, 8, 10,
1, 6, 3, 8, 6, 10, 3, 8, 2, 7, 6, 5, 7, 6, 8, 6, 7, 5, 6, 6,
5, 6, 7, 5, 6, 4, 8, 6, 8, 10 };

/* za svaki odgovor, odredite vrednost elementa niza odgovor


i uzmite tu vrednost kao indeks niza frekvOcena i da bi se
pozicionirali na taj element niza frekvOcena i povecajte ga za 1 */

for(i = 0; i < BROJ_STUDENATA; i++)


{
++frekvOcena[ odgovor[i] ];
} /* kraj for petlje */

/* prikazi rezultate */
printf( "Ocena Broj glasova\n" );

/* Prikaz u tabelarnom formatu */


for ( i = 1; i < FREKV_VELICINA; i++ )
{
printf("%5d%14d\n", i, frekvOcena[i]);
} /* kraj for */

return 0;
} /* kraj funkcije main */
8. Дефинисати низ од 10 елемената. Иницијализовати елементе низа на произвољне вредности мање
од 30. Написати програм који исписује вредност сваког елемента низа а поред њега, у виду
хистограма, број звездица једнак вредности елемента низа.

#include <stdio.h>

#define VELICINA 10 /* definisi velicinu niza */

int main()
{
/* inicializacija niza n */
int n[VELICINA] = { 19, 3, 15, 7, 11, 9, 13, 5, 17, 1 };
int i; /* brojac za elemente polja */
int j; /* brojac zvezdica */

printf("Element Vrednost Histogram\n" );

/* za svaki element polja ispisi index, vrednost i nacrtaj histogram */


for ( i = 0; i < VELICINA; i++ )
{
/* ispis indeksa i vrednosti*/
printf( "%7d%10d ", i, n[i]) ;

for ( j = 1; j <= n[i]; j++ )


{
printf( "%c", '*' ); /* ispisi jednu zvezdicu */
} /* kraj unutrasnje petlje */
printf( "\n" ); /* kraj ispisa histigrama za jedan element niza */
} /* kraj spoljasnje petlje */

return 0;
} /* kraj funkcije main */
9. Написати програм који применом методе bubble sort сортира елементе низа

#include <stdio.h>
#define DIMENZIJA 10

int main()
{
/* inicijalizacija niza a */
int a[DIMENZIJA] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 };
int prolaz; /* brojac prolaza */
int i; /* brojac poredjenjar */
int priv; /* privremeno cuvanje vrednosti */

printf( "Vrednosti niza u pocetnom redosledu\n" );

/* ispisi vrednosti u pocetnom redosledu */


for ( i = 0; i <DIMENZIJA; i++ )
printf( "%4d", a[ i ] );

/* bubble sort */
for ( prolaz = 1; prolaz < DIMENZIJA; prolaz++ )
{
for ( i = 0; i < DIMENZIJA - 1; i++ )
{
/* poredi vrednost susednih elemenata i yameni im mesta ako je
vrednost prvog elementa veca od drugog */
if ( a[i] > a[i + 1] )
{
priv = a[i];
a[i] = a[i + 1];
a[i + 1] =priv;
} /* kraj if */
} /* kraj unutrasnje for petlje */
} /* kraj spoljasnje for petlje */

printf( "\nVrednosti niza nakon sortiranja\n" );

/* Ispis vrednosti */
for ( i = 0; i < DIMENZIJA; i++ )
printf( "%4d", a[ i ] );

printf( "\n" );

return 0;
} /* kraj funkcije main */
Увод у програмски језик C

Задаци за вежбу
ПОКАЗИВАЧИ
1. Демонстрација рада са показивачима.

#include <stdio.h>

int main()
{
int broj_a;
int *ptr_br;
float real1, real2;
float *ptr_re;

broj_a=4;
real1=3.2f;

ptr_br = &broj_a; /* pointer ukazuje na adresu prom. broj_a*/


broj_a = broj_a + *ptr_br + 1; /* *ptr_br je sadrzaj adrese na koju ukazuje
*/
printf("\n%d\n",broj_a);

ptr_re=&real1;
real2= *ptr_re;

printf("%f\n",real2);

return 0;
} /* kraj funkcije main */

После извршења наредбе ptr_br = &broj_a; показивач ptr_br показује на адресу где је
смештена променљива broj_a. Наредбом broj_a = broj_a + *ptr_br + 1; променљива
broj_a добија вредност 4+4+1 ...

2. Демонстрација рада са показивачима.

#include <stdio.h>

int main()
{
int broj_a, broj_b, broj_c;
int *ptr_br;

broj_a=8;
broj_b=4;
ptr_br=& broj_c; /* pokazivac pokazuje na adresu promen. broj_c */
*ptr_br= broj_a + broj_b; /* isto sto i broj_c = broj_a + broj_b */

printf("\n%d\n",broj_c);

ptr_br=& broj_a; /* pokazivac pokazuje na adresu promen. broj_a */


broj_a = broj_b * broj_c; /* mnozenje */
printf("\n%d\n",*ptr_br);

ptr_br=& broj_b; /* pokazivac pokazuje na adresu promen. broj_b */


printf("\n%d\n",*ptr_br);

return 0;
} /* kraj funkcije main */
3. Написати програм који путем показивача приступа 5. и 7. елементу низа и исписати њихове
вредности. Низ треба да има 10 елемената. Затим, такође, путем показивача у 5. елемент низа
уписати вредност збира 6 и 7. елемента низа. Елементи низа могу да имају проиѕвољну вредност.

#include <stdio.h>

int main()
{
int niz[10]={10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int broj_a;
int *ptr_br;

/* pointer ukazuje na 0ti indeks niza */


ptr_br=niz; /* isto sto i ptr =niz[0] ili ptr=&niz[0] */

broj_a= *(ptr_br+4); /* *(ptr+4) citaj kao sadrzaj 5 elementa niza (indeks


4) */
printf("\n%d\n",broj_a);

ptr_br=&niz[6]; /* isto sto i ptr =niz[6] */


printf("\n%d\n",*ptr_br);

*(ptr_br-1)=*ptr_br + *(ptr_br +1);


/* ptr pokazuje na niz[6], *(ptr_br-1) je sadrzaj niz[5], *ptr_br je sadrzaj
niz[6]
*(ptr_br +1); je sadrzaj niz[6], pa je ovo ekvival. niz[5]=niz[6]+ niz[7]
*/

printf("\n%d\n",*(ptr_br-1));
printf("\n%d\n",niz[5]);

return 0;
} /* kraj funkcije main */
4. Коришћењем показивача: уписати све елементе низа од 10 елемената а потом исписати сваки парни
елемент низа.

Решење 1
#include <stdio.h>

int main()
{
int niz[10];
int i;
int *pok;

i=1;
for(pok=niz; pok <= &niz[9]; pok++)
{
printf("upisite %d. element niza\n",i);
scanf("%d", pok);
i++;
}

i=2;
for(pok=&niz[1];pok <= &niz[9]; pok = pok+2)
{
printf("%d. element je: %d\n",i, *pok);
i+=2;
}
return 0;
}

Решење 2
#include <stdio.h>

int main()
{
int niz[10];
int i;
int *pok;

for(pok=niz, i=1; pok <= &niz[9]; pok++, i++)


{
printf("upisite %d. element niza\n",i);
scanf("%d", pok);
}

for(pok=&niz[1], i=2; pok <= &niz[9]; pok = pok+2, i+=2)


printf("%d. element je: %d\n",i, *pok);

return 0;
}
Напомена: приметите да су наредбе унутар петље раздвојене зарезом (,) и тача-зарезом (;).
5. Демонстрација рада са показивачима

#include <stdio.h>
main()
{
int a[8] = {1,23,17,4,-5,100,55,44};
int *pa, *pb;
int x, y;

pa=&a[4]; /* pa ukazuje na a[4] tj na vrednost -5 */


printf("Vrednost *pa nakon naredbe pa=&a[4] je: %d\n", *pa);
x=*(pa+3); /* x=a[7]=44 */
printf("Vrednost x nakon naredbe x=*(pa+3) je: %d\n", x);
y=*pa+3; /* y=a[4]+3=-2*/
printf("Vrednost y nakon naredbe y=*pa+3; je: %d\n", y);
*pa++; /* povecava se sadrzaj pokazivaca, isto sto i *(pa++)
ili pa=&a[5] */
printf("Vrednost *pa nakon naredbe *pa++ je: %d\n", *pa);
(*pa)++; /* povecava se pokazani podatak a[5]=a[5]+1=101 */
printf("Vrednost *pa nakon naredbe (*pa++) je: %d\n", *pa);
pb=&a[2];
}

6. Рад са malloc функцијом

#include <stdio.h>
#include <stdlib.h> /* potrebno zbog malloc i free funkcije */

main()
{
int number;
int *ptr;
int i;

printf("Koliko int vrednosti zelite da sacuvate? ");


scanf("%d", &number);

ptr = malloc(number*sizeof(int)); /* zahtev za dodelu memorije */


/* ptr = (int *)malloc(number*sizeof(int)); */ /* moze i ovako */

if(ptr!=NULL)
{
for(i=0 ; i<number ; i++)
{
*(ptr+i) = i;
}
for(i=number ; i>0 ; i--)
{
printf("%d\n", *(ptr+(i-1))); /* prikazi u suprotnom redosledu */
}

free(ptr); /* oslobodi dodeljenu memoriju */


}
else
printf("\nDodela memorije nije izvrsena - nema dovoljno
memorije.\n");
}
7. Рад са calloc функцијом

#include <stdio.h>
#include <stdlib.h> /* potrebno zbog malloc i free funkcije */

main()
{
float *ptr_c1, *ptr_c2, *ptr_m1, *ptr_m2;
int i;

ptr_c1 = calloc(3, sizeof(float)); /* moze se zahtevati konverzija */


ptr_c2 = calloc(3, sizeof(float));
ptr_m1 = malloc(3 * sizeof(float));
ptr_m2 = malloc(3 * sizeof(float));

if(ptr_c1!=NULL && ptr_c2!=NULL && ptr_m1!=NULL && ptr_m2!=NULL)


{
printf("adresa ptr_c1 je %05.5p,\n", ptr_c1);
printf("adresa ptr_c2 je %05.5p,\n", ptr_c2);
printf("adresa ptr_m1 je %05.5p,\n", ptr_m1);
printf("adresa ptr_m2 je %05.5p,\n\n", ptr_m2);

for(i=0 ; i<3 ; i++)


{
printf("*ptr_c1[%d] ima vrednost %05.5f,\n", i, *(ptr_c1+i));
printf("*ptr_c2[%d] ima vrednost %05.5f,\n", i, *(ptr_c1+i));
printf("*ptr_m1[%d] ima vrednost %05.5f\n", i, *(ptr_m1+i));
printf("*ptr_m2[%d] ima vrednost %05.5f,\n\n", i, *(ptr_c1+i));
}

free(ptr_c1);
free(ptr_c2);
free(ptr_m1);
free(ptr_m2);
}
else
printf("Nema dovoljno memorije\n");
}
8. Рад са realloc функцијом

#include<stdio.h>
#include <stdlib.h>

int main()
{
int *ptr;
int i;

ptr = calloc(5, sizeof(int)); /*dinamicki niz od 5 elemenata indeks 0-4


*/

if(ptr!=NULL) /* ako je dodeljena memorija...*/


{
*ptr = 1; /* isto sto i ptr[0]=1 ili *ptr=1 */
*(ptr+1) = 2; /* isto sto i ptr[1]=2 */
*(ptr+2) = 4;
*(ptr+3) = 8;
*(ptr+4) = 16;

printf("\nNakon naredbe calloc(5, sizeof(int)) i dodele


vrednosti...\n");
for(i=0 ; i<5 ; i++)
printf("*(ptr+%d) ukazuje na vrednost %d\n", i, *(ptr+i));

ptr = realloc(ptr, 7*sizeof(int)); /* dodaj jos 2 int (bilo je vec 5)*/

if(ptr!=NULL)
{
printf("\n Nakon naredbe ptr = realloc(ptr, 7*sizeof(int));... \n");
for(i=0 ; i<7 ; i++)
printf("*(ptr+%d) ukazuje na vrednost %d\n", i, *(ptr+i));

*(ptr+5) = 32;
*(ptr+6) = 64;

printf("\n Nakon naredbe dodele vrednosti 6. i 7. elementu... \n");


for(i=0 ; i<7 ; i++)
printf("*(ptr+%d) ukazuje na vrednost %d\n", i, *(ptr+i));

realloc(ptr,0); /* isto sto i free(ptr); */


}
else
printf("Nema dovoljno memorije - realloc neuspesan.\n");
}
else
printf("Nema dovoljno memorije - calloc neuspesan.\n");
}
Увод у програмски језик C
Рад са фајловима

Задаци за вежбу

1
1. Написати програм који усписује у фајл (klijenti.dat) податке о броју рачуна, имену клијента и стању на
рачуну. Број оваквих записа треба да је произвољан, све док корисник не унесе Ctrl+Z.

Решење:

/* Upis podataka u fajl */


#include <stdio.h>

int main()
{
int broj_racuna; /* broj racuna korisnika */
char ime[ 30 ]; /* ime korisnika */
double stanje; /* stanje na racunu */

FILE *prt_na_fajl; /* prt_na_fajl = fajl pointer */

/* fopen otvara fajl, w za upisivanje. */


/* Ukoliko ne uspe pointer je jednak 0, izadji iz programa */
if ( ( prt_na_fajl = fopen( "klijenti.dat", "w" ) ) == NULL )
{
printf( "Fajl se ne moze otvoriti\n" );
} /* kraj if */
else
{
printf( "Unesite broj racuna, ime korisnika i stanje.\n" );
printf( "Unesite Ctrl+Z za kraj rada.\n" );
printf( "? " );
scanf( "%d%s%lf", &broj_racuna, ime, &stanje );

/* Upisite broj racuna, ime i stanje u fajl nredbom fprintf */


while ( !feof( stdin ) )
{
fprintf( prt_na_fajl, "%d %s %.2f\n", broj_racuna, ime, stanje );
printf( "? " );
scanf( "%d%s%lf", &broj_racuna, ime, &stanje );
} /* kraj while */

fclose( prt_na_fajl ); /* fclose zatvara fajl */


} /* kraj else */

return 0; /* oznacava uspesan zavrsetaka */

} /* kraj main */

Функција feof( stdin ) одређује да ли је прочитан end-of-file индикатор у дефинисаном улазу. У овом
примеру је дефинисани улаз тастатура (stdin), мада дефинисани улаз може бити и фајл уколико се из њега
читају подаци. Уколико функција прочита ознаку (Ctrl+Z) za крај фајла (end-of-file), функција feof враћа
вредност 1.

Приликом рада са овим програмом унесите вредности тако да неки од корисника имају стање на рачуну 0
неки позитивно стање а неки негативно (ради рада у наредним примерима)

? 100 Petric 324.22


? 121 Markovic 0.00
? 111 Simic 32.33
? 246 Коvac -34.56
? 343 Jack -200
? 654 Jon 9567.34
? ^Z

2
2. Прочитати све податке из фајла (претходни пример), и испишите их на екран у одговарајућем формату.

Решење:
/* citanje podataka iz fajla*/
#include<stdio.h>
int main()
{
int broj_racuna; /* broj racuna korisnika */
char ime[ 30 ]; /* ime korisnika */
double stanje; /* stanje na racunu */

FILE *prt_na_fajl; /* prt_na_fajl = fajl pointer */

/* fopen otvara fajl, r (read) za citanje. */


/* Ukoliko ne uspe pointer je jednak 0, izadji iz programa */
if ( ( prt_na_fajl = fopen( "klijenti.dat", "r" ) ) == NULL )
{
printf( "Fajl se ne moze otvoriti\n" );
} /* kraj if */
else
{
printf( "%-14s%-16s%s\n", "Broj racuna","Ime","Stanje" );
fscanf( prt_na_fajl,"%d%s%lf", &broj_racuna, ime, &stanje );

/* Citanje podataka iz fajla naredbom fscanf */


while ( !feof( prt_na_fajl ) )
{
printf( "%-14d%-16s%7.2f\n", broj_racuna,ime, stanje );
fscanf( prt_na_fajl,"%d%s%lf", &broj_racuna, ime, &stanje );
} /* kraj while */

fclose( prt_na_fajl ); /* fclose zatvara fajl */


} /* kraj else */

return 0; /* oznacava uspesan zavrsetaka */

} /* kraj main */

3
3. Написати програм који из фајла формираног у првом задатку чита податке и на основу захтева
корисника:
а. исписује податке о рачунима који имају стање 0
б. исписује податке о рачунима који имају негативно стање
в. исписује податке о рачунима који имају позитивно стање
г. прекида рад

Решење:

#include<stdio.h>
int main()
{
int zahtev;
int broj_racuna; /* broj racuna korisnika */
char ime[ 30 ]; /* ime korisnika */
double stanje; /* stanje na racunu */
FILE *prt_na_fajl; /* prt_na_fajl = fajl pointer */

/* fopen otvara fajl, r (read) za citanje. */


/* Ukoliko ne uspe pointer je jednak 0, izadji iz programa */
if ( ( prt_na_fajl = fopen( "klijenti.dat", "r" ) ) == NULL )
printf( "Fajl se ne moze otvoriti\n" );
else
{
/* prikazi zahtevane opcije */
printf( "Unesite zahtev\n"
" 1 - Izlistaj racune sa stanjem NULA\n"
" 2 - Izlistaj racune sa stanjem u MINUSu\n"
" 3 - Izlistaj racune sa POZITIVNIM stanjem\n"
" 4 - Kraj\n? " );
scanf( "%d", &zahtev );

while(zahtev !=4)
{
fscanf( prt_na_fajl,"%d%s%lf", &broj_racuna, ime, &stanje );
switch(zahtev)
{
case 1:
printf( "\nRacuni sa stanjem NULA:\n" );
/* citaj sadrzaj fajla do kraja (sve do eof) */
while ( !feof( prt_na_fajl ) )
{
if ( stanje == 0 )
printf( "%-14d%-16s%7.2f\n", broj_racuna, ime, stanje );
/* procitaj broj racuna, ime i stanje iz fajla */
fscanf( prt_na_fajl, "%d%s%lf", &broj_racuna, ime, &stanje );
} /* kraj while */
break;

4
case 2:
printf( "\nRacuni sa stanjem u MINUSu:\n" );
/* citaj sadrzaj fajla do kraja (sve do eof) */
while ( !feof( prt_na_fajl ) )
{
if ( stanje < 0 )
printf( "%-14d%-16s%7.2f\n", broj_racuna, ime, stanje );
/* procitaj broj racuna, ime i stanje iz fajla */
fscanf( prt_na_fajl, "%d%s%lf", &broj_racuna, ime, &stanje );
} /* kraj while */
break;
case 3:
printf( "\nRacuni sa POZITIVNIM stanjem:\n" );
/* citaj sadrzaj fajla do kraja (sve do eof) */
while ( !feof( prt_na_fajl ) )
{
if ( stanje > 0 )
printf( "%-14d%-16s%7.2f\n", broj_racuna, ime, stanje );
/* procitaj broj racuna, ime i stanje iz fajla */
fscanf( prt_na_fajl, "%d%s%lf", &broj_racuna, ime, &stanje );
} /* kraj while */
break;
}/* kraj switch */

fseek(prt_na_fajl, 0, SEEK_SET); /* pozicioniraj se na pocetak fajla*/


/*potpuno je isto sto i rewind( ptr_na_fajl); */
printf( "\n? " );
scanf( "%d", &zahtev );

} /* kraj while(zahtev !=4 ) */

printf("Kraj rada\n");
fclose( prt_na_fajl ); /* fclose zatvara fajl */
} /* kraj else */

return 0; /* oznacava uspesan zavrsetak */


} /* kraj main */

5
4. Дефинишите 100 рачуна применом структуре. Елементи структуре трегба да буду: број рачуна, презиме
клијента, име клијента и стање на рачуну. Иницијализујте вредност сваке структуре на вредности 0 за
број рачуна, празан стринг за име и презиме и 0 за стање на рачуну. Упишите 100 оваквих структура у
фајл применом наредбе fwrite

/* Rad sa binarnim fajlovima */


#include <stdio.h>

/* Definicija strukture podaci_klijenta */


struct podaci_klijenta
{
int broj_racuna; /* broj_racuna klijenta */
char prezime[ 15 ]; /* prezime klijenta */
char ime[ 10 ]; /* ime klijenta */
double stanje; /* stanje na racunu */
}; /* kraj definicije strukture */

int main()
{
int i; /* brojac racuna od 1 do 100 */

/* kreiraj promen. novi_klijent tipa strukture podaci_klijenta i inicijalizuj */


struct podaci_klijenta novi_klijent = { 0, "", "", 0.0 };

FILE *ptr_fajl; /* fajl pointer */

/* fopen otvara fajl, izlaz iz programa ukoliko ne uspe */


if ( ( ptr_fajl = fopen( "kredit.dat", "wb" ) ) == NULL )
printf( "Fajl se ne moze otvoriti.\n" );
else
{
/* upisi 100 "praznih" zapisa (struktura) u fajl */
for ( i = 1; i <= 100; i++ )
fwrite( &novi_klijent, sizeof( struct podaci_klijenta ), 1, ptr_fajl );

fclose ( ptr_fajl ); /* fclose zatvara fajl */


} /* kraj else */

return 0; /* indicates successful termination */


} /* end main */

6
5. У бинарни фајл формиран у претходном примеру унесите потребне податке. Корисник треба да има
могућност да унесе број рачуна од 1 до 100 и да за тај рачун унесе податке (име презиме и стање).

/* Rad sa binarnim fajlovima */


#include <stdio.h>

/* Definicija strukture podaci_klijenta */


struct podaci_klijenta
{
int broj_racuna; /* broj_racuna klijenta */
char prezime[ 15 ]; /* prezime klijenta */
char ime[ 10 ]; /* ime klijenta */
double stanje; /* stanje na racunu */
}; /* kraj definicije strukture */

int main()
{
struct podaci_klijenta klijent = { 0, "", "", 0.0 };
FILE *ptr_fajl; /* fajl pointer */

/* fopen otvara fajl, izlaz iz programa ukoliko ne uspe */


if ( ( ptr_fajl = fopen( "kredit.dat", "rb+" ) ) == NULL )
printf( "Fajl se ne moze otvoriti.\n" );
else
{
/* traziti od korisnika da unese broj racuna */
printf("Unesite broj racuna (1-100):");
scanf("%d", &klijent.broj_racuna);
/* Korisnik treba da unese podatke za klijenta */
while(klijent.broj_racuna>0 && klijent.broj_racuna<101)
{
/* Unos prezimena, imena i stanja */
printf( "Unesite prezime, ime i stanje\n? " );
/* vrednosti */
fscanf( stdin, "%s%s%lf", &klijent.prezime, &klijent.ime, &klijent.stanje );

/* Pozicioniraj se na poziciju racuna (zadao je korisnik) */


fseek( ptr_fajl, ( klijent.broj_racuna - 1 ) *
sizeof( struct podaci_klijenta), SEEK_SET );

/* upisi unete vrednosti u fajl */


fwrite( &klijent, sizeof( struct podaci_klijenta), 1, ptr_fajl);

/* Omoguсi korisniku da unese podatke za druge racune */


printf( "Unesite broj racuna\n? " );
scanf( "%d", &klijent.broj_racuna );
} /* kraj while*/

fclose( ptr_fajl ); /* fclose zatvara fajl */


} /* kraj else */

return 0; /* oznacava uspesan zavrsetak */


} /* kraj main */

7
6. Написати програм који чита податке записане у облику рачуна (структура) у претхосном задатку.

/* Rad sa binarnim fajlovima */


#include <stdio.h>

/* Definicija strukture podaci_klijenta */


struct podaci_klijenta
{
int broj_racuna; /* broj_racuna klijenta */
char prezime[ 15 ]; /* prezime klijenta */
char ime[ 10 ]; /* ime klijenta */
double stanje; /* stanje na racunu */
}; /* kraj definicije strukture */

int main()
{
struct podaci_klijenta klijent = { 0, "", "", 0.0 };

FILE *ptr_fajl; /* fajl pointer */

/* fopen otvara fajl, izlaz iz programa ukoliko ne uspe */


if ( ( ptr_fajl = fopen( "kredit.dat", "rb" ) ) == NULL )
printf( "Fajl se ne moze otvoriti.\n" );
else
{
printf( "%-6s%-16s%-11s%10s\n", "Racun", "Prezime","Ime", "Stanje" );
/* Procitaj sve racune do kraja fajla */
while(!feof(ptr_fajl))
{
fread( &klijent, sizeof( struct podaci_klijenta ), 1, ptr_fajl );
/* prikazi podatke racuna */
if ( klijent.broj_racuna != 0 )
printf( "%-6d%-16s%-11s%10.2f\n",klijent.broj_racuna, klijent.prezime,
klijent.ime,klijent.stanje );
} /* kraj while */

fclose( ptr_fajl ); /* fclose zatvara fajl */


} /* kraj else */

return 0; /* oznacava uspesan zavrsetak */


} /* kraj main */

8
OSNOVE C JEZIKA

1./*Napisati program koji na ekranu ispisuje poruku Zdravo svete!*/

#include<stdio.h>
void main()
{
printf("Zdravo svete!\n");
}

Funkcija void main() je glavna funkcija i postoji samo jedna ova funkcija u C programu.
“()”označava da main nema argumenata. printf je funkcija za štampanje poruke “Zdravo svete!.
Karakter ‘\n’ predstavlja oznaku za novu liniju. Svaki iskaz se mora završiti karakterom ’;’, koji
ima ulogu terminatora iskaza. Karakteri ‘{‘ i ‘}’ objedinjuju više pojedinačnih iskaza u jednu
programsku celinu i oni su obavezni jer se tu izvršava neka obrada.
scanf je funkcija slična printf. Razlika je što se argumenti funkcije printf prenose sa
vrednošću, dok se kod scanf prenose svojom adresom, jer se učitana vrednost mora vratiti u
pozivajući program. To se postiže navođenjem karaktera ’&’ (operator adresiranja) ispred
argumenta u listi argumenata. Npr.

scanf(“%d”,&x); - %d - broj koji se unosi je celobrojni.


- %8.2f – ostavljanje mesta za zapis realnog broja

Escape karakteri Konverzioni karakteri funkcije printf


\b – povratnik \nnn – vrednost karaktera Konverz. kar. Konverzija izlaznog niza
\f – from feed \\ - obrnuta kosa crta c Karakter (char)
\n – nova linija \” – dvostuka navodnica d ceo broj (int)
\r – carriage return \’ – jednostruke navodnice f realan broj (float)
\t – horizontalni tab \ - nastavak linije s niz karaktera (string)
\v – vertikalni tab e realan br. u naučnoj notaciji
le double

1.2.2 Variables - Promenljive


Promenljiva je objekt jezika koji ima ime i kome se mogu dodeljivati različite vrednosti u toku
izvršavanja programa.

Imena promenljivih se grade od velikih i malih slova, cifara od 1 do 9 i karaktera (donja crta _ ).
Ime ne sme počinjati cifrom, niti sme sadržati rezervisane reči. Nedozvoljeni znaci su i
matematički operatori (+, -, *, /, %).

Variable names are case sensitive – imena promenljivih su osetljiva na mala i velika slova..

Ime promenljive (indentifikator):


skola
y
Ab63c
auto_skola

1
Osnovni tipovi podataka
Osnovni tipovi podataka su int, float, double i char.
Podaci tipa int su celobrojne vrednosti. Tu spadaju celobrojne konstante, promenljive,
izrazi i funkcije. Opseg celobrojnig vrednosti je različit i može se menjati primenom
kvalifikatora long, short i unsigned. Kvalifikator long povećava opseg vrednosti celobrojnih
promenljivih. Kvalifikator short ispred int smanjuje opseg celobrojnih promenljivih. Kvalifikator
unsigned ispred int deklariše promenljivu tako da može memorisati samo pozitivne vrednosti.
Promenlljive tipa float ili double memorišu vrednosti realnih brojeva, odnosno, vrednosti
sa decimalnim (pokretnim) zarezom. Promenljive daklarisane kao double mogu memorisati oko
dva puta više decimalnih cifara od promenljivih tipa float.
Promenljive i konstante tipa char memorišu karaktere. Konstante tipa char dobijaju se
stavljanjem karaktera između jednostrukih navodnica, npr. ‘A’, ‘1’, itd. ‘A’ treba razlikovati od
“A”, jer “A” predstavlja konstantni niz karaktera koji u C jeziku ima posebnu predstavu i
tretman.

Primeri:
int bob=32;
Creates variable "bob" and initializes it to the value 32. (Kreirana promenljivba "bob" i izvršena
inicijalizacija na 32.)
boolean yes=1;
Creates variable "yes" as type "char" and sets its value to 1.

Aritmetički izrazi i operatori

Aritmetički operatori C jezika su +, -, *, / i % koji odgovaraju matematičkim operacijama


sabiranja, oduzimanja, množenja, deljenja i deljenja po modulu, respektivno. Ovi operatori su
binarni, jer zahtevaju dva operanda, sa izuzetkom operatora -, koji može biti i unaran. Operator
deljenja po modulu (%) daje ostatak posle celobrojnog deljenja.

2
Tablica operatora.

Operator Namena Primer Rezultat


+ Sabiranje 5+6 11
- Oduzimanje 7 - 3 4
* Množenje 4*4 16
/ Deljenje 12 / 6 2
% Deljenje sa ostatkom 5%2 1
% operator se naziva još i modulus operator .

Aritmetički operatori jednako dobro rade sa negativnim brojevima kao i sa pozitivnim, sa


izuzetkom modulus operatora, rade sa celim brojevima jednako dobro kao i sa realnim.

Konstante (nepromenjive)

- Varijable su promenjive dok su konstante izrazi sa fiksnim, nepromenjivim vrednostima.


- Kostante su objekti koji dobijaju vrednost pre nego što počne izvršavanje programa i u toku
rada programa se ne mogu menjati.

Primer definisanja konstanti:


#define PI 3.141592 #define PI 3.141592 #define POREZ 20
#define POREZ 20 main(){
.....
Obim=2*r*PI;
...
}

#define IME “VLADE DIVAC”


#define BROJ 52
main()
{
printf(“Kosarkas %s ima br. Cip.%f”,IME, BROJ);
}

Odnosni operatori

Odnosni operatori se npr. koriste ako želite napraviti program koji će iz baze podataka odrediti
osobe sa više od 30 godina i slično.

Odnosni operatori: if ((a>b)&&(b>c)) || (b>d)

Operator Značenje Primer


&& logičko I (i>1)&&(j<6)
|| logičko ILI x=10||20;
! logička negacija if(!b) brojac=0;

3
Odnosne naredbe – naredbe uslova

Kao i aritmetički operatori, odnosni operatori su binarni tj. uspoređuju dva operanda. Naredba sa
dva operanda i odnosnim operatorom zove se odnosna naredba (eng. relational expression.)
Rezultat odnosne naredbe je Boolean vrednost odnosno istinu ili laž (true ili false). S ovom
tablicom možete videti kako to funkcioniše.

U ovoj tablici se koriste konkretne ( literal ) vrednosti koje ne mogu biti promenjene. 4 je
konkretna vrednost (konstanta), i ona se ne može menjati (moglo bi se menjati da se umesto
konstanta koriste promenljive).

Operator inkrementiranja i dekrementiranja

Operator inkrementiranja ++ i dekrementiranja -- su unarni operatori i javljaju se u


prefiksnom i postfiksnom obliku. Operator inkrementiranja ++ promenljivoj p dodaje vrednost 1,
dok operator dekrementiranja -- promeljivoj p oduzima vrednost 1, pa važi:

p++ je ekvivalentno p=p+1 p-- je ekvivalentno p=p-1 (postfiksni oblik)


++p je ekvivalentno p=p+1 --p je ekvivalentno p=p-1 (prefiksni oblik)

Ako se koristi oblik ++x to znači da se x prvo uvećava pa tek onda koristi u izrazu. Oblik x++
znači da se x prvo koristi u izrazu pa tek onda uvećava. Anaklogno važi za operaciju --.
x+=2 je x=x+2
x/2 je x=x/2
x*=2 je x=x*2
x%=2 je x=x%2

Rezervisane reči - Keywords

The following keywords are reserved and may not be used as an identifier for any other purpose.

auto double int long


break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while

4
Elementarne algoritamske strukture
Algoritamske strukture se dele u tri osnovne grupe:

 Linijska (sekvencija)
 Razgranata (selekcija)
 Ciklična (iteracija)

Linijska struktura:
Karakteristika linijske strukture je da se svi elementi izvršavaju samo jednom i koraci se odvijaju u nizu
jedan za drugim bez ponavljanja ili "skretanja".
Primjer u BASIC-u Primjer u C-u
INPUT a, b #include <stdio.h>
zbir = a + b
PRINT zbir void main () {
END int a, b, zbir;

printf("a,b? ");
scanf("%d%d", &a, &b);
zbir = a + b;
printf("a + b = %d\n", zbir);
}

Razgranata struktura:
Razgranata struktura će se pojaviti kod algoritma koji ima blok odlučivanja kao što su IF i CASE, pri čemu
se vrši testiranje određenog uslova a prema rezultatu (obično TRUE ili FALSE) algoritam se grana i
nastavlja tok jednom od grana- opcija. Primjer na slici je tipičan gdje se otklanja blokiranje programa
provjerom da li je djelilac jednak nuli. Ako je djelilac različit od nule, daće rezultat dijeljenja, u suprotnom
će dati samo poruku da dijeljenje nulom nema smisla i nastaviti dalje prema sledećoj proceduri ili kraju
programa.
Primjer u BASIC-u Primjer u C-u
INPUT a,b #include<stdio.h>
IF b <> 0 THEN
PRINT a/b void main () {
ELSE float a, b;
PRINT "Ne mogu
deliti nulom" scanf("%f%f", &a, &b);
END if (b == 0) {
printf("Ne mogu deliti
nulom\n");
} else {
printf("a : b = %f\n", a /
b);
}
}

Ciklična struktura
Ciklični algoritam će se pojaviti kada treba isti posao uraditi više puta. Postoji više varijanti ove srtukture,
a dve osnovne poele su:

5
 Broj iteracija (ponavljanja) je unapred poznat. Primer ove petlje je na slici i tu se obično koristi
petlja FOR.
 Iteracija se vrši dok se ne zadovolji određen uslov. Koriste se petlje tipa WHILE...DO.

Kod Iteracije sa proverom istinitosti uslova (da li je uslov zadovoljen) postoje varijante s proverom uslova
na ulazu u petlju, odnosno na kraju petlje. Razlika između ove dvije varijante je što kod provere istinitosti
uslova na kraju petlje program mora proći bar jednom kroz petlju.
Primjer u BASIC-u Primjer u C-u
zbir = 0 #include <stdio.h>
INPUT b
FOR a = 1 TO b void main() {
zbir = zbir + a int a, b, zbir = 0;
NEXT a
PRINT zbir scanf("%d", &b);
END for (a = 1; a <= b; a++) {
zbir += a;
}

printf("%d\n", zbir);
}

Primer algoritma kada nije poznat konačan broj iteracija sa provjerom na početku petlje

Primjer u BASIC-u Primjer u C-u


Kod provere istinitosti na ulazu u petlju zbir = 0 #include <stdio.h>
postoji mogućnost da se ne izvrši ni WHILE zbir < 200
jedno ponavljanje. Razlog je INPUT a void main() {
zbir = zbir + a int a, zbir = 0;
jednostavan, ako uslov nije ispunjen
WEND
odmah se "preskače" na sledeću liniju while (zbir < 200) {
izvan petlje. Za ovu vrstu petlje u većini PRINT zbir scanf("%d", &a);
programa se koristi ključna reč END zbir += a;
"WHILE" prilagođena sintaksi }
programskog jezika.
printf("%d\n", zbir);
}

Primer algoritma kada nije poznat konačan broj iteracija sa proverom na kraju petlje

Primjer u BASIC-u Primjer u C-u


Kod provere istinitosti na kraju petlje, zbir = 0 #include <stdio.h>
ne postoji mogućnost da se ne izvrši DO
ni jedno ponavljanje. Razlog je INPUT a void main() {
zbir = zbir + a int a, zbir = 0;
jednostavan, provera se vrši u
WHILE (zbir < 200)
posednjem redu bloka kôda, pe se PRINT zbir do {
mora proći barem jedanput kroz čitav END scanf("%d", &a);
blok. Za ovu vrstu petlje u većini zbir += a;
programa se koristi ključna reč } while (zbir < 200);
"DO..WHILE" prilagođena sintaksi
programskog jezika. printf("%d\n", zbir);
}

6
2. /*Primer za operatore inkrementiranja i dekrementiranja*/

#include<stdio.h>
void main()
{
int a=0,b=0,c=0;
printf("\na=%d b=%d c=%d\n",a,b,c);
a=++b + ++c;
printf("a=%d b=%d c=%d\n",a,b,c);
a=b++ + c++;
printf("\na=%d b=%d c=%d\n",a,b,c);
a=++b + c++;
printf("\na=%d b=%d c=%d\n",a,b,c);
a=++c + c;
printf("\na=%d b=%d c=%d\n",a,b,c);
}
3. /*Napisati program kojim se obračunavaju troškovi putovanja ako je udaljenost S
kilometara, potrošnja automobila na 100 km L litara, a cena litra goriva C dinara.*/

#include<stdio.h>
void main()
{
float s,l,c,t;
printf("Rastojanje u kilometrima\n");
scanf("%f",&s);
printf("Potrosnja u litrima na 100 km\n");
scanf("%f",&l);
printf("Cena goriva u dinarima\n");
scanf("%f",&c);
t=2*s/100*l*c;
printf("Troskovi putovanja su %0.2f dinara\n",t);
}
4./*Napisati program koji datom prirodnom četvorocifrenom broju:
a) izračunava proizvod cifara;
b) izračunava razliku sume krajnjih i srednjih cifara broja;
c) izračunava sumu kvadrata cifara;
d) određuje broj koji se dobija ispisom cifara u obrnutom porektu.*/
a)
#include<stdio.h>
void main()
{
int n,a,b,c,d,proizvod;
printf("Uneti cetvorocifren broj\n");
scanf("%d",&n);
a=n%10;
b=((n%100)/10);
c=((n/100)%10);
d=n/1000;
proizvod=a*b*c*d;
printf("Proizvod cifara broja %d je: %d\n",n,proizvod);
}

7
b)
#include<stdio.h>
void main()
{
int n,a,b,c,d,razlika;
printf("Uneti cetvorocifren broj\n");
scanf("%d",&n);
a=n%10;
b=((n%100)/10);
c=((n/100)%10);
d=n/1000;
razlika=(a+d)-(b+c);
printf("Razlika sume krajnjih i srednjih cifara broja %d je: %d\n",n,razlika);
}
c)
#include<stdio.h>
void main()
{
int n,a,b,c,d,suma;
printf("Uneti cetvorocifren broj\n");
scanf("%d",&n);
a=n%10;
b=((n%100)/10);
c=((n/100)%10);
d=n/1000;
suma=a*a+b*b+c*c+d*d;
printf("Suma kvadrata cifara broja %d je: %d\n",n,suma);
}
d)
#include<stdio.h>
void main()
{
int n,a,b,c,d,suma;
printf("Uneti cetvorocifren broj\n");
scanf("%d",&n);
a=n%10;
b=((n%100)/10);
c=((n/100)%10);
d=n/1000;
suma=1000*a+100*b+10*c+d;
printf("Broj %d u obrnutom redosledu je: %d\n",n,suma);
}
5./*Napisati program u kome se unose vrednost ASCII koda (npr. 66) i štampa znak tog
koda.*/

#include <stdio.h>
void main()
{
int ascii;
printf("Uneti ASCII ko nekog znaka: ");
scanf("%d", &ascii);
printf("%d je ASCII kod za %c.\n", ascii, ascii);
}

8
If iskaz

if je kontrolna struktura za ostvarivanje programskih granjanja. Prosta forma ovog iskaza je:

if (izraz)
iskaz;
sledeci_iskaz;

Međutim, ako postoji višestruko granjanje koristi se:

if(izraz1)
iskaz1;
else if(izraz2)
iskaz2;
.....
else
iskazn;

If statements
if ( statement is TRUE )
Execute this line of code

Else
if ( TRUE ) {
/* Execute these statements if TRUE */
}
else {
/* Execute these statements if FALSE */
}

*) Primer:

#include <stdio.h>

int main() /*Most important part of the program!*/


{
int age; /* Need a variable... */

printf( "Please enter your age" ); /* Asks for age */


scanf( "%d", &age ); /* The input is put in age */
if ( age < 100 ) { /*If the age is less than 100*/
printf ("You are pretty young!\n" ); /*Just to show you it works.*/
}
else if ( age == 100 ) { /*I use else just to show an example*/
printf( "You are old\n" );
}
else {
printf( "You are really old\n" ); /*Executed if no other statement is*/
}
return 0;
}

9
Osnovne bibliotečne funkcije <math.h>

sin(x) - sin(x)
cos(x) - cos(x)
tan(x) - tg(x)
exp(x) - ex
log(x) - log e (x), x>0
log10(x) - log 10 (x), x>0
pow(x,y) - x y
sqrt(x) - x , x>=0
fabs(x) - |x| apsolutna vrednost od x
ceil(x) – vrednost funkcije je najmanja celobrojna vrednost koja nije manja od x (zaokružuje naviše).
floor(x) - vrednost funkcije je najveća celobrojna vrednost koja nije veća od x (zaokružuje na najbliži
manji ceo broj).

Examples
Sample value Floor [ ] Ceiling [ ] Fractional part { }
−2.7 −3 −2 0.3
−2 −2 −2 0
12/5 = 2.4 2 3 2/5 = 0.4
2.7 2 3 0.7

6. /*Napisati program za izračunavanje apsolutne vrednosti celog broja*/

#include<stdio.h>
void main()
{
int broj,a_vred;
printf("Ukucajte ceo broj?");
scanf("%d",&broj);
a_vred=broj;
if(a_vred<0) a_vred=-a_vred;
printf("Apsolutna vrednost broja %d je %d\n", broj, a_vred);
}

7. /*Napisati program koji ispituje da li je karakter malo


ili veliko slovo, cifra ili specijalni karakter - if else iskaz*/

#include<stdio.h>
void main()
{
char c;
printf("Ukucajte karakter?");
scanf("%c",&c);
if(c>='a'&&c<='z')
printf("Karakter %c je malo slovo\n",c);

10
else if(c>='A'&&c<='Z')
printf("Karakter %c je veliko slovo\n",c);
else if(c>='0'&&c<='9')
printf("Karakter %c je cifra\n",c);
else
printf("Karakter %c je specijalni karakter\n",c);
}

8./*Izračunati površinu trougla zadatog stranicama x, y i z po formuli za površinu


p=sqrt(s*(s-x)*(s-y)*(s-z)), gde je s=(x+y+z)/2. */
#include<stdio.h>
#include<math.h>
void main()
{
double x,y,z,p,s;
printf("Unesite stranice\n");
scanf("%lf%lf%lf",&x,&y,&z);
if((x+y>z)&&(x+z>y)&&(y+z>x))
{
s=(x+y+z)/2;
p=sqrt(s*(s-x)*(s-y)*(s-z));
printf("Povrsina trougla je=%0.2f\n",p);
}
else printf("Ne moze se konstruisati trougao\n");
}

9. /*Napisati program koji za dati trocifreni prirodan broj n proverava da li je


Armstrongov. Broj je Armstrongov ako je jednak zbiru kubova svojih cifara.*/

#include<stdio.h>
void main()
{
int c1,c2,c3,n;
printf("Uneti trocifren broj\n");
scanf("%d",&n);
c1=n%10;
c2=n/10%10;
c3=n/100;
if(c1*c1*c1+c2*c2*c2+c3*c3*c3==n)
printf("Broj %d je Armstrongov\n",n);
else
printf("Broj %d nije Armstrongov\n",n);
}

10. /*Napisati program koji za dato x izračunava y po formuli.*/


 2 x,........  2  x  2
3x  1,........5  x  7
y
1 / x,........za..ostale...slucajeve

#include<stdio.h>
11
void main()
{
double x,y;
printf("Uneti vrednost za x\n");
scanf("%d",&x);
if (x<=-2)
y=1/x;
else
if (x<2)
y=2*x;
else
if (x<5)
y=1/x;
else
if (x<=7)
y=3*x-1;
else
y=1/x;
printf("y=%f ",y);

11. Napišite program koji učitava dva cela broja i, ako su oba parna ispisuje njihovu sumu;
inače treba ispisati proizvod.

#include <stdio.h>
main ( ) {
int prvibroj , drugibroj ;

printf("Unesite prvi broj:") ;


scanf("%d", &prvibroj ) ;
printf("Unesite drugi broj :" ) ;
scanf("%d" , &drugibroj ) ;

if ( ( prvibroj % 2 == 0) && ( drugibroj % 2 == 0 ) )


printf ("%d\n" , prvibroj + drugibroj ) ;
else
printf("%d\n" , prvibroj * drugibroj ) ;

return 0 ;
}

12. Napisati program koji broji razmake, tabulatore i nove redove.

#include <stdio.h>
main () {
int c,nb,nt,nl;

nb=0;
nt=0;
nl=0;
while ((c = getchar()) != EOF){
if(c ==' ')
12
++nb;
if (c =='\t')
++nt;
if (c =='\n')
++nl;
}
printf("%d%d%d\n" , nb, nt, nl ) ;
}

13. Napisati program koji za uneti prirodan broj n ispituje da li je deljiv sa 5 i štampa
odgovarajuće obaveštenje.

#include <stdio.h>
main ( ) {
int n;
printf("Unetite prirodan broj:");
scanf("%d",&n);
if (n%5==0){
printf("Broj je deljiv sa 5\n");
}
else{
printf("Broj nije deljiv sa 5\n");
}
return 0;
}

Operator višestrukog izbora SWITCH

Omogućava grananje u programu izborom jednog između više operatora


switch (izraz)
{
case konstanta1: operator1
......
break;
case konstanta2: operator2
.........
break;
.....
default : operatorn
break;
}

Naredba switch

- Izraz u naredbi switch mora imati celobrojnu vrednost (char, int).


- Nakon ključne reči case pojavljuju se celobrojne konstante ili konstantni izrazi.
- Na početku izvršavanja naredbe switch prvo se testira izraz. Ako je vrednost izraza jednaka
konstanta_i onda se izvršava naredba_i i sve naredbe koje dolaze nakon nje, sve do prve

13
break naredbe ili kraja switch naredbe. Nakon toga program se nastavlja prvom naredbom
iza switch naredbe.
- Ako izraz nije jednak ni jednoj konstanti, onda se izvršava naredba koja dolazi posle ključne
reči default (ako postoji) i sve naredbe iza nje, sve do kraja switch naredbe.
- Slučaj default ne mora biti nužno prisutan u switch naredbi. Ako nije, i ako nema
podudaranja vrednosti izraza i navedenih konstanti, program se nastavlja prvom naredbom
iza switch naredbe.

Primer:

switch(operator) {
case'z':
printf("%g\n",a+b);
break;
case'o':
printf("%g\n",a-b);
break;
case'm':
printf("%g\n",a*b);
break;
default:
printf("Nedopustena operacija!");
}

14./*Napisati program koji će zamentiti u unetom tekstu . sa ! i slovo a sa A.*/

#include <stdio.h>
void main()
{
char ch;
int ct1 = 0;
int ct2 = 0;
while ((ch = getchar()) != '#')
{
switch(ch)
{
case '.' : putchar('!'); ++ct1; break;
case 'a' : putchar('A'); ++ct2; break;
default : putchar(ch);
}
}
printf("\n");
printf("Zamenjeno je %d . sa !\n", ct1);
printf("Zamenjeno je %d slova a with A\n", ct2);
}

14
15./*Napisati program koji za uneti broj meseca (na primer, 1=Januar, 2=Februar, itd.)
ispisuje njegov broj dana. U slučaju unete vrednosti 2 pitati korisnika da li je godina
prestupna.*/
#include<stdio.h>
void main()
{
int mesec;
char ch;
printf("Uneti redni broj meseca\n");
scanf("%d",&mesec);
switch(mesec)
{
case 1:case 3:case 5:case 7:case 8:case 10: case 12: printf("31 dan\n"); break;
case 4: case 6: case 9: case 11: printf("30 dana\n"); break;
case 2: printf("Da li je godina prestupna (d/n)?\n"); scanf("%c%c",&ch,&ch);
if((ch=='d')||(ch=='D'))
printf("29 dana\n");
else
printf("28 dana\n");
break;
default: printf("Nekorektan broj meseca\n");
}
}

16. Napisati program koji na ulazu ima prirodan broj a i realan broj x. Program treba da
izračuna vrednost funkcije y i da je odštampa i to na sledeći način:
- ako je a = 1 tada je y = 3x-2
- ako je a = 2 tada je y = sin(2x)-3x+1
- ako je a = 3 tada je y = x 3 - x+1
- a ako je a bilo šta drugo onda je y = x.

#include <stdio.h>
#include <math.h>
main ( ) {
int a;
double x, y;

printf("Unetite ceo broj a i realan broj x:");


scanf("%d%lf",&a, &x);

switch (a){
case 1: y=3*x-2; break;
case 2: y=sin(2*x)-3*x+1; break;
case 3: y=pow(x,3)-x+1; break;
default: y=x; break;
}
printf("rezultujuca funkcija je:%.4lf\n", y);
}

15
- ako je a = 1 tada je y = |x| + |x-5|....................................................y = fabs(x)+fabs(x-5)
- ako je a = 2 tada je y najveći ceo broj koji nije veći od x..............y = floor(x)
- ako je a = 3 tada je y = sin(x+5)-e x ...............................................y = sin(x+5)+exp(x)
- ako je a = 4 tada je y najmanji ceo broj ne manji od x...................y = ceil(x)

While petlja

while(uslov_petlje)
while_iskaz;
sledeci_iskaz;

While iskaz se izvršava sve dok je uslov_petlje istinit (različit od nule), a kad je neistinit
onda se prelazi na sledeci_iskaz;. While_iskaz se izvršava jednom ili više puta, zavisno od
uslova_petlje.

17./*Program za izračunavanje sume prvih n=10 celih brojeva, pri čemu se koriste različite
petlje*/

#include <stdio.h>
void main()
{
int i,n=10,S=0;
i=1;
while (i <= n)
{
S+=i;
i++;
}
printf("\n Suma je %d\n", S);
}

i=1; i=1; for (i=1; i <= n; i++)


while (i <= n) do {
{ { S+=i;
S+=i; S+=i; }
i++; i++;
} } while (i <= n);

16
18./*Program za štampanje tabele koja pretvara Fahrenheitove stepene u Celzijuse. Za
Fahrenheitove stepene koristiti redom brojeve od 0, 20, ..., 300. celsius=5*(fahr-32)/9*/

#include <stdio.h> /* stampanje Fahrenheit-Celsius tabele za fahr = 0, 20, ..., 300 */


void main()
{
int fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
fahr = lower;
while (fahr <= upper)
{
celsius = 5 * (fahr-32) / 9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + step;
}
}

19. /*Program za određivanje srednje vrednosti n celih pozitivnih brojeva*/

#include<stdio.h>
void main()
{
int n, brojac=0;
float suma=0, x;
printf("Ukupno brojeva?\n");
scanf("%d",&n);
while(brojac<n)
{
printf("Ukucajte %d. broj?", brojac+1);
scanf("%f",&x);
suma+=x;
brojac+=1;
}
printf("Srednja vrednost ovih borjeva je %6.2f\n",suma/n);
}

17
Do-while petlja
do
do_iskaz;
while(uslov_petlje)
sledeci_iskaz;

U do-while iskazu prvo se izvršava do-iskaz. Zatim se izvršava uslov_petlje. Ako je


istinit, petlja se nastavlja, inače se petlja završava i kontrola prenosi na sledeci_iskaz. Do-while
iskaz se koristi za slučaj da je petlju neophodno izvršiti najmanje jedanput.

20. /*Program za permutovanje cifara celog broja*/

#include<stdio.h>
void main()
{
int broj;
printf("Ukucajte ceo broj?\n");
scanf("%d",&broj);
printf("Permutovan broj je\n");
do
{
printf("%d",broj%10);
broj/=10;
}
while(broj);
printf("\n");
}

For petlja

for(pocetni_izraz; uslov_petlje; izraz_petlje)


programski_iskaz;
sledeci_iskaz;

pocetni_izraz, postavlja početne parametre petlje (može ih biti više, pri čemu se
razdvajaju zarezom). uslov_petlje predstavlja uslov koji je potreban da bi se petlja nastavila, a
ako je uslov_petlje jednak 0 (neistinit) telo petlje se ne izvršava i kontrola se prenosti na
sledeci_iskaz.

- Beskonačna petlja koja ne radi ništa:


for(;;);

21. /*Program za izračunavanje faktorijela*/


#include<stdio.h>
void main()
{
int i,n;
long fak=1;
printf("Izracunavanje n!\nUkucajte broj (<33)?");
scanf("%d",&n);
for(i=1;i<=n;i++)
fak*=i;
printf("%d!=%ld\n",n,fak);
}
18
22. /*Program za odredjivanje srednje vrednosti n celih pozitivnih brojeva-for iskaz*/

#include<stdio.h>
void main()
{
int n, brojac=1;
float suma=0, x;
printf("Ukupno brojeva?\n");
scanf("%d",&n);
for(;brojac<=n;++brojac,suma+=x) /*for(;...) - brojac je na pocetku postavljen na 1*/
{
printf("Ukucajte %d. broj?", brojac);
scanf("%f",&x);
}
printf("Srednja vrednost ovih brojeva je %6.2f\n",suma/n);
}

FUNKCIJE
Funkcija je programska celina koja uzima neke ulazne podatke, izvršava određen niz naredbi i
vraća rezultat svog izvršavanja.

Definicija funkcije ima oblik:


tip_p ime_funkcije(tip_1 arg_1, ... ,tip_n arg_n)
{
telo funkcije
}

gde je tip_p tip podatka koji će funkcija vratiti kao rezultat svog izvršavanja. Unutar zagrada
nalazi se deklaracija formalnih argumenata funkcije. Prvi argument, arg_1, je promenljiva tipa
tip_1 itd. Deklaracije pojedinih argumenata međusobno se odvajaju zarezima. Unutar vitičastih
zagrada pojavljuje se telo funkcije koje se sastoji od deklaracija promenljivih i izvršnih naredbi.

poruka()
{ /*Zaglavlje funkcije*/
printf(“Zdravo!\n”); /*Telo funkcije su svi iskazi izmedju { i }*/
}

Primer :

#include <stdio.h>
Sledeća funkcija pretvara mala slova (engleske abecede) u velika.

char malo_u_veliko(char z) {
char c;
c= (z >= 'a' && z <= 'z') ? ('A' + z - 'a') : z;
return c;
}

19
Poziv funkcije:

int main(void) {
char malo, veliko;
printf("Unesite malo slovo: ");
scanf("%c", &malo);
veliko = malo_u_veliko(malo);
printf("\nUneseno slovo = %c\n",veliko);
return 0;
}

char malo_u_veliko(char z)
{
if(z >= 'a' && z <= 'z')
return('A' + z - 'a');
else
return z;
}

if naredba i uslovni operator

Sedeće dve naredbe su ekvivalentne:

1) max = a>b ? a : b

2) if(a>b) max=a;
else max=b;

Funkcija tipa void:


Kada funkcija ne vraća nikakvu vrednost onda se za tip vraćene vrednosti koristi ključna reč
void:

Primer:
#include <stdio.h>

void maximum(int x, int y)


{
int z;
z=(x>=y) ? x : y;
printf("\nMaksimalna vrednost =%d\n",z);
return;
}

int main(void)
{
int x,y;
printf("Unesite dva cela broja: ");
scanf("%d %d", &x,&y);
maximum(x,y);
return 0;
}

20
void maximum(int x, int y)
{
int z;
if(x>y) z=x;
else z=y;
printf("\nMaksimalna vrednost =%d\n",z);
return;
}

23. /*Napisati program za izračunavanje sume kvadrata celih brojeva od 1 do n*/

#include<stdio.h>
suma_kvadrata(int n)
{
int i;
long suma=0;
for(i=1; i<=n; suma+=(long)i*i,++i);
printf("Suma kvadrata od 1 do %d je %ld\n",n,suma);
}
main()
{
suma_kvadrata(10);
suma_kvadrata(15);
suma_kvadrata(20);
}

Funkcija suma_kvadrata(n) je deklaracija funkcije, koja definiše ime funkcije (identifikator


suma_kvadrata), broj argumenata funkcije i njihova imena, i predstavljaju formalne argumente.
Ovde je definisan samo jedan argument n koji predstavlja formalni argument jer se koristi samo
u definiciji funkcije. Na kraju funkcije se nalazi return promenljiva; gde se kao rezultat funkcije
vraća vrednost promenljive. Funkcija se poziva tako što se u glavnom programu napiše ime
funkcije sa odgovarajućim argumentima funkcije. Kada se pozove funkcije, u zagradi stoje
stvarni argumenti

24./*Napisati program u kome se definiše funkcija prost() koja ispituje da li je broj prost i
funkcija main() koja njenim korišćenjem štampa sve proste brojeve do datog prirodnog
broja n.*/
#include<stdio.h>
#include<math.h>
int prost(int n)
{
int i;
for (i=2;i<=sqrt(n);i=i+1)
if(n%i==0)
return 0;
return i;
}
void main()
{
int i,n;
printf("Uneti broj\n");
scanf("%d",&n);
printf("Prosti brojevi su\n");
for(i=2;i<=n;i=i+1)

21
if(prost(i)) printf("%d\n",i);
}

25./*Napisati program kojim se ispisuju parovi prijateljskih brojeva do n. Za dva broja


kažemo da su prijateljski, ako je jedan broj jednak sumi delioca drugog broja. U sumu
delioca ne ulazi sam taj broj. Sumu delioca računati korišćenjem funkcije Npr. prijateljski
brojevi su:
220=1+2+4+71+142
284=1+2+4+5+10+11+20+22+44+55+110*/

#include<stdio.h>
#include<math.h>
int sumadelioca(int n)
{
int s=1,i;
for (i=2;i<=sqrt(n);i++)
if(n%i==0) s+=i+(n/i)*(i!=n/i); //uslov (i!=n/i) izost. duplir. faktora npr. za 36
return s;
}
void main()
{
int s,i,n;
printf("Uneti broj n\n");
scanf("%d",&n);
printf("Trazeno svojstvo do %d imaju:\n",n);
for(i=2;i<=n;i=i+1)
{
s=sumadelioca(i);
if(s<=i&&sumadelioca(s)==i) printf("%5d%5d\n",i,s);
}
}

26./*Napisati program za izračunavanje faktorijela zadatog broja n korišćenjem funkcije


fakt().*/
#include<stdio.h>
int fakt(int n)
{
int p=1,i;
for(i=2;i<=n;i++)
p*=i;
return p;
}
void main()
{
int n;
long broj;
printf("Uneti broj ciji faktorijel trazimo\n");
scanf("%d",&n);
broj=fakt(n);
printf("Faktorijel broja %d je: %ld\n",n,broj);
}

22
21./*Napisati program kojim se štampaju svi trocifreni brojevi (ako ih ima) koji su jednaki
sumi faktorijela svojih cifara.*/
#include<stdio.h>
int fakt(int n)
{
int p=1,i;
for(i=2;i<=n;i++)
p*=i;
return p;
}
void main()
{
int n,a,b,c;
printf("Trocifreni brojevi jednaki sumi faktorijela svojih cifara su:\n");
for(n=100;n<1000;n++)
{
a=n%10;
b=n/10%10;
c=n/100;
if(n==fakt(a)+fakt(b)+fakt(c)) printf("%d\n",n);
}
}

Funkcije getchar i putchar: (<stdio.h>)

int getchar(void);
int putchar(int);

Funkcija getchar čita jedan znak sa standardnog ulaza (tastature). Funkcija nema argumenata pa je
sintaksa poziva:
c_var=getchar();
Funkcija putchar šalje jedan znak na standardni izlaz (ekran). Ona uzima jedan argument (znak koji
treba ispisati) i vraća celobrojnu vrednost. Najčešće poziv funkcije ima oblik
putchar(c_var);
pri čemu se vraćena vrednost ignoriše.

D O D A T A K

Naredba break

Naredba break služi za zaustavljanje petlje i izlazak iz switch naredbe. Može se koristiti sa for,
while i do-while petljom. Pri nailasku na naredbu break kontrola programa se prenosi na prvu
naredbu iza petlje ili switch naredbe unutar koje se break nalazi.

Primer:
int i;
while(1){
scanf("%d",&i);
if (i<0) break;
.........
}

23
while(1) je beskonačna petlja. Iz nje se izlazi ukoliko se učita negativan broj.

Naredba goto

goto naredba prekida sekvencijalno izvršavanje programa i nastavlja izvršavanje s naredbom


koja je označena labelom koja se pojavljuje u goto. Oblik joj je
goto labela;
gdje je label identifkator koji služi za označavanje naredbe kojom se nastavlja program. Sintaksa
je
labela: naredba;
Labela na koju se vrši skok mora biti unutar iste funkcije kao i goto naredba (pomoću goto se ne
može izaći iz funkcije).

Naredba continue

Naredba continue koristi se unutar for, while i do-while petlje. Nakon nailaska na continue
preostali deo tela petlje se preskače i program nastavlja sa sledećim prolazom kroz petlju.

int i;
while{1){
scanf("%d",&i);
if (i<0) continue;
.........
}
Sada nam u delu koda koji obrađuje pozitivne brojeve treba neki drugi način izlaza iz petlje.

Primer:

scanf("%d",&i);
while{i<=100){
.......
if (i<0) goto error;
.........
scanf("%d",&i);
}
.......
/* detekcija greske */
error: {
printf("Greska : negativna vrednost!\n");
exit(-1);
}

Naredbe break i continue mogu se izvesti pomoću goto naredbe. Na primer, kod

for(...) {
.......

24
if (...) continue;
........
}

je ekvivalentan s

for(...) {
.......
if (...) goto cont;
.......
cont: ;
}

Slično vredi i za continue unutar while i do-while petlje.

22./* Napisati program za rekurzivnu funkciju za izračunavanje n-tog stepena realnog


broja x0, ako je n ceo broj.*/
1, n0
 n 1
x  x  x , n  0
n

1 / x  n , n  0

može se izvršiti sledeća rekurzivna formula:
1, n0

stepen x, n   x  stepen x, n  1, n  0
1 / stepen x,n , n  0

na osnovu ovoga se formira sledeća rekurzivna funkcija:

#include<stdio.h>
double stepen(double x, int n)
{
if (n==0) return 1;
if(n>0) return x*stepen(x,n-1);
if(n<0) return 1/stepen(x,-n);
}
void main()
{
int n;
double x;
printf("Uneti vrednosti realnog broja\n");
scanf("%lf",&x);
printf("Uneti vrednosti stepena\n");
scanf("%d",&n);
printf("Vrednost %d stepena broja %lf je %lf\n",n,x,stepen(x,n));

JEDNODIMENZIONALNI I VIŠEDIMENZIONALNI NIZOVI


Nizovi predstavljaju skup homogenih podataka. Nizove treba razlikovati od struktura
koje predstavljaju skup heterogenih podataka. Elementi niza su istog tipa, dok su elementi
struktura različitih tipova. Niz se obeležava:

25
int a[20];
gde int deklariše tip svih elemenata niza, kojih ima 20 (broj između uglastih zagrada). Da bi se
dodelila početna vrednost elementima niza na ovaj način, mora se staviti ključna reč static pre
deklaracije. Npr.:
static int ocena[5]={6,7,8,9,10};
deklariše celobrojni niz čije su početne vrednosti 6, 7, 8, 9, 10. Ili slično imamo:
static char slova[5]={‘a’,’e’,’i’,’o’,’u’};

Primer: int broj[100];

Ovim se uvodi niz broj koji se sastoji iz 100 celobrojnih promenljivih sa imenima broj[0],
broj[2], broj[3],...., broj[99] . Prema tome indeksiranje elemenata niza je od 0, a ne od 1.

12 broj[0] (sadrži prvi broj, na primer 12)


4 broj[1] (sadrži prvi broj, na primer 4)
10 broj[2] (sadrži prvi broj, na primer 10)
....
....
7 broj[99] (sadrži prvi broj, na primer 7)

29. /*Napišite funkciju koja kao argumente uzima niz realnih brojeva i ceo broj n (koji
označava dužinu niza). Funkcija treba uzlazno da sortira niz. Napišite i kako se funkcija
poziva (pretpostavite da imate učitani niz sa n elemenata)*/

#include <stdio.h>

void sort(double x[] , int n) {


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

int main(void){
double a[50];int n;
...
sort(a, n);
}

int main(void){
double a[50];int n;
...
sort(a, n);
}

26
Česte greške:
sort(a[], n);
sort(a[n], n);
sort(a[0], n);

30. /*Napisati program za unos i stampanje 10 ocena ucenika*/


#include<stdio.h>
void main()
{
int i,ocena[10];
printf("Uneti ocene ucenika\n");
for(i=0;i<10;i++)
scanf("%d",&ocena[i]);
printf("Unete ocene ucenika su:\n");
for(i=0;i<10;++i)
printf("%c ocena[%2d]=%2d",(i%5==0)?'\n':' ',i,ocena[i]);
printf("\n");
}

31. /*Program za sortiranje jednodimenzionalnih nizova realnih brojeva od najmanjeg do


najveceg*/
#include<stdio.h>
void main()
{
int n,i,j;
float priv, x[100];
do
{
printf("Koliko brojeva za sortiranje?[<100]:");
scanf("%d",&n);
}
while(n>=100||n<=0);
printf("\n");
/*Ucitavanje n brojeva*/
for(i=0;i<n;++i)
{
printf("? x[%2d]=",i);
scanf("%f",&x[i]);
}
/*Sortiranje*/
for(j=0;j<n-1;++j)
for(i=j+1;i<n;++i)
if(x[i]<x[j])
{
priv=x[j];
x[j]=x[i];
x[i]=priv;
}
/*Stampanje sortiranih brojeva*/
printf("\nSortiranji brojevi:\n");
for(i=0;i<n;++i)
printf("x[%2d]=%15.6e\n",i,x[i]);
}

32./*Napisati program za određivanje broja maksimalnih elemenata niza. U rešavanju koristiti funkciju za
unos članova niza.*/

27
#include <stdio.h>
void citaj(float a[],int n)
{
int i;
printf("Uneti niz \n");
for(i=0;i<n;i++)
{
printf("a[%d]=",i);
scanf("%f",&a[i]);
}
}

int BrojMax(float a[],int n)


{
float max;
int i,k;
max=a[0]; k=1;
for(i=1;i<n;i++)
if(a[i]>max)
{
max=a[i];
k=1;
}
else if(a[i]==max)
k++;
return k;
}
void main()
{
float a[100];
int n;
printf("Uneti broj elemenata niza\n");
scanf("%d",&n);
citaj(a,n);
printf("U nizu ima %d maksimalnih clanova\n", BrojMax(a,n));
}

33. /*Dat je niz realnih brojeva. Napisati funkciju koja:


a) izračunava sumu elemenata niza koji prethode prvoj nuli u nizu;
b) određuje broj elemenata koji prethode prvom negativnom elementu u nizu;
c) izračunava proizvod elemenata između prve i druge nule u nizu (niz ima bar dve nule);*/
#include <stdio.h>
void citaj(float a[],int n)
{
int i;
printf("Uneti niz \n");
for(i=0;i<n;i++)
scanf("%f",&a[i]);
}
float suma(float a[],int n)
{
int i=0;
float s=0;
while(i<n&&a[i])
s+=a[i++];
return s;
}

28
int BrojPoz(float a[],int n)
{
int k=0,i;
for(i=0;i<n&&a[i]>=0;i++)
k++;
return k;
}
proizvod(float a[],int n)
{
int i,k=0;
float p=1;
for(i=0;i<n&&k<2;i++)
{
if(a[i]==0)k++;
if(k==1&&a[i]!=0)
p*=a[i];
}
return p;
}
void main()
{
float a[100];
int n;
printf("Uneti broj elemenata niza\n");
scanf("%d",&n);
citaj(a,n);
printf("Suma elemenata niza koji prethode prvoj nuli u nizu je %f\n", suma(a,n));
printf("Broj elemenata koji prethode prvom negativnom elementu je %d\n",BrojPoz(a,n));
printf("Proizvod elemenata niza izmedju prve i druge nule je %f\n",proizvod(a,n));

}
34./*Dat je niz realnih brojeva. Napisati program koji sažima niz uklanjanjem elemenata čija je
vrednost jednaka zadatom broju X.*/
#include <stdio.h>
void citaj(float a[],int n)
{
int i;
printf("Uneti niz \n");
for(i=0;i<n;i++)
scanf("%f",&a[i]);
}
void pisi(float a[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%f\t",a[i]);
}

void main()
{
float a[100],x;
int k=-1,i,n;
printf("Uneti broj elemenata niza\n");
scanf("%d",&n);
printf("Uneti x\n");
scanf("%f",&x);
citaj(a,n);

29
for(i=0;i<n;i++)
if(a[i]!=x)
a[++k]=a[i];
n=k+1;
printf("Novi niz je\n");
pisi(a,n);
prinf("\n");
}
35. /*Dat je niz realnih brojeva. Napisati funkciju koja:
d) ispisuje sve elemente niza koji se u nizu pojavljuju tačno jedanput;
e) proverava da li u nizu postoji par jednakih elemenata;
#include <stdio.h>
void citaj(float a[],int n)
{
int i;
printf("Uneti niz \n");
for(i=0;i<n;i++)
scanf("%f",&a[i]);
}
void tacnojednom(float a[],int n)
{
int k,i,j;
for(i=0;i<n;i++)
{
k=0;
for(j=0;j<n;j++)
if(a[i]==a[j])
k++;
if(k==1)
printf("%f\n",a[i]);
}
}
void parjednakih(float a[],int n)
{
int k,i,j;
for(i=0;i<n-1;i++)
{
k=0;
for(j=i+1;j<n;j++)
if(a[i]==a[j])
k++;
if(k==1)printf("%f\n",a[i]);
}

}
void main()
{
float a[100];
int n;
printf("Uneti broj elemenata niza\n");
scanf("%d",&n);
citaj(a,n);
printf("Elementi koji se pojavljuju tacno jedanput su:\n");
tacnojednom(a,n);
printf("Par jednakih je \n");
parjednakih(a,n);
}

30
36./*Napisati program koji za uneti niz a od n elemenata, prebacuje negativne elemente na kraj niza bez
obzira na njihov poredak*/
#include <stdio.h>
void citaj(float a[],int n)
{
int i;
printf("Uneti niz \n");
for(i=0;i<n;i++)
{
printf("a[%d]=",i);
scanf("%f",&a[i]);
}
}
void uredi(float a[],int n)
{
float pom;
int i,j;
i=0; j=n-1;
while(i<j)
if(a[i]>0) i++;
else
{
if(a[j]>0)
{
pom=a[i];
a[i]=a[j];
a[j]=pom;
j--;
}
}
}
void pisi(float a[],int n)
{
int i;
printf("Formirani niz\n");
for(i=0;i<n;i++)
printf("a[%d]=%5.2f\n",i,a[i]);
}
void main()
{
float a[100];
int n;
printf("Uneti broj elemenata niza\n");
scanf("%d",&n);
citaj(a,n);
uredi(a,n);
pisi(a,n);
}

37. /*Dat je niz celih brojeva A dimenzija n. Napisati funkciju na programskom jeziku C koja
vraca zbir poslednjih 8 clanova niza A.*/

Uradjen ceo program.

31
#include<stdio.h>

#define DIM 100

void main(){
int A[DIM];
int i, n;
int zbir=0;

printf("Unesite broj elemenata niza:\n");


scanf("%d", &n);

printf("Unesite elemenateniza:\n");
for(i=0; i<n; i++)
scanf("%d", &A[i]);

for(i=n-1; i>n-9; i--)


zbir+=A[i];

printf("Zbir zadnjih osam elemenata niza je: %d\n", zbir);


}

ili kao funkcija:

int zbirZadnjihOsam(int niz[], int n)


{
int i;
int zbir=0;
for(i=n-1; i>n-9; i--)
zbir+=niz[i];

return zbir;
}

VIŠEDIMENZIONALNI NIZOVI

Označavanje matrice M od i vrste i j kolona M[i][j], ili višedimenzionalnog vektora Z[i][j][k] itd.
Dvodimenzionalni vektori se inicijalizuju na sličan način kao jednodimenzionalni. Inicijalizacioni
elementi se navode po vrstama. Vitičaste zagrade se mogu koristi za izdvajanje inicijalizacionih
elemenata jedne vrste od druge. Inicijalizacija matrice M je:

static int M[4][3]={


{13,-18,21},
{36,101,0},
{-5,0,-9},
{3,1,9}
};

Npr:
int x[10];
int y[10][20];
int z[15][25][35];
...

32
printf("%d", y[7][13]);
scanf("%d", &y[2][0]);
scanf("%d", &z[6][24][10]);

Kod prosleđivanja višedimenzionalnih polja u funkciju, u zaglavlju funkcije se moraju navesti dimenzije
polja osim prvog.

void funkcija(int z[][25][35]);

38. /*Program za skalarno množenje matrica*/

#include<stdio.h>
void main()
{
int vrsta,kol;
float scalar;
static float matrica[3][5]={
{7.0,16.83,55.131,13.1,12.91},
{15.0,10.9,42.99,0.0,7.7},
{-2.2,1.1,2.2,4.4,9.9}
};
printf("Originalna matrica:\n");
for(vrsta=0;vrsta<3;++vrsta)
{
for(kol=0;kol<5;++kol)
printf("%10f",matrica[vrsta][kol]);
printf("\n");
}
printf("\n Scalar?\n");
scanf("%f",&scalar);
for(vrsta=0;vrsta<3;++vrsta)
for(kol=0;kol<5;++kol)
matrica[vrsta][kol]*=scalar;
printf("\n Matrica posle skalarnog mnozenja:\n");
for(vrsta=0;vrsta<3;++vrsta)
{
for(kol=0;kol<5;++kol)
printf("%10f\t", matrica[vrsta][kol]);
printf("\n");
}
}

39. /*Napisati program za sabiranje matrica a i b dimenzije n i štampanje rezultujuće matrice c*/

#include <stdio.h>
void citaj(int a[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
}
void zbir(int a[][10],int b[][10],int c[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
{

33
for(j=0;j<n;j++)
{
c[i][j]=a[i][j]+b[i][j];
printf("%d\t",c[i][j]);
}
printf("\n");
}
}
void main()
{
int a[10][10],b[10][10],c[10][10];
int n;
printf("Uneti broj vrsta i kolona matrice a i b\n");
scanf("%d",&n);
printf("Uneti elemente matrice a\n");
citaj(a,n);
printf("Uneti elemente matrice b\n");
citaj(b,n);
printf("Zbir matrica a i b je:\n");
zbir(a,b,c,n);
}

40./*Program za množenje dve zadate matrice*/

#include<stdio.h>
void citaj(float m[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%f",&m[i][j]);
}
void mnozenje(float m1[][10], float m2[][10],float m3[][10],int n)
{
int i,j,k;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
for(m3[i][j]=0,k=0;k<n;++k)
m3[i][j]+=m1[i][k]*m2[k][j];
}
void pisi(float m[][10],int n)
{
int i,j;
for(i=0;i<n;++i)
{
for(j=0;j<n;++j)
printf("%5.2f\t",m[i][j]);
printf("\n");
}
}
void main()
{
float m1[10][10],m2[10][10],m3[10][10];
int n;
printf("Uneti dimenziju matrica \n");
scanf("%d",&n);
printf("Uneti elemente matrice m1\n");

34
citaj(m1,n);
printf("Uneti elemente matrice m2\n");
citaj(m2,n);
printf("\n\nProizvod matrica m1*m2\n");
printf("...................................\n");
mnozenje(m1,m2,m3,n);
pisi(m3,n);
}

41./*Program za transponovanje matrice a dimenzije n*/

#include <stdio.h>
void citaj(int a[][10],int n)
{
int i,j;
printf("Uneti elemente matrice \n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
}
void transponovana(int a[][100],int n)
{
int i,j,p;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
p=a[i][j];
a[i][j]=a[j][i];
a[j][i]=p;
}
}
void pisi(int a[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%\t",a[i][j]);
printf("\n");
}
}
void main()
{
int a[100][100];
int n;
printf("Uneti broj vrsta i kolona matrice\n");
scanf("%d",&n);
citaj(a,n);
transponovana(a,n);
pisi(a,n);
}

42./*Napisati program koji u matrici realnih brojeva a određuje:


a) maksimalni element;
b) sumu elemenata ispod glavne dijagonale;
c) sumu elemenata iznad sporedne dijagonale.*/

35
#include <stdio.h>
void citaj(float a[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf(”%f”,&a[i][j]);
}
float maksimalni(float a[][10],int n)
{
int i,j;
float max=a[0][0];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(max<a[i][j]) max=a[i][j];
return max;
}
float sumaispodgd(float a[][10],int n)
{
float s=0;
int i,j;
for(i=1;i<n;i++)
for(j=0;j<i;j++)
s+=a[i][j];
return s;
}
float sumaiznadsd(float a[][10],int n)
{
float s=0;
int i,j;
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++)
s+=a[i][j];
return s;
}
void main()
{
float a[10][10];
int n;
printf(“Uneti broj vrsta i kolona matrice a \n”);
scanf(“%d”,&n);
printf(“Uneti elemente matrice a\n”);
citaj(a,n);
printf(“Maksimalni element matrice a je: %f\n\n”,maksimalni(a,n));
printf(“Suma elemenata ispod glavne dijagonale je: %f\n\n”,sumaispodgd(a,n));
printf(“Suma elemenata iznad sporedne dijagonale je: %f\n\n”,sumaiznadsd(a,n));
}

II način

#include <stdio.h>
void citaj(float a[][10],int n)
{
int i,j;
for(i=0;i<n;i++)

36
for(j=0;j<n;j++)
scanf("%f",&a[i][j]);
}
float maksimalni(float a[][10],int n)
{
int i,j;
float max=a[0][0];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(max<a[i][j]) max=a[i][j];
return max;
}
float sumaispodgd(float a[][10],int n)
{
float s=0;
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i>j)
s+=a[i][j];
return s;
}
float sumaiznadsd(float a[][10],int n)
{
float s=0;
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i+j<n-1)
s+=a[i][j];
return s;
}
void main()
{
float a[10][10];
int n;
printf("Uneti broj vrsta i kolona matrice a \n");
scanf("%d",&n);
printf("Uneti elemente matrice a\n");
citaj(a,n);
printf("Maksimalni element matrice a je: %f\n\n",maksimalni(a,n));
printf("Suma elemenata ispod glavne dijagonale je: %f\n\n",sumaispodgd(a,n));
printf("Suma elemenata iznad sporedne dijagonale je: %f\n\n",sumaiznadsd(a,n));
}

43. Data je matrica celih brojeva x dimenzije nxn. Napisati program za sortiranje matrice po
vrstama u rastućem poretku.

#include<stdio.h>
void citaj(int x[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf("x[%d,%d]=",i,j);
scanf("%d",&x[i][j]);

37
}
}
void pisi(int x[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%3d",x[i][j]);
printf("\n");
}
}
void razmeni(int*a,int*b)
{
int pom;
pom=*a;*a=*b;*b=pom;
}
void sort(int a[][10],int n)
{
int i,j,k;
for(i=0;i<n;i++)
for(j=0;j<n-1;j++)
for(k=j+1;k<n;k++)
if(a[i][j]>a[i][k])
razmeni(&a[i][j],&a[i][k]);
}

main()
{
int n;
int x[10][10];
printf("\nUneti broj vrsta matrice:");
scanf("%d",&n);
printf("\nUnesi elemente matrice po vrstama :\n");
citaj(x,n);
sort(x,n);
printf("matrica posle sortiranja je:\n");
pisi(x,n);
}

44. Napisati funkciju za soritranje matrice a dimenzije nxn po kolonama u rastućem redosledu.
void sort(int a[][10],int n)
{
int i,j,k;
for(j=0;j<n;j++)
for(i=0;i<n-1;i++)
for(k=i+1;k<n;k++)
if(a[i][j]>a[k][j])
razmeni(&a[i][j],&a[k][j]);
}

45. Napisati funkciju za soritranje elemenata na glavnoj dijagonali matrice a dimenzije nxn u
rastućem redosledu.
void sort(int a[][10],int n)
{
int i,j;
for(i=0;i<n-1;i++)

38
for(j=i+1;j<n;j++)
if(a[i][i]>a[j][j])
razmeni(&a[i][i],&a[j][j]);
}

46. Napisati funkciju za soritranje elemenata spredne dijagonale matrice a dimenzije nxn u
rastućem redosledu.
void sort(int a[][10],int n)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(a[i][n-i-1]>a[j][n-j-1])
razmeni(&a[i][n-i-1],&a[j][n-j-1]);
}

47. Data je matrica M dimenzije nxn. Formirati niza A dimenzije n od maksimalnih elemenata
matrice po vrstama.
#include<stdio.h>
void citaj(int x[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf("x[%d,%d]=",i,j);
scanf("%d",&x[i][j]);
}
}
void pisi(int x[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d\n",x[i]);
}
void niza(int n, int M[][10], int A[])
{
int i, j;
for(i=0; i<n; i++)
{
A[i]=M[i][0];
for(j=1; j<n; j++)
if(A[i]<M[i][j])
A[i]=M[i][j];
}
}

main()
{
int n, j, i;
int M[10][10], A[10];
printf("\nUneti broj vrsta matrice:");
scanf("%d",&n);
printf("\nUnesi elemente matrice po vrstama :\n");
citaj(M,n);
niza(n,M,A);
printf("Dobijeni niz je:\n");

39
pisi(A,n);
}

48. Data je matrica x dimenzije nxn. Napisati program koji koristi funkciju za sortiranje v vrste
matrice x.
#include<stdio.h>
void citaj(int x[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf("x[%d,%d]=",i,j);
scanf("%d",&x[i][j]);
}
}
void pisi(int x[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%3d",x[i][j]);
printf("\n");
}
}

void razmeni(int*a,int*b)
{
int pom;
pom=*a;*a=*b;*b=pom;
}
void sort(int a[][10],int n, int v)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(a[v][i]>a[v][j])
razmeni(&a[v][i],&a[v][j]);
}

main()
{
int n, v;
int x[10][10];
printf("\nUneti broj vrsta matrice:");
scanf("%d",&n);
printf("\nUnesi elemente matrice po vrstama :\n");
citaj(x,n);
printf("\nUneti indeks vrste koja se sortira:");
scanf("%d",&v);
sort(x, n, v);
printf("Matrica posle sortiranja je:\n");
pisi(x,n);
}

40
49. Učitati kvadratnu matricu M sa tastature i formirati matricu realnih brojeva C na čijoj glavnoj
dijagonali se dobijaju prosečne vrednosti pojedinih vrsta matrice M, a svi ostali elementi su
jedinice.

#include<stdio.h>
#define DIM 100

void main(){
int M[DIM][DIM];
float C[DIM][DIM];
static float sumaRedova[DIM];//Početne vrednosti su nule
int i, j, n;

printf("Uneti dimenzije matrice: ");


scanf("%d", &n);

printf("Uneti elemente matrice:\n");


for(i=0; i<n; i++)
for(j=0; j<n; j++)
scanf("%d", &M[i][j]);
/*Sumiranje elemenata matrice M po redovima i smestanje vrednosti u niz sumaRedova*/
for(i=0; i<n; i++)
for(j=0; j<n; j++)
sumaRedova[i]+=M[i][j];

/*Formiranje matrice C od prosecnih vrednosti vrsta matrice na glavnoj dijagonali, a ostali


elementi su jedinice (van glavne dijagonale)*/
for(i=0; i<n; i++)
for(j=0; j<n; j++)
if(i==j)
C[i][j]=sumaRedova[i]/n;
else
C[i][j]=1.;

/*Stampanje matrice C na standardnom izlazu*/


printf("\n\nNovodobijena matrica C je:\n\n");

for(i=0; i<n; i++){


printf("\n");
for(j=0; j<n; j++){
printf(" %4.2f ", C[i][j]);
}
}

printf("\n\n");
}

POKAZIVAČI (POINTERI)

Pokazivačka promenljiva je promenljiva koja “pokazuje “ na drugu promenljivu, odnosno sadrži


adresu memorijske lokacije u kojoj se čuva ta promenljiva.
Deklariše se tako što se u specifikaciji zada tip promenljive na koju ukazuje pokazivačka promenljiva.

Ispred imena promenljive piše se *

int *pi /*pokazivač na celobrojnu promenljivu */


41
char *pc /*pokazivač na znakovnu promenljivu */
float *a, *b /*pokazivač na float promenljive */
x = *pi dodeljuje promenljivoj x celobrojnu vrednost koja se nalazi na adresi sadržanoj u promenljivoj
pi.

Primer (pokazivači) :

#include<stdio.h>
void kvadrat(int*x,int*y)
{
*y=*x**x;
printf("Unutar funkcije: x=%d, y=%d.\n",*x,*y);
}

main()
{
int x=3,y=5;
printf("Prije poziva: x=%d, y=%d.\n",x,y);
kvadrat(&x,&y);
printf("Nakon poziva: x=%d, y=%d.\n",x,y);
return 0;
}

Prenos adrese argumenata

int a; /* promenljiva tipa int */


int *pok; /* pokazivač na int tip */
a = 10; /* inicijalizacija promenljive a na 10 */
pok = &a; /* inicijalizacija pokazivač tako da pokazuje na promenljivu a */
*pok = 100; /* promena sadržaja promenljive a na 100 preko pokazivača */
a = 100;

Pokazivači omogućavaju formiranje složenih dinamičkih struktura podataka (liste, magacini,


stabla, redovi i dr.) i s tim u vezi dinamičko dodeljivanje memorije, prenos argumenata funkcije
referisanjem, efikasniji rad sa vektorima i prenos funkcija kao argumenata u druge funkcije. Proizvoljna
programska promenljiva memorisana je u određenom memorijskom bloku, na određenoj programskoj
lokaciji ili adresi. Pokazivači omogućavaju indirektni način za pristupanje programskim promenljivim,
korišćenjem i manipulacijom adresama promenljivih. U C jeziku možemo deklarisati promenljivu, prom:
int *prom;
koja omogućava da se indirektno pristupi vrednosti promenljive prom. Karakter zvezdica ‘*’ deklariše
promenljivu kao pokazivač, a tip int da je promenljiiva prom pokazivač na celobrojnu promenljivu, što

42
znači, ovo predstavlja indirektan pristup celobrojnim promenljivim. Adresni operator & se koristi u
funkciji scanf za prenos učitane vrednosti u pozivajuću funkciju main().
Operator indirekcije * omogućava indirektno pristupanje promenljivoj koristeći pokazivač na tu
promenljivu. Ako je x deklarisana kao int, tada se iskazom
x=*prom;
promenljivoj x dodeljuje vrednost promenljive na koju pokazivačj prom ukazuje. Operatori * i & su
inverzni.
U C jeziku postoji specijalni operator za indirektnu selekciju članova strukture. To je operator ->.
Operator -> je operator selekcije članova strukture sa pokazivačem na strukturu.

Dinamičke strukture podataka

Dinamičke strukture zahtevaju eksplicitno rezervisanje i oslobađanje memorije. U sistemskoj biblioteci


svakog C prevodioca postoje funkcije malloc, calloc, realloc i free, kojima se rezerviše i oslobađa
mimorijski blok. Za kreiranje dinamičkih objekata koriste se funkcije malloc() i calloc(), a za njihovo
uništavanje funkcija free(). Pri korišćenju ovih funkcija treba priključiti zaglavlje <alloc.h>.Definicija
ovih funkcija je sledeća:
1. char *malloc(size). Rezerviše memorijski blok veličine size bajtova, koji se inicijalizuje na 0.
Argument size je unsigned. U slučaju uspešne rezervacije malloc vraća pokazivač na rezervisani
memorijski blok. U protivnom, vraća 0.

char *malloc(unsigned n)
int *pint;
pint=(int*)malloc(200); /* izdvaja 200 bajtova. Vrednost f-je je pokazivač na char
koji se kast operatorom konvertuje u pokazivač na int tip.*/

2. char *calloc(n, size). Rezerviše memorijski blok dovoljan za memorisanje n elemenata svaki
veličine size bajtova, znači n*size. Rezervisan memorijski blok je inicijalizovan na 0. U slučaju
uspešne rezervacije calloc vraća pokazivač na char, koji pokazuje na rezervisan memorijski blok.
U protivnom, vraća 0.

char *calloc(unsigned n, unsigned vel) /*n je br. elemenata za koje treba izdvojiti memoriju,
a vel memorijski prostor koji zauzima svaki
element.*/

3. void free(pokaz). Oslobađa memorijski blok, koji je rezervisan funkcijama calloc i malloc.
Argument pokaz je pokazivač na char, koji pokazuje na memorijski blok za oslobađanje. Funkcija
free ne vraća nikakvu vrednost.
4. char *realloc(pokaz, size). Oslobađa rezervisani memorijski blok i rezerviše novi veličine size
bajtova. Argument pokaz je pokazatelj na char i defimniše memorijski blok, koji se realocira.
Argument size je unsigned i određuje veličinu realociranog memorijskog bloka. Ako je
realociranje uspoešno realloc vraća pokazivač na char, koji pokazuje na memorijski blok. U
protivnom, realloc vraća 0.

50./*Izračunati zbir i razliku dva broja koristeći pokazivače na funkciju*/


#include<stdio.h>
int zbir(int *a,int *b)
{
return *a+*b;
}
int razlika(int *a,int *b)
{
return *a-*b;
}

43
void main(void)
{
int a=10, b=5, r_zbir, r_razlika;
int (*pointer[2])(int *,int *);
pointer[0]=zbir;
pointer[1]=razlika;
r_zbir=(*pointer[0])(&a,&b);
r_razlika=(*pointer[1])(&a,&b);
printf("zbir =%d razlika=%d\n",r_zbir,r_razlika);
}

51./*Stranice a i b pravougaonika su prirodni brojevi. Odrediti, na koliko se kvadrata maksimalne


površine može iseći dati pravougaonik. Ispisati dimenzije kvadrata. Na primer za a=12 i b=7 se
ispisuje:
1 kvadrata stranice: 7
1 kvadrata stranice: 5
2 kvadrata stranice: 2
2 kvadrata stranice: 1
#include<stdio.h>
void razmeni(int *a, int *b)
{
int t;
t=*a;
*a=*b;
*b=t;
}
void main()
{
int a,b;
printf("Uneti stranice pravougaonika\n");
scanf("%d%d",&a,&b);
if(a==b)
printf("Jedan kvadrat stranice %d\n",a);
else
while(a)
{
if(a<b) razmeni(&a,&b);
printf("%d kvadrata stranice: %d\n",a/b,b);
a=a%b;
}
}
52. /*Nizovi i pokazivaci*/
#include<stdio.h>
void main()
{
float a,b,c,fniz[5]={0.01,0.1,0.5,1.0,10.0};
float *p_fniz;
char tekst[]={"Ovo je znakovni niz\n"};
char *p_tekst;
int i;
p_fniz=fniz;
a=*p_fniz;
b=*(p_fniz+2);
p_fniz=&fniz[2];
c=*(p_fniz+2);
printf("a=%f b=%f c=%f\n",a,b,c);
for(i=0;tekst[i]!='\0';++i)putchar(tekst[i]);

44
for(p_tekst=tekst;*p_tekst!='\0';++p_tekst)putchar(*p_tekst);
}

53. /*Program za odredjivanje duzine stringa*/


#include<stdio.h>
int duzina(char *p_string);
void main(int argc,char *argv[])
{
char *p_text={"ovo je znakovni niz\n"};
int i;
for(i=1;i<argc;i++)
printf("argument%d%s\n",i,argv[i]);
i=duzina(p_text);
printf("duzina stringa je %d\n",i);
}
int duzina(char *p_string)
{
int l=0;
char*p;
p=p_string;
while(*p!='\0')
{
++l;
++p;
}
return l;
}

54./*Data je kvadratna matrica celih brojeva a dimenzije n i prirodan broj k<n. Napisati program
koristeći funkciju koja realizje simetrično preslikavanje u odnosu na sporednu dijagonalu, trougla
određenog pozicijama (0,0), (0,k-1) i (k-1,0) u odgovarajući trougao i obrnuto.*/
#include <stdio.h>
void citaj(int a[][10],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
}

void razmeni (int *x,int *y)


{
int p;
p=*x; *x=*y; *y=p;
}

void f(int a[][10],int n, int k)


{
int i,j;
for(i=0;i<k;i++)
for(j=0;j<k-i;j++)
razmeni(&a[i][j],&a[n-1-j][n-1-i]);
}
void pisi(int a[][10],int n)
{
int i,j;
for(i=0;i<n;i++)

45
{
for(j=0;j<n;j++)
printf("%d\t",a[i][j]);
printf("\n");
}
}
void main()
{
int a[10][10];
int n,k;
printf("Uneti broj vrsta i kolona matrice a \n");
scanf("%d",&n);
printf("Uneti elemente matrice a\n");
citaj(a,n);
printf("Uneti k \n");
scanf("%d",&k);
printf("Dobijena matrica je:\n");
f(a,n,k);
pisi(a,n);
}

55./*Program za izračunavanje zbira kubova i kvadrata.*/

#include <stdio.h>
main()
{
int m,n,k,l,p,q,r;
void kavdrat_kub(); /*deklaracija f-je*/
kavdrat_kub(2,4,&p,&q); /*poziv f-je*/
printf("p=%d q=%d\n",p,q);
scanf("%d%d%d%d",&m,&n,&k,&l);
kavdrat_kub(m,n,&p,&q); /*poziv f-je*/
printf("p=%d q=%d\n",p,q);
kavdrat_kub(m-k,n+l,&p,&r); /*poziv f-je*/
printf("p=%d q=%d\n",p,r);
}
void kvadrat_kub(int m, int n, int *kv, int *kub) /*definicija f-je*/
{
int i;
*kv=*kub=0;
for(i=m;i<=n;i++)
{
*kv+=i*i;
*kub+=i*i*i;
}
}

56. /*Napisati program koji unosi jedan po jedan elemenat celobrojnog niza (vektora) B[9]. Kada je
unošenje završeno određuje se koji je najveći broj u ovom nizu i na kojoj poziciji se nalazi i štampa
se ovaj element, njegov indeks, i niz B.*/

#include <stdio.h>
main()
{

46
int B[9], max, ind_max, i;

for(i=0;i<9;i++){
printf("Uneti sledeci element niza:\n");
scanf("%d",&B[i]);
}
max=B[0];
ind_max=0;

for(i=0;i<9;i++){
if(B[i]>max){
max=B[i];
ind_max=i;
}
}
printf("\n");

printf("Najveci element niza je %d, a njegov indeks %d \n", max, ind_max);

printf("Izgled vektora (niza) B:\n");


for(i=0;i<9;i++){
printf("%d ",B[i]);
}
printf("\n");
return 0;
}

Dodatak – Nizovi i pokazivači

int x[4], *p;


p=x;

p p+1 p+2 p+3


x[0] x[1] x[2] x[3]
56006 56007 56008 56009 56010 56011 56012 56013

x+2=&x[2]
*(x+2)=x[2]

*(x+i)=x[i]

1. Napisati program kojim se odredjuje koliko je ucesnika takmicenja iz programiranja imalo


natprosecne rezultate.

Problem se moze razloziti na sledece module:

1. Ucitavanje vrednosti elemenata niza.


2. Izracunavanje prosecnog rezultata:
3. Prebrojavanje natprosecnog rezultata.
4. Ispisivanje izvestaja (izlazni podaci)

#include<stdio.h>
void main()
{
int n,i,broj, ocena[50];

47
float prosek(); /*deklaracija f-je prosek*/

printf("Uneti broj takmicara\n");


scanf("%d",&n);

/*Ucitavanje elemenata niza*/


for(i=0;i<n;++i)
{
printf("ocena[%d]=",i);
scanf("%d",&ocena[i]);
}
/*Prebrojavanje natprosecnih rezultata*/
broj=0;
for(i=0;i<n;++i)
if (ocena[i]>prosek(ocena,n))
broj++;
printf("Prosecan rezultat je: %f.\n", prosek(ocena,n));
printf("Natprosecne rezultate je imalo: %d takmicara.\n",broj);
}

float prosek(int x[], int n) /*definicija f-je prosek*/


{
int i, suma;
suma=0;
for(i=0; i<n; suma+=x[i], i++);
return((float)suma/n);
}

II način: (Operatori - int x[] i int *x su ekvivalentni, jer oba deklarišu primenljivu x kao pokazivač
na niz celih brojeva )

x[4] je isto što i *(x+4)


x[i] je isto što i *(x+i)

float prosek(int *x, int n)


{
int pom, i;
suma=0;
for(i=0; i<n; suma+=*(x+i), i++);
return((float)suma/n);
}

2. Napisati funkciju kojom se realizuje ciklično premeštanje vrednosti elemenata niza a[0],
a[1],...a[n-1] za jedno mesto u levo.

Traženo premeštanje se realizuje tako što vrednost a[0]sklanjamo u pomoćnu promenljivu pom, a zatim u
n-1 koraka vrednost premeštamo ulevo kroz dodele: a[0]=a[1], a[1]=a[2], ..., a[n-2]=a[n-1], i dodelom
a[n-1]=pom sačuvanu vrednost od a[0] kopiramo u a[n-1].

void levo_za_1(int a[], int n)


{
int pom, i;
pom=a[0];
for(i=1; i<n; a[i-1]=a[i], i++);
a[n-1]=pom;

48
}

II način: Ako bi umesto deklaracije int a[]; stavili int *a; { a[i] je isto što i *(a+i) }

void levo_za_1(int *a, int n)


{
int pom, i;
pom=*a;
for(i=1; i<n; *(a+i-1)=*(a+i), i++);
*(a+n-1)=pom;
}

STRINGOVI

 String je niz znakova koji završava nul znakom '\0' (ASCII kod 0)
 <string.h> sadrži skup funkcija za manipulaciju stringovima, npr:
strlen, strcpy, strcat, strcmp …
 Stringovne konstante se navode unutar dvostrukih navodnika:
"Pero Peric", "A", "" (prazni niz), "23"
 String dužine 10 (npr. "Pero Peric") zauzima 11 byteova u memoriji.
 Primeri deklaracije:
char niz [velicina];
char *niz; (uz obvezni malloc kasnije)
 Ispis stringa : koristi se format %s, npr. printf("%s", niz)
 Primeri učitavanja stringa:
 gets(niz);
 scanf("%s", niz);
 scanf("%[^\n]", niz);

Standardni fajlovi zaglavlja

Prototipovi bibliotecnih funkcija su dati u nekoliko standardnih fajlova zaglavlja. Npr. standardni fajlovi
su:
- stdio.h-sadrzi definisane funkcije printf , scanf , putchar i getchar
- assert.h-assertions
- ctype.h-definisane su funikcije za ispitivanje karaktera
- float.h-ograničenja sistema za realne tipove podataka
- limits.h-ograničenja sistema za celobrojne tipove podataka
- math.h - matematicke funkcije
- setjmp.h-nelokalni skokovi
- signal.h-javljanje grešaka i signala
- stdarg.h-lista parametara promenljive dužine
- stdlib.h-utility functions; number conversions, memory allocation, exit and system, Quick Sort
- string.h-funkcije stringova
- time.h-vremenske i datumske funkcije

Nizovi karaktera su jednodimenzionalni vektori tipa char.

U standardnom zaglavlju stdio.h definisane su sledeće funkcije:


- getchar() - čita sledeći znak, uključujući i bele znakove, preko tastature. Vrednost funkcije je kod
pročitanog znaka ili simbolička konstanta EOF (end of file) ukoliko je pročitan signal za kraj datoteke
kao i u slučaju greške u toku čitanja.

49
- putchar(c) - funkcija za ispisivanje znaka c na ekranu.
- gets(s) - funkcija za čitanje jednog reda teksta
- puts(s)-funkcija za ispisivanja jednog reda teksta
- getc(c)-unos jednog karaktere
- putc(c)-štampanje jednog karaktera
- stdin-standardni ulazni tok
- stdout-standardni izlazni tok
- stderr-standardne greške
- EOF-end of file
- printf(“format”, arg1,...)-štampanje formatiranih podataka
- sprintf(s,“format”, arg1,...)-štampanje u string s
- scanf(“format”, &ime1,...)-unos formatiranih podataka
- sscanf(s,“format”, &ime1,...)-unos iz stringa s
- FILE *fp-deklaracija pokazivača na fajl
- fopen(“ime”,”mod-režim”)-pokazivač na ime fajla (mod: r-čitanje(read), w-upis(write), a-dodavanje
(append))
- fprintf(fp,“format”,arg1,...)-upis u fajl
- fscanf(fp,“format”,arg1,...)-čitanje iz fajla
- fclose(fp)-zatvaranje fajla
- ferror(fp)-nenulta vrednost ukoliko je greška
- feof(fp)-nenulta vrednost ukoliko je kraj datoteke
- fgets(s,max,fp)-čita liniju u string s (< max karaktera) iz datoteke fp
- fputs(s,fp)-ispisuje string s u datoteku fp

U standardnom zaglavlju string.h definisane su sledeće funkcije:


- strlen(cs)-vraća duzinu stringa cs.
- strcmp(cs,ct)-upoređuje niz cs sa nizom ct; vraća <0 ako je cs<ct, 0 ako je cs=st ili >0 ako je cs>ct.
- strcpy(s, c)-kopira niz c u niz s.
- strcpy(s, c,n)-kopira niz c u niz s prvih n karaktera.
- srtcat(s, c)-povezuje niz karaktera c iza niza s
- srtcat(s, c,n)-povezuje niz karaktera c iza niza s počevši od n-tog karaktera
- srtcmp(s, c)-upoređuje niz karaktera s sa nizom c
- srtcmp(s, c,n)-upoređuje prvih n karaktera niza s sa nizom c
- strchr(s, c)-pokazivač na prvi karakter niza c u nizu s
- strrchr(s, c)-pokazivač na poslednji karakter niza c u nizu s
- memcpy(s, c, n)-kopira n karaktera iz niza c u niz s
- memmove(s, c, n)-kopira n karaktera iz niza c u niz s sa mogućnošću preklapanja
- memchr(s, c, n)-pozakizvač na prvi c u privih n karaktera u nizu s
- memset(s, c, n)-smešta c u prvih na karaktera niza s

U standardnom zaglavlju ctype.h definisane su sledeće funkcije:


- isalnum(c)-ispituje da li je c alfanumerički karakter (slovo ili broj)
- isalpha(c)-ispituje da li je c alfabetski karakter (slovo)
- iscntrl(c)-ispituje da li je c kontrolni karakter
- isdigit(c)-ispituje da li je c cifra
- isgraph(c)-ispituje da li je c štampani karakter (ne uključuje prazninu)
- islower(c)-ispituje da li je c malo slovo
- isprint(c)-ispituje da li je c karakter (samo da nije praznina)
- ispunct (c)- ispituje da li je c znak izuzimajući praznine, slovo ili broj
- isspace(c)-ispituje da li je c praznina, formfeed, nova linija, vertikalni, horizontalni karaker
- isupper(c)-ispituje da li je c veliko slovo
- isxdigit(c)-ispituje da li je c heksadecimalni broj
- tolower(c)-pretvara c u malo slovo
- toupper(c)-pretvara c u veliko slovo
- isblank(c)- ispituje da li je c razmak ili '\t' (TAB)?

50
57. Napišite program koji učitava jednu reč maksimalne dužine 17 znakova i ispisuje:
a) tu reč
b) tu reč bez prvog znaka
c) treće slovo te reči (pretpostavite da je reč dovoljno dugačka)

#include <stdio.h>

int main(void) {
char rec[18];

printf("Upisite rec: "); scanf("%s", rec);

printf("a) rec: %s\n", rec);


printf("b) rec bez prvog znaka: %s\n", &rec[1]);
printf("c) treci znak: %c\n", rec[2]);

return 0;
}

58. /*Prikazivanje tablice ASCII kodova*/


#include<stdio.h>
void main()
{
char c; int i;
printf("\t\t Tablica ASCII kodova\n\n");
for(c=' ';c<' '+19;++c){
for(i=0;i<95;i+=19)
printf("%3d %c ",c+i,c+i);
putchar('\n');
}
}

59/*Napisati program kojim se ucitavaju znaci sve dok se ne unese # i onda daje izvestaj o broju
ucitanih praznina, novih linija i broju svih ostalih ucitanih karaktera.*/
#include <stdio.h>
void main()
{
char ch;
int praznina = 0, nl = 0,ostalo = 0;
while ((ch = getchar()) != '#')
{
if (ch == ' ')
praznina++;
else if (ch == '\n')
nl++;
else
ostalo++;
}
printf(" Broj praznina: %d\n Novih linija: %d\n Ostali karakteri: %d\n", praznina, nl, ostalo);
}

60. /*Program za odredjivanje duzine nizova karaktera*/


#include<stdio.h>
unsigned strlen(s)
char *s;

51
{
unsigned i;
for(i=0;*s!='\0';++s,++i);
return(i);
}
main()
{
char demo[]="Uvod u C jezik";
printf("Duzina niza demo je %d\n",strlen(demo));
}

61. /*Primer koji radi sa stringovima korišćenjem <string.h> zaglavlja*/

#include<stdio.h>
#include<string.h>

void main(){
char buffer[80];
int brojSlova;
char lozinka[80];
int provera;
char novi [ ]= "Student ";

printf("Uneti recenicu:\n");

/*scanf("%s", buffer);*/
/*Bolje je koristiti gets jer scanf uzima string sa tastature samo do prvog razmaka u recenici*/
gets(buffer);

/*Provera unetog stringa*/


printf("Uneta je recenica: %s\n", buffer);

/*Funkcija strlen daje duzinu stringa, odnosno broj karaktera u stringu*/


brojSlova=strlen(buffer);
printf("Broj slova u recenici je: %d\n", brojSlova);

/*Funkcija strlwr menja sva slova u zadatom stringu u mala slova*/


strlwr(buffer);
printf("Uneta je recenica: %s\n", buffer);

/*Funkcija strupr menja sva slova u zadatom stringu u velika slova*/


strupr(buffer);
printf("Uneta je recenica: %s\n", buffer);

/*Funkcija strcmp poredi dva stringa (drugi sa prvim argumentom)*/


printf("Uneti lozinku: ");
gets(lozinka);
provera=strcmp(buffer, lozinka);

if (provera==0) /*ili if(!provera)*/


printf("tacno uneta lozinka\n");
else
printf("pogresno uneta lozinka\n");

printf("Uneta je recenica: %s\n", buffer);

52
/*Funkcija strcat spaja dva stringa u jedan i pamti rezultat u prvom argumentu*/
strcat(novi, buffer);
printf("Dobijen je novi string: %s\n", novi);
}

62. /*Zadatak pokazuje vezu pointera i nizova karaktera (stringova) . Pokazivač sa inicijalizuje
adresom početka niza (njegovim imenom), a zatim se pomeranjem za jedan u pokazivaču pamti
ostatak niza, sve dok se ne dođe do zadnjeg elementa u nizu karaktera.*/

#include<stdio.h>
#include<string.h>

void main(){
char niz[ ]= "Marko Markovic";
int i;

char *pniz;
pniz=niz;

printf("String je:\n");
for(i=0; i<(int)strlen(pniz); i++)
printf("%s\n", pniz+i);
}

63. /*Program za ilustraciju brojanja reci u nizu karaktera*/


#include<stdio.h>
unsigned wc(s)
char *s;
{
unsigned n=0;
while(*s)
{
while(*s==' '||*s=='\n'||*s=='\t')
++s;
if(*s)
{
++n;
while(*s!=' '&&s!='\n'&&*s!='\t'&&*s!='\0')
++s;
}
}
return(n);
}
main()
{
static char string[]="Ilustracija procesiranja nizova\t karaktera\n\t\n";
printf("Broj reci je %u\n",wc(string));
}

return l;
}

64./*Napisati program za odredjivanje broja velikih i malih slova u unetom tekstu.*/


#include <stdio.h>
void main()
{
int ch;

53
int uct = 0,lct = 0;
while ((ch = getchar()) != EOF)
if (isupper(ch))
uct++;
else if (islower(ch))
lct++;
printf("\n");
printf("velikih slova: %d\n", uct);
printf("malih slova: %d\n", lct);

65./*Napisati program za odredjivanje ukupnog broja karaktera u unetom tekstu.*/


#include <stdio.h>
int main(void)
{
int ch;
int ct = 0;

while ((ch = getchar()) != EOF)


ct++;
printf("\n");
printf("Uneto je %d karaktera\n", ct);
}

66./*Napisati program kojim se iz stringa s briše svaki znak koji odgovara bilo kom znaku stringa t.*/
#include <stdio.h>
#include <string.h>
void main()
{
char s[50], t[50];
int i,j;
gets(s);
gets(t);
for(i=j=0;s[i];i++)
if(!strchr(t,s[i]))
s[j++]=s[i];
s[j]='\0';
puts(s);
}

67./*Napisati program koji iz datog stringa s izbacuje sve komentare oblika /*...*/, s tim što u komentaru
nema komentara*/
#include <stdio.h>
#include <string.h>
void main()
{
char s[100], *p,*q;
gets(s);
while(p=strstr(s,"/*"))
{
q=strstr(s,"*/");
strcpy(p,q+2);
}
puts(s);
}

54
68./*Napisati program koji iz datog stringa s određuje prosečan broj slova u rečima parne dužine*/
#include <stdio.h>
void main()
{
char s[100];
int i,k=0,br=0;
float q=0;
gets(s);
for(i=0;s[i];i++)
if(s[i]!=' ') k++;
else
if(k>0)
{
if(k%2==0)
{
br++; q+=k;
}
k=0;
}
if(k>0)
if(k%2==0)
{
br++;
q+=k;
}
printf("Prosecan broj simbola u recima parne duzine je %f\n",q/br);
}

69. /*Napisti program za ucitavanje neuredjenog spiska imena prekog glavnog ulaza, po jedno ime iz
svakog reda, sve dok umesto prezimena i imena ne procita dve tacke sa znakom razmaka izmedju. Po
zavrsetku citanja imena treba urediti i potom ispisati na glavnom izlazu, po jedno ime u svakom redu*/

#include<stdio.h>
#include<string.h>
#define N 100
#define D 40
void main()
{
char ljudi[N][D+1];
int i, n=0;
/*Citanje neuredjenog niza imena*/
printf("Neuredjen niz prezimena i imena?\n\n");
do
gets(ljudi[n]);
while(strcmp(ljudi[n++],". .")!=0);
n--;
/*Uredjivanje niza imena*/
for(i=0; i<n-1;i++){
int j,m=i;
for(j=i+1;j<n;j++)
if(strcmp(ljudi[j],ljudi[m])<0)m=j;
if(m!=i){
char osoba[D+1];

55
strcpy(osoba , ljudi [i]);
strcpy(ljudi[i],ljudi[m]);
strcpy(ljudi[m],osoba );
}
}
/*Ispisivanje uredjenog niza imena*/
printf("\nUredjeni niz imena:\n\n");
for(i=0;i<n;puts(ljudi[i++]));
}

70. /*Program za konverziju niza ASCII cifara u celobrojnu vrednost*/


#include<stdio.h>
int isspace(c)
char c;
{
return(c==' '||c=='\t'||c=='\n');
}
int isdigit(c)
char c;
{
return(c>='0'&&c<='9');
}
int atoi(s)
char *s;
{
int value=0,sign=1;
char c;
if(*s=='-')
{
++s;
sign=-1;
}
else if(*s=='+')
++s;
while(isspace(*s))
++s;
while(isdigit(c=*s++))
value=10*value+c-'0';
return(sign*value);
}
void main()
{
char niz[81];
printf("Ukucajte broj:\n");
scanf("%s",niz);
printf("\"%s\"=%d\n",niz,atoi(niz));
}

71. /* Napišite funkciju koja kao argument prima jedan string i iz njega briše svako treće slovo.
Napišite i program koji pokazuje kako se funkcija upotrebljava.*/

#include <stdio.h>
#include <ctype.h>

void izbaci(char *s){


int i,j,br=0;
for(i=0, j=0 ; s[i] != '\0' ; i++){

56
if (! (isalpha(s[i]) && ++br % 3 == 0) )
s[j++] = s[i];
}
s[j] = '\0';
}

int main ( void) {


char s[] = "Ovo je niz iz kojeg treba izbaciti svako 3. slovo.";
izbaci(s);
printf("%s\n", s);
return 0;
}

72. /*Napišite funkciju koja kao argument prima jedan string i iz njega briše svako treće slovo.
Napišite i program koji pokazuje kako se funkcija upotrebljava.*/

Rešenje 2: – umesto indeksa i i j koristimo pomoćni pokazivač

void izbaci(char *s){


char *p; int br=0;
p = s;
for(; *s ; s++){
if (! (isalpha(*s) && ++br % 3 == 0) ){
*p = *s;
p++;
}
}
*p = '\0';
}
73. /*Program koji ucitava 7 imena i prezimena studenata. Imena nisu duza od 15 karaktera, a
prez. 25. Zatim formira novi tekst koji je oblika: Ime Prezime: za svakog studenta. Potom
odredjuje koji od ovako novoformiranih tekstova je najduzi i stampa ga.*/

#include<stdio.h>
#include<string.h>
#define BR_ST 7
#define D_IME 15
#define D_PRZ 25
main(){
char ime[BR_ST][D_IME];
char prezime[BR_ST][D_PRZ];
char rez[BR_ST][D_IME+D_PRZ+2];
char Najduzi[D_IME+D_PRZ+2];

int i, Max;
int D[BR_ST];

for(i=0; i<BR_ST; i++){


printf("Uneti ime sledeceg studenta: ");
gets(ime[i]);
printf("Uneti prezime sledeceg studenta: ");
gets(prezime[i]);
strcpy(rez[i], ime[i]);
strcat(rez[i], " ");
strcat(rez[i], prezime[i]);
strcat(rez[i],":");
D[i]=strlen(rez[i]);

57
}
Max=0;
for(i=0;i<BR_ST;i++){
if(Max<D[i]){
Max=D[i];
strcpy(Najduzi, rez[i]);
}
}
printf("\nNajduzi tekst - kombinacija imena i prezimena je:%s\n ", Najduzi);
return 0;
}

74. /* Napišite funkciju int palindrom(char *s) koja vraća 1 ako je string s palindrom; inače treba vratiti
0. Funkcija treba biti case-insensitive (tj. ne sme praviti razliku između velikih i malih slova) i mora
ignorisati sve znakove koji nisu slovo. Pri tome ne sme menjati string s. Npr. string “Ana voli:
Milovana!” treba prepoznati kao palindrom.*/

int palindrom(char *s){


int i=0,j;
for(j=0 ; s[j]!='\0'; j++);
while(i < j){
if (!isalpha(s[i])){
i++; continue;
}
if (!isalpha(s[j])){
j--; continue;
}
if (tolower(s[i]) != tolower(s[j]))
return 0;
else{
i++;j--;
}
}
return 1;
}

Dinamički alocirani stringovi

char *string;
int len;
printf("Duzina stringa: ");
scanf("%d", &len);
string = (char*)malloc((len+1)*sizeof(char));
scanf("%s", string);

 Ukoliko je string definisan kao pokazivač pre njegovog korištenja (scanf, printf) obavezno treba
alocirati memoriju za njega

 Napomena:
char string[20] -> sizeof(string) je 20
char *string -> sizeof(string) je 4

75. Napišite funkciju koja kao argument uzima string, i iz njega briše sve samoglasnike. Dodatno,
napišite i program koji pokazuje kako se funkcija upotrebljava.

58
void brisi_samoglasnike(char s[]) {
int i, j = 0;
for (i = 0; s[i] != '\0'; i++) {
char c = tolower(s[i]);
if (!(c == 'a' || c == 'e' ||
c == 'i' ||
c == 'o' || c == 'u'))
s[j++] = s[i];
}
s[j] = '\0';
}

int main (void) {


char s[17];
printf("Upisite string: ");
scanf("%[^\n]", s);
brisi_samoglasnike(s);
printf("Rez: \"%s\"\n", s);

return 0;
}

59
STRUKTURE PODATAKA

Strukture su skupovi heterogenih elemenata (jedan elemenat je char, drugi je int itd.). U C jeziku
postoji mogućnost grupisanja logički povezanih promenljivih različitog tipa u jednu celinu, strukturu.
Koristeći ključnu reč struct možemo definisati strukturu datum sa tri celobrojne komponente, koje
predstavljaju dan, mesec i godinu. Ovo se deklariše:

struct datum {
int dan;
int mesec;
int godina;
};
Struktura datum sadrži tri elementa tipa int: dan, mesec i godina, koji se nazivaju članovima
strukture. Ključna reč struct definiše strukturu tako da promenljive mogu biti deklarisane kao tip struct
datum. Za selekciju članova strukture koristi se operator .(tačka), tako što se specificira ime promenljive,
operator tačka i ime člana. Operator . ima najviši prioritet među operatorima C jezika i istog je prioriteta
sa operatorom selekcije elementa vektora (uglaste zagrade). Selekcija člana strukture ima opštu formu

ime_promenljive.ime_clana

Inicijalizacija strukture je slična inicijalizaciji vektora. Inicijalizacione vrednosti se navode


između vitičasti zagrada razdvojene zarezom.

76. /*Program koji za za zadato tekuće vreme određuje naredno vreme.*/


#include<stdio.h>
void main()
{
struct vreme{
int sat;
int minut;
int sekund;
}tekuce_vreme,naredno_vreme;
printf("Unesite tekuce vreme?[cc:mm:ss]");
scanf("%d:%d:%d",&tekuce_vreme.sat,
&tekuce_vreme.minut,
&tekuce_vreme.sekund);
naredno_vreme=tekuce_vreme;
if(++naredno_vreme.sekund==60)
{
naredno_vreme.sekund=0;
if(++naredno_vreme.minut==60)
{
naredno_vreme.minut=0;
if(++naredno_vreme.sat==24)
naredno_vreme.sat=0;
}
}
printf("Naredno vreme je %02d:%02d:%02d\n", naredno_vreme.sat,
naredno_vreme.minut, naredno_vreme.sekund);
}

77. /*Napisati program za formiranje strukture student sa karakteristikama Ime, Prezime, broj
indeksa, srednja ocena. Za uneti broj studenata n, sortirati studente prema srednjoj oceni i ispisati
na ekranu*/
#include<stdio.h>
typedef struct student{
char Ime[20],Prezime[20];
int broj_indeksa;
60
float srednja_ocena;
};
void razmeni(struct student *a, struct student *b)
{
struct student pom;
pom=*a;
*a=*b;
*b=pom;
}
void sort(struct student STF[], int n)
{
int i, j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(STF[i].srednja_ocena<STF[j].srednja_ocena)
razmeni(&STF[i],&STF[j]);
}

void main()
{
int n;
int i;
struct student STF[100];
printf("Unesite broj studenata: \n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("Unesi ime: \n");
scanf("%s",STF[i].Ime);
printf("Unesi prezime: \n");
scanf("%s",STF[i].Prezime);
printf("Unesi broj indeksa: \n");
scanf("%d",&STF[i].broj_indeksa);
printf("Unesi srednju ocenu: \n");
scanf("%f",&STF[i].srednja_ocena);
}
sort(STF,n);
for(i=0;i<n;i++)
{
printf("student broj %d\n",i+1);
printf("Ime:%s\n",STF[i].Ime);
printf("Prezime:%s\n",STF[i].Prezime);
printf("Broj indeksa: %d\n",STF[i].broj_indeksa);
printf("Srednja ocena: %5.2f\n\n\n",STF[i].srednja_ocena);
}
}

78. /*Program za prevodjenje srpskih reci na engleske (srpsko-engleski recnik)*/


#include<stdio.h>
struct element {
char srpski[20];
char engleski[50];
};
int strcmp(char*s1,char*s2)
{
while(*s1==*s2)
{
if(!*s1)
61
return(0);
++s1;
++s2;
}
return(*s1-*s2);
}
int bin_search(struct element recnik[],char*ukaz_niz,unsigned n)
{
int low=0;
int mid,high=n-1;
int result;
while(low<=high)
{
mid=(low+high)/2;
result=strcmp(ukaz_niz,recnik[mid].srpski);
if(result<0)
high=mid-1;
else if(result>0)
low=mid+1;
else
return(mid+1);
}
return(0);
}
void main(){
static struct element recnik[100]=
{{"baba","old woman,grandmother"},
{"babica","widwife"},
{"badem","almond"},
{"bager","dredge"},
{"bajka","fairytale"},
{"bakalin","grocer"}};
unsigned j;
int n=10;
char rec[20];
printf("Ukucajte rec:\n");
scanf("%s",rec);
j=bin_search(recnik,rec,6);
if(!j)
printf("Zalim, rec %s nije u recniku\n",rec);
else
printf("%s\n",recnik[j-1].engleski);
}
79./* Napisati program koji pravi rang listu studenata koji su polagali prijemni ispit. Sa
standardnog ulaza se unose sledeci podaci: ime studenta, cetiri ocene iz prethodnog skolovanja i
broj bodova na prijemnom ispitu.*/

#include<stdio.h>
#define DIM 10
typedef struct student{
char ime[20];
int brBodova;/*Ukupna suma bodova svakog studenta: ocene + prijemni*/
};
void razmeni(struct student *a, struct student *b){
struct student tmp;
tmp=*a;
*a=*b;
*b=tmp;
62
}
void sort(struct student niz[], int n){
int i, j;
for(i=0; i<n-1; i++)
for(j=i; j<n; j++)
if(niz[i].brBodova<niz[j].brBodova)
razmeni(&niz[i], &niz[j]);
}
void main(){
struct student nizStudenata[DIM];
int n, i, j;
static int ocene[5];
int bodovi;
static int sumaOcena[DIM];/*Suma ocena iz prethodnog skolovanja*/
printf("Uneti broj studenta koji je polagao prijemni: ");
scanf("%d", &n);
for(i=0; i<n; i++){
printf("Uneti ime studenta: ");
scanf("%s", &nizStudenata[i].ime);
printf("Uneti cetiri ocene iz prethodnog skolovanja: ");
for(j=0; j<4; j++){
scanf("%d", &ocene[j]);
sumaOcena[i]+=ocene[j];
//printf("Suma ocena je: %d\n", sumaOcena[i]);
}
printf("Uneti broj bodova sa prijemnog: ");
scanf("%d", &bodovi);

nizStudenata[i].brBodova=sumaOcena[i]+bodovi;
printf("Ukupna suma bodova svakog studenta: ocene + prijemni je: %d\n",
nizStudenata[i].brBodova);
}
sort(nizStudenata, n);
printf("Rang lista studenata je:\n\n");
for(i=0; i<n; i++)
printf("%s\t%d\n", nizStudenata[i].ime, nizStudenata[i].brBodova);

80. /*Definisati strukturu GRAD sa podacima clanovima: ime, broj_stanovnika,


prosecan_dohodak_radnika. Napisati program kojim se unose podaci o gradovima u Srbiji i
stampati na standardnom izlazu ime grada sa najvecim brojem stanovnika. Izracunati ukupan
dohodak svih unetih gradova.*/

#include<stdio.h>
#define DIM 10
typedef struct grad{
char ime[20];
int brStan;
float dohodak;
};
void main(){
struct grad nizGradova[DIM];
int i, n;
float ukupanDohodak=0.0;
int najveci;
int indeksNajvecegGrada;
printf("Uneti koliko gradova ima: ");
63
scanf("%d", &n);
for(i=0; i<n; i++){
printf("Uneti ime grada: ");
scanf("%s", &nizGradova[i].ime);
printf("Uneti broj stnovnika: ");
scanf("%d", &nizGradova[i].brStan);
printf("Uneti dohodak: ");
scanf("%f", &nizGradova[i].dohodak);
ukupanDohodak+=nizGradova[i].dohodak;
}
printf("Ukupan dohodak svih gradova je: %6.2f\n", ukupanDohodak);
najveci=nizGradova[0].brStan;
indeksNajvecegGrada=0;
for(i=0; i<n; i++){
if(nizGradova[i].brStan>najveci){
najveci=nizGradova[i].brStan;
indeksNajvecegGrada=i;
}
}
printf("Grad sa najvise stanovnika je %s\n", nizGradova[indeksNajvecegGrada].ime);
}

81. /*Napisati program za formiranje strukture podataka telefonski_imenik sa poljima: prezime,


broj i adresa. Napisati program za sortiranje imenika prema prezimenu pretplatnika.*/
#include<stdio.h>
#define DIM 10
typedef struct telefonski_imenik{
char prezime[20];
char broj[10];
char adresa[20];
};
void razmeni(struct telefonski_imenik *a, struct telefonski_imenik *b){
struct telefonski_imenik tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
void sort(struct telefonski_imenik niz[], int n){
int i, j;
for(i=0; i<n-1; i++)
for(j=i; j<n; j++)
if(niz[i].prezime<niz[j].prezime)
razmeni(&niz[i], &niz[j]);
}
void main(){
struct telefonski_imenik nizImenik[DIM];
int n, i;
printf("Uneti broj telefonskih pretplatnika: ");
scanf("%d", &n);
for(i=0; i<n; i++){
printf("Uneti prezime pretplatnika: ");
scanf("%s", &nizImenik[i].prezime);
printf("Uneti broj telefona pretplatnika: ");
scanf("%s", &nizImenik[i].broj);
printf("Uneti adresu pretplatnika: ");
scanf("%s", &nizImenik[i].adresa);;
}
sort(nizImenik, n);
64
printf("\nTelefonski imenik sortiran po prezimenu pretplatnika je:\n\n");
for(i=0; i<n; i++)
printf("%s\t%s\t%s\n", nizImenik[i].prezime, nizImenik[i].broj, nizImenik[i].adresa);

RAD SA DATOTEKAMA

Datotekama se pristupa korišćenjem pokazatelja na strukturu FILE, koja je definisana u


include datoteci stdio.h. Datoteka stdio.h se uključuje u program iskazom #include. U stdio.h
definisane su i konstante EOF i NULL. Konstanta EOF označava kraj datoteka i najčešće ima
vrednost -1. Konstanta NULL ima vrednost 0, i vraća se kao rezultat nekih funkcija za
upravljanje datotekama u slučaju neuspešnog izvršavanja funkcija.
fopen vraća pokazatelj na strukturu FILE, koji se dodeljuje promenljivoj in_file istog
tipa. U slučaju neuspešnog otvaranja fopen, vraća vrednost NULL. Iz tog razloga neophodno je
ispitati vraćenu vrednost, odnosno, dodati iskaz

if(in_file==NULL)
printf(“Datoteka file1 ne moze biti otvorena\n”);
Da bi se izvršila neka operacija datoteka mora biti otvorena, pozivanjem odgovarajuće
funkcije i specificiranjem imena datoteke. Prilikom otvaranja datoteke, mora se specificirati tip
željene ulalzno/izlazne operacije. Npr. ako se želi pročitati sadržaj datoteke, specificira se režim
čitanja "r"(eng. read mode); ako se neki sadržaj upisuje u datoteku, specificira se režim upisa "w"
(eng. write mode); ako se želi dodati neki sadržaj, specificira se režim dodavanja "a" (eng.
append mode). Da bi se ažurirao sadržaj datoteke (naizmenično čitanje i pisanje), prethodnim
oznakama se dodaje znak +, nezavisno koji je osnovni režim rada. Pri radu sa binarnim
datotekama prethodnim oznakama se dodaje i slovo b.
Iza svakog od ovih formata može se dodati ili b (za binarne datoteke) ili t za tekstualne
datoteke. Ako se ne navede ništa, podrazumijeva se da se radi o tekstualnim datotekama.

Zatvaranje datoteke vrši se funkcijom fclose čija je deklaracija:


int fclose(FILE *dat);

dat je pokazivač datoteke koji je pridružen datoteci koja se zatvara. Vrednost funkcije je nula u
slučaju uspeha, a smibolička konstanta EOF u slučaju otkrivanja greške.
Funkcija koja čita iz datoteke dat najviše br podataka veličine vel bajtova u memoriju
počev od adrese niz:
int fread(void *niz, int vel, int br, FILE *dat);

Primer za čitanje niza od najviše n_max celobrojnih podataka iz datoteke podaci:


n=fread(vektor, sizeof(int), n_max, podaci);
int fwrite(const void *niz, int vel, int br, FILE *dat);
Funkcije za štampanje i unos podataka:
 fprintf-za štampanje podataka u datoteci (fajlu)
 sprintf-za štampanje znakovnog niza
 fscanf-za unos podataka u datoteku
 sscanf-za unos znakovnog niza.
Funkcija getc() učitava jedan karakter iz specificirane datoteke. Ova funkcija je vrlo
slična već opisanoj funkciji getchar, s tom razlikom što se učitavanje ne obavlja sa terminala
nego iz datoteke. getc vraća vrednost EOF, ako je dosegnut kraj datoteke.
Funkcija putc upusuje karakter u specificiranu datoteku. Zaglavlje funkcije je
int putc(c,file_pointer)
char c;

65
FILE*file_pointer;
Na pr. pozivom putc(‘z’,in_file); u datoteku in_file upisujemo karakter ‘z’.
Pozicioniranje na mesto u datoteci dat čija je udaljenost pomeraj bajtova od označene
reperne tačke data je funkcijom:
int fseek(FILE*dat, long pomeraj, int reper);
Moguće reperne tačke obeležavaju se sibmoličkim konstantama SEEK_SET (početak datoteke),
SEEK_CUR (trenutna pozicija u datoteci) ili SEEK_END (kraj datoteke). Sledeće čitanje ili
pisanje vršiće se počevši od ovako odabrane pozicije u datoteci. Funkcija za pozicioniranje na
početak datoteke dat je:
void rewind(FILE *dat);

82. /*Odrediti broj linija u tekstualnom fajlu sa imenom knjiga.txt.*/

#include<stdio.h>
void main()
{
int k=0;
FILE *fp;
char s[256];
if((fp=fopen("knjiga.txt","r"))==NULL)
{
perror("Greska");
return;
}
while(fgets(s,256,fp)!=NULL)k++;
printf("Fajl ima %d linija\n",k);
fclose(fp);
}
83. /*Napisati program kojim se sadržaj fajla test.dat formiran od velikih slova alfabeta šifriran šalje u fajl sifra.dat. Znak se šifrira tako što se
zamenjuje sledećim ASCII znakom, a znak Z zamenjuje sa A.*/

#include<stdio.h>
void main()
{
int c;
FILE *inf,*outf;
inf=fopen("test.dat","r");
outf=fopen("sifra.dat","w");
while((c=fgetc(inf))!=EOF)
{
if('A'<=c&&c<'Z')
c++;
else c='A';
putc(c,outf);
}
fclose(inf);
fclose(outf);
}

84. /*U tekstualnom fajlu odrediti najdužu liniju. Ako ima više linija najveće dužine odrediti prvu među njima.*/

#include<stdio.h>
#include<string.h>
void main()
{
66
unsigned k=0,maxl;
char s[256],maxs[256];
FILE *fp;
if((fp=fopen("test.txt","r"))==NULL)
{
printf("Greska\n ");
return;
}
maxl=0;
while(fgets(s,256,fp)!=NULL)
if(strlen(s)>maxl)
{
maxl=strlen(s);
strcpy(maxs,s);
}
printf("Najduza linija\n%s\n ima duzinu %d\n",maxs,maxl);
fclose(fp);
}

85. /*Napisati program koji poredi dva fajla i ispisuje prvu liniju u kojoj se razlikuju.*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXLINE 100
void main()
{
FILE *fp1;
FILE *fp2;
void filecomp(FILE *fp1, FILE *fp2);
if((fp1=fopen("prvi.txt","r"))==NULL)
{
perror("Ne moze se otvoriti prvi.txt");
return;
}
if((fp2=fopen("drugi.txt","r"))==NULL)
{
perror("Ne moze se otvoriti drugi.txt");
return;
}
filecomp(fp1,fp2);
fclose(fp1);
fclose(fp2);
}
void filecomp(FILE *fp1,FILE *fp2)
{
char line1[MAXLINE], line2[MAXLINE];
char *lp1,*lp2;
do
{
lp1=fgets(line1, MAXLINE, fp1);
lp2=fgets(line2, MAXLINE, fp2);
if(lp1==line1&&lp2==line2)
{
67
if(strcmp(line1,line2)!=0)
{
printf("Prva razlika je u liniji\n%s\n",line1);
lp1=lp2=NULL;
}
}
else
if(lp1!=line1&&lp2==line2)
printf("Kraj prvog fajla u liniji \n%s\n",line2);
else
if(lp1==line1&&lp2!=line2)
printf("Kraj drugog fajla u liniji \n%s\n",line1);
}
while(lp1==line1&&lp2==line2);
}

86./*Napisati program za učitavanje datoteke pod imenom ulaz.dat i formiranje datoteke sa nazivom izlaz.dat koja sadrži samo one redove ulazne
datoteke ulaz.dat u kojima se nalazi reč “fakultet”.*/

#include<stdio.h>
#include<string.h>
void main()
{
FILE *ulaz;
FILE *izlaz;
char buffer[80];
char trazenaRec[]="fakultet";
if((ulaz=fopen("ulaz.dat","r"))==NULL)
printf("Datoteka ulaz.dat nije otvorena.");
if((izlaz=fopen("izlaz.dat","w"))==NULL)
printf("Datoteka izlaz.dat nije otvorena.");
while(!feof(ulaz)){
fgets(buffer,80,ulaz);
if(strstr(buffer,trazenaRec)!=NULL){
printf("%s",buffer); /*stamanje na ekranu*/
fprintf(izlaz,"%s",buffer);
}
}
fclose(ulaz);
fclose(izlaz);
}

87. /*Napisati program koji cita podatke iz datoteke ULAZ.TXT (ime studenta, broj bodova na
prijemnom ispitu), broji sve studente koji imaju broj bodova veci od proseka i upisuje podatke o
takvim studentima u datoteku IZLAZ.TXT.*/

#include<stdio.h>
#define DIM 10
typedef struct student{
char ime[20];
int brBodova;
};
int main(){
struct student nizStudenata[DIM];
int i;

68
int brojStudenata=0;
int suma=0;
float prosek;
FILE *ulaz;
FILE *izlaz;
ulaz=fopen("ulaz.txt", "r");
if(ulaz==NULL){
printf("Ulazna datoteka nije otvorena!\n");
return 1;
}
izlaz=fopen("izlaz.txt", "w");
if(izlaz==NULL){
printf("Izlazna datoteka nije kreirana!\n");
return 1;
}
while(!feof(ulaz)){
fscanf(ulaz, "%s%d", &nizStudenata[brojStudenata].ime,
&nizStudenata[brojStudenata].brBodova);
suma+=nizStudenata[brojStudenata].brBodova;
brojStudenata++;
}
prosek=(float)suma/brojStudenata;
for(i=0; i<brojStudenata; i++)
if(nizStudenata[i].brBodova>prosek)
fprintf(izlaz, "%s\t%d\n", nizStudenata[i].ime, nizStudenata[i].brBodova);
fclose(ulaz);
fclose(izlaz);
return 0;
}

88. /*Napisati program za nalazenje i stampanje na ekranu zbira ASCII kodova svih znakova
zadate datoteke pod imenom ULAZ.TXT*/

#include<stdio.h>
#include<string.h>
int main(){
FILE *in;
int ascii;
int suma=0;
in=fopen("ulaz.txt", "r");
if(in==NULL){
printf("Ulazni fajl nije otvoren!");
return 1;
}
while(!feof(in)){
ascii=fgetc(in);
suma+=ascii;
printf("%c=\t%d\n",ascii, ascii);
//putc(fgetc(in), stdout);
}
printf("Suma svih znakova je: %d\n",suma);
fclose(in);
return 0;
}
89. /*U datoteci IMENIK.TXT nalaze se sledeci podaci: ime, prezime i broj telefona telefonskog
pretplatnika. Napisati program koji vrsi sortiranje imenika prema prezimenu pretplatnika i za
zadato prezime prikazuje telefonski broj pretplatnika na standardnom izlazu.*/

69
#include<stdio.h>
#include<string.h>
#define DIM 10
typedef struct telefonski_imenik{
char ime[10];
char prezime[20];
char broj[10];
};
void razmeni(struct telefonski_imenik *a, struct telefonski_imenik *b){
struct telefonski_imenik tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
void sort(struct telefonski_imenik niz[], int n){
int i, j;
for(i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(niz[i].prezime<niz[j].prezime)
razmeni(&niz[i], &niz[j]);
}
int main(){
struct telefonski_imenik nizImenik[DIM];
int n, i;
FILE *in;
char trazi[20];
in=fopen("imenik.txt", "r");
if(in==NULL){
printf("Ulazni fajl nije otvoren!");
return 1;
}
i=0;
while(!feof(in)){
fscanf(in, "%s%s%s", &nizImenik[i].ime, &nizImenik[i].prezime, &nizImenik[i].broj);
i++;
}
fflush(in);
n=i+1;
sort(nizImenik, n);
printf("\nTelefonski imenik sortiran po prezimenu pretplatnika je:\n\n");
for(i=0; i<n; i++)
printf("%s\t%s\t%s\n", nizImenik[i].prezime, nizImenik[i].ime, nizImenik[i].broj);
printf("Ukupan broj telefonskih pretplatnika je: %d\n",n);
printf("Zadati prezime pretplatnika: ");
scanf("%s", &trazi);
for(i=0; i<n; i++){
if(strcmp(nizImenik[i].prezime,trazi)==0){
printf("Broj telefoma trazenog pretplatnika je:\n");
printf("%s\t%s\t%s\n", nizImenik[i].prezime, nizImenik[i].ime,
nizImenik[i].broj);
}
}
fclose(in);
return 0;
}

90. /*Datoteka sadrzi proizvoljan broj tacaka u ravni predstavljenih (x, y) koordinatama. Napisati
program koji za ucitanu tacku odredjuje minimalno rastojanje od tacaka u navedenoj datoteci.*/
70
#include<stdio.h>
#include<math.h>
int main(){
FILE *in;
double rastojanje;
int x0, y0, x, y;
int brojacTacaka=0;
double minimalnoRastojanje;
int i;
double nizRastojanja[100];
in=fopen("tacke.txt", "r");
if(!in){
printf("Ulazna datoteka ne postoji!\n");
return 1;
}
printf("Uneti x i y koordinatu referentne tacke: ");
scanf("%d%d", &x0, &y0);
while(!feof(in)){
fscanf(in, "%d%d", &x, &y);
if(x0<x && y0<y)
rastojanje=sqrt(pow(x-x0, 2) + pow(y-y0, 2));
else if(x0>x && y0>y)
rastojanje=sqrt(pow(x0-x, 2) + pow(y0-y, 2));
else if(x0<x && y0>y)
rastojanje=sqrt(pow(x-x0, 2) + pow(y0-y, 2));
else if(x0>x && y0<y)
rastojanje=sqrt(pow(x0-x, 2) + pow(y-y0, 2));

nizRastojanja[brojacTacaka]=rastojanje;/*Rastojanje svake tacke od referentne pamtimo


u nizu*/
printf("Rastojanje od %d tacke je: %8.4le\n", brojacTacaka+1,
nizRastojanja[brojacTacaka]);
brojacTacaka++;
}
minimalnoRastojanje=nizRastojanja[0];/*Pretpostavimo da je minimalno rastojanje izmedju prve
tacke*/
for(i=0; i<brojacTacaka; i++){
if(nizRastojanja[i]<minimalnoRastojanje)
minimalnoRastojanje=nizRastojanja[i];
}
printf("Rastojanje najblize tacke od referentne je: %8.4le\n", minimalnoRastojanje);
fclose(in);
return 0;
}
91. /*Dodavanje novih zapisa u datoteku o stedisama*/ stednovi.c
#include<stdio.h>
typedef struct{char prezime[16], licno_ime[16];} Ime_i_prezime;
typedef struct{Ime_i_prezime ime; double stanje;} Stedisa;
void main(){
FILE *stednja;
Stedisa stedisa;
Stedisa prazno={0};
unsigned int sifra;
unsigned int veldat;
/*Otvaranje datoteka o stedisama*/

71
if ((stednja=fopen("stedise.dat","r+b"))==NULL)
/*Datoteka postoji, citanje broja zapisa u datoteci*/
fread(&veldat, sizeof veldat, 1, stednja);
else{
/*Datoteka ne postoji, stvaranje prezne datoteke*/
stednja=fopen("stedise.dat","w+b"); veldat=0;
fwrite(&veldat, sizeof veldat, 1, stednja);
}
/*Dodavanje zapisa o novim stedisama*/
while(1){
/*Citanje podataka o stedisi*/
printf("\nSifra stedise? "); scanf("%d",&sifra);
if(sifra==0) break; /*Zavrsetak programa*/
printf("Prezime stedise? ");
scanf("%s", stedisa.ime.prezime);
printf("Licno ime stedise? ");
scanf("%s", stedisa.ime.licno_ime);
stedisa.stanje=0;
/*Priprema za upisivanje podataka u datoteku*/
if(sifra>veldat){
/*Novi zapis je iza kraja datoteka, promena velicine datoteke*/
fseek(stednja, 0L, SEEK_END);
while(++veldat<sifra) fwrite(&prazno, sizeof prazno, 1, stednja);
veldat=sifra;
}else
/*Novi zapis je pre kraja datoteke, nalazenje njegovog mesta*/
fseek(stednja, (sizeof veldat)+(long) (sifra-1)*(sizeof stedisa),
SEEK_SET);
/*Upisivanje podataka u datoteku*/
fwrite(&stedisa, sizeof stedisa, 1, stednja);
rewind(stednja); fwrite(&veldat, sizeof veldat, 1, stednja);
}
}
92. /*Ispisivanje sadrzaja datoteke o stedisama*/ stedpisi.c

#include<stdio.h>
#include"stedisa.h"
typedef struct{char prezime[16], licno_ime[16];} Ime_i_prezime;
typedef struct{Ime_i_prezime ime; double stanje;} Stedisa;
void main(){
FILE*stednja;
Stedisa stedisa;
unsigned int sifra;
unsigned int veldat;
unsigned int i, k;
/*Otvaranje datoteke o stedisama*/
if((stednja=fopen("stedise.dat","r+b"))==NULL) exit(1);
fread(&veldat, sizeof veldat, 1, stednja);
/*Ispisivanje podataka o pojedinim stedisama*/
for(sifra=1;sifra<=veldat;sifra++){
/*Citanje sledeceg zapisa iz datoteke*/
printf("%3d", sifra);
fread(&stedisa, sizeof stedisa, 1, stednja);
72
if(stedisa.ime.prezime[0]!='\0'){
/*Prikaz podataka o postojecem stedisi*/
k=printf("%s%s", stedisa.ime.prezime, stedisa.ime.licno_ime);
for(i=k; i<34; i++) putchar(' ');
printf("%8.2f\n",stedisa.stanje);
}else
/*Prazan zapis, stedisa ne postoji*/
printf("***Ne postoji stedisa sa ovom sifrom***\n");
}
}
93. /*Azuriranje zapisa u datoteci o stedisama*/ stedazur.c

#include<stdio.h>
typedef struct{char prezime[16], licno_ime[16];} Ime_i_prezime;
typedef struct{Ime_i_prezime ime; double stanje;} Stedisa;
void main(){
FILE*stednja;
Stedisa stedisa;
unsigned int sifra;
unsigned int veldat;
double promena;
/*Otvaranje datoteke o stedisama*/
if((stednja=fopen ("stedise.dat", "r+b"))==NULL) exit(1);
fread(&veldat, sizeof veldat, 1, stednja);
/*Azuriranje stanja uloga pojedinih stedisa*/
while(1){
/*Citanje sifre sledeceg stedise za obradu*/
printf("\nSifra stedise?", " ");
scanf("%d",&sifra);
if(sifra==0)break;
if(sifra<=veldat){
/*Citanje zatecenih podataka o stedisi iz datoteke*/
fseek(stednja, (sizeof veldat)+(long)(sifra-1)*(sizeof stedisa),
SEEK_SET);
fread(&stedisa, sizeof stedisa, 1, stednja);
if(stedisa.ime.prezime[0]){
/*Prikazivanje zatecenih podataka o stedisi*/
printf("Stedisa=%s %s\n",stedisa.ime.prezime,
stedisa.ime.licno_ime);
printf("Staro stanje=%8.2f\n", stedisa.stanje);
/*Citanje promene stanja uloga*/
printf("Promena stanja? ");
scanf("%lf",&promena);
stedisa.stanje+=promena;
/*Upisivanje novog sadrzaja zapisa o stedisi u datoteku*/
fseek(stednja, -(long) (sizeof stedisa), SEEK_CUR);
fwrite(&stedisa, sizeof stedisa, 1, stednja);
}else
printf("***Ne postoji stedisa sa tom sifrom***\n");
}else
printf("***Ne postoji stedisa sa tom sifrom***\n");
}
}
73
74
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 1 - Okruženje Microsoft Visual Studio 2013

Microsoft Visual Studio 2013 predstavlja integrisano okruženje za razvoj softvera. Sastoji se od sledećih
celina:
 Visual C++,
 Visual Basic,
 Visual C#
 MSDN Library.
 Druge…
Visual studio C++ je okruženje koje omogućava razvoj i pisanje programa u programskom jeziku C++,
a samim tim i u programskom jeziku C.

Pokretanje Visual Studio 2013 okruženja


Okruženje Visual Studio 2013 se može otvoriti klikom na taster Start i izborom stavke Microsoft Visual
Studio 2013 iz liste programa. Nakon startovanja otvoriće se osnovi prozor okruženja Visual Studio
2013 koji je prikazan na slici 1.

Slika 1. Izgled osnovnog prozora po otvaranju Visual C++-a

Kreiranje projekta za konzolnu aplikaciju


Da bi se napisao, kompilirao, izvršio i eventualno debagirao C program, u Visual Studiju je
potrebno kreirati projekat koji sadrži odgovarajuće datoteke sa izvornim kodom programa. Za
potrebe pisanja programa u C-u biće korišćen najjednostavniji tip projekta koji obezbeđuje
pravljenje konzolnih aplikacija. Konzolne aplikacije su programi koji se izvršavaju u komandnom
(DOS) prozoru i koriste standardni ulaz i izlaz.
1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Kreiranje projekta se vrši startovanjem stavke iz menija File/New, izborom kartice Project i stavke
Visual C++ i zatim Win32 Console Application (slika 2).

Slika 2. Izgled prozora za kreiranje novog projekta

Pri kreiranju projekta potrebno je uneti naziv projekta u polje Project name, i eventualno promeniti
direktorijum na disku gde će projekat biti kreiran (polje Location). Po unosu naziva projekta aktiviraće
se taster OK. Klikom na ovaj taster pojaviće se prozor za izbor tipa konzolnog projekata koji se želi
kreirati (slika 4). U ovom slučaju ne treba ništa menjati jer je već odabrana opcija za kreiranje praznog
projekta (An empty project). Da bi se kreirao projekat potrebno je kliknuti na taster Finish. Ukoliko
želite možete klikunit i na dugme next. U tom slučaju će Vam biti prikazan sledeći prozor sa
dodatnim popcijama.

Slika 3. Izgled prozora za izbor tipa konzolnog projekta koji će biti kreiran

Kreiranje i dodavanje datoteka za izvorni kod programa


Nakon kreiranja praznog projekta za konzolnu aplikaciju potrebno je kreirati i dodati u projekat
datoteke koje će se koristiti za unos izvornog koda programa. U Vs2013 obično je za Vas već
kreiran fajl koji se zove isto kao vaš projekat. Ukoliko nije potrebno je kreirati i dodati datoteku na
sledeći način. Pozivate stavku iz menija File/New File i stavke Visual C++. Zatim možete izabrati

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
izmežu C++ File ili Header File (slika 4). Potrebno je uneti željeni naziv datoteke u polje File
name i kliknuti na taster OK.

Slika 4. Izgled prozora za kreiranje i dodavanje datoteka za izvorni kod programa

Po kreiranju i dodavanju nove datoteke u projekat potrebno je uneti odgovarajući sadržaj (ukucati
program). Za to se koristi centralni deo glavnog prozora (slika 5). Visual Studio poseduje neke napredne
opcije za prikaz izvornog koda programa kao što su bojenje ključnih reči i komentara.

Slika 5. Deo za unos i prikaz sadržaja datoteka sa izvornim kodom

Prikaz i otvaranje datoteka i funkcija koje projekat sadrži


Za prikaz datoteka koje su uključene u projekat koristi se panel sa leve strane osnovnog prozora
Visual C++-a. Ovaj panel sadrži dva kartice ClassView i Solution Explorer. Kartica Solution
Explorer omogućava pregled i otvaranje datoteka koje su dodate u projekat. Datoteke se grupisane
po tipu koji je određen eksenzijama (Source Files - *.cpp datoteke, Header Files - *.h datoteke).
Duplim klikom na naziv datoteke, sadržaj odgovarajuće datoteke će biti prikazan u centralnom delu
prozora Visual C++-a. Naziv datoteke koja je trenutno otvorena prikazan je u naslovnoj liniji
glavnog prozora.

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Kartica ClassView je izvorno namenjena za prikaz informacija o klasama definisanim u C++
programu. Kako programski jezik C ne podržava rad sa klasama u prikazu vezanom za ovu karticu
pobrojane su samo funkcije definisane u datotekama koje projekat sadrži. Duplim klikom na naziv
funkcije otvara se odgovarajuća datoteka i postavlja se na početak odgovarajuće funkcije. Na slici 6
ilustrovani su FileView i ClassView prikazi.

Slika 6. Prikaz datoteka i funkcija koje projekat sadrži

Kompiliranje programa i izveštaj o greškama


Nakon unosa koda programa u odgovarajuće datoteke moguće je izvršiti kompiliranje, povezivanje
i izvršavanje programa. U ovu svrhu se koriste stavke iz menija Build ili iz odgovarajuće prečice sa
alatima (vidi sliku 7).

Slika 7. Alati za kompiliranje programa


Najjednostavniji način za iniciranje procesa kompiliranja svih datoteka sa izvornim kodom,
kreiranje izvršne (EXE) datoteke programa i njeno startovanje je korišćenjem stavke
Build/Execute..., kombinacije tastera Ctrl+F5 sa tastature ili odgovarajuće prečice (ikonica "").
Ukoliko program nije prethodno preveden ili je izmenjen od vremena kada je poslednji put
preveden, pojaviće se prozor sa pitanjem da li treba izvršiti prevođenje (kompajliranje) programa. U
oba slučaja potrebno je kliknuti na dugme Yes nakon čega će uslediti kompiliranje i povezivanje
(linkovanje) izvršnog programa. Ukoliko je program uspešno preveden automatski će se izvršiti
njegovo startovanje, u suprotnom u donjem delu osnovnog prozora će biti prikazan izveštaj o
otkrivenim greškama (slika 8). Za svaku otkrivenu grešku ili upozorenje pored koda i opisa,
navedena je datoteka i linija koda u kojoj je greška nađena. na liniju sa opisom greške u ovom
izveštaju automatski se otvara odgovarajuća datoteka i vrši pozicioniranje kursora na problematičnu
liniju.

4
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Slika 8. Prikaz izveštaja o greškama i upozorenjima


Nakon ispravljanja greški potrebno je ponovo izvršiti startovanje procesa prevođenja i izvršenja
programa. Na slici 9 prikazan je prozor u kome se izvršava program. Nakon završetka izvršenja
programa biće ispisan tekst "Press any key to continue". Pritiskom na neki taster prozor u kome se
program izvršavao će biti zatvoren.

Slika 9. Izgled prozora u kome se izvršava program

Prekompajlirani hederi
Prekompajlirani hederi predstavljaju C i C++ heder fajlove koji se pre kompajliranja pripreme i
prebace u intermediate formu koju kompajler može brže da kompajliura. Ova forma se naziva još i
prekompajlirani heder.Korišćenje ovakvih hedera može skratiti vreme kompajliranja, naročito kada
se primeni na velike heder fajlove. Problem kompajliranja velikog broja uključenih fajlova postoji i
kod drugih programskih jezika i svaki od njih ga rešava na neki svoj način. Demonstrirajmo
primerom kako se to rešava u C++ jeziku. Uzmimo za primer dprojekat koji ima dodata dva fajla
heder fajl header.h i sors fajl source.cpp:
//header.hpp
...

//source.cpp
#include "header.hpp"
...
U slučaju da je opcija za prekompajlirane hedere uključena, kompajler će generisati prekompajlirani
heder fajl header.pch. Kada sledeći put budete kompajlirali fajlove, ukoliko se vreme zadnje
promene fajla header.h nije promenilo, računar će preskočiti kompajliranje i iskoristiti već postojeći
header.pch fajl. U suprotnom novi fajl heaader.pch će biti kreiran, a stari obrisan.

Prilikom korišćenja visual studia 2013 postoji fajl stdafx.h koji predstavlja prekompajlirani heder za sve one
biblioteke koje želite da uključite u vaš program, a koje se retko menjaju. To znači da sve include direktive
treba pisati u vom fajlu.

5
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Debagiranje programa
Pored sintaksnih grešaka koje se otkrivaju u toku prevođenja, program može da sadrži i logičke
greške koje sprečavaju da se izvršava na način koji je programer predvideo. Ovakve greške se
nazivaju bug-ovi, a proces njihovog uklanjanja debugging. Proces debagiranja podrazumeva
postavljanje prekidnih tačaka u kojima će se izvršenje programa privremeno prekinuti u cilju
očitavanja vrednosti pojedinih promenljivih i sl. Postavljanje (ili uklanjanje) prekidnih tačaka vrši
se pozicioniranjem kursora na odgovarajuću liniju i klikom na dugme u obliku šake (vidi sliku 11).
Druga varijanta za dodavanje (ili uklanjanje) prekidne tačke je desni klik na odgovarajuću
programsku liniju i izbor stavke Insert/Remove Brakepoint iz padajućeg menija. Za startovanje
izvršenja programa u ovom modu koristi se stavka iz menija Build/Start Debug/Go, taster F5 ili
odgovarajuća prečica iz linije sa alatima (vidi sliku 10).

Slika 10. Alati za debagiranje programa


Pri debagiranju, program će se izvršavati normalno sve dok se ne dođe do neke od zadatih
prekidnih tačaka. U tom trenutku se zaustavlja izvršenje i postaje aktivno okruženje Visual C++-a
prekonfigurisano za debagiranje. Na slici 11 prikazan je izgled okruženja u modu za debagiranje.

Slika 11. Okruženje za debagiranje programa

Za kontrolu izvršenja koriste se komande menija Debug. Značenja pojedinih komandi su sledeća:
 Go (taster F5) – nastavlja izvršenje do naredne prekidne tačke.
 Restart (kombinacija tastera Ctrl+Shift+F5) – resetuje izvršenje programa u modu za
6
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
debagiranje.
 Stop Debugging (kombinacija tastera Shift+F5) – prekida debagiranje programa.
 Step Into (taster F11) – ulazi u funkciju koja čeka na izvršenje. Ukoliko je u pitanju neka
druga naredba izvršava je i prelazi na narednu liniju u kodu.
 Step Over (taster F10) – izvršava funkciju ili naredbu i prelazi na narednu liniju u kodu.
 Step Out (kombinacija tastera Shift+F11) – izvršava tekuću funkciju do kraja i izlazi na nivo iz
koga je pozvana.
 Run to Cursor (kombinacija tastera Ctrl+F10) – izvršava program do linije koda na koju
ukazuje položaj kursora.
Po zaustavljanju izvršenja moguće je očitati vrednosti pojedinih promenljivih i prikaz konteksta
(funkcija) iz kojeg se došlo do prekidne tačke. Očitavanje vrednosti promenljivih se može izvršiti
na nekoliko načina:
1. Zadržati pokazivač miša iznad naziva promenljive negde u kodu, što će rezultovati ispisivanjem
vrednosti pored pokazivača.
2. Dodavanjem naziva promenljive čije se praćenje želi u panelu Watch (desno ispod koda).
3. Direktno, ukoliko je promenljiva automatski izlistana u spisku promenljivih koje se trenutno
koriste (panel levo ispod koda).

7
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 1: Napisati i pokrenuti program.
void main()
{
printf("Moj prvi program u C jeziku\n");
}

Zadatak 2: Napisati i pokrenuti program.


void main()
{
int razlika;
razlika = 100 -90;
printf("Razlika 100 -90= %d\ n", razlika);
}

Zadatak 3:Napisati i izvršiti program. Probajte da debagirate program.


void main()
{
int zbir = 0;
int i;
for (i=0; i<10; i++)
{
zbir = zbir + i;
printf("i=%d zbir=%d\n", i, zbir);
}
printf("\nzbir=%d\n", zbir);
}

Zadatak 4:Nacrtati algoritam za sledeće zadatke:


A. Sastaviti dijagram toka i napisati program kojim se izračunava vrednost funkcije:
 x, x2

y   2, 2  x  3 .
x  1, x  3

B. Nacrtati algoritam koji štampa vaše ime 1000 puta.
C. Nacrtati algoritam koji računa N5
D. Nacrtati algoritam koji računa Nx

8
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 2 – Tipovi Podataka, naredba scanf, printf, operatori


Osnovne definicije
 Promenljiva (Variable) – ime ili referenca na zapmćenu vrednost (obično u memoriji)
 Tip podatka (Data type) – određuje veličinu promenljive u memoriji, koje vrednosti ona može da uzme, i koje
operacije su za ovu promnljivu dozvoljene
 Operator (Operator) – operacija koja se obavlja sa jednom do tri promenljive
 Izraz (Expression) – kombinacija litralnih vrednosti i promenljivih sa operacijma ili funkcijama
 Opseg važenja (Scope) – deo programa u kome je ime nekog entiteta (promenljive ili funkcije) validno i može
se iskorititi za pristup tom entitetu

Osnovni tipovi podataka i deklaracija podataka

Osnovni opsezi i veličina podataka razlikuju se od računara do računara i uglavnom zavise od arhitekture procesora.

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Konverzioni znaci za različite tipove podataka
\Konverzacioni znak Opis
%c Jedan karakter znakovnog tipa
%d Označeni ceo broj
%e Broj u pokretnom zarezu, e -notacija
%E Broj u pokretnom zarezu, E -notacija
%f Broj u pokretnom zarezu, decimalna not.
%i Označeni ceo broj
%X Neoznačeni heksadecimalni broj (A do F)
%x Neoznačeni heksadecimalni broj (a do f)
%s Karakterni niz

ESCAPE KARAKTERI
Escape karakteri se koriste za definisanje nekih specijalnih znakova koje inače nije moguće napisati u string konstantama.
Ovo je lista specijalnih znakova:
Escape sequence Description Representation
\' single quote byte 0x27
\" double quote byte 0x22
\? question mark byte 0x3f
\\ backslash byte 0x5c
\0 null character byte 0x00
\a audible bell byte 0x07
\b backspace byte 0x08
\f form feed - new page byte 0x0c
\n line feed - new line byte 0x0a
\r carriage return byte 0x0d
\t horizontal tab byte 0x09
\v vertical tab byte 0x0b

OPERATORI
U programskom jeziku C direktno je moguća primena osnovnih matematičkih operatora +, -, *, / i operatora koji ne
postoje u drugim programskim jezicima: inkrement i dekrement. Ostale matematičke operatore možemo uključiti iz skupa
datoteka zaglavlja koji sadrži datoteku <math.h> i koja se po potrebi u procesu strukturnog programiranja uključuje u
izvorni program naredbom #include .
Aritmetički operatori u C jeziku Komentar
Dodela vrednosti (=)
Aritmetički operatori (+, -, *, /, % )
Inkrement (++) Efekti primene izraza su različiti
Dekrement (--) Efekti primene izraza su različiti
+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=
Relacioni operatori ( ==, !=, >, <, >=, <= ) Koristimo ih kod logičkih izraza (npr. IF naredbe)
Logički operatori ( !, &&, || ) Za povezivanje više logičkih izraza
Uslovni operator (uslov ? iz1; iz2) a>b ? a : b
Operatori nad bitovima ( &, |, ^, ~, <<, >> )
sizeof(data_type) x = sizeof (char);
cast operator int i; float f = 3.14; i = (int) f;
Direktiva #include <stdio.h> u zaglavlju programa - uključuje stdio.h biblioteku koja je deo paketa C kompajlera i sadrži
informacije o ulazno/izlaznim funkcijama za računar. Naziv potiče od STanDard Imput/Output.

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Prioritet Operatora
U sledećoj tabeli možete naći operatore u C jeziku od najvećeg ka najmanjem prioritetu:
Level Precedence group Operator Description Grouping
1 Scope :: scope qualifier Left-to-right
++ -- postfix increment / decrement
() functional forms
2 Postfix (unary) Left-to-right
[] subscript
. -> member access
++ -- prefix increment / decrement
~! bitwise NOT / logical NOT
+- unary prefix
3 Prefix (unary) &* reference / dereference Right-to-left
new delete allocation / deallocation
sizeof parameter pack
(type) C-style type-casting
4 Pointer-to-member .* ->* access pointer Left-to-right
5 Arithmetic: scaling */% multiply, divide, modulo Left-to-right
6 Arithmetic: addition +- addition, subtraction Left-to-right
7 Bitwise shift << >> shift left, shift right Left-to-right
8 Relational < > <= >= comparison operators Left-to-right
9 Equality == != equality / inequality Left-to-right
10 And & bitwise AND Left-to-right
11 Exclusive or ^ bitwise XOR Left-to-right
12 Inclusive or | bitwise OR Left-to-right
13 Conjunction && logical AND Left-to-right
14 Disjunction || logical OR Left-to-right
= *= /= %= += -=
assignment / compound assignment
15 Assignment-level expressions >>= <<= &= ^= |= Right-to-left
?: conditional operator
16 Sequencing , comma separator Left-to-right

Zadatak 1. Sastaviti program na programskom jeziku C za upotrebu specifikatora konverzije u odnosu na


očekivane vrednosti celobrojnih promenljivih.
#include <stdio.h>
void main()
{
unsigned neoznacen = -39000;
printf ("neoznacen = %u, i nije %d\n", neoznacen,neoznacen);
printf ("Characters: %c %c \n", 'a', 65);
printf ("Decimals: %d %ld\n", 1977, 650000L);
printf ("Preceding with blanks: %10d \n", 1977);
printf ("Preceding with zeros: %010d \n", 1977);
printf ("Some different radices: %d %x %o %#x %#o \n", 100, 100, 100, 100,
100);
printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
printf ("Width trick: %*d \n", 5, 10);
printf ("%s \n", "A string");
}
Napisati izlaz iz programa i prokomentarisati rezultat tamo gde je potrebno:

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 2. Sastaviti program na programskom jeziku C za formatiranje ulaza u pokretnom zarezu.
void main()
{
/* deklaracija podataka */
float f_pro;
double d_pro;
/*dodela vrednosti*/
f_pro = 106,11;
d_pro = -0,0000654;
/*štampanje vrednosti promenljivih */
printf ("Promenljiva f_pro=%2f\n", f_pro);
printf ("Promenljiva d_pro=%.11f\n", d_pro);
printf ("Promenljiva f_pro=%e\n", f_pro);
printf ("Promenljiva d_pro=%G\n", d_pro) ;
}

Izlaz iz programa je:

Zadatak 3. Sastaviti program na programskom jeziku C za unos proizvoljnog karaktera i za štampanje ASCII
koda tog karaktera.
#include<stdio.h>
void main()
{
char ch;
printf("Unesite proizvoljan karakter.\n");
scanf("%c",&ch); /*naredba za unos podataka*/
printf("ASCII kod unetog karaktera %c je %d\n",ch,ch);
}
Prepišite izlaz iz programa:

Zadatak 4. Napisati program na C jeziku za štampanje dva cela broja x i y u kao i njihovog inkrementa i
dekrementa koristeći prefiksni i postfiksni operator.
Napomena: Operator inkrementa se koristi da bi se povećala vrednost promenljive za jedan. Operator dekrementa se
koristi da bi se smanjila vrednost promenljive za jedan. Pravila po kojima se primenjuje postfiksni i prefiksni zapis
operatora dekrementa na celobrojne promenljive i izraze su potpuno analogna pravilima upotrebe operatora inkrementa i
mogu se sagledati iz navedenog primera.
void main()
{
int x,y;
x=10; y=10;
printf("Vrednost izraza ++x je %d\n",++x);
printf("Vrednost izraza y++ je %d\n",y++);
printf("Nakon inkrementiranja vrednost za x je %d\n",x);
printf("Nakon inkrementiranja vrednost za y je %d\n",y);
printf("Vrednost izraza --x je %d\n",--x);
printf("Vrednost izraza y-- je %d\n",y--);
printf("Nakon dekrementiranja vrednost za x je %d\n",x);
printf("Nakon dekrementiranja vrednost za y je %d\n",y);
}

4
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Upisati rezultate rada programa i objasniti razliku između prefiksnog i postfiksnog operatora:

Zadatak 5. Šta označavaju vitičaste zagrade u jeziku C? Zašto koristimo ove zagrade pri definiciji main (ili bilo
koje druge ) funkcije

Zadarak 6. Opišite razliku između 7,”7”,’7’?

Zadatak 7. Napišite vrednosti sledećih izraza na osnovu tablice prioriteta operatora:


1. ( (5 == 5) && (3 > 6) )
2. ( (5 == 5) || (3 > 6) )
3. a=2; b=7; c = (a>b) ? a : b; Koliko je c?
4. a=2, b=7, a += 3 + b, b=1; Koliko je a i b?
5. a=2, b=7, a += 3 + b, b=1; Koliko je a i b?
1.
2.
3.
4.

5
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 3 –If naredba, predprocesorske direkltive, scanf

Predprocesorske direktive
Preprocessor directives are lines included in the code of programs preceded by a hash sign (#). These lines are not program
statements but directives for the preprocessor. The preprocessor examines the code before actual compilation of code
begins and resolves all these directives before any code is actually generated by regular statements.

These preprocessor directives extend only across a single line of code. As soon as a newline character is found, the
preprocessor directive is ends. No semicolon (;) is expected at the end of a preprocessor directive. The only way a
preprocessor directive can extend through more than one line is by preceding the newline character at the end of the line
by a backslash (\).
#define TABLE_SIZE 100

Zadatak 1: Napišite logički izraz kojim možete da proverite da li je uneti karakter c:


 Malo slovo (Answer: c>=’a’&& c<=’z’ )
 Veliko slovo (Answer: c>=’A’&& c<=’Z’ )
 cifra (Answer: c>=’0’&& c<=’9’ )
 beli znak (uključujući blanko, tab I novi red) (Answer: c==’\n’|| c==’\t’|| c==’’ )

Zadatak 2: Sastaviti program na programskom jeziku C za upotrebu funkcije rand() kojom se uključuje generator
slučajnih brojeva i štampa celobrojni slučajni broj i njegova dvostruka vrednost. Štampati i slučajan borj između 0 i
9. Štmpati slučajan broj između 10 i 19.

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void main()
{
int slucajan, dvostruki, x, y;
srand (time(NULL)); /* initialize random seed: */

slucajan = rand();
dvostruki = slucajan*2;
x = rand() % 10; /*slucajan izmedju 0 i 9*/
y = rand() % 10 + 10; /*slucajan izmedju 10 i 19*/
printf("Slucajan broj je %d\n", slucajan);
printf("Dvostruki slucajan broj je %d\n", dvostruki);
printf("Jos neki slucajni brojevi %d, \t %d \n", x, y);
}
Prepišite izlaz iz programa. Funkcija rand() je deo koje biblioteke?

Zadatak 3: Proveriti upravljačku strukturu if naredbe:

#include <stdio.h>
void main()

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

{
int x, y, z; x = 10; y= 3; z = ( x / y ) * y;
if (x == z)
{ printf ( "Vrednosti x-a i z-a su jednake\n");
printf ( "Vrednost x-a je %d\n", x );
printf ( "Vrednost z-a je %d\n", z );
}
if ( x <= z)
{ printf ("Vrednost x-a je < ili = od vredriosti z-a\n");
printf( "Vrednost x-a je %d\n", x );
printf( "Vrednost z-a je %d\n", z );
}
if ( x >= z)
{ printf ( "Vrednost x-a je > ili = od vredriosti z-a\n" );
printf ( "Vrednost x-a je %d\n", x );
printf ( "Vrednost z-a je %d\n", z );
}
}

Prepisati rezultat:

Zadatak 4: Napisati program na C jeziku za rešavanje kvadratne jednačine x2 + x - 2 = 0 korišćenjem


obrasca:
 b  b 2  4ac
x1, 2 
2a
i štampanje vrednosti za x1 i x2.

#include<stdio.h>
#include<math.h>
void main()
{
double a,b,c;
double x1,x2,pom;
a = 1; b = 1; c = -2;
pom = sqrt(b*b-4*a*c);
x1 = ( (-b) + pom ) / 2 * a;
x2 = ( (-b) - pom ) / 2 * a;
printf("Vrednost prvog korena x1 = %f\n",x1);
printf("Vrednost drugog korena x2 = %f\n",x2);
}

Opisati rezultate rada programa :

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 5: Napisati isti program ali u opštem obliku kada se veličine a, b i c učitavaju sa tastature.
Napisati izvorni kod programa:

Zadatak 6: Napisati program na C jeziku za izračunavanje ukamaćene vrednosti ako je poznata mesečna
kamatna stopa, period oročavanja u mesecima i iznos glavnice. Štampati dobijene rezultate i proveriti
matematičku postavku programa.

Napomena: Koristiti pow funkciju iz biblioteke math.h koja izračunava x na y. Kamata se računa kao glavnica *
(1+kamata/100)period.
#include <stdio.h>
#include <math.h>
void main( )
{
double stopa, period, glavnica;
printf( "Unesite mesecnu kamatnu stopu: " ) ;
scanf( "%lf", &stopa ) ; /* ulaz u pokretnom zarezu */
/* konverzija u procente */
stopa = stopa / 100.0;
printf( "Unesite glavnicu: " );
scanf( "%lf", &glavnica );
printf( "Unesite vreme orocavanja u mesecima: " );
scanf( "%lf", &period ) ;
printf( "Ukamacena vrednost je = %.2f\n",
glavnica * pow( (1.0+stopa), period));
}
Proveriti izlaz iz programa za sledeće vrednosti: Kamatna stopa: 1, glvnica: 100, oročavnje: 3 meseca. Koliko će
iznositi krajnja vrednost?

Zadatak 7: Objasnite zašto su ovi izrazi netačni:


a) #include <stdio.h>;

b) int main(int arg1){ return arg1-1 }

c) int 2nd value=10;

d) #define MESSAGE = "Happy new year!"


printf("%s",MESSAGE);

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 4 – for petlja, while petlja, makroi

For petlja

ulaz

izraz 1

izraz 3

T
izraz 2 naredba

N
izlaz

Upravljačke informacije kod for petlje, za razliku od while petlje, su smeštene na jednom mestu i to na vrhu iteracije.
Petlja for je definisana, što znači da unapred znamo koliko puta će petlja da se izvrši, a njena osnovna konstrukcija je:
 Inicijalizacija – inicijalizacije vrednosti brojača. i = 0
 Uslov – na primer upoređenje brojača sa graničnom vrednošću. i < 10
 Inkrementirnje – ažuriranje brojača pri svakoj iteraciji. i ++
Prema tome, opšti oblik naredbe for je: for ( izraz1, izraz2, izraz3 )
naredba
uz napomenu da neki od izraza u for petlji može ostati prazan i tada se za taj izraz smatra da ima vrednost true..

Zadatak 1 Napisati program na C jeziku za prikaz neparnih brojeva manjih ili jednakih 20 korišćenjem for petlje.

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

While petlja
Ulaz

T
izraz naredba

Izlaz

Upravljačku strukturu while karakterišu četiri osobine:


 petlja se ponavlja sve dok izraz koji se testira ne postane netačan ( logička 0 );
 petlja je sa ulaznim uslovom : odluka o još jednom prolasku kroz telo petlje se donosi pre izvršenja naredbi petlje;
 while petlja mora sadr`avati promenu vrednosti izraza tako da postane la`an posle odre|enog broja iteracija, kako
petlja ne bi postala beskonačna;
 jedna naredba se posmatra kao deo upravljačke strukture while petlje, bilo ona prosta ili složena.

Zadatak 2. Napisati program na C jeziku za izračunavanje zbira celih brojeva upotrebom while petlje.
Izračunavanje se prekida kada se unese ‘0’;
void main()
{
long sum = 0L;
int num;
printf("Unesite broj za sumiranje Ili 0 za izlaz\n");
scanf("%ld", &num);
while (num != 0)
{
sum = sum+num;
printf("Unesite naredni broj za sabiranj ili 0 za quite :::::::: %d \n ", num);
scanf("%ld", &num);
}
printf("Zbir unetih brojeva je %ld.\n", sum);
}

Upisati rezultate rada programa :

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 3. Napisati program u C jeziku za permutovanje cifara celog broja - while iskaz: (npr. 54321 u 12345 )
Postupak: celi broj 54321 delimo po modulu 10 - rezultat je 1
celi broj 54321 delimo sa 10 - rezultat je 5432
celi broj 5432 delimo po modulu 10 - rezultat je 2
celi broj 5432 delimo sa 10 - rezultat je 543
celi broj 543 delimo po modulu 10 - rezultat je 3
celi broj 543 delimo sa 10 - rezultat je 54
celi broj 54 delimo po modulu 10 - rezultat je 4
celi broj 54 delimo sa 10 - rezultat je 5
celi broj 5 delimo po modulu 10 - rezultat je 5
Petlja se prekida jer broj postaje nula !!!

#include <stdio.h>
void main()
{
int broj;
printf("Ukucajte ceo broj ? ");
scanf("%d", &broj );
printf("Permutovani broj je ");
while ( broj )
{
printf("%d", broj % 10);
broj = broj/10;
}
printf("\n");
}

Rezultat za uneti broj 8612 je:

Zadatak 4. Napisati program na C jeziku za određivanje srednje vrednosti n celih pozitivnih brojeva –pomoću
while petlje. Testirati program za vrednosti n=4, brojevi su redom 34.345, 234.2876, 45.98, 453.32. Koliki je
rezultat?

Zadatak 5. Razmotrite izraz : double ans = 18.0/squared(2+1). Izračunati vrednost izraza ako je funkcija makro
squared() definisana kao:
A. #define squared(x) x*x

B. #define squared(x) (x*x)

C. #define squared(x) (x)*(x)

D. #define squared(x) ((x)*(x))

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 6. Napisati algoritam na programskom jeziku C koji vrednosti 3 promenljive rotira za k mesta u levo.
Vrednosti promenljivih i vrednost promenljive k zadaje korisnik. Prikazati vrednost promenljivih nakon rotacije.

Zadatak 7 Šta je mrtva petlja?Napisati primer mrtve petlje za for i while naredbe i objasniti.

4
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 5 – do while petlja, switch case

Petlja sa ulaznim uslovom do while


U slučaju do while petlje obavezno izvršavanje bar jedne iteracije se postiže tako što je upravljački
izraz petlje na samom dnu petlje. Tako se uslov petlje proverava nakon izvršenih naredbi tela petlje.
Strukturni dijagram toka može se prikazati kao:

ulaz

naredba

T
izraz

izlaz

Zadatak 1. Napisati program za izrašunavanje n! primenom do while structure:

Rešenje:
#include <stdio.h>
void main() /* Program za izracunavanje faktorijela */
{
int i, fak;
long n ;
i = 1; n = 1;
printf("lzracunavanje n!\nUkucajte broj ? ");
scanf("%d", &fak);
do{
n *= i;
i++;
} while (i <= fak);
printf("%d! = %ld\n", fak,n);
}

Koliko puta se izvrši naredba n *= i. Napisati isti program koristeći samo for petlju:

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Bezuslovno grananje : naredbe break i continue


Prekid izvršenja naredbi tela petlje se može realizovati i pre nego što uslovni izraz dobije logičku netačnu
vrednost. Naredba kojom je moguće realizovati iskakanje iz upravljaške strukture se realizuje korišćenjem kljušne reši
break. Ova naredba inicira sledeća dva procesa:
 Prekid izvršenja naredbi tela petlje u upravljaškim strukturama while, for i do while iskakanjem iz tela petlje.
Programski tok se nastavlja neposredno na prvoj naredbi iza naredbe upravljačke strukture.
 Preskakanje preostalih naredbi unutar višestrukog grananja, koje se ostvaruju naredbom switch,

Prekid izvršenja trenutnog ciklusa petlja, preskakanja svih ostalih naredbi i prelazak na sledeću iteraciju sa
obavlja naredbom continue.

Naredba višestrukog grananja – Switch Case


Naredba višestrukog grananja je ekvivlentna upotrei naredbe if then else if. Koristi se kada vrednost nekog izraza može
imati više od dve vrednosti. Sintaksa narede je:
switch (promenljiva)
{
case literarna vrednost: naredba; break;
case literarna vrednost: naredba; break;
case literarna vrednost: naredba; break;
default nardba; break;
}

Zadatak 2. Primer programa u kome se koristi naredba break u kombinaciji sa naredbom switch za
izračunavanje broja samoglasnika u delu proizvoljnog teksta:

void main()
{
char ch;
int a_ct,e_ct,i_ct,o_ct,u_ct;
a_ct=e_ct=i_ct=o_ct=u_ct=0;
printf("Unesi priozvoljan tekst; Unesi # za izlaz.\n");
while((ch=getchar())!= '#')
{
switch (ch)
{
case 'a' : a_ct++; break;
case 'A' : a_ct++; break;
case 'e' : e_ct++; break;
case 'E' : e_ct++; break;
case 'i' : i_ct++; break;
case 'I' : i_ct++; break;
case 'o' : o_ct++; break;
case 'O' : o_ct++; break;
case 'u' : u_ct++; break;
case 'U' : u_ct++; break;
default: break;
} /* kraj switch */
} /* dok petlji nije kraj */
printf("Broj samoglasnika: A E I O U\n");
printf("%4d %4d %4d %4d %4d\n", a_ct,e_ct,i_ct,o_ct,u_ct);
}

Izlaz iz programa je:

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 3. Sastaviti program na C jeziku za rešavanje sistema linearnih jednačina primenom Kramerovog
pravila:
1   
x1  , x2  2 , x3  3 ,    , xn  n
   
i praktično rešiti sistem jednačina:
x1 + x2 + 2x3 = 9
4x1 - x2 + 3x3 = 11
-2x1 + 2x2 + x3 = 5
1 1 2 9 1 2 1 9 2 1 1 9
gde je :   4  1 3 , 1  11  1 3 ,  2  4 11 3 , 3  4  1 11
2 2 1 5 2 1 2 5 1 2 2 5
void main()
{
int x1, x2, x3; int a1, a2, a3; int b1, b2, b3;
int c1, c2, c3; int r1, r2, r3;

scanf("%d %d %d %d", &a1, &b1, &c1, &r1);


scanf("%d %d %d %d", &a2, &b2, &c2, &r2);
scanf("%d %d %d %d", &a3, &b3, &c3, &r3);

int d = a1*b2*c3 + a2*b3*c1 + a3*b1*c2 - c1*b2*a3 - c2*b3*a1 - c3*b1*a2;


int d1 = r1*b2*c3 + r2*b3*c1 + r3*b1*c2 - c1*b2*r3 - c2*b3*r1 - c3*b1*r2;
int d2 = a1*r2*c3 + a2*r3*c1 + a3*r1*c2 - c1*r2*a3 - c2*r3*a1 - c3*r1*a2;
int d3 = a1*b2*r3 + a2*b3*r1 + a3*b1*r2 - r1*b2*a3 - r2*b3*a1 - r3*b1*a2;

x1 = d1/d; x2 = d2/d; x3 = d3/d;

printf ("determinante: %d %d %d %d", d, d1, d2, d3);


printf ("\npromenljive: %d %d %d\n", x1, x2, x3);
}
Proveriti rešenja ovog sistema linearnih jednačina. Rešenje treba da bude: x1=1, x2=2 i x3=3.

Zadatak 4. For petlja i do while petlja se mogu transformisati u while petlju. Transformišite sledeće primere
a) Primer 1: Prevesti dati izraz koristeći while petlju:
int i , ret = 1;
for ( i = 2; i <= n; i++)
ret ∗= i ;

b) Primer 2: Prevesti dati izraz koristeći for petlju


int i=1; int z = 0;
do {
z = z + i;
i++;
}
while (i <= 10 );

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

c) Primer 3: Prevesti dati izraz koristeći while petlju


int i=1;
int z = 0;
do
{
z = z + i;
i++;
while (i <= 10 );
}
return n;
}

Zadatak 5. Napisati program sa menijem:


1- Program matematika
2- Program finansija
3- Program zabave
4- Exit
upotrebom naredbe switch i case. Korisnik unosi broj od 1 do 4. Nakon unosa program štampa ime
odabrane opcije i nudi mogućnost za novi izbor sve dok se ne izabere opcija 4 (Exit).

4
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 6 –Funkcije
1. Potprogrami i struktura programa

Potprogrami predstavljaju mehanizam koji direktno podržava funkcionalnu dekompoziciju kao jednu od
osnovnih metoda strukturnog programiranja. Oni su samostalni segmenti programskog koda koji se pozivaju radi
obavljanja konkretno specificiranog zadatka. Potprogram može biti neograničeno puta pozivan iz istog ili u okviru
različitih programa. Programski jezik C sadrži module (biblioteke) u kojima se nalaze grupe deklaracija promenljivih i
deklaracija potprograma kao jedinice fizičke dekompozicije. Ovakav pristup za direktnu posledicu ima stvaranje opštih
programskih rešenja i mogućnost višestrukog korišćenja istog programskog koda u različitim softverskim proizvodima.
Svaki podprogram se sastoji od:
 Deklaracije kojom se definiše interfejs potprograma prema programu, koja uključuje ime potprograma, listu
parametara koja ne mora biti neprazna i opciono tip vraćene vrednosti
 Tela potprograma koje se sastoji od deklaracija i naredbi.

Postoje dva tipa potprograma:


 FUNKCIJA: je segment programskog koda koji na osnovu nijednog, jednog ili više argumenata, uvek daje
kao rezultat jednu tačno određenu vrednost koja se naziva vrednost funkcije.

 PROCEDURA:je tip potprograma koji takođe može prihvatiti nijednu, jednu ili više vrednosti u obliku
argumenata. Na osnovu prihvaćene vrednosti rezultat procedure može biti nijedna ili više vrednosti.
Programski jezik c ne podržava kreiranje procedura.

Rezervisana reč void se koristi kao oznaka za povratnu vrednost kada funkcija ne vraća ništa.

Definicija funkcije u opštem slučaju ima sledeći oblik:


povratni_tip ime_funkcije ( lista_argumenata )
{
naredba
naredba

return ime_promenljive
}

Izvršavanje se može prekinuti naredbama return ili exit.

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatrak 1 Poziv funkcija bez argumenata


#include <stdio.h>
#define IME "Visa tehnicka skola"
#define ADRESA "Beogradska 20"
#define MESTO "18000 Nis"
#define LIMIT 65
void zvezde(); /* deklaracija funkcije bez argumenata */

void main()
{
zvezde(); /* poziv korisnicke funkcije */
printf("%s \n",IME); /*poziv funkcije iz standardne biblioteke*/
printf("%s \n",ADRESA);
printf("%s \n",MESTO);
zvezde();
}

/*definicija korisnickih funkcija*/


void zvezde() /*potprogramska funkcija nema argumenata*/
{
int brojac;
for ( brojac=1; brojac <= LIMIT; brojac++)
printf("%c",'*');
printf("\n");
}

1.1 Sagledati tok glavnog programa i potprograma i utvrditi u kojoj programskoj liniji nastaju "tačke prekida"
glavnog program i kada se kontrola prebacuje na izvršavanje potprograma.

1.2 Šta označava ključna reč void?

1.3 Zašto je neophodno prvo deklarisati funkciju zvezde()? Šta bi se desilo da nismo deklarisali funkciju? Da li je
moguće napisati funkciju tako da se deklaracija i definicija funkcije obave zajedno? Kako?

1.4 Koristeći isti program umesto konstanti IME, ADRESA i MESTO uneti vase podatke. Kompajlirati,
linkovati i izvršiti ovako modifikovan program.

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 2. Poziv funkcija sa 2 argumenata: Sastaviti program na C jeziku za izračunavanje minimuma dva cela
broja. U glavnom programu obezbediti štampanje oba broja i njihovog minimum. Potprogramu treba kao
parameter da primi dva broja i da vrati manji od njih.
#include<stdio.h>
int imin ( int n, int m); // Deklaracija funkcije

void main() /* glavni program */


{
int broj1, broj2, vrati, rez;
printf("Unesite 2 proizvoljna broja: \n");
vrati=scanf("%d %d",&broj1,&broj2);
rez = imin(broj1,broj2);
if (vrati == 2)
{
printf("Manji od %d i %d je %d\n",broj1,broj2, imin(broj1,broj2));
printf("Manji od %d i %d je %d\n",broj1,broj2, rez);
}
}

int imin( int n, int m ) /* potprogram – definicija funkcije */


{
int min;
if (n<m)
min=n;
else
min=m;
return min;
}

2.1 Šta vraća funkcija scanf?

2.2 Obajsnite sledeću naredbu: printf("Manji od %d i %d je %d\n",broj1,broj2, imin(broj1,broj2));

Zadatak 3. Sastaviti program korišćenjem struktura IF...THEN....ELSE IF za izračunavanje funkcije y. U


glavnom programu obezbediti štampanje rezultata, a u potprogramu definisati vrednosti funkcije po datim
uslovima. Brojevi su integer tipa.
x1+x2, x1<x2
y= x1*x2, x1=x2
x1-x2, x1>x2
Napisati program:

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 4. Napisati program za izračunavanje hipotenuze pravouglog trougla. U glavnom program izvršiti unos
vrednosti prve i druge katete i štampati vrednost hipotenuze. U potprogramu izračunati vrednost hipotenuze.

Zadatak 5. Sastaviti program za prenos argumenata pozivom po vrednosti.


#include <stdio.h>
void promeni(int u, int v)
{ int temp;
printf("U funkciji originalne vrednosti su: u = %d a v= %d.\n", u, v);
temp=u;
u=v;
v=temp;
printf("U funkciji nakon promene vrednosti su: u = %d a v= %d.\n", u, v);
}

void main ( )
{ int x = 5, y = 10;
printf("U programu oriqinalne vrednosti: x = %d a y = %d.\n", x, y);
promeni(x,y);
printf("U programu nakon poziva funkcije je: x = %d a y = %d.\n", x, y);
}
4
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

5.1 Napisati reaultate rada programa. Zašto promenljive x i y nisu zamenile vrednosti u glavnom program, a
jesu unutar funkcije? Izmeniti i napisati kod programa funkcije promeni tako da promenljive x i y zamene mesta
i u glvnom programu. Problem možete rešiti pomoću pokazivača ili referenci.

5
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 7 –Nizovi

1. Izvedeni tipovi podataka - nizovi


Niz je homogena struktura u kojoj su svi objekti istog tipa. Objekti u nizu se nazivaju elementi niza. Tip niza
predstavlja implicitnu konsekvencu tipa svojih elemenata. Korišćenjem indeksa u nizu se veoma lako pretražuju
homogeni tipovi podataka, vrši se njihovo sortiranje ili prestruktuiranje elemenata na neki drugi način. Nizovi mogu biti:
nizovi celih, nizovi realnih brojeva, nizovi pokazivača, nizovi karaktera, nizovi objekata itd.
Opšti oblik deklaracije niza je: tip_podatka ime_niza [veličina]

2. Pokazivači
Pokazivač je promenljiva koja sadrži adresu objekta ili funkcije. Rad sa pokazivačkim promenljivama je veoma
teško razumeti bez razumevanja koncepta indirekcije, odnosno koncepta posrednog pristupa. Objekti programskog
rešenja se uvek memorišu u određenom programskom bloku, i to na tačno određenoj memorijskoj lokaciji. Pokazivači

omogućuju indirektni pristup vrednostima programskih promenljivih korišćenjem njihovih memorijskih adresa. U
neposrednoj vezi sa pokazivačima su dva specijalna operatora programskog jezika.operator adresa-od u oznaci & je
operator koji daje memorijsku adresu objekta na koga je primenjen; posredni operator * je operator kojim se upravlja
memorijskim lokacijama u pokazivačkim promenljivama.
Adresni operator & je unarni operator vrlo visokog prioriteta, Što je slučaj i sa ostalim unarnim operatorima.
Ovaj operator predstavlja način da se sazna memorijska lokacija gde je taj objekat smešten u memoriji računara.
Asocijativnost ovog unarnog operatora je s desna na levo, a opseg vrednosti koji može da ima je skup nenegativnih celih
brojeva (unsigned int). Operator indirekcije * omogućava deklarisanje pokazivačke promenljive i indirektni pristup do
vrednosti za koje su korišćene pokazivačke promenljive. U razvoju programskih rešenja se vrlo često informacija o
memorijskoj adresi promenljive ili funkcije čuva i kasnije koristi. Za implementaciju ovog koncepta je neophodno
obezbediti mesto u memoriji gde se smešta informacija o adresi programskog objekta, koju dobijamo deklarisanjem
pokazivačke promenljive. Paradigma pokazivačkih promenljivih u C jeziku bi izgledala:

Pokazivači se često koriste u sprezi sa nizovima kako bi se lakše dolazilo do određenog člana niza što predstavlja
adekvatnu upotrebu aritmetičkih operacija nad pokazivačima. Dozvoljene operacije su sabiranje i oduzimanje celobrojnih
podataka, dodela vrednosti jednog pokazivača drugom, poređenje dva pokazivača, poređenje pokazivača i nule kao
celobrojne vrednosti, oduzimanje vrednosti pokazivača istog tipa.

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Deklaracija Niza
Svaki niz mora biti deklarisan pre nego što se može koristiti:
type variable_name[lengthofarray];

Ilustrujmo to primerima:
double height[10]; float width[20]; int min[9]; char name[20];

U C jeziku elemnti niza počinju od pozicije (indeksa) 0. Elementi niza se nalaze ne susednim memoriskim lokacijama.
Samo ime niza ustvari predstavlja pokazivač na memorisku lokaciju prvog elemnta niza. Zato je moguće pristupiti bilo
kom elementu niza navođenjem odgovarajućeg indeksa tog elementa:
m=height[0];

U prethonom primeru promenljiva m će dobiti vrednost prvog elementa niza height.

Inicijalizacija Niza
Inicijalizacija niza predstavlja dodelu inicijalne vrednosti svim njegovim članovima. Sledeći kod ilustruje deklaraciju i
inicijalizaciju niza:
int myArray[5] = {1, 2, 3, 4, 5}; //istovremena deklaracija i inicijalizacija
int studentAge[4]; studentAge[0]=14; studentAge[1]=13;
studentAge[2]=15; studentAge[3]=16;

Dinamička deklaracija niza


Nizove je moguće deklarisati:
 statički – u statičkom delu memorije ili steku
 dinamički – u dinamičkom delu memorije ili heap-u
O dinamičkom alociranju memorije ćemo dettljnije učiti na kursu programski jezici II.

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

1. Zadatak 1. Napisati program za unos i izračunavanje zbira članova niza sa 5 elemenata.


void main(void)
{
float broj[5]; //deklaracija niza
double rez = 0; int i; //pomocne promenljive

for(i=0; i < 5; i++) //uzmi podatke i smesti ih u broj


{
printf("Unesite broj %d : ", i+1);
scanf("%f", &broj[i] );
}

for(i = 4; i+1 ; i--) //saberi


rez += broj[i];

printf("Zbir unesenih brojeva je %lf \n", rez); //prikazi rezultat


}

1.1 Testirajte program. Navedite unešene vrednosti za niz i rezultat:

1.2 Deklarisati niz od 4 elemenata tipa char i inicijalizovati sve članove niza na vrednost ‘a’. Ilustrovati oba na;ina
inicijalizacije:

1.3 Dodeliti vednost ‚m‘ drugom i cetvrtom elemntu niza.

1.4 Šta će se desiti ukoliko pokušamo da petom elemntu ovog niza dodelimo vrednost ‘m’

Zadatak 2. Napisati program kojim se određuje redni broj maksimalnog elementa u celobrojnom nizu X od N
elemenata.
Rešenje:
start

N, (X(I), I=1,N)

IMAX=1

I=2,N

X(IMAX)<X(I) ne
da
IMAX=I

(X(I),I=1,N)

IMAX,X(IMAX)

kraj

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 3. Primer prenosa argumenata funkcije pokazivačkim promenljivim za realizaciju sabiranja članova
niza.
#include <stdio.h>
#define VELIC 10
long sump(int *pok, int vel);

void main()
{
static int niz[VELIC] = {20,10,5,39,4,16,19,26,31,20};
long odgovor;
odgovor = sump(niz, VELIC);
printf("Suma niza je: %ld.\n", odgovor);
}

long sump(int *ar, int n) /* koristi pokazivacku aritmetiku */


{
int i ;
long ukupno = 0;
for(i = 0; i < n; i++) {
ukupno += *ar; /* dodaje vrednost na ukupno */
ar++; /* pomera pokazivac na sledeci elemenat */
}
return ukupno;
}
Rezultat ovog programa je:

Zadatak 4. Napisati program za štampanje niza i množenje elemenata niza konstantnom vrednošću.
#include <stdio.h>
#define VELICINA 5

void main()
{
double dip[VELICINA] = {20.0, 17.66, 8.2, 15.3, 22.22};
int i;
for(i = 0; i < VELICINA; i++)
dip[i] *= mnozi;

printf("\n");
for(i = 0; i < n; i++)
printf("%8.3f ", dip[i]);
printf ("\n");
}

Napisati rezultate rada programa:

4
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 4.1. Izmeniti kod iz prethodnog zadatka tako da se svaki element niza uveća (umesto pomnoži) za neku
konstantnu vrednost koja se unosi sa tastature.

Zadatak 4.2 Izmeniti kod iz prethodnog zadatka tako da se štampanje niza i množenje niza obavi u potprogramu.

5
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 5. Razmotriti rad programa pisanog u C programskom jeziku, koji sortira dati vektor ar =
{7,3,9,2,11,20,17,19,6,4} korišćenjem metode "bubble sort" algoritma. Program se najpre sastoji u pisanju
funkcije "swap" koja vrši zamenu vrednosti dve promenljive i smešta ih u dve memorijske lokacije. Zatim tu
funkciju koristimo da bi izvršili sortiranje datog vektora. "Bubble sort" ispituje svake dve ćelije vektora i ako nisu
sortirane - svapuje ih. Ako se obezbedi upoređenje i svapovanje n-1 put nad svim ćelijama vektora, on će biti
kompletno sortiran.

#include <stdio.h>
void swap (int *a, int *b);

void main()
{
int ar[10] = {7, 3, 9, 2, 11, 20, 17, 19, 6, 4};
int i,j,n;

printf("Vektor pre sortiranja:\n");


for(i=0;i<10;i++)
printf("ar[%d]=%d\n",i,ar[i]);

n=10; /*broj clanova u vektoru koji se sortira*/


for(i=0;i<n-1;i++)
for(j=0;j<n-1;j++)
{
if(ar[j]>ar[j+1])
swap(&ar[j],&ar[j+1]);
}

printf("\nVektor posle sortiranja:\n");


for(i=0;i<10;i++)
printf("ar[%d]=%d\n",i,ar[i]);
}

void swap ( int *a,int *b)


{
int temp;
temp=*a;
*a=*b;
*b=temp;
}

Prepisati rezultate rada programa:

6
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

Zadatak 6: Napisati program u programskom jeziku C koji određuje broj elemenata niza koji se javljaju samo
jednom.

Zadatak 7: Napisati program u programskom jeziku C koji za dva uneta niza A i B proverava da li ovi nizovi
imaju zajedničkih elemenata. Ukoliko zajednički elementi postoje, od njih se formira novi niz C i na kraju
zadataka štampa na standardni izlaz.

Primer A = { 1, 2, 3 ,4 ,5}; B = {2, 7, 4, 9, 8};


U ovom slučaju C će biti {2, 4};

7
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 8 – Znakovni nizovi


Zadatak 1. Sastaviti program na programskom jeziku C za ispisivanje tablice ASCII kodova za sve štampajuće
znake.
ASCII kod sa brojem 32 je blanko simbol ili razmak. Prvih 32 ASCII kodova i svi ASCII kodovi veći ili
jednaki 127 predstavljaju specijalne simbole koji se koriste u različite svrhe i najčešće nemaju neko jasno slovno
značenje. Koristili su se za iscrtavanje DOS prozora, i na taj način simulirali grafiku u tekstualnom režimu rada.
Konkretno prozori razvojnog okruženja Turbo C su napravljeni na ovaj način. ASCII kodovi između 33 i 126 su
štampajući znaci.
Znaci se prikazuju po kolonama. U jednoj koloni se prikazuje po 19 znakova, a u jednom redu se prikazuje po
5 znakova (5x19=95). Prikazaćemo sve ASCII kodove od 32 do 126.

#include <stdio.h>
void main()
{
char c=' ';
int i;

printf ("\t\tTablica ASCII kodova \n \n");


for (i=0; i<95; i++)
printf("%3d %c ",c+i,c+i);
if (i%19 == 0)
printf("\n");
}
1.1 Koji je kod za karaktere ‘a’, ‘A’, ‘#’?

Zadatak 2 Poređati sledeći niz naredbi u odgovarajući redosled tako da program odštampa jednostavnu poruku
“Ja s am student prve godine”
1. return 0;
2. const char msg[] = MSG1;
3. }
4. #define MSG1 "All your base are belong to us!"
5. int main(void){
6. #include <stdio.h>
7. puts(msg);

Zadatak 3. Unos i štampanje karaktera


Program učitava i broji karaktere sa ulaza sve dok se ne otkuca znak za kraj unosa EOF. EOF se može generisati
kucanjem Control + Z, a zatim enter.
#include <stdio.h>
void main()
{
int ch, i = 0;
while((ch = getchar()) != EOF)
i ++;
printf("%d\n", i);
}
3.1 Šta je EOF? U kom fajlu (biblioteci) je ona definisana? Pronadjite kolika je njena celorojna vrednost:

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 4. Sastaviti program koji iz skupa unetih karaktera (na primer: ’’Ja sam rodjen 1990. god u 12. mesecu,
i u petak!’’) izračunava broj unetih slova, brojeva i ostalih karaktera. Tekst se unosi sa tastature, a program se
prekida pritiskom na ctrl+Z, a zatim enter.

Zadatak 5. Napisati program konvertuje velika u mala slova. Recenica se unosi sa tastature a program se prekid
unošenjem karaktera %.

5.1 Koju celobronu vredsnot imaju znakovi ‘a’, ‘A’ i ‘#’?

Zadatak 6 Napisati program na programskom jeziku C koji učitava dva znakovna niza, čije se dužine unose kao
podatak sa tastature, izvrši nadovezivanje drugog na prvi, okrene “naopako“ dobijeni niz i ispiše ga na
standardnom izlaznom uređaju. Znakovni nizovi su maksimalne dužine 200 karaktera.

6.1 Da li je moguće deklariati niz sledećim izrazom int niz[n], gde je n neka promenljiva. Zašto?

6.2 Napisati primer unetih vrednosta za niz i dobijeni rezultat.

6.3 Napisati koje još naredbe znate za rad sa nizovima i kratko objanisiti šta rade:

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
6.4 Da li je moguće promeniti veličinu već deklarisnaog niza. Zašto?

Zadatak 7. Sastaviti program na jeziku C za učitavanje imena gradova uz njihovo uređivanje po abecednom
redosledu i ispisivanje rezultata. U svakom redu se učitava po jedno ime sve dok se ne učita prazan red.
Program:

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 9 –Matrice

Multidimenzijalni nizovi
U C jeziku mogu postojati i višedimenzijalni nizovi. Probajmo da to ilustrujemo primerom jedne matrice dimenzija 4 x
5:

Column numbers (j)


0 1 2 3 4
Row
0 11 3 5 -9 -6
number
1 5 6 -8 7 24
(i)
2 -8 9 2 12 45
3 10 13 -10 4 5

Neka je ime naše matrice X. Za pristup elemntu matrice mramo da koristimo dva indeksa, jedan za red a drugi za vrstu
matrice. Izraz bi u ovom slučaju izgledao X [i] [j], gde je i indeks reda, a j indeks kolone. To znači da bi X [0] [0]
referencirao vrednost 10, X [2] [1] referencira vrednost 9. Ukratko, multidimenzijalni nizovi se definišu na isiti način
kao i obični nizovi samo što korite veći broj indeksa za pristup svojim elementima. Mi ćemo za sada raditi samo sa
dvodimenzijalnim nizovima. Deklarisanje ovakvog niza se može uraditi ovako:
float table [50] [50];
char line [24] [40];

Prvi primer definiše matricu (dvodimenzionalni niz) float vednosti koja ima 50 vrsta i 50 kolona. To znači da će ukupan
broj elementata biti 50x50=2500. Drugi primer deklariše matricu char elemenat sa 24 vrsta i 40 kolona. Ukupan broj
elemenata je 24 x 40 = 1920 elemenata.

Pokažimo još jedan primer matrice 3 x 4 sa vrednostima {1, 2, 3, 4, 5, 6, 7, 8, 9, 10. 11, 12, };
Values [0] [0] = 1 Values [0] [1] = 2 Values [0] [2] = 3 Values [0] [3] = 4
Values [1] [0] = 5 Values [1] [1] = 6 Values [1] [2] = 7 Values [1] [3] = 8
Values [2] [0] = 9 Values [2] [1] = 10 Values [2] [2] = 11 Values [2] [3] = 12

Prvi indeks označava vrstu a drugi kolonu. Prvi indeks može uzeti vrednosti od 0 do 2 što ukupno čini 3 vrst. Drugi
indeks može uzeti vrednosti od 0 do 3 što ukupno čini 4 kolone. Ova matrica se može deklarisati i inicijalizovti i na
sledeći način:
int values [3] [4] = {
{ 1, 2, 3, 4 }
{ 5, 6, 7, 8 }
{ 9, 10, 11, 12 }
};

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 1. Sastaviti program na programskom jeziku C koji štampa sadržaj kvadratne matrice 5 * 5 vrstu po
vrstu, a potom sporednu dijagonalu, sleva-udesno. Matricu formirati generatorom slučajnih brojeva RAND()
#include <stdio.h>
void main()
{
int a[5][5], n, i, j;
for (i=0; i<5; i++)
{
/*alocira memoriju za n elemenata vrste koji su tipa int*/
for (j=0; j<5; j++)
a[i][j] = rand()%10;
}

for (i=0; i<5; printf("\n"), i++)


for (j=0; j<5; j++)
printf(" %d", a[i][j]);
printf("\n");

for (i=4; i>=0; i--)


printf(" %d", *(*(a+i)+5-1-i));
printf("\n");
}

Prepisati rezultate rada programa. Napisati na drugi način izraz printf(" %d", *(*(a+i)+5-1-i)).

Zadatak 2. Neka je data kvadratna matrica u formatu:


1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Članove matrice uneti u program kao konstantne celobrojne veličine, a kao izlaz iz programa predvideti
štampanje ove matrice u pokazanom formatu kao polazne matrice i štampanje nove matrice u istom obliku ali
sada unazad od člana a44,a43,a42a41,......,a11.
void main()
{
int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j;
printf("\nPolazna matrica je\n");
for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
printf("%2d ",mat[i][j]);
printf("\n");
}

printf("\nNova matrica je\n");


for(i=3;i>=0; i--)
{
for(j=3;j>=0; j--)
printf("%2d ",mat[i][j]);
printf("\n");
}
}

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Napisati rezultate rada programa:
ulazni nizovi: obrnuti izlazni niz

Zadatak 3. Napisati program na C++ jeziku koji izračunava sumu svih elemenata u svakom redu pojedinačno,
pravougaone matrice [4x4].
1 2 3 4
5 6 7 8
A=
9 10 11 12
13 14 15 16
void main()
{
int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j,s=0;

printf("\nPolazna matrica je\n");


for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
printf("%2d ",mat[i][j]);
printf("\n");
}

for(i=0;i<4; i++)
{
printf("\nSuma %d reda je:",i+1);
for(j=0;j<4; j++)
s=s+mat[i][j];
printf("%2d\n",s);
s=0;
}
}
Napisati rezultat rada programa:

Zadatak 4. Napisati program na C jeziku koji će izračunati sumu elemenata na glavnoj dijgonali proizvoljne
marice dimenzija 5x5.

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I

VEŽBA 10 –Rad sa fajlovima

Upis i čitanje iz fajla


U drugoj laboratoriskoj vežbi smo učili kako da izvršimo upis sa standardnog ulaza, odnosno ispis na standardni izlaz u
programskom jeziku C. U ovoj vežbi ćemo naučiti kako da creiramo, otvorimo, upišemo, pročitamo i zatvorimo
tekstualni ili binanrni fajl.

Otvaranje fajla
Za otvaranje fajlova se koristi funkcija fopen. Svaki fajl se mora otvoriti pre korišćenja i zatvoriti nakon korišćenja
kako bi sve promene na fajlu bile zapamćene. Ukoliko fajl ne postoji ova funkcija će ga kreirati, otvoriti, inicijalizovati
objekat tipa FILE, koji sadrži sve informacije neophodne za kontrolu toka (stream) podataka. Pogledaj mo deklaraciju
ove funkcije:
FILE *fopen( const char * filename, const char * mode );
U ovom primeru filename je string literal i predstavlja putanju i ime fajla. Mode predstavlja pristupni mod i može imati
sledeće vrednosti:

Mod Opis

r Otvara trenutni tekstualni fajl kako bi se izvršilo čitanje.

Otvara tekstualni fajl kako bi se izvršio upis. Ako fajl ne postoji , novi fajl će biti kreiran i program
w
če izvršiti upis na početak fajla.

Otvara tekstualni fajl za upis. Ako fajl ne postoji novi fajl će biti kreiran. Upis će izvršiti dodavanje
a
sadržaja na već postojeći sadržaj fajla.

r+ Otvara tekstualni fajl za čitanje i pisanje.

Otvara tekstualni fajl za čitanje i pisanje. Sav sadržaj fajla se briše. Ukoliko fajl ne postoji kreira
w+
se novi fajl.

Otvara teksualni fajl za čitanje i pisanje. Kreira fajl ukoliko ne postoji. Čitanje će početi na
a+
početku fajla, ali pisanje će izvršiti dodavanje sadržaja na kraju fajla.
Ukoliko želite da koristite binarne fajlove onda morate koristiti sledeće modove:
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"

Zatvaranje fajla
Za zatvaranje fajla koristite funkciju fclose(). Deklaracija ove funkcije je:
int fclose( FILE *fp );
Ova funkcija vraća nulu ukoliko je poziv uspešan ili EOF ukoliko postoji greška pri zatvaranju fajla. Ova funkcija
ustvari prazni bafer koji se koristi za rad sa fajlom, zatvara fajl i oslobađa memoriju koja se koristila za fajl. EOF je
konstanta definisana u zaglavlju stdio.h fajla i najčešće ima vrednost -1.

Upis u fajl
Najjednostavnija funkcija za upis jednog karaktera u fajl je:
int fputc( int c, FILE *fp );
Ova funkcija vrši upis jednog karaktera koji ima vreedsnot c na tok podataka referenciran sa fp. U našem primeru fp će
referencirati neki fajl. Funkcija će prilikom upisa izvršiti internu konverziju karaktera u tip unsigned char. Funkcija
vraća karakter koji je upisan u slučaju da je funkcija uspešno izvršena, u suprotnom vraća EOF.

Sledeća funkcija se moće koristiti za upis null-termineted stringa:


int fputs( const char *s, FILE *fp );
Ova funkcija vrši upis stringa s u tok podataka referenciran sa fp. Ukoliko je funkcija upešno izvršena vraća se neka
nenegativna vrednost. U slučaju greške vraća se EOF. Moćete koristiti i funkciju int fprintf(FILE *fp,const char
*format, ...) za upis jednog stringa u fajl.Ilustrujmo to primerom:

1
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 1: Primer upisa u fajl.
#include <stdio.h>
void main()
{
FILE *fp;

fp = fopen("test.txt", "w+");
fprintf(fp, "This is testing for fprintf...\n");
fputs("This is testing for fputs...\n", fp);
fclose(fp);
}
1.1 Šta će se desiti ukoliko fajl "test.txt" ne posotji?

1.2 Gde će se ovaj fajl kreirati? Zašto?

1.3 Šta bi se desilo da je pristupni mod bio a+?

1.4 Kojoj biblioteci (fajlu) pripadaju funkcije

Čitanje fajla
Sledeća funkcija vrši čitanje jednog karaktera u fajl:
int fgetc( FILE * fp );
Funkcija fgets() vrši čitanje jednog karaktera iz toka podataka referenciranog sa fp. Povratna vrednost funkcije je
pročitani karakter ukoliko je ona uspešna. Ukoliko je došlo do greške funkcija će vratiti EOF.

Sledeća funkcija omogućava čitanje stringa iz ulaznog toka podataka:


char *fgets( char *buf, int n, FILE *fp );
Funkcija fgets() čita do n-1 karaktera sa ulaznog toka podataka referenciranog sa fp. Ona kopira pročitani string u bafer
buf i dodaje null karkater kako bi završila string. Ako ova funkcija pročita karakter za novi red '\n' ili karakter za kraj
fajla EOF pre nego što je pročitala svih n-1 karaktera ona će prekinuti dalje čitanje podataka. Zadnji karakter koji će
vratiti će biti znak za novi red.

Za čitanje stringa se može koristiti i funkcija int fscanf(FILE *fp, const char *format, ...). Ona će prekinuti čitanje
nakon prvog blanko znaka. Ukoiko je uspena funkcija će vratiti broj argumenata koji su pročitani. Na primer funkcija
fscanf(fp, "%s %s", ime, prezime); će vratiti vrednost 2 ukoliko je uspešna ili EOF ako je neuspešna.
Ilustrujmo ovo primerom:

Zadatak 2: Primer čitanja iz fajla:


void main()
{
FILE *fp;
char buff[255];
fp = fopen("test.txt", "r");
fscanf(fp, "%s", buff);
printf("1 : %s\n", buff );

fgets(buff, 255, (FILE*)fp);


printf("2: %s\n", buff );

fgets(buff, 255, (FILE*)fp);


printf("3: %s\n", buff );
fclose(fp);
}
2.1 Šta radi prethofni zadatak i šta će on ispisati na ekranu:

2
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 3: Fajlovi zad4.txt sadrži podatke o poenima koje su studenti osvojili na ispitu iz predmeta programski
jezici 1. Za svakog studenta je zapamćen broj poena koje je student dobio na ispitu. Odštampati imena svih
studenata koji su položili ispit. Ispit su položili svi studenti koji imaju više od 50 poena. Listu odštampati na
standardni ulaz i u fajl rezultati.txt. Primer fajla zad4.txt je:
Pera Peric 30
Ivana Stojicic 65
Marko Knezevic 45
Milutin Milankovic 80
void main()
{
FILE *fp, *fpr;
char ime[20], prezime[20];
int i=1, rez=0, r1=0, r3=0;
fp = fopen("zad3.txt", "r");
fpr = fopen("rez.txt", "w");
while (fscanf(fp, "%s", ime) != EOF)
{
r1 = fscanf(fp, "%s", prezime);
r3 = fscanf(fp, "%d", &rez);

if (rez >= 50)


{
printf("%d: %s %s %d \n", i, ime, prezime, rez);
fprintf(fpr, "%d: %s %s %d \n", i, ime, prezime, rez);
// printf("%d: %d %d \n", i, r1, r3 );
i++;
}
}
fclose(fp);
}

3.1 Gde se nalazi datoteka rez.txt i koji je njen sadržaj nakon izvršenja programa?

3.2 Zašto se u naredbi fscanf(fp, "%s", prezime); promenljiva prezime koristi bez operatora referenciranja &, a
promenljiva rez u naredbi fscanf(fp, "%d", &rez) se koristi sa ovim operatorom?

3.3 Da li možete da napišete program tako da se sve tri promenljive ime, prezime i rez čitaju odjednom?
Dovoljno je napisati samo deo koda koji se razlikuje od trenutnog rešenja. Koliku će vrednost u tom slučaju
vratiti funkcija fscanf?

3
Visoka tehnička škola strukovnih studija u Nišu
Laboratorijske vežbe iz Programskih jezika I
Zadatak 4: Fajl zad4.txt sadrži odlomak jednog našeg poznatog romana. Tokom kucanja odlomka greškom je
umesto slova “lj” kucano slovo q i umesto slova “nj”, slovo w . Izvršiti ispravku grešaka pri kucanju ovog
odlomka i unete ispravke upisati u fajl rez4.txt. Izbrojati koliko je izmena ukupno bilo. Primer sadržaja fajla
zad4.txt je: “Vesti o qubicastom cvetu qiqanu mozete naci na wegovm blogu”. Napisati program, šta štampa program na
standardni izlaz i sadržaj fajla rez4.txt nakon izvršenja programa.

4
PRIMERI PROGRAMA ZA PRIPREMU PRVOG
KOLOKVIJUMA
/* abs funkcija za PRIMER APSOLUTNE VREDNOSTI CELOG BROJA */

#include <stdio.h>
#include <math.h>

int main(void)
{
int number = -1234;

printf("broj: %d ima apsolutnu vrednost: %d\n", number, abs(number));


return 0;
}

/* exp funkcija za IZRAČUNAVANJE BROJA e NA REALNI STEPEN */

#include <stdio.h>
#include <math.h>

int main(void)
{
double result;
double x = 4.0;

result = exp(x);
printf("'e' dignuto na stepen %lf (e ^ %lf) = %lf\n",
x, x, result);

return 0;
}
/* log funkcija za PRIMER LOGARITMA REALNOG BROJA */

#include <math.h>
#include <stdio.h>

int main(void)
{
double result;
double x = 8.6872;

result = log(x);
printf("Prirodni logaritam %lf je %lf\n", x, result);

return 0;
}

/* sin funkcija za PRIMER IZRAČUNAVANJA SINUSA REALNOG BROJA */

#include <stdio.h>
#include <math.h>

int main(void)
{
double result, x = 0.5;

result = sin(x);
printf("Sinus od %lf je %lf\n", x, result);
return 0;
}

/* poly funkcija za PRIMER IZRAČUNAVANJA VREDNOSTI POLINOMA */

#include <stdio.h>
#include <math.h>
/*program za resavanje vrednosyi polinoma*/
/* polynomial: x**3 - 2x**2 + 5x - 1 */

int main(void)
{
double array[] = { -1.0, 5.0, -2.0, 1.0};
double result;
result = poly(2.0, 3, array);
printf("Polinom: x**3 - 2.0x**2 + 5x - 1 na 2.0 je %lf\n", result);
return 0;
}

/* pow funkcija za PRIMER IZRAČUNAVANJA REALNOG BROJA NA STEPEN */

#include <math.h>
#include <stdio.h>

int main(void)
{
double x = 2.0, y = 3.0;

printf("%lf na stepen %lf je %lf\n", x, y, pow(x, y));


return 0;
}

/* pow funkcija za PRIMER IZRAČUNAVANJA n-tog KORENA REALNOG BROJA */

#include <math.h>
#include <stdio.h>

float main(void)
{int n=5;
double x = 32.0,rezultat;
rezultat=pow(x,1./n);
printf("%d_ti koren broja %lf je: %lf\n",n, x,rezultat);
return 0;
}

NAPOMENA: u opštem slučaju rezultat = n x m = pow ( x , m . / n)

/* sqrt funkcija kao PRIMER IZRACUNAVANJA KVADRATNOG KORENA REALNOG BROJA */

#include <math.h>
#include <stdio.h>

int main(void)
{
double x = 4.0, resultat;
resultat = sqrt(x);
printf("KVADRATNI KOREN %lf JE %lf\n", x, resultat);
return 0;
}

/* log10 funkcija za PRIMER LOGARITMA ZA OSNOVU 10 REALNOG BROJA */

#include <math.h>
#include <stdio.h>

int main(void)
{
double result;
double x = 800.6872;

result = log10(x);
printf("LOGARITAM BROJA %lf JE %lf\n", x, result);

return 0;
}

/* rand funkcija za PRIMER GENERISANJA SLUCAJNIH BROJEVA */

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
int i;
printf("Deset slucajnih brojeva od 0 do 99 su:\n\n");
for(i=0; i<10; i++)
printf("%d\n", rand() % 100);
return 0;
}
Napisati program za generisanje slučajnog broja, izračunati njegovu dvostruku vrednost i prikazati sledeći
slučajni broj.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void main()
{
int slucajan, dvostruki;
slucajan = rand();
dvostruki = slucajan*2;
printf("Slucajan broj je %d\n", slucajan);
printf("Dvostruki slucajan broj je %d\n", dvostruki);
printf("Naredni slucajan broj je %d\n", rand());
}

/* Rad sa specijalnim karakterima */


#include <stdio.h>
int main(void)
{printf("Alert: zvucni ili vizuelni signal \a\n");
printf("Alert: NESTO SE CUJE \n");
printf("Alert: PONOVO zvucni ili vizuelni signal \a\n");
printf("Po\bvratnik ili b\backspace: sakrij me\b \n");
printf("Form feed. \f\n");
printf ("Horizontalni\ttab\n");
return 0;}
vezba 1-2
/*Stampanje vrednosti stepena Farenhajta i Celzijusa pocev od 0 do 300 sa korakom 20 */
#include <stdio.h>
int main(void)
{
float fahr, celsius; /*vrednosti stepena Celzijusa, Farenhajta*/
int lower, upper, step; /* donja vrednost skale - lower, gornja vrednost skale -upper, korak skaliranja */
/*inicijalizacije*/
lower = 0;
upper = 300;
step = 20;
/*stampanje zaglavlja "tabele" */
printf("F C\n\n");
/*stampanje vrednosti stepena pocev
od 0 do 300 sa korakom 20 */
fahr = lower;
while(fahr <= upper)
{
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f %6.1f\n", fahr, celsius);
fahr = fahr + step;
}
return 0;
}
vezba 1-3
obrnuto

#include <stdio.h>

/* print Fahrenheit-Celsius table */


int
main()
{
int fahr;

for (fahr = 300; fahr >= 0; fahr = fahr - 20)


printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));

return 0;
}
Primer za štampanje rezultata množenja (od 1*1 do 9*9 u redovima po 9 ).

#include<stdio.h>
void main()
{
int i,j;
for(i=1;i<10;i++)
{
for(j=1;j<10;j++)
printf("%3d",i*j);
printf("\n");
}
}

Određivanje znaka unetog broja

#include<stdio.h>
void main()
{
int n;
printf("Unesi ceo broj: ");
scanf("%d",&n);
if(n>=0)
printf("Broj je pozitivan !\n");
if(n<0)
printf("Broj je negativan !\n");
}

Drugi način sa if alse strukturom :

#include<stdio.h>
void main()
{
int n;
printf("Unesi ceo broj: ");
scanf("%d",&n);
if(n>=0)
printf("Broj je pozitivan !\n");
else
printf("Broj je negativan !\n");
}

Napisati program za rešavanje kvadratne jednačine ax2+bx+c=0.

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void main()
{
float delta,a,b,c,x1,x2;
printf("Unesite a : ");
scanf("%f",&a);
printf("Unesite b : ");
scanf("%f",&b);
printf("Unesite c : ");
scanf("%f",&c);
delta=b*b-(4*a*c);
printf("Podkorena velicina delta je:%f",delta);
if(delta<0)
{
printf("Jednacina nema resenja !\n");
exit(0);
}
if(delta==0)
{
x1=-b/(2*a);
printf("E Jednacina ima dva ista resenja !\n");
printf("x1=x2=%f",x1);
exit (0);
}

x1=(-b+sqrt(delta))/(2*a);
x2=(-b-sqrt(delta))/(2*a);

printf("\nResenja jednacine su:");


printf("\nX1=%f",x1);
printf("\nX2=%f\n",x2);
}
Napisati program sa menijem:

1- Program matematika
2- Program finansija
3- Program zabave
4- Exit

upotrebom while naredbe i if, else if strukture za startovanje svih stavki iz menija.

#include<stdio.h>
#include<stdlib.h>
void main()
{
int choice;

while(1)
{
printf("\n\nMeni:\n");
printf("1- Program matematika\n2- Program finansija\n");
printf("3- Program zabave\n4- Exit");
printf("\n\nVas izbor -> ");
scanf("%d",&choice);

if(choice==1)
printf("\nProgram matematika Runs. !");
else if(choice==2)
printf("\nProgram finansija Runs. !");
else if(choice==3)
printf("\nProgram zabave Runs. !");
else if(choice==4)
{
printf("\nKraj programa!.\n");
exit(0);
}
else
printf("\nPogresan izbor");
}
}
Isti zadatak samo upotrebom naredbe switch i case.

#include<stdio.h>
#include<stdlib.h>
void main()
{
int choice;

while(1)
{
printf("\n\nMeni:\n");
printf("1- Program matematika\n2- Program finansija\n");
printf("3- Program zabave\n4- Exit");
printf("\n\nVas izbor -> ");
scanf("%d",&choice);

switch(choice)
{ case 1 :
printf("\nProgram matematika Runs. !");
break;
case 2 :
printf("\nProgram finansija Runs. !");
break;
case 3 :
printf("\nProgram zabave Runs. !");
break;
case 4 :
{
printf("\nKraj programa!.\n");
exit(0);
}
default:
printf("\nPogresan izbor");
}
}}

x 2 ⋅ sin( x ) − 1
Napisati program za izračunavanje funkcije y = 3
.
x
#include <stdio.h>
#include <math.h>
void main()
{
double x,y,pom;
printf("Unesite broj\n");
scanf("%lf",&x);
pom=pow(x,1./3.);
y=(x*x*sin(x)-1)/pom;
printf("Vrednost izraza je %lf a vrednost korena %lf\n",y,pom);
}
//Operator inkrementa
#include <stdio.h>
void main()
{
int x, y;
x = 10;
y =10;
printf("Vrednost izraza ++x je %d\n", ++x);
printf("Vrednost izraza y++ je %d\n", y++);
printf{"Nakon inkrementiranja vrednost x-a je %d\n",x);
printf{"Nakon inkrementiranja vrednost y-a je %d\n", y);
}

//Operator dekrementa
#include <stdio.h>
void main()
{
int x, y;
x = 10;
y = 10;
printf( "Vrednost izraza --x je %d\n", --x);
printf( "Vrednost izraza y-- je %d\n", y--) ;
printf( "Nakon dekrementiranja vrednost x-a je %d\n",x);
printf( "Nakon dekrementiranja vrednost y-a je %d\n", y);
}
//Operator dodeljivanja
#include <stdio.h>
void main()
{
int x, y;
x = 6;
y = 6;
if ( x = 7)
{
printf( " Prvi <if> je zadovoljen\n" );
}
else
{
printf( " Prvi <if> nije zadovoljen\n" );
}
if ( y == 7 )
{
printf( " Drugi <if> je zadovoljen\n" );
}
else
printf( " Drugi <if> nije zadovoljen\n" );
}

//Relacioni izrazi i logicki operatori


#include <stdio.h>
void main()
{
int minimum,maximum;
int prl, pr2;
minimum=10;
maximum = 1000;
prl = 110;
pr2 = 1123;
if( (prl < maximum && prl > minimum) || (pr2 < maximum && pr2 > minimum) )
printf( "Najmanje jedna vrednost je u opsegu\n" );
if( (prl < maximum && prl > minimum) && (pr2 < maximum && pr2 > minimum) )
{
printf( "Obe vrednosti su u opsegu\n" ) ;
}
}
//Poziv funkcije stdio.h i primena kod izlaznog tipa promenljive.
#include <stdio.h>
void main()
{
float n1=3.0;
double n2=3.0;
long n3=2000000000;
long n4=1234567890;
printf("%.le, %.le, %ld, %ld\n", n1,n2,n3,n4);
printf("%ld, %ld\n", n3, n4);
printf("%f, %f, %ld, %ld\n", n1,n2,n3,n4);
}

//Obracun kamata u pokretnom zarezu


#include <stdio.h>
#include <math.h>
void main( )
{
double stopa, period, glavnica;
printf( "Unesite kamatnu stopu: " ) ;
scanf( "%lf", &stopa ) ; /* ulaz u pokretnom zarezu */
/* konverzija u procente */
stopa = stopa / 100.0;
/* kamata se izracunava mesecno */
stopa= stopa / 12.0;
printf( "Unesite glavnicu: " );
scanf( "%lf", &glavnica );
printf( "Unesite vreme orocavanja: " );
scanf( "%lf", &period ) ;

/*Stopa je konvertovana na mesecnu osnovicu*/


period = period * 12.0;
printf( "Ukamacena vrednost je = %.2f\n",
glavnica * pow( (1.0+stopa), period));
}
//Zaokruzivanje vrednosti
#include <stdio.h>
void main()
{
float fvr_pz;
double dvr_pz;
fvr_pz= 123.45;
printf("l. Vrednost u pokretnom zarezu je %f\n", fvr_pz);
fvr_pz /= 3.30;
fvr_pz *= 3.30;
printf("2. Vrednost u pokretnom zarezu je %f\n", fvr_pz);
dvr_pz = 123.45;
printf("l. Vrednost u dvostrukoj preciznosti je %f\n", dvr_pz);
dvr_pz /= 3.30;
dvr_pz *= 3.30;
printf("2. Vrednost u dvostrukoj preciznosti je %f\n", dvr_pz);
}

//Formatiranje ulaza u pokretnom zarezu


#include <stdio.h>
void main()
{
/* deklaracija podataka */
float f_pro;
double d_pro;
/*dodela vrednosti*/
f_pro=106.11;
d_pro=-0.0000654;
/*stampanje vrednosti promenljivih */
printf ("Promenljiva f_pro=%2f\n", f_pro);
printf ("Promenljiva d_pro=%.11f\n", d_pro);
printf ("Promenljiva f_pro=%e\n", f_pro);
printf ("Promenljiva d_pro=%G\n", d_pro) ;
}
//Upravljacka struktura if
#include <stdio.h>
void main()
{
int x, y, z;
x = 10;
y= 3;
z = ( x / y ) * y;
if (x == z)
{
printf ( "Vrednosti x-a i z-a su jednake\n");
printf ( "Vrednost x-a je %d\n", x );
printf ( "Vrednost z-a je %d\n", z );
}
if ( x <= z)
{
printf ("Vrednost x-a je < ili = od vredriosti z-a\n");
printf( "Vrednost x-a je %d\n", x );
printf( "Vrednost z-a je %d\n", z );
}
if ( x >=z)
{
printf ( "Vrednost x-a je > ili = od vredriosti z-a\n" );
printf ( "Vrednost x-a je %d\n", x );
printf ( "Vrednost z-a je %d\n", z );
}
}

//Formiranje zbira celih brojeva while petljom

#include <stdio.h>
void main()
{
long num, sum = 0L;
int status;
printf("Unesite broj za sumiranje\n");
printf("Ili q za izlaz\n");
status = scanf("%ld", &num);
while (status==1)
{
sum = sum+num;

printf("Unesite naredni broj za sabiranje\n");


printf("Unesite q za quit!\n");
status=scanf("%ld", &num);
}
printf("Zbir unetih brojeva je %ld.\n", sum);
}
//Neparni brojevi sa for petljom

#include <stdio.h>
void main()
{
int broj;
for (broj=1;broj<=20;broj=broj+2)
printf("\n%d",broj);
}

//Naredba break sa naredbom switch


#include <stdio.h>
void main()
{
char ch;
int a_ct,e_ct,i_ct,o_ct,u_ct;
a_ct=e_ct=i_ct=o_ct=u_ct=0;
printf("Unesi priozvoljan tekst; Unesi # za izlaz.\n");
while((ch=getchar())!= '#')
{
switch (ch)
{
case 'a' :
case 'A' : a_ct++;
break;
case 'e' :
case 'E' : e_ct++;
break;
case 'i' :
case 'I' : i_ct++;
break;
case 'o' :
case 'O' : o_ct++;
break;
case 'u' :
case 'U' : u_ct++;
break;
default:
break;
} /* kraj switch */
} /* dok petlji nije kraj */
printf("Broj samoglasnika: A E I O U\n");
printf(" %d %d %d %d %d\n", a_ct,e_ct,i_ct,o_ct,u_ct);
}

//Ispisivanje brojeva Morzeovom azbukom


#include <stdio.h>
int main()
{ int broj;
printf("Unesi jedan broj izmedju 0 i 9:");
scanf("%d",&broj);
if((broj<0)||(broj>9))
{ printf("Broj nije u opsegu izmedju 0 i 9\n");}
else
{ printf("Broj %d prikazan Morzeovom azbukom je:",broj);}
if(broj==0) printf(“-----“);
if(broj==1) printf(“.----“);
if(broj==2) printf(“..---“);
if(broj==3) printf(“...--“);
if(broj==4) printf(“....-“);
if(broj==5) printf(“.....“);
if(broj==6) printf(“-....“);
if(broj==7) printf(“--...“);
if(broj==8) printf(“---..“);
if(broj==9) printf(“----.“);
return 0;
}
Program za izračunavanje sume prvih 20 prirodnih brojeva.
#include <stdio.h>
int main(void) /* suma prvih 20 prirodnih brojeva */
{
int brojac,suma; /* deklaracijska naredba */
brojac=1; /* naredba pridruzivanja */
suma =0; /* isto */
while(brojac++ < 21) /* while */
suma += brojac; /* naredba */
printf("suma = %d\n",suma); /* funkcijska naredba */
return 0;
}

Postavimo sada sledeći zadatak: za zadani prirodan broja treba ispisati sve njegove delitelje.

#include <stdio.h>
int main(void)
{
long num; // broj koji proveravamo
long div; // potencijalni delitelj
unsigned flag = 0; // prim broj?
printf("Unesite celi broj ili q za izlaz: ");
while(scanf("%ld",&num) == 1)
{
for(div=2; (div*div) <= num; ++div)
{
if(num % div == 0)
{
if(div * div != num)
printf("%d je deljiv sa %d i %d\n", num, div,
num/div);
else
printf("%d je deljiv s %d.\n", num, div);
flag=1;
}
}
if(flag == 0) printf("%ld je prom broj.\n",num);
printf("Unesite celi broj ili q za izlaz: ");
}
return 0;
}
U sledećem primeru učitavaju se dva broja i jedan znak koji predstavlja izbor računske operacije. U
zavisnosti od učitanog znaka izvršava se jedna od četiri računske operacije.

#include <stdio.h>
int main(void)
{
float a,b;
char operacija;
printf("Upisati prvi broj: ");
scanf(" %f",&a);
printf("Upisati drugi broj: ");
scanf(" %f",&b);
printf("Upisati operaciju: zbir(z), oduzimanje(o),\n");
printf(" mnozenje(m),deljenje(d) :");
scanf(" %c",&operacija);
if(operacija=='z')
printf("%f\n",a+b);
else if(operacija=='o')
printf("%f\n",a-b);
else if(operacija=='m')
printf("%f\n",a*b);
else if(operacija=='d')
printf("%f\n",a/b);
else
printf("Nedopustena operacija!\n");
return 0;
}
U sledećem primeru učitavaju se dva broja i jedan znak koji predstavlja izbor njihovog odnosa (< manje, >
veće, = jednako ). U zavisnosti od učitanog znaka ispituje se jedan od tri odnosa za poređenje ova dva
broja.Ako je odnos tačan štampati poruku "Izabrali smo pravi odnos brojeva a i b", a ako nije "Izabrali
smo pogresan odnos brojeva a i b". U slučaju da se unese pogrešan znak za poređenje štampati poruku
"Nedopusteni znak za odnos brojeva!" .

#include<stdio.h>
#include <stdio.h>
int main(void)
{
float a,b;
char znak;
printf("Upisati prvi broj: ");
scanf(" %f",&a);
printf("Upisati drugi broj: ");
scanf(" %f",&b);
printf("Upisati znak poredjenja: manje <, vece >,\n");
printf(" jednako = :");
scanf(" %c",&znak);
if(znak=='<')
{if(a<b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");}
else if(znak=='>')
{if(a>b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");}
else if(znak=='=')
{if(a==b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");}
else
{printf("Nedopusteni znak za odnos brojeva!\n");}
return 0;
}

Program za izračunavanje srednje vrednostin upisanih brojeva.

#include <stdio.h>
/* Srednja vrednost upisanih brojeva (razlicitih od 0). */
int main(void)
{
int i=0;
double sum=0.0,x[];
printf(" Upisite niz brojeva !=0, ili nulu za kraj.\n");
printf(" x[0]= "); scanf("%lf",&x);
while (x!=0.0){
sum+=x;
printf(" x[%d]= ",++i);
scanf("%lf",&x);
}
sum/=i;
printf(" Srednja vrednost = %f\n",sum);
return 0;
}

/* Program za nalazenje najveceg zajednickog delioca dva nenegativna cela broja */


#include<stdio.h>
void main()
{
int prvi, drugi, pomocni;
printf("Ukucajte dva nenegativna cela broja ?\n");
scanf("%d%d", &prvi, &drugi );
while (drugi==0)
{
pomocni = prvi % drugi;
prvi = drugi;
drugi = pomocni;
}
printf("Najveci zajednicki delilac ovih brojeva je %d\n", prvi);
}

/* Program za permutovanje cifara celog broja - while iskaz */


#include<stdio.h>
void main()
{
int broj;

printf("Ukucajte ceo broj ? ");


scanf("%d", &broj );
printf("Permutovani broj je ");
while ( broj )
{
printf("%d", broj % 10);
broj = broj/10;
}
printf("\n");
}

/* Program za odredjivanje srednje vrednosti n celih pozitivnih brojeva -while iskaz */


#include<stdio.h>
void main()
{
int n, brojac = 0;
float suma = 0, x;
printf("Ukupno brojeva ? ");
scanf("%d", &n);
while (brojac < n)
{
printf("Ukucajte %d. broj ? ", brojac+1);
scanf("%f", &x );
suma += x ;
brojac += 1;
}
printf("Srednja vrednost ovih brojeva je %f\n", suma/n);
}

/* Program za izracunavanje faktorijela */


#include <stdio.h>
#include <math.h>
void main()
{
int i, n;
long fak = 1;
printf("lzracunavanje n!\nUkucajte broj ? ");
scanf("%d", &n);
for ( i=1; i<=n; ++i)
fak *= i;
printf("%d! = %ld\n", n, fak);
}

/* Program za odredjivanje srednje vrednosti n celih pozitivnih brojeva -for iskaz */


#include<stdio.h>
void main()
{
int n, brojac =1;
float suma =0, x ;
printf("Ukupno brojeva ? ");
scanf("%d", &n);
for ( ; brojac<=n; ++brojac, suma+=x )
{
printf("Ukucajte %d broj ?",brojac);
scanf("%f",&x);
}
printf("Srednja vrednost ovih brojeva je %f\n", suma/n);
}

Rešiti funkciju primenom operatora uslovnog izraza:

⎧− 1 broj < 0

s=⎨ 0 broj = 0
⎪ 1 broj > 0

#include<stdio.h>
void main()
{
int s, broj;
printf("Unesite broj za odredjivanje uslova:");
scanf("%d",&broj);
s=(broj < 0) ? -1 : ((broj==0) ? 0 : 1);
printf("Vrednost izraza za uneti broj %d je s=%d\n",broj,s);
}
RAD SA NIZOVIMA KARAKTERA
//PROGRAM 1.

#include <stdio.h>
int main()
{
printf("Alert: zvucni ili vizuelni signal \a\n");
printf("Po\bvratnik ili b\backspace: sakrij me\b \n");
printf("Upravljacki znak carriage return, \r, pomera aktivnu poziciju do inicijalne pozicije
tekuce linije.\n");
printf("Form feed. \f\n");
printf ("Horizontalni\ttab\n");
printf("Vertikalni tab \v je trikovit, jer mu je ponasanje nije specificirano pod izvesnim
uslovima\n");
return 0;
}

/* Posle unosa sa tastature se za uneti EOF (uglavnom control-D ili control-Z karakter, ali ne
obavezno), stampa 0. Inace, stampa se 1. Akoje Vas input stream baferovan (a verovatno jeste),
onda morate pritisnuti ENTER taster pre nego dobijete izlaznu poruku */

//PROGRAM 2.

#include <stdio.h>
int main()
{
printf("Na mom sistemu vrednost za EOF je %d\n\n", EOF);
return 0;
}

1
//PROGRAM 3.

//Unos i štampanje karaktera


#include<stdio.h>//PRIMER 1.
int main()
{
char recenica[80];
printf("Unesite niz karaktera: ");
scanf("%s",&recenica);
printf("Prikaz unetog sadrzaja: %s\n",recenica);
return 0;
}

//PROGRAM 4.

//Unos i štampanje karaktera

#include<stdio.h>
void main( ) {
char c;
printf("Unesite jedan proizvoljni karakter:");
c = getchar( );
putchar('\n');//Prelazak u novi red
printf("Uneli ste karakter:");
putchar(c);//Stampanje unetog karaktera
putchar('\n');//Prelazak u novi red
}

2
//PROGRAM 5.
//Unos i štampanje karaktera

#include<stdio.h>
void main( ) {
char c[30];
printf("Unesite niz proizvoljnih karaktera:");
gets(c);
printf("\n");//Prelazak u novi red
printf("Uneli ste karakter:");
puts(c);//Stampanje unetog karaktera
printf("\n");//Prelazak u novi red
}

//PROGRAM 6.
//Unos i štampanje karaktera

#include <stdio.h>
main()
{ int vrednost;
vrednost='A';
printf("%s\nkarakter=%3c\nvrednost=%3d\n","Veliko slovo",vrednost,vrednost);
vrednost='a';
printf("%s\nkarakter=%3c\nvrednost=%3d\n","Malo slovo",vrednost,vrednost); }

//PROGRAM 7.
//Unos i štampanje karaktera

#include <stdio.h>
void main()
{
int c1, c2;
c1 = getchar();
printf("------------\n");
c2 = getchar();

3
printf("c1 = %d, c2 = %d\n",c1, c2);
printf("c1 = %c, c2 = %c\n",c1, c2);
putchar(c1); /* isto je kao i printf("%c",c1); */
putchar(c2); /* isto je kao i printf("%c",c2); */
putchar('\n');
/* Za ispisivanje karaktera a */
putchar('a');
/* dozvoljeno je : printf("abc"); printf("a"); */
/* nedozvoljeno je : printf('a'); putchar('abc'); putchar("abc"); */
}

//PROGRAM 8.
//Program čita jedan karakter i ispisuje ga.
#include <stdio.h>
void main()
{
int c; /* Karakter - obratiti paznju na int */
printf("Unesite jedan proizvoljni karakter:");
c = getchar(); /* cita karakter sa standardnog ulaza */
printf("\nUneli ste karakter:");
putchar(c); /* pise karakter zapamćen u promenljivoj c na standardni izlaz */
putchar('\n'); /* prelazak u novi red */
printf("Ispisuje malo a:");
putchar('a'); /* ispisuje malo a */
printf("\nIspisuje ASCI 97:");
putchar(97); /* ekvivalentno prethodnom */
putchar('\n');/* prelazak u novi red */
}

4
//PROGRAM 9.
//Program čita ceo izraz i ispisuje ga.

#include <stdio.h>
int main()
{
char my_string[50];
printf("Otkucaj nesto!\n");
gets(my_string);
printf("Otkucao si:%s\n", my_string);
return 0;
}

//PROGRAM 10.
//Program čita ceo izraz i ispisuje ga pomoću funkcija gets i puts.

#include <stdio.h>

int main()
{
char my_string[500];
printf("Otkucaj nesto!\n");
gets(my_string);
printf("Otkucao si:\n");
puts(my_string);
return 0;
}

5
//PROGRAM 11.
//Unos i štampanje karaktera
Program učitava broj karaktera sa ulaza sve dok se ne otkuca znak za kraj unosa EOF. EOF
se može generisati kucanjem Control /Z.

#include <stdio.h>
main()
{ int ch, i = 0;

while((ch = getchar()) != EOF)


i ++;
printf("%d\n", i);
}

//PROGRAM 12.
//Unos i štampanje niza karaktera
/*Program koristi getchar da učita liniju sa standardnog ulaza
stdin, postabvlja takav ulaz u buffer, onda završava string pre
štampanja linije na ekranu. */

#include <stdio.h>
void main( void )
{
char buffer[81];
int i, ch;
printf( "Enter a line: " );
/* Read in single line from "stdin": */
for( i = 0; (i < 80) && ((ch = getchar()) != EOF)
&& (ch != '\n'); i++ )
buffer[i] = (char)ch;
/* Terminate string with null character: */
buffer[i] = '\0';
printf( "%s\n", buffer );
}

6
//PROGRAM 13.
//Unos i štampanje karaktera
Program konvertuje ulazne karaktere u velika slova. Da bi ovo učinili moramo dodati
funkciju toupper iz biblioteke za konverziju karaktera ctype.h

#include <ctype.h> /* For definition of toupper */


#include <stdio.h> /* For definition of getchar, putchar, EOF */

void main()
{ int ch;
while((ch = getchar()) != EOF)
putchar(toupper(ch));
}

//PROGRAM 14.

//Unos i štampanje karaktera

Program koji koristi gets i puts to double space typed input.

#include <stdio.h>

void main()
{ char line[256]; /* Definiše string dužine 256 karaktera koji se pamti kao ulazna linija */

while(gets(line) != NULL) /* Čitanje linije */


{ puts(line); /* Print linije */
printf("\n"); /* Print prazne linije */
}
}

7
//PROGRAM 15.
//Unos i štampanje karaktera

//Proghram stanpa broj karaktera pre ispisivanja linije:


#include<stdio.h>
void main( ) {
int n;
char line[100];
n = 0;
while( (line[n++]=getchar( )) != '\n' );
line[n] = '\0';
printf("%d:\t%s", n, line);
}

//PROGRAM 15.
//Unos i štampanje karaktera

#include <stdio.h>
#include <string.h>
main()
{char linija_teksta[81];
while( fgets(linija_teksta,81, stdin)!= NULL)
/* Unos u liniju teksta se prekida i petlja sa kontrolnim karakterom Ctrl/z */
{continue;}
printf("Linija je : %s\n",linija_teksta);}

8
//PROGRAM 17.

//Unos i štampanje karaktera

/*(Funkcije getchar(), putchar() ) NCP koji sadržaj standardnog ulaza štampa znak po znak
na standardni izlaz sve do markera kraja ulaza.*/

#include <stdio.h>
main()
{ int znak;
znak=getchar(); /*promenljivoj znak se dodeljuje znak sa ulaza */
while( znak !=EOF) //End of file Ctrl/Z
{ putchar(znak); /*dodeljeni znak se kopira na izlaz */
znak=getchar(); } }

//PROGRAM 18.

//Unos i štampanje karaktera


/*. NCP koji će ispisati na standardni izlaz ukupan broj karaktera standardnog ulaza do
markera kraja, kao i broj prelazaka u novi red. Pretpostaviti da je za ukupan broj karaktera
(zajedno sa enter i blanko) i ukupan broj prelazaka u novi red dovoljan opseg long
promenljivih. */

#include <stdio.h>
void main()
{
int znak; /*prihvata znak sa ulaza */
long linije=0 ; /*brojac linija */
long br_znak=0; /*brojac znakova na ulazu */
while ( (znak=getchar() ) != EOF)
{ br_znak++;
if (znak=='\n') linije ++;
}
printf("Prelazaka u novi red: %ld, karaktera: %ld \n",linije,br_znak);
}

9
//PROGRAM 19.

//Unos i štampanje karaktera

//Testira duzinu i jednakost dva stringa


#include <stdio.h>
#include <string.h>
void main()
{
char a[3], b[3],ch[3];
int i=0;
printf("Unesi priozvoljan tekst; Unesi # za izlaz!\n");
ch[i]=getchar();
while(ch[i]!='#')//izlazak iz petlje kada je uneto #
{putchar(ch[i]);i=i+1;//ispisuje trenutno uneti karakter direktno na izlaz
ch[i]=getchar();}
printf("\nNiz ch je: %s, kojih ima ukupno %d\n",ch,i) ;
strcpy(a, "abc");//kopiranje niza karaktera u vektor a
strcpy(b, "abc");//kopiranje niza karaktera u vektor b
printf("Ovako izgleda a niz:%s\n",a) ;
printf("Ovako izgleda b niz:%s\n",b) ;
printf("Ovako izgleda clan a[0] niza:%c\n", a[0]);
printf("Ovako izgleda clan a[1] niza:%c\n", a[1]);
printf("\nDuzina izraza a po broju karaktera je:%d\n",strlen(a)) ;//izracunavanje duzine
niza
printf("\nDuzina izraza b po broju karaktera je:%d\n",strlen(b)) ;//izracunavanje duzine
niza
if (strcmp(a,b) == 0) //komparacija-uporedjivanje dva niza
{ printf("Ovo su jednaki NIZOVI!\n") ;}
else
printf("Ovo nisu jednaki NIZOVI!\n");
}

10
//PROGRAM 20.
//Unos i štampanje karaktera

//Program za prikazivanje tablice ASCII kodova:

#include <stdio.h>
main()
{
char c=' ';
int i;
printf ("\t\tTablica ASCII kodova \n \n");
linija:
i=0;
znak:
printf("%3d %c ",c+i,c+i);
i=i+19;
if (i<95) goto znak;
printf("\n");
c=c+1;
if (c<' '+19) goto linija;
}

//PROGRAM 21.

//NCP koji pronalazi najduzu liniju sa ulaza. Nije poznat ukupan broj linija, ali svaka linija
nema vise od 80 karaktera ( izlaz CTRL/Z).

#include <stdio.h>
#include <string.h>
#define MAX_DUZINA_LINIJE 81

main()

11
{
char linija[MAX_DUZINA_LINIJE];
char najduza_linija[MAX_DUZINA_LINIJE];
int duzina_linije = 0;
int duzina_najduze_linije = 0;
najduza_linija[0] = '\0';
while( fgets(linija, MAX_DUZINA_LINIJE, stdin) != NULL)
{
duzina_linije=strlen(linija);
if (duzina_linije>duzina_najduze_linije)
{strcpy(najduza_linija, linija);
duzina_najduze_linije = duzina_linije;}
}
printf("Najduza linija je : %s\n",najduza_linija);
}

//PROGRAM 22.

// NCP koji stampa liniju sa ulaza pod uslovom da linija nema vise od 80 karaktera.

#include <stdio.h>
void main( void )
{
char buffer[81];
int i, ch;

printf( "Unesi liniju teksta: " );

/* Citanje linije karaktera sa standardnog "stdin": */


for( i = 0; (i < 80) && ((ch = getchar()) != EOF)
&& (ch != '\n'); i++ )
buffer[i] = (char)ch;

/* String se terminira sa NULL karakterom: */


buffer[i] = '\0';
printf( "%s\n", buffer );
}

12
//PROGRAM 23.

//NCP koji stampa liniju konstantnog niza karaktera.


#include <stdio.h>
void main( void )
{
char buffer[81];
int i, ch;
printf( " Unesi liniju teksta: " );

/* Citanje linije karaktera sa standardnog "stdin": */


for( i = 0; (i < 80) && ((ch = getchar()) != EOF)
&& (ch != '\n'); i++ )
buffer[i] = (char)ch;
/* String se terminira sa NULL karakterom: */
buffer[i] = '\0';
printf( "%s\n", buffer );
}

//PROGRAM 24.

/*Uraditi program za unos niza karaktera ”Moram da položim drugi kolokvijum iz Programskih
jezika 1” u vektor Niz1. Odštampati ovaj niz karaktera u potpunoj formi, i izračunati dužinu ovog
unetog niza. Iskopirati sadržaj vektora Niz1 u vektror Niz2 i utvrditi dali su to isti nizovi.
Prebrojati koliko praznina (blanko karaktera) ima u nizu Niz1.*/

#include <stdio.h>
#include <string.h>
void main()
{ int brojznak=0,i=0;
char Niz1[81],Niz2[81];
printf("Unesi clanove niza Niz1, za kraj Ctrl/z/");
while( fgets(Niz1,81, stdin)!= NULL)
/* Unos u liniju teksta se prekida i petlja sa kontrolnim karakterom Ctrl/z */
{continue;}
printf("Linija niza Niz1 je : %s\n",Niz1);
printf("\nDuzina niza po broju karaktera je:%d\n",(strlen(Niz1)-1));
strcpy(Niz2,Niz1);
printf("Linija niza Niz2 je : %s\n",Niz2);

13
if (strcmp(Niz1,Niz2)==0)//Komparacija-uporedjivanje dva niza
{ printf("Ovo su jednaki NIZOVI!\n");}
else
printf("Ovo nisu jednaki NIZOVI!\n");
while (Niz1[i]!='\n')
{ if(Niz1[i]==' ')brojznak++;i=i+1;}
printf("Broj blanko znakova u nizu Niz1 je:%ld \n",brojznak); }

//PROGRAM 25.

/*Sastaviti program koji iz skupa unetih karaktera ( naPRIMER: rečenice ’’Ja sam rodjen
1990. god u 12. mesecu, i u petak!!’’izračunava broj unetih slova, brojeva i ostalih
karaktera.*/

#include<stdio.h>
#include<conio.h>
main( )
{
int slovo, broj, ostalo, c;
slovo = broj = ostalo = 0;
while( (c=getchar( )) != EOF )
if( ('A'<=c && c<='Z') || ('a'<=c && c<='z') )
++ slovo;
else if( '0'<=c && c<='9' ) ++broj;
else ++ostalo;
printf("Uneli ste:%d slova, %d brojeva,%d ostalih\n", slovo, broj, ostalo);
}

//PROGRAM 26.
//Formatiranje izlaza

14
#include <stdio.h>
#define IME "Srbija"
#define ADRESA "Ul. Beogradska 20."
#define MESTO "18000 Nis"
#define LIMIT 65
void main()
{void zvezde(void);/*deklaracija funkcije bez argumenata*/
zvezde(); /*poziv korisnicke funkcije */
printf("%s \n ",IME) ; /*poziv funkcije iz standardne biblioteke*/
printf("%s\n", ADRESA);
printf("%s\n", MESTO) ;
zvezde ( ) ;} /*definicija korisnicke funkcije */
void zvezde() /*funkcija nema argumenata*/
{ int brojac;
for(brojac=l;brojac<=LIMIT;brojac++)
putchar ( '*' );
putchar ( '\n' ) ; }

//PROGRAM 27.

//Program koji kopira ulaz svakog karaktera direktno na izlaz. `%' označava kraj ulaza.

#include <stdio.h>
void main( ) {
char c;
while( (c=getchar( )) != '%' )
putchar(c);
}

15
//PROGRAM 28.
//Program konvertuje velika u mala slova
#include <stdio.h>
void main( ) {
char c;
while( (c=getchar( )) != '%' )
if( 'A'<=c && c<='Z' )
putchar(c+'a'-'A');
else
putchar(c);
}

//PROGRAM 29.
//Program broji karaktere, brojeve i praznine u tekstu. Završava se unosom %.
#include <stdio.h>
void main( ) {
int let, dig, other, c;
let = dig = other = 0;
while( (c=getchar( )) != '%' )
if( ('A'<=c && c<='Z') || ('a'<=c && c<='z') )
++let;
else if( '0'<=c && c<='9' ) ++dig;
else ++other;
printf("%d slova, %d broja, %d ostalih karaktera\n", let, dig, other);

16
//PROGRAM 30.
//Izračunavanje dužine zapisanog stringa, IZLAZ ENTER.

#include <stdio.h>
void main( ) {
int n, c;
char line[100];
n = 0;
while( (c=getchar( )) != '\n' ) {
if( n < 100 )
line[n] = c;
n++;
}
printf("duzina stringe je: = %d\n", n);
}

//PROGRAM 31.
//Dužina stringa sa izlazom ENTER

void main( ) {
int n;
char line[100];
n = 0;
while( (line[n++]=getchar( )) != '\n' );// Karakter \n kao ENTER za kraj
line[n] = '\0';
printf("Duzine stringa je %d:\t%s", n, line);
}

17
OPŠTI ZADACI

/* 2.1 MINIMUM TRI CELA BROJA */

#include<stdio.h>
#include<math.h>
void main()
{int a,b,c,m;
printf("\nUnesite vrednosti za a , b i c\n");
scanf("%d%d%d",&a,&b,&c);
m=a;
if(b<m) m=b;
if(c<m) m=c;
printf("Minimum brojeva a=%d b=%d i c=%d je broj %d\n",a,b,c,m);}

/* 2.2 Program za odredjivanje da li je godina prestupna ili nije*/


#include<stdio.h>
#include<math.h>
void main()
{
int godina,ost_4,ost_100,ost_400;
printf("Ukucajte godinu ? ");
scanf("%d", &godina);
ost_4=godina%4;
ost_100=godina%100;
ost_400=godina%400;
if (ost_4 ==0 && ost_100 != 0 || ost_400== 0)
printf("Godina %d je prestupna\n", godina);
else
printf("Godina %d nije prestupna\n", godina);
}

18
/2.3* Program za permutovanje cifara
nenegativriog celog broja - do-while iskaz */

#include<stdio.h>
#include<math.h>
void main()
{int broj;
printf("Ukucajte ceo broj ? ");
scanf("%d", &broj );
printf("Permutovani broj je ");
do
{printf("%d", broj%10);
broj =broj/10;}
while (broj);
printf("\n"); }

/2.4* Program za odredjivanje srednje vrednosti n celih pozitivnih brojeva -for iskaz */
#include<stdio.h>
#include<math.h>
void main()
{
int n,brojac;
float suma =0, x ;
printf("Ukupno brojeva ? ");
scanf("%d", &n);
for (brojac=1 ; brojac<=n; ++brojac, suma+=x )
{
printf("Ukucajte %d broj ?",brojac);
scanf("%f",&x);
}
printf("Srednja vrednost ovih brojeva je %f\n", suma/n);
}

19
/2.5* Program za izracunavanje faktorijela */

#include <stdio.h>
#include <math.h>
void main()
{
int i, n;
long fak = 1;
printf("lzracunavanje n!\nUkucajte broj ? ");
scanf("%d", &n);
for ( i=1; i<=n; ++i)
fak *= i;
printf("%d! = %ld\n", n, fak);
}

/2.6* Program za izracunavanje prostih aritmetickih izraza


u formi operand1 operator operand2 */

#include <stdio.h>
#include <math.h>
void main()
{
float operand1, operand2;
char op;
printf("Ukucajle lzraz ? \n");
scanf("%f%c%f", &operand1, &op, &operand2);
switch (op)
{
case '+':
printf("%f\n", operand1+operand2);
break;
case '-':
printf("%f\n", operand1-operand2 );

20
break;
case '*':
printf("%f\n", operand1*operand2 );
break;
case '/':
printf("%f\n", operand1/operand2);
break;
default:
printf("Nepoznat operator\n");
}}

∗Odredjivanje u ulaznom tekstu broja praznih karaktera, kao i broja


/2.7∗
znakova: tacka, zarez, dvotacka i tacka-zarez (naredbe switch i break)
- za izlaz CTRL/Z∗∗/

#include <stdio.h>
void main( )
{ int c, prazno=0, interp=0;
while((c=getchar())!=EOF)
switch(c)
{ case ' ':
prazno++;
break;
case '.':
case ',':
case ':':
case ';':
interp++;
break;
default:
break; }
printf("\nBroj praznina: %d", prazno);
printf("\nBroj znakova tacka, zarez, dvotacka i tacka-zarez: %d\n", interp); }

//2.8 Štampanje elemenata matrice

21
#include<stdio.h>
#include<math.h>
void main()
{
static int mat[2][3]={{0,1,2},{3,4,5}};
int i,j;
for(i=1;i<=2;++i)
{
printf("Elementi %d.reda su:\n",i);
for(j=1;j<=3;++j)
printf("kolona%d:%d\n",j,mat[i-1][j-1]);
}
printf("\n");
}

2.9 Neka je data kvadratna matrica u formatu:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Članove matrice uneti u program kao konstantne celobrojne veličine, a kao izlaz iz
programa predvideti štampanje ove matrice u pokazanom formatu kao polazne matrice i
štampanje nove matrice u istom obliku ali čiji su svi članovi sada pomnoženi skalarom 2.

/* 1 STAMPANJE CLANOVA MATRICE I CLANOVA MATRICE POMNOZENE


SKALAROM*/
#include<stdio.h>
#include<math.h>
void main()
{int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j;
printf("\nPolazna matrica je\n");
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{printf("%2d ",mat[i][j]);}printf("\n");}
printf("\nNova matrica je\n");
for(i=0;i<4;i++)

22
{
for(j=0;j<4;j++)
{printf("%2d ",2*mat[i][j]);}printf("\n");}}

2.10 Neka je data kvadratna matrica u formatu:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Članove matrice uneti u program kao konstantne celobrojne veličine, a kao izlaz iz
programa predvideti štampanje ove matrice u pokazanom formatu kao polazne matrice i
štampanje nove matrice u istom obliku ali sada unazad od člana a44,a43,a42a41,......,a11.

/* 2 STAMPANJE CLANOVA MATRICE I CLANOVA MATRICE UNAZAD*/


#include<stdio.h>
#include<math.h>
void main()
{int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j;
printf("\nPolazna matrica je\n");
for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
{printf("%2d ",mat[i][j]);}printf("\n");}
printf("\nNova matrica je\n");
for(i=3;i>=0; i--)
{
for(j=3;j>=0; j--)
{printf("%2d ",mat[i][j]);}printf("\n");}}

23
2.11 Napisati program na C++ jeziku koji izračunava sumu svih elemenata u svakom redu
pojedinačno, pravougaone matrice [4x4].

1 2 3 4
5 6 7 8
A=
9 10 11 12
13 14 15 16

#include<stdio.h>
#include<math.h>
void main()
{int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j,s=0;
printf("\nPolazna matrica je\n");
for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
{printf("%2d ",mat[i][j]);}printf("\n");}

for(i=0;i<4; i++)
{printf("\nSuma %d reda je:",i+1);
for(j=0;j<4; j++)

{s=s+mat[i][j];}
printf("%2d\n",s);s=0;}
return 0;}

24
2.12 NCP koji sa standardnog ulaza učitava 3x3 matricu i ispisuje je na standardni izlaz tako
da centralno polje a[1][1] bude jednako sumi gornjeg levog (a[0][0]) i donjeg desnog polja
(a[2][2]). Pre ucitavanja popuniti matricu proizvoljnim vrednostima.

#include <stdio.h>
void main()
{
int a[3][3] = {{0, 1, 2}, {10, 11, 12}, {20, 21, 22}}; /* deklaracija i inicijalizacija matrice a, može
se uraditi za konkretan primer date matrice*/
int i, j; /*brojaci u ciklusu */
/* unos elemenata matrice */
for(i=0; i<3; i++)
for(j=0; j<3; j++)
{
printf("\na[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
printf("\n*******************\n");
a[1][1] = a[0][0] + a[2][2]; /* 0 + 22 = 22 */
/*ispis matrice */
for(i=0; i<3; i++)
{
for(j=0; j<3; j++) printf("%d\t", a[i][j]);
printf("\n");
}
}

25
2.13 Neka je data kvadratna matrica u formatu:
a11 a12 a13
a 21 a 22 a 23
a31 a32 a33
Uneti članove matrice u program kao celobrojne veličine, a kao izlaz iz programa
predvideti štampanje takve matrice u pokazanom formatu kao i štampanje izračunate
vrednosti njene determinante urađene preko funkcije.

#include<stdio.h>
#include<math.h>
#include<iomanip.h>
main()
{static int mat[4][4];
int i,j;
float delta;
printf("Unesite proizvoljne elemente pravougle matrice:\n");
for(i=0;i<4;++i)
for(j=0;j<4;++j)
{printf("a[%d][%d]=",i,j);
scanf("%d",&mat[i][j]);printf("\n");}
printf("\nPolazna matrica je\n");
for(i=0;i<4;++i)
{for(j=0;j<4;++j)
printf("%3d ",mat[i][j]);printf("\n");}
printf("\nDeterminanta sistema je:\n");
delta=mat[0][0]*((mat[1][1]*mat[2][2]*mat[3][3]

26
+mat[1][2]*mat[2][3]*mat[3][1]
+mat[2][1]*mat[3][2]*mat[1][3])
-(mat[1][3]*mat[2][2]*mat[3][1]
+mat[1][1]*mat[2][3]*mat[3][2]
+mat[1][2]*mat[2][1]*mat[3][3]))-
mat[0][1]*((mat[1][0]*mat[2][2]*mat[3][3]
+mat[1][2]*mat[2][3]*mat[3][0]
+mat[2][0]*mat[3][2]*mat[1][3])
-(mat[1][3]*mat[2][2]*mat[3][0]
+mat[1][0]*mat[2][3]*mat[3][2]
+mat[1][2]*mat[2][0]*mat[3][3]))+
mat[0][2]*((mat[1][0]*mat[2][1]*mat[3][3]
+mat[1][3]*mat[2][0]*mat[3][1]
+mat[2][0]*mat[3][1]*mat[1][3])
-(mat[1][3]*mat[2][1]*mat[3][0]
+mat[3][1]*mat[2][3]*mat[1][0]
+mat[1][1]*mat[2][0]*mat[3][3]))-
mat[0][3]*((mat[1][0]*mat[2][1]*mat[3][2]
+mat[1][1]*mat[2][2]*mat[3][0]
+mat[2][0]*mat[3][1]*mat[1][2])
-(mat[1][2]*mat[2][1]*mat[3][0]
+mat[3][1]*mat[2][2]*mat[1][0]
+mat[1][1]*mat[2][0]*mat[3][2]));
printf("Vrednost determinante je :%f",delta);
return 0;}

2.14 Sastaviti program za izračunavanje sume:


n
S= ∏ i!
i =1

27
Napomena: radi se o integer veličinama ali voditi računa da ne dođe do preopterećenja
memorije!

#include<stdio.h>
#include<math.h>
main()
{int i,n;
float F=1,S=1;
printf("Unesite verdnost za n\n n=");
scanf("%d",&n);
for(i=2;i<=n;i++)
{F=F*i;
S=S*F;};
printf("\nRezultat proizvoda i! je S=%lf\n",S);
return 0;}

2.15 Napisati program za nalaženje proizvoda prva 3 slučajna broja.

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
int i,R;
long int P=1;
printf("Tri slucajna broja od 0 do 99 su:\n\n");
for(i=0; i<3; i++)
{R= rand()% 100;
printf("%d\n",R );
P=R*P;}
printf("Proizvod prva 3 slucajna broja je: %d\n", P);
return 0;
}

28
2.16 U sledećem primeru učitavaju se dva broja i jedan znak koji predstavlja izbor njihovog
odnosa (< manje, > veće, = jednako ). U zavisnosti od učitanog znaka ispituje se jedan
od tri odnosa za poređenje ova dva broja. Ako je odnos tačan štampati poruku "Izabrali smo
pravi odnos brojeva a i b", a ako nije "Izabrali smo pogresan odnos brojeva a i b". U
slučaju da se unese pogrešan znak za poređenje štampati poruku "Nedopusteni znak za odnos
brojeva!" .
#include <stdio.h>
int main(void)
{
float a,b;
char operacija;
printf("Upisati prvi broj: ");
scanf(" %f",&a);
printf("Upisati drugi broj: ");
scanf(" %f",&b);
printf("Upisati operaciju: zbir(z), oduzimanje(o),\n");
printf(" mnozenje(m),deljenje(d) :");
scanf(" %c",&operacija);
if(operacija=='z')
printf("%f\n",a+b);
else if(operacija=='o')
printf("%f\n",a-b);
else if(operacija=='m')
printf("%f\n",a*b);
else if(operacija=='d')
printf("%f\n",a/b);
else
printf("Nedopustena operacija!\n");
return 0;
}

2.17 Sastaviti program na C jeziku za izračunavanje površine trougla po obrascu


a+b+c
PTROUGLA = p ( p − a )( p − b)( p − c) gde je p =
2

#include<stdio.h>
#include <stdio.h>
#include <math.h>

float main(void)
{
float a,b,c,p,PTROUGLA;

29
printf("Upisati broj a: ");
scanf(" %f",&a);
printf("Upisati broj b: ");
scanf(" %f",&b);
printf("Upisati broj c: ");
scanf(" %f",&c);
p=(a+b+c)/2.;
printf("Vrednost prolazne promenljive je:%f\n",p);
PTROUGLA=sqrt(p*(p-a)*(p-b)*(p-c));
printf("Povrsina trougla izracunata datim obrascem je:%f\n",PTROUGLA);
return 0;
}

2.18 U sledećem primeru učitavaju se dva broja i jedan znak koji predstavlja izbor njihovog
odnosa (< manje, > veće, = jednako ). U zavisnosti od učitanog znaka ispituje se jedan
od tri odnosa za poređenje ova dva broja. Ako je odnos tačan štampati poruku "Izabrali smo
pravi odnos brojeva a i b", a ako nije "Izabrali smo pogresan odnos brojeva a i b". U
slučaju da se unese pogrešan znak za poređenje štampati poruku "Nedopusteni znak za odnos
brojeva!" .
#include<stdio.h>
#include <stdio.h>
int main(void)
{
float a,b;
char znak;
printf("Upisati prvi broj: ");
scanf(" %f",&a);
printf("Upisati drugi broj: ");
scanf(" %f",&b);
printf("Upisati znak poredjenja: manje <, vece >,\n");
printf(" jednako = :");
scanf(" %c",&znak);
if(znak=='<')
{if(a<b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");}
else if(znak=='>')
{if(a>b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");}
else if(znak=='=')
{if(a==b) printf("Izabrali smo pravi odnos brojeva a i b\n");

30
else printf("Izabrali smo pogresan odnos brojeva a i b\n");}
else
{printf("Nedopusteni znak za odnos brojeva!\n");}
return 0;
}

FUNKCIJE
1. Pokazati kako funkcioniše prototip funkcije.

#include<stdio.h>
myfunc();/*inicijalizacija funkcije bez argumenata*/
void main()
{
myfunc();/*pozivanje funkcije bez argumenata*/
}
myfunc()/*definisanje funkcije bez argumenata*/
{
printf("ZDRAVO, ovo je test\n");
return 0;}

2. Korišćenje prototipa funkcije sa argumentom.

31
#include<stdio.h>
napisi(int count);
void main()
{napisi(4);}
napisi(int count)
{
int c;
for(c=0;c<count;c++)
printf("\nZDRAVO");
return 0;}

3. Test funkcije

#include<stdio.h>
test();
void main()
{
printf("Ulazimo unutar test funkcije\n");
test();
printf("\nVracamo se iz test funkcije\n");
}
test()
{
int a,b;a=100;
b=a+100;
printf("a je %d i b je %d",a,b);
return 0;}

4. Naći minimum od dva cela broja. U glavnom programu obezbediti štampanje, a u funkciji
njihovo poređenje.

#include<stdio.h>
int imin(int n,int m);
void main()/* glavni program */
{ int broj1,broj2,vrati;
printf("Unesite dva cela broja\n");

32
vrati=scanf("%d %d",&broj1,&broj2);
if(vrati==2)
printf("Manji od %d i %d je %d\n",broj1,broj2,imin(broj1,broj2));}

int imin(int n,int m)/* potprogram */


{
int min;
if (n<m)
min=n;
else
min=m;
return min;
}

5. Isti kao 4. samo na drugi način.

#include<stdio.h>
int min(int a, int b);
main()
{
int m;
m=min(3,6);
printf("Minimum je %d\n",m);
return 0;
}

int min(int a, int b)


{
if(a<b)
return a;
else
return b;
}

33
6. Formiranje zbira preko funkcije

#include <iostream.h>

int Add (int x, int y);


int main()
{
cout << "Ja sam u main()!\n";
int a, b, c;
cout << "Unesite dva broja: ";
cin >> a;
cin >> b;
cout << "\nPozivam Add()\n";
c=Add(a,b);
cout << "\nNazad u main().\n";
cout << "c ima vrednost " << c;
cout << "\nIzlazim....\n\n";
return 0;
}

int Add (int x, int y)


{
cout << "U Add(), preuzimam " << x << " i " << y << "\n";
return (x+y); }

7.Uraditi meni sa izborom operacija za sabiranje, oduzimanje i množenje dva cela realna
broja. U funkciji izvesti opisane računske radnje.

#include<stdio.h>
#include<stdlib.h>
add();
subtract();
multiply();
void main()
{
int choice;
while(1)
{
printf("\n\nMenu:\n");

34
printf("1- Add\n2- Subtract\n");
printf("3- Multiply\n4- Exit");
printf("\n\nYour choice -> ");
scanf("%d",&choice);
switch(choice)
{ case 1 : add();
break;
case 2 : subtract();
break;
case 3 : multiply();
break;
case 4 : printf("\nProgram Ends. !");
exit(0);
default:
printf("\nInvalid choice");

}
}
}

add()
{
float a,b;
printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
printf("a+b=%f",a+b);
return 0;}

subtract()
{
float a,b;
printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
printf("a-b=%f",a-b);
return 0;}

multiply()
{
float a,b;
printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
printf("a*b=%f",a*b);
return 0;}

35
8. Pozivanje funkcije po vrednosti

/*Pozivanje po vrednosti*/
#include<stdio.h>
void test(int a);
main()
{
int m;
m=2;
printf("\nM je %d",m);
test(m);
printf("\nM je %d",m);
return 0;
}

void test(int a)
{
a=5;}

9.MNOZENJE I SABIRANJE DVA REALNA BROJA PREKO FUNKCIJE

#include<stdio.h>
#include<math.h>
mno();
sab();

36
void main()
{ mno();
sab();}

mno()
{float a,b;
printf("\nUnesite vrednosti za a i b\n");
scanf("%f%f",&a,&b);
printf("a*b=%f",a*b);
return 0;}

sab()
{float a,b;
printf("\nUnesite vrednosti za a i b\n");
scanf("%f%f",&a,&b);
printf("a+b=%f",a+b);
return 0;}

10. MINIMUM TRI CELA BROJA PREKO FUNKCIJE

#include<stdio.h>
#include<math.h>
min();
void main()
{ min();}

min()
{int a,b,c,m;
printf("\nUnesite vrednosti za a , b i c\n");
scanf("%d%d%d",&a,&b,&c);
m=a;
if(b<m) m=b;
if(c<m) m=c;
printf("Minimum brojeva a=%d b=%d i c=%d je broj %d\n",a,b,c,m);
return 0;}

37
11.Poziv funkcije salje vrednost promenljive m funkciji a ne salje promenljivu samu sebi:
m=2, M=2

/*Pozivanje po referenci*/
#include<stdio.h>
void test(int *ptr);
main()
{
int m;
m=2;
printf("\nM je %d",m);
test(&m);
printf("\nM je %d",m);
return 0;
}

void test(int *ptr)


{
*ptr=5;
}
/*Poziv funkcije salje vrednost promenljive m po referenci: m=2, M=5*/

12. Suma kvadrata celih brojeva od 1 do N preko funkcije

/*Program za izracunavanje sume


kvadrata celih brojeva od 1 do n*/
#include <stdio.h>
#include <math.h>
suma_kvadrata(int n);

void main( )
{

38
suma_kvadrata(10);
suma_kvadrata(15);
suma_kvadrata(20);
}

suma_kvadrata(int n) /*f ja za izracunavanje*/


/*sume kvadrata*/
{
int i;
long suma=0;
for (i=1; i<=n; suma+=(long)i*i, ++i);
printf("Suma kvadrata od 1 do %d je %ld\n", n, suma);
return 0;}

13. Napisati program za rešavanje kvadratne j-ne ax2+bx+c=0.

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void main()
{
float delta,a,b,c,x1,x2;

printf("Enter a : ");
scanf("%f",&a);
printf("Enter b : ");
scanf("%f",&b);
printf("Enter c : ");
scanf("%f",&c);
delta=b*b-(4*a*c);
if(delta<0)
{
printf("Jednacina NEMA resenja !\n");
exit(0);//Potrebna hederska funkcija stdlib
}
if(delta==0)
{
x1=-b/(2*a);
printf("Jednacina IMA dva ista resenja !\n");
printf("x1=x2=%f",x1);
exit(0);
}

39
x1=(-b+sqrt(delta))/(2*a);
x2=(-b-sqrt(delta))/(2*a);
printf("\nX1=%f",x1);
printf("\nX2=%f\n",x2);
}

14. F-ja ne vraca nikakvu vrednost


#include<stdio.h>
void ispis(int i1, int i2, int i3); /* F-ja ne vraca nikakvu vrednost*/
main()
{
int a,b,c;
a=b=c=1;
ispis(a,b,c);
a=b=c=2;
ispis(a,b,c);
return 0;}

void ispis(int i1, int i2, int i3)


{
printf("Vrednost promenljive param1 je %d.\n",i1);
printf("Vrednost promenljive param2 je %d.\n",i2);
printf("Vrednost promenljive param3 je %d.\n",i3);
}

15. Poziv funkcije bez argumenta

#include <stdio.h>
#define IME "VTS"
#define ADRESA "Ul. Generala Medvedeva 20."
#define MESTO "18000 Nis"
#define LIMIT 65

40
void zvezde();
void main()
{ void zvezde(); /*deklaracija funkcije bez argumenata*/
zvezde(); /*poziv korisnicke funkcije */
printf("%s \n ", IME) ; /*poziv funkcije iz standardne biblioteke*/
printf("%s\n", ADRESA);
printf("%s\n", MESTO) ;
zvezde ( ) ; }
/*definicija korisnicke funkcije */
void zvezde() /*funkcija nema argumenata*/
{ int brojac;
for(brojac=1;brojac<=LIMIT;brojac++)
putchar ( '*' );
putchar ( '\n' ) ; }

16. Primer kada program poziva dve funkcije


#include<stdio.h>
#include<math.h>
void Hipotenuza(void);// funkcijski prototipovi
void Ucitaj(void); //funkcijski prototipovi
double a,b,c;/* deklaracija globalne promenljive, pre pocetka programa*/
void main()
{ Ucitaj();
Hipotenuza();
printf("nHipotenuza je %f.",c);}

void Hipotenuza(void)
{c=sqrt(a*a+b*b);}

void Ucitaj(void)
{printf("Prva kateta:");
scanf("%lf",&a);
printf("Druga kateta:");
scanf("%lf",&b);}

41
17. Primer za izracunavanje y=sin2(x)+cos2(x)
#include<stdio.h>
#include<math.h>
double Funkcija(double x);
void main()
{double x,y;/* deklaracija lokalnih promenljivih, posle pocetka programa*/
printf("Unesite vrednost za x:");
scanf("%lf",&x);
y=Funkcija(x);
printf("Vrednost funkcije je %f.",y);}
double Funkcija(double x)
{double y;
y=sin(x)*sin(x)+cos(x)*cos(x);
return y;}

18. Izracunavanje povrsine trougla sa dve funkcije


#include<stdio.h>
#include<math.h>
void Povrsina(void);
void Ucitaj(void);
double a,b,c,p,pt;/* deklaracija globalne promenljive, pre pocetka programa*/
void main()
{Ucitaj();
Povrsina();
printf("/nPovrsina trougla je %f.",pt);}
void Povrsina(void)
{p=(a+b+c)/2;
pt=sqrt(p*(p-a)*(p-b)*(p-c));}
void Ucitaj(void)
{printf("Prva kateta:");
scanf("%lf",&a);
printf("Druga kateta:");
scanf("%lf",&b);
printf("Treca kateta:");
scanf("%lf",&c);}

42
19. Neka je data kvadratna matrica u formatu:

a11 a12 a13 a14


a 21 a 22 a 23 a 24
a31 a32 a 33 a34
a 41 a 42 a 43 a 44
Uneti članove matrice u program kao celobrojne veličine, a kao izlaz iz programa
predvideti štampanje takve matrice u pokazanom formatu kao i štampanje izračunate
vrednosti njene dijagonale a11*a22*a33*a44 urađene preko funkcije.
#include<stdio.h>
#include<math.h>
#include<iomanip.h>
main()
{static int mat[4][4];
int i,j;
float dijagonala;
printf("Unesite proizvoljne elemente pravougle matrice:\n");
for(i=0;i<4;++i)
for(j=0;j<4;++j)
{printf("a[%d][%d]=",i,j);
scanf("%d",&mat[i][j]);printf("\n");}
printf("\nPolazna matrica je\n");
for(i=0;i<4;++i)
{for(j=0;j<4;++j)
printf("%3d ",mat[i][j]);printf("\n");}
dijagonala=mat[0][0]*mat[1][1]*mat[2][2]*mat[3][3];
printf("Vrednost dijagonale je :%f", dijagonala);
return 0;}

43
20.Četiri računske radnje preko funkcije choice i switch naredbi.
#include<stdio.h>
#include<stdlib.h>
void add(void);
void subtract(void);
void multiply(void);
void divide(void);
float a,b,rezultat;
void main()
{int choice;

while(1)
{
printf("\n\nMenu:\n");
printf("1- Add\n2- Subtract\n");
printf("3- Multiply\n4- Divide\n5-Exit");
printf("\n\nYour choice -> ");
scanf("%d",&choice);
switch(choice)
{ case 1 : add();printf("Rezultat operacije je:%f\n",rezultat);
break;
case 2 : subtract();printf("Rezultat operacije je:%f\n",rezultat);
break;
case 3 : multiply();printf("Rezultat operacije je:%f\n",rezultat);
break;
case 4 : divide();printf("Rezultat operacije je:%f\n",rezultat);
break;
case 5 : printf("\nProgram Ends. !");
exit(0);
default:
printf("\nInvalid choice");}
}}
void add(void)
{printf("\nEnter a:");
44
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
rezultat=(a+b);}
void subtract(void)
{printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
rezultat=(a-b);}

void multiply(void)
{printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
rezultat=(a*b);}

void divide(void)
{printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
rezultat=(a/b);}

45
PRIMERI PROGRAMA ZA PRIPREMU PRVOG
KOLOKVIJUMA

1. ULAZ - IZLAZ ..................................................................................................................................... 2


2. OPERATORI ...................................................................................................................................... 4
3. IF NAREDBA...................................................................................................................................... 5
4. POMOĆNE FUNKCIJE ........................................................................................................................ 9
5. SWITCH – CASE NAREDBA ...............................................................................................................12
6. FOR PETLJA .....................................................................................................................................13
7. WHILE i DO WHILE PETLJE ...............................................................................................................16

1
1. ULAZ - IZLAZ

Zadatak 1: Primer rada sa specijalnim karakterima.


int main(void)
{
printf("Alert: zvucni ili vizuelni signal \a\n");
printf("Alert: NESTO SE CUJE \n");
printf("Alert: PONOVO zvucni ili vizuelni signal \a\n");
printf("Povratnik ili backspace: sakrij me\b \n");
printf("Form feed. \f\n");
printf ("Horizontalni\ttab\n");
return 0;
}

Zadatak 2: Primer poziva funkcije printf:


#include <stdio.h>
void main()
{
float n1=3.0;
double n2=3.0;
long n3=2000000000;
long n4=1234567890;
printf("%.le, %.le, %ld, %ld\n", n1,n2,n3,n4);
printf("%ld, %ld\n", n3, n4);
printf("%f, %f, %ld, %ld\n", n1,n2,n3,n4);
}

Zadatak 3: Zaokruzivanje vrednosti.


#include <stdio.h>
void main()
{
float fvr_pz;
double dvr_pz;
fvr_pz= 123.45;
printf("l. Vrednost u pokretnom zarezu je %f\n", fvr_pz);
fvr_pz /= 3.30;
fvr_pz *= 3.30;
printf("2. Vrednost u pokretnom zarezu je %f\n", fvr_pz);
dvr_pz = 123.45;
printf("l. Vrednost u dvostrukoj preciznosti je %f\n", dvr_pz);
dvr_pz /= 3.30;
dvr_pz *= 3.30;
printf ("2. Vrednost u dvostrukoj preciznosti je %f\n", dvr_pz);
}

2
Zadatak 4: Formatiranje ulaza u pokretnom zarezu
void main()
{
/* deklaracija podataka */
float f_pro;
double d_pro;
/*dodela vrednosti*/
f_pro=106.11;
d_pro=-0.0000654;
/*stampanje vrednosti promenljivih */
printf ("Promenljiva f_pro=%2f\n", f_pro);
printf ("Promenljiva d_pro=%.11f\n", d_pro);
printf ("Promenljiva f_pro=%e\n", f_pro);
printf ("Promenljiva d_pro=%G\n", d_pro) ;
}

Zadatak 5: Obračun kamata u pokretnom zarezu. Kamata se računa kao glavnica *


(1+kamata/100)period.
#include <stdio.h>
#include <math.h>
void main( )
{
double stopa, period, glavnica;
printf( "Unesite mesecnu kamatnu stopu: " ) ;
scanf( "%lf", &stopa ) ; /* ulaz u pokretnom zarezu */
/* konverzija u procente */
stopa = stopa / 100.0;
printf( "Unesite glavnicu: " );
scanf( "%lf", &glavnica );
printf( "Unesite vreme orocavanja u mesecima: " );
scanf( "%lf", &period ) ;
printf( "Ukamacena vrednost je = %.2f\n",
glavnica * pow( (1.0+stopa), period));
}

3
2. OPERATORI

Zadatak 6: Primer za operatore inkrementa i dekrementa:


void main()
{
int x, y;
x = 10; y =10;
printf("Vrednost izraza ++x je %d\n", ++x);
printf("Vrednost izraza y++ je %d\n", y++);
printf("Nakon inkrementiranja vrednost x je %d\n",x);
printf("Nakon inkrementiranja vrednost y je %d\n\n\n", y);

x = 10; y =10;
printf( "Vrednost izraza --x je %d\n", --x);
printf( "Vrednost izraza y-- je %d\n", y--) ;
printf( "Nakon dekrementiranja vrednost x je %d\n",x);
printf( "Nakon dekrementiranja vrednost y je %d\n", y);
}

Zadatak 7: Primer za relacione izraze i logicke operatore:


void main()
{
int minimum,maximum;
int prl, pr2;
minimum=10;
maximum = 1000;
prl = 110;
pr2 = 1123;
if( (prl < maximum && prl > minimum) || (pr2 < maximum && pr2 > minimum) )
printf( "Najmanje jedna vrednost je u opsegu\n" );
if( (prl < maximum && prl > minimum) && (pr2 < maximum && pr2 > minimum) )
{
printf( "Obe vrednosti su u opsegu\n" ) ;
}
}

Zadatak 8: 43. Rešiti funkciju primenom operatora uslovnog izraza:

#include<stdio.h>
void main()
{
int s, broj;
printf("Unesite broj za odredjivanje uslova:");
scanf("%d",&broj);
s=(broj < 0) ? -1 : ((broj==0) ? 0 : 1);
printf("Vrednost izraza za uneti broj %d je s = %d\n",broj,s);
}

4
3. IF NAREDBA

Zadatak 9: Primer IF naredbe:


void main()
{
int x, y;
x = 6;
y = 6;
if ( x = 7)
printf( " Prvi <if> je zadovoljen\n" );
else
printf( " Prvi <if> nije zadovoljen\n" );
if ( y == 7 )
printf( " Drugi <if> je zadovoljen\n" );
else
printf( " Drugi <if> nije zadovoljen\n" );
}

Zadatak 10: Za uneti broj odrediti da li je pozitivan ili negativan.


void main()
{
int n;
printf("Unesi ceo broj: ");
scanf("%d",&n);
if(n>=0)
printf("Broj je pozitivan !\n");
if(n<0)
printf("Broj je negativan !\n");
}
Drugi način sa if else strukturom :
void main()
{
int n;
printf("Unesi ceo broj: ");
scanf("%d",&n);
if(n>=0)
printf("Broj je pozitivan !\n");
else
printf("Broj je negativan !\n");
}

Zadatak 11: Napisati program sa menijem:


 1- Program matematika
 2- Program finansija
 3- Program zabave
 4- Exit
upotrebom if, else if strukture za startovanje svih stavki iz menija. Ukoliko se izabere stavka
u meniju koja ne postoji štampati poruku “Pogrešan izbor”.
#include<stdio.h>
#include<stdlib.h>
void main()
{
int choice;
printf("\n\nMeni:\n");
printf("1- Program matematika\n2- Program finansija\n");
printf("3- Program zabave\n4- Exit");
printf("\n\nVas izbor -> ");
scanf("%d",&choice);
if(choice==1)
printf("\nProgram matematika Runs. !");

5
else if(choice==2)
printf("\nProgram finansija Runs. !");
else if(choice==3)
printf("\nProgram zabave Runs. !");
else if(choice==4)
{
printf("\nKraj programa!.\n");
exit(0);
}
else
printf("\nPogresan izbor");
}
Napisati program koji de unetu cifru ispisiati Morzeovom azbukom. Sldeda tablica prikazuje izgled cifre
prevedene na Morzeovu azbuku:
0 "-----"
1 (".----"
2 "..---"
3 "...--"
4 "....-"
5 "....."
6 "-...."
7 "--..."
8 "---.."
9 "----.")

int main()
{
int broj;
printf("Unesi jedan broj izmedju 0 i 9:");
scanf("%d",&broj);
if((broj<0)||(broj>9))
printf("Broj nije u opsegu izmedju 0 i 9\n");
else
{
printf("Broj %d prikazan Morzeovom azbukom je:",broj);
if(broj==0) printf("-----");
if(broj==1) printf(".----");
if(broj==2) printf("..---");
if(broj==3) printf("...--");
if(broj==4) printf("....-");
if(broj==5) printf(".....");
if(broj==6) printf("-....");
if(broj==7) printf("--...");
if(broj==8) printf("---..");
if(broj==9) printf("----.");
}
printf("\n\n");
}

Zadatak 12: U sledećem primeru učitavaju se dva broja i jedan znak koji predstavlja izbor
njihovog odnosa (< manje, > veće, = jednako ). U zavisnosti od učitanog znaka ispituje se
jedan od tri odnosa za poreĎenje ova dva broja. Ako je odnos tačan štampati poruku
"Izabrali smo pravi odnos brojeva a i b", a ako nije "Izabrali smo pogresan odnos brojeva a i
b". U slučaju da se unese pogrešan znak za poreĎenje štampati poruku "Nedopusteni znak za
odnos brojeva!" .
int main(void)
{
float a,b;
char znak;
printf("Upisati prvi broj: ");

6
scanf(" %f",&a);
printf("Upisati drugi broj: ");
scanf(" %f",&b);
printf("Upisati znak poredjenja: manje <, vece >,\n");
printf(" jednako = :");
scanf(" %c",&znak);
if(znak=='<')
{
if(a<b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");
}
else if(znak=='>')
{
if(a>b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");
}
else if(znak=='=')
{
if(a==b) printf("Izabrali smo pravi odnos brojeva a i b\n");
else printf("Izabrali smo pogresan odnos brojeva a i b\n");
}
else
printf("Nedopusteni znak za odnos brojeva!\n");
return 0;
}

Zadatak 13: U sledećem primeru učitavaju se dva broja i jedan znak koji predstavlja izbor
računske operacije (s za sabiranje, o za oduzimanje, m za množenje i d za deljenje). U
zavisnosti od učitanog znaka izvršava se jedna od četiri računske operacije i štampanje
rezultata.
int main(void)
{
float a,b;
char operacija;
printf("Upisati prvi broj: ");
scanf(" %f",&a);
printf("Upisati drugi broj: ");
scanf(" %f",&b);
printf("Upisati operaciju: zbir(z), oduzimanje(o),\n");
printf(" mnozenje(m),deljenje(d) :");
scanf(" %c",&operacija);
if(operacija=='z')
printf("%f\n",a+b);
else if(operacija=='o')
printf("%f\n",a-b);
else if(operacija=='m')
printf("%f\n",a*b);
else if(operacija=='d')
printf("%f\n",a/b);
else
printf("Nedopustena operacija!\n");
return 0;
}

7
Zadatak 14: Izračunavanje vrednosti funkcije
Sastaviti dijagram toka i napisati program kojim se izračunava vrednost funkcije:
 x, x2

y   2, 2  x  3 .
x  1, x  3

Za 10 različitih vrednosti argumenta x štampati vrednosti argumenta i vrednosti funkcije.


#include<stdio.h>
#include<stdlib.h>
void main()
{
int x, y;
printf("Unesi x\n");
scanf("%d",&x);

if (x < 2)
y = x;
else if(x>=2 && x<3)
y = 2;
else
y = x-1;

printf("Rezultat funkcije je %d\n", y);


}

8
4. POMOĆNE FUNKCIJE

Zadatak 15: Primeri korišćenja funkcija abs, exp, log, sin. sqrt
#include <math.h>
#include <stdio.h>

void main(void)
{
int number = -1234;
double x = 4.0, y = 8.6872, result, z = 0.5;

printf("broj: %d ima apsolutnu vrednost: %d\n\n", number, abs(number));


result = exp(x);
printf("'e' dignuto na stepen %lf (e ^ %lf) = %lf\n\n", x, x, result);
result = log(y);
printf("Prirodni logaritam %lf je %lf\n\n", y, result);
result = sin(z);
printf("Sinus od %lf je %lf\n\n", z, result);
result = sqrt(x);
printf("KVADRATNI KOREN %lf JE %lf\n\n", x, result);
}

Zadatak 16: pow funkcija za PRIMER IZRAČUNAVANJA REALNOG BROJA NA


STEPEN
#include <math.h>
#include <stdio.h>

int main(void)
{
double x = 2.0, y = 3.0;
printf("%lf na stepen %lf je %lf\n", x, y, pow(x, y));
return 0;
}

Zadatak 17: pow funkcija za PRIMER IZRAČUNAVANJA n-tog KORENA REALNOG


BROJA
#include <math.h>
#include <stdio.h>
float main(void)
{
int n=5;
double x = 32.0,rezultat;
rezultat=pow(x,1./n);
printf("%d_ti koren broja %lf je: %lf\n",n, x,rezultat);
return 0;
}

Zadatak 18: 9. log10 funkcija za PRIMER LOGARITMA ZA OSNOVU 10 REALNOG


BROJA
#include <math.h>
#include <stdio.h>

int main(void)
{
double result;
double x = 100;
result = log10(x);
printf("LOGARITAM BROJA %lf JE %lf\n", x, result);
return 0;
}

9
Zadatak 19: rand funkcija za PRIMER GENERISANJA SLUCAJNIH BROJEVA
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
int i;
/* initialize random seed: */
srand (time(NULL));

printf("Deset slucajnih brojeva od 1 do 100 su:\n\n");


for(i=0; i<10; i++)
printf("%d\n", rand() % 100 + 1);
return 0;
}

Zadatak 20: Sastaviti program na programskom jeziku C za upotrebu funkcije rand()


kojom se uključuje generator slučajnih brojeva i štampa celobrojni slučajni broj i njegova
dvostruka vrednost. Štampati i slučajan borj izmeĎu 0 i 9. Štmpati slučajan broj izmeĎu 10 i
19.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void main()
{
int slucajan, dvostruki, x, y;
srand (time(NULL)); /* initialize random seed: */

slucajan = rand();
dvostruki = slucajan*2;
x = rand() % 10; /*slucajan izmedju 0 i 9*/
y = rand() % 10 + 10; /*slucajan izmedju 10 i 19*/
printf("Slucajan broj je %d\n", slucajan);
printf("Dvostruki slucajan broj je %d\n", dvostruki);
printf("Jos neki slucajni brojevi %d, \t %d \n", x, y);
}

Zadatak 21: Napisati program za izračunavanje funkcije:


( )
.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void main()
{
double x,y,pom;
printf("Unesite broj\n");
scanf("%lf",&x);
pom=pow(x,1./3.);
y=(x*x*sin(x)-1)/pom;
printf("Vrednost izraza je %lf a vrednost korena %lf\n",y,pom);
}

Zadatak 22: Napisati program za rešavanje kvadratne jednačine ax2+bx+c=0.


void main()
{
double a,b,c;
double x1,x2,pom;
// a = 1; b = 1; c = -2;

10
scanf("%lf%lf%lf", &a, &b, &c);
pom = sqrt(b*b-4*a*c);
x1 = ( (-b) + pom ) / 2 * a;
x2 = ( (-b) - pom ) / 2 * a;
printf("Vrednost prvog korena x1 = %f\n",x1);
printf("Vrednost drugog korena x2 = %f\n",x2);
}

Zadatak 23: Sastaviti program na C jeziku za izračunavanje površine trougla po obrascu


abc
PTROUGLA  p( p  a)( p  b)( p  c) gde je p 
2
#include<stdio.h>
#include <stdio.h>
#include <math.h>

float main(void)
{
float a,b,c,p,PTROUGLA;
printf("Upisati broj a: ");
scanf(" %f",&a);
printf("Upisati broj b: ");
scanf(" %f",&b);
printf("Upisati broj c: ");
scanf(" %f",&c);
p=(a+b+c)/2.;
printf("Vrednost prolazne promenljive je:%f\n",p);
PTROUGLA=sqrt(p*(p-a)*(p-b)*(p-c));
printf("Povrsina trougla izracunata datim obrascem je:%f\n",PTROUGLA);
return 0;
}

11
5. SWITCH – CASE NAREDBA

Zadatak 24: Naredba break sa naredbom switch. Uneti neki tekst. Unos teksta prekinuti
unošenjem znaka #. Izbrojati koliko kojih samoglasnika ima u unetom tekstu.
#include <stdio.h>
void main()
{
char ch;
int a_ct,e_ct,i_ct,o_ct,u_ct; a_ct=e_ct=i_ct=o_ct=u_ct=0;
printf("Unesi priozvoljan tekst; Unesi # za izlaz.\n");
while((ch=getchar())!= '#')
{
switch (ch)
{
case 'a' :
case 'A' : a_ct++;
break;
case 'e' :
case 'E' : e_ct++;
break;
case 'i' :
case 'I' : i_ct++;
break;
case 'o' :
case 'O' : o_ct++;
break;
case 'u' :
case 'U' : u_ct++;
break;
default: break;
} /* kraj switch */
} /* dok petlji nije kraj */
printf("Broj samoglasnika: \n A %d\n E %d\n I %d\n O %d\n U %d\n\n",
a_ct,e_ct,i_ct,o_ct,u_ct);
}

Zadatak 25: Napisati program sa menijem:


1- Program matematika
2- Program finansija
3- Program zabave
4- Exit
upotrebom naredbe switch i case.
void main()
{
int choice;
while(1)
{
printf("\n\nMeni:\n");
printf("1- Program matematika\n2- Program finansija\n");
printf("3- Program zabave\n4- Exit");
printf("\n\nVas izbor -> ");
scanf("%d",&choice);
switch(choice)
{
case 1 : printf("\nProgram matematika Runs. !"); break;
case 2 : printf("\nProgram finansija Runs. !"); break;
case 3 : printf("\nProgram zabave Runs. !"); break;
case 4 : printf("\nKraj programa!.\n"); exit(0);
default: printf("\nPogresan izbor");
}
}
}

12
6. FOR PETLJA

Zadatak 26: Napisati program koji računa proizvod 5 slučajno izabranih jednocifrenih
brojeva.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

int main(void)
{
int i,R;
long int P=1;
srand(time(NULL));
printf("Pet slucajnih brojeva izmedju 0 i 9 su: \n\n\n");
for(i=0; i<5; i++)
{
R= rand() % 10;
printf("%d\n",R );
P=R*P;
}
printf("Proizvod 5 slucajnih brojeva je: %d\n\n\n", P);
return 0;
}

Zadatak 27: Odštampati sve neparne brojeve manje od 200 koristeći for petlju:
#include <stdio.h>
void main()
{
int broj;
for (broj=1; broj<=200; broj=broj+2)
printf("\n%d",broj);
}

Zadatak 28:
1. Napisati program koji štampa tablicu množenja (od 1*1 do 9*9 tako da kao rezultat
dobijete tablicu koja ima 9 redova i 9 kolona).
#include<stdio.h>
void main()
{
int i,j;
for(i=1;i<10;i++)
{
for(j=1;j<10;j++)
printf("%3d",i*j);
printf("\n");
}
}

13
Zadatak 29: Napisati program koji računa faktorijel unetog broja (N! = 1*2*3*...* (N-1) *N)
void main()
{
int i, n;
long fak = 1;
printf("lzracunavanje n!\nUkucajte broj ? ");
scanf("%d", &n);
for ( i=1; i<=n; ++i)
fak *= i;
printf("%4d! = %ld\n", n, fak);
}

Zadatak 30: Napisati program koji računa aritmetičku sredinu za n proizvoljno unetih
realnih brojeva.
void main()
{
int n, brojac;
float suma = 0, x;
printf("Ukupno brojeva ?");
scanf("%d", &n);
for ( brojac=1; brojac<=n; ++brojac)
{
printf("Ukucajte %d broj ?", brojac);
scanf("%f",&x);
suma+=x;
}
printf("Srednja vrednost ovih brojeva je %4.2f\n", suma/n);
}

Zadatak 31: Sastaviti program za izračunavanje sume:


n
S   i!
i 1
ukoliko je n celobrojna vrdnost. (Za n=5 proizvod S=34560)
float main()
{
int i,n;
float F=1,S=1;
printf("Unesite verdnost za n\n n=");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
F=F*i;
S=S*F;
}
printf("\nRezultat proizvoda je S=%lf\n",S);
return 1;
}

14
Zadatak 32: Štampanje vrednosti stepena Farenhajta i Celzijusa pocev od 0 do 300 sa
korakom 20
#include <stdio.h>
int main()
{
int fahr;
for (fahr = 300; fahr >= 0; fahr = fahr - 20)
printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
return 0;
}

15
7. WHILE i DO WHILE PETLJE

Zadatak 33: Izračunajte zbira n proizvoljno unetih celih brojeva korišćenjem while petlje.
#include <stdio.h>
void main()
{
long sum = 0L;
int num;
printf("Unesite broj za sumiranje Ili 0 za izlaz\n");
scanf("%ld", &num);
while (num != 0)
{
sum = sum+num;
printf("Unesite naredni broj za sabiranj ili 0 za quite :::::::: %d
\n ", num);
scanf("%ld", &num);
}
printf("Zbir unetih brojeva je %ld.\n", sum);
}

Zadatak 34: Npisati program za izračunavanje sume prvih 20 prirodnih brojeva


korišćenjem while petlje.
#include <stdio.h>
int main(void)
{
int brojac,suma; /* deklaracija promenljive */
brojac = 1; /* inicijalizacija promenljive */
suma = 0; /* isto */
while(brojac++ < 21) /* while */
suma += brojac; /* naredba */
printf("suma = %d\n",suma); /* funkcijska naredba */
return 0;
}

Zadatak 35: Napisati program koji računa srednju vrednosti n realnih brojeva pomoću
while petlje.
void main()
{
int n, brojac = 0;
float suma = 0, x;
printf("Ukupno brojeva? ");
scanf("%d", &n);
while (brojac < n)
{
printf("Ukucajte %d. broj ? ", brojac+1);
scanf("%f", &x );
suma += x ;
brojac += 1;
}
printf("Srednja vrednost ovih brojeva je %f\n", suma/n);
}

Zadatak 36: Program za permutovanje cifara celog broja - while iskaz (npr. 54321 u 12345 )
Postupak: celi broj 54321 delimo po modulu 10 - rezultat je 1
celi broj 54321 delimo sa 10 - rezultat je 5432
celi broj 5432 delimo po modulu 10 - rezultat je 2
celi broj 5432 delimo sa 10 - rezultat je 543
celi broj 543 delimo po modulu 10 - rezultat je 3

16
celi broj 543 delimo sa 10 - rezultat je 54
celi broj 54 delimo po modulu 10 - rezultat je 4
celi broj 54 delimo sa 10 - rezultat je 5
celi broj 5 delimo po modulu 10 - rezultat je 5
Petlja se prekida jer broj postaje nula !!!
#include <stdio.h>
void main()
{
int broj;
printf("Ukucajte ceo broj ? ");
scanf("%d", &broj );
printf("Permutovani broj je ");
while ( broj )
{
printf("%d", broj % 10);
broj = broj/10;
}
printf("\n");
}

Zadatak 37: Napisati program na jeziku C koji za zadani prirodan broja treba da izračuna i
ispiše sve njegove delitelje.
int main(void)
{
long num; // broj koji proveravamo
long div; // potencijalni delitelj
unsigned flag = 1; // prost broj?
printf("Unesite celi broj: ");
scanf("%ld",&num);
printf("%d je deljiv sa 1 i %d\n", num, num);
for (div=2; div<=num/2; div++)
if(num % div == 0)
{
printf("%d je deljiv sa %d i %d\n", num, div, num/div);
flag = 0;
}

if(flag == 1) printf("%ld je prost broj.\n",num);


return 0;
}

Zadatak 38: Napisati program na jeziku C koji proverava da li je uneti broj prost?
int main(void)
{
long num; // broj koji proveravamo
long div; // potencijalni delitelj
unsigned flag = 1; // prost broj?
printf("Unesite celi broj: ");
scanf("%ld",&num);
for (div=2; div<=num/2; div++)
if(num % div == 0)
flag = 0;

if(flag == 1)
printf("%ld je prost broj.\n",num);
else
printf("%ld je slozen.\n",num);
return 0;
}

Zadatak 39: Napisati program za izrašunavanje n! primenom do while structure:

17
#include <stdio.h>
void main() /* Program za izracunavanje faktorijela */
{
int i, fak;
long n ;
i = 1; n = 1;
printf("lzracunavanje n!\nUkucajte broj ? ");
scanf("%d", &fak);
do{
n *= i;
i++;
} while (i <= fak);
printf("%d! = %ld\n", fak,n);
}

Zadatak 40: Napisati program na jeziku C koji računa najvećeg zajedničkog delioca dva
nenegativna cela broja. Za izračunavanje koristiti Euklidovu metodu koja se sastoji iz
sledećih koraka:
 Neka su a i b dva broj za koje važi da je a >= b
 Izračunaj c = a MOD b
 Ako je c = 0, b je najvedi zajednički delilac
 Ako je c != 0, onda de a da uzme vrdnost b, a b de uzeti vrednost c.
 Ponoviti postupak sve dok c ne bude jednako 0
#include<stdio.h>
void main()
{
int prvi, drugi, pomocni;
printf("Ukucajte dva nenegativna cela broja ?\n");
scanf("%d%d", &prvi, &drugi );
if (prvi < drugi)
{
pomocni = prvi;
prvi = drugi;
drugi = pomocni;
}

while (drugi != 0)
{
pomocni = prvi % drugi;
prvi = drugi;
drugi = pomocni;
}
printf("Najveci zajednicki delilac ovih brojeva je %d\n", prvi);
}

Zadatak 41: Napisati program za permutovanje cifara nenegativnog celog broja koristeći
do-while iskaz.
#include<math.h>
void main()
{
int broj;
printf("Ukucajte ceo broj ? ");
scanf("%d", &broj );
printf("Permutovani broj je ");
do
{
printf("%d", broj%10);
broj =broj/10;
}
while (broj);
printf("\n");

18
}

19
Zadaci za pripremu II kolokvijum iz predmeta
programski jezici I

Sadržaj
Zadaci za pripremu II kolokvijum iz predmeta programski jezici I .................................................... 1
Nizovi ................................................................................................................................................... 2
Funkcije i procedure............................................................................................................................. 4
Rad sa nizovima karaktera ................................................................................................................. 14
Matrice ............................................................................................................................................... 21
Opšti zadaci ........................................................................................................................................ 26

1
Nizovi
Zadatak 1: Napisati program za unos i izračunavanje zbira članova niza sa 5 elemenata.
void main(void)
{
float broj[5]; //deklaracija niza
double rez = 0; int i; //pomocne promenljive

for(i=0; i < 5; i++) //uzmi podatke i smesti ih u broj


{
printf("Unesite broj %d : ", i+1);
scanf("%f", &broj[i] );
}

for(i = 4; i+1 ; i--) //saberi


rez += broj[i];

printf("Zbir unesenih brojeva je %lf \n", rez); //prikazi rezultat


}

Zadatak 2: Napisati program za štampanje niza i množenje elemenata niza konstantnom


vrednošću.
#include <stdio.h>
#define VELICINA 5

void main()
{
double dip[VELICINA] = {20.0, 17.66, 8.2, 15.3, 22.22};
int i;
for(i = 0; i < VELICINA; i++)
dip[i] *= mnozi;

printf("\n");
for(i = 0; i < n; i++)
printf("%8.3f ", dip[i]);
printf ("\n");
}

Zadatak 3: Razmotriti rad programa pisanog u C programskom jeziku, koji sortira dati
vektor ar = {7,3,9,2,11,20,17,19,6,4} korišćenjem metode "bubble sort" algoritma.
Program se najpre sastoji u pisanju funkcije "swap" koja vrši zamenu vrednosti dve
promenljive i smešta ih u dve memorijske lokacije. Zatim tu funkciju koristimo da bi
izvršili sortiranje datog vektora. "Bubble sort" ispituje svake dve ćelije vektora i ako nisu
sortirane - svapuje ih. Ako se obezbedi upoređenje i svapovanje n-1 put nad svim ćelijama
vektora, on će biti kompletno sortiran.
#include <stdio.h>
void swap (int *a, int *b);

void main()
{
int ar[10] = {7, 3, 9, 2, 11, 20, 17, 19, 6, 4};
int i,j,n;

printf("Vektor pre sortiranja:\n");


for(i=0;i<10;i++)
printf("ar[%d]=%d\n",i,ar[i]);

n=10; /*broj clanova u vektoru koji se sortira*/


for(i=0;i<n-1;i++)
for(j=0;j<n-1;j++)
2
{
if(ar[j]>ar[j+1])
swap(&ar[j],&ar[j+1]);
}

printf("\nVektor posle sortiranja:\n");


for(i=0;i<10;i++)
printf("ar[%d]=%d\n",i,ar[i]);
}

void swap ( int *a,int *b)


{
int temp;
temp=*a;
*a=*b;
*b=temp;
}

3
Funkcije i procedure
Zadatak 4: Pokazati kako funkcioniše prototip funkcije.
void myfunc();/*inicijalizacija funkcije bez argumenata*/
void main()
{
myfunc();/*pozivanje funkcije bez argumenata*/
}

void myfunc()/*definisanje funkcije bez argumenata*/


{
printf("ZDRAVO, ovo je test\n");
}

Zadatak 5: Korišćenje prototipa funkcije sa argumentom.


void napisi(int count);
void main()
{
napisi(4);
}

void napisi(int count)


{
int c;
for(c=0;c<count;c++)
printf("\nZDRAVO");
}

Zadatak 6: Naći minimum od dva cela broja. U glavnom programu obezbediti štampanje, a
u funkciji njihovo poređenje.
int imin(int n,int m);
void main()/* glavni program */
{
int broj1,broj2,vrati;
printf("Unesite dva cela broja\n");
vrati=scanf("%d %d",&broj1,&broj2);
if(vrati == 2)
printf("Manji od %d i %d je %d\n",broj1,broj2,imin(broj1,broj2));
}

int imin(int n,int m)/* potprogram */

4
{
int min;
if (n<m)
min=n;
else
min=m;
return min;
}

Zadatak 7: Uraditi meni sa izborom operacija za sabiranje, oduzimanje i množenje dva


cela realna broja. U funkciji izvesti opisane računske radnje.
void add();
void subtract();
void multiply();

void main()
{
int choice;
while(1)
{
printf("\n\nMenu:\n");
printf("1- Add\n2- Subtract\n");
printf("3- Multiply\n4- Exit");
printf("\n\nYour choice -> ");
scanf("%d",&choice);
switch(choice)
{ case 1 : add();
break;
case 2 : subtract();
break;
case 3 : multiply();
break;
case 4 : printf("\nProgram Ends. !");
exit(0);
default:
printf("\nInvalid choice");

}
}
}

void add()
{
float a,b;
printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
printf("a+b=%f",a+b);
}

void subtract()
{

5
float a,b;
printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
printf("a-b=%f",a-b);
}

void multiply()
{
float a,b;
printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
printf("a*b=%f",a*b);
}

Zadatak 8: Prenošenje parametara funkcije po vrednosti i po referenci


void test1(int a)
{
a=5;
}

void test2(int &a)


{
a=5;
}

void test3(int* a)
{
*a = 5;
}

int main()
{
int m;
m=2;
printf("\nM je %d",m);
test1(m);
printf("\nM je i dalje %d iako je vrednost promenjna u funkciji",m);
6
printf("\n\n\nM je %d",m);
test2(m);
printf("\nM je promenila vrednost i sada je %d\n",m);

printf("\n\n\nM je %d",m);
test3(&m);
printf("\nM je promenila vrednost i sada je %d\n",m);
return 0;
}

Zadatak 9: MNOZENJE I SABIRANJE DVA REALNA BROJA PREKO FUNKCIJE


int mno(int x, int y);
int sab(int x, int y);
void main()
{
int a,b;
printf("\nUnesite vrednosti za a i b\n");
scanf("%d%d",&a,&b);
printf ("\nproizvod je %d\n", mno(a,b));
printf ("\nZbir je %d\n", sab(a,b));
}

int mno(int x, int y)


{
return x*y;
}

int sab(int x, int y)


{
return x+y;
}

Zadatak 10: MINIMUM TRI CELA BROJA PREKO FUNKCIJE


#include<math.h>
void min();
void main()
{
min();
}

void min()
{
int a,b,c,m;
printf("\nUnesite vrednosti za a , b i c\n");
scanf("%d%d%d",&a,&b,&c);
m=a;
if(b<m) m=b;
if(c<m) m=c;
printf("Minimum brojeva a=%d b=%d i c=%d je broj %d\n",a,b,c,m);
}

7
Zadatak 11: Suma kvadrata celih brojeva od 1 do N preko funkcije
#include <stdio.h>
#include <math.h>
suma_kvadrata(int n);

void main( )
{
suma_kvadrata(10);
suma_kvadrata(15);
suma_kvadrata(20);
}

suma_kvadrata(int n) /*f ja za izracunavanje*/


/*sume kvadrata*/
{
int i;
long suma=0;
for (i=1; i<=n; suma+=(long)i*i, ++i);
printf("Suma kvadrata od 1 do %d je %ld\n", n, suma);
return 0;}

Zadatak 12: Primer funkcije bez povratnih vrednosti


void ispis(int i1, int i2, int i3); /* F-ja ne vraca nikakvu vrednost*/
void main()
{
int a,b,c;
a=b=c=1;
ispis(a,b,c);
a=b=c=2;
ispis(a,b,c);
}

void ispis(int i1, int i2, int i3)


{
printf("\nVrednost promenljive param1 je %d.\n",i1);
printf("Vrednost promenljive param2 je %d.\n",i2);
printf("Vrednost promenljive param3 je %d.\n",i3);
}

8
Zadatak 13: Poziv funkcije bez argumenta
void main()
{
void zvezde(); /*deklaracija funkcije bez argumenata*/
zvezde(); /*poziv korisnicke funkcije */
printf("%s \n ", IME) ; /*poziv funkcije iz standardne biblioteke*/
printf("%s\n", ADRESA);
printf("%s\n", MESTO) ;
zvezde ( ) ;
}
/*definicija korisnicke funkcije */
void zvezde() /*funkcija nema argumenata*/
{
int brojac;
for(brojac=1; brojac <= LIMIT; brojac++)
putchar ( '*' );
putchar ( '\n' ) ;
}

Zadatak 14: Napisati program za izračunavanje hipotenuze pravouglog trougla. U glavnom


program izvršiti unos vrednosti prve i druge katete i štampati vrednost hipotenuze. U
potprogramu izračunati vrednost hipotenuze.
#include<stdio.h>
float hipotenuza( float n, float m); // Deklaracija funkcije

void main() /* glavni program */


{
float kat1, kat2, hip;
printf("Unesite 2 proizvoljna broja: \n");
scanf("%f %f",&kat1,&kat2);
hip = hipotenuza(kat1,kat2);
printf("Hipotenuza je %4.2f\n",hip);
}

float hipotenuza( float n, float m ) /* potprogram – definicija


funkcije */
{
float rez = sqrt(n*n + m*m);
return rez;
}

Zadatak 15: Napisati program za izračunavanje hipotenuze pravouglog trougla. U glavnom


programu štampati vrednost hipotenuze. U potprogramu izračunati vrednost hipotenuze.
U drugom potpotprogramu izvršiti unos vrednosti kateta.

#include<stdio.h>
float hipotenuza( float n, float m); // Deklaracija funkcije
void unos( float &n, float &m);

void main() /* glavni program */


{
9
float kat1, kat2, hip;
unos(kat1, kat2);
hip = hipotenuza(kat1,kat2);
printf("Hipotenuza je %4.2f\n",hip);
}

float hipotenuza( float n, float m ) /* potprogram – definicija


funkcije */
{
float rez = sqrt(n*n + m*m);
return rez;
}

void unos( float &n, float &m)


{
printf("Unesite 2 proizvoljna broja: \n");
scanf("%f %f",&n,&m);
}

Zadatak 16: Primer za izracunavanje y=sin2(x)+cos2(x)


double Funkcija(double x)
{
double y;
y=sin(x)*sin(x)+cos(x)*cos(x);
return y;
}
void main()
{
double x,y;/* deklaracija lokalnih promenljivih, posle pocetka programa*/
printf("Unesite vrednost za x:");
scanf("%lf",&x);
y=Funkcija(x);
printf("Vrednost funkcije je %f.",y);
}

Zadatak 17: Izracunavanje povrsine trougla sa dve funkcije


#include<stdio.h>
#include<math.h>
float Povrsina(int &a, int &b, int &c);
void Ucitaj(int &a, int &b, int &c);
void main()
{
int a, b,c;
Ucitaj(a, b, c);

10
float pt = Povrsina(a, b, c);
printf("\nPovrsina trougla je %f.",pt);
}

float Povrsina(int &a, int &b, int &c)


{
float p = (a+b+c)/2;
p = sqrt(p*(p-a)*(p-b)*(p-c));
return p;
}

void Ucitaj(int &a, int &b, int &c)


{
printf("Prva kateta:");
scanf("%d",&a);
printf("Druga kateta:");
scanf("%d",&b);
printf("Treca kateta:");
scanf("%d",&c);
}

Zadatak 18: Četiri računske radnje preko funkcije choice i switch naredbi.
#include<stdio.h>
#include<stdlib.h>
float add(float aa, float bb);
float subtract(float aa, float bb);
float multiply(float aa, float bb);
float divide(float aa, float bb);

void main()
{
int choice;
float a, b, rezultat;
while(1)
{
printf("\n\nMenu:\n");
printf("1- Add\n2- Subtract\n");
printf("3- Multiply\n4- Divide\n5-Exit");
printf("\n\nYour choice -> ");
scanf("%d",&choice);
if (choice != 5)
{
printf("\nEnter a:");
scanf("%f",&a);
printf("\nEnter b:");
scanf("%f",&b);
}
switch(choice)
{
case 1: rezultat = add(a,b);
printf("Rezultat operacije je:%f\n",rezultat);
break;
case 2: rezultat = subtract(a,b);
printf("Rezultat operacije je:%f\n",rezultat);

11
break;
case 3: rezultat = multiply(a,b);
printf("Rezultat operacije je:%f\n",rezultat);
break;
case 4: rezultat = divide(a,b);
printf("Rezultat operacije je:%f\n",rezultat);
break;
case 5: printf("\nProgram Ends. !");
exit(0);
default: printf("\nInvalid choice");}
}
}

float add(float aa, float bb)


{
return (aa+bb);
}

float subtract(float aa, float bb)


{
return (aa-bb);
}

float multiply(float aa, float bb)


{
return (aa*bb);
}

float divide(float aa, float bb)


{
return (aa/bb);
}

Zadatak 19: Primer prenosa niza kao parametra funkcije za realizaciju sabiranja članova
niza.
#include <stdio.h>
#define VELIC 10
long sump(int *pok, int vel);

void main()
{
12
static int niz[VELIC] = {20,10,5,39,4,16,19,26,31,20};
long odgovor;
odgovor = sump(niz, VELIC);
printf("Suma niza je: %ld.\n", odgovor);
}

long sump(int *ar, int n) /* koristi pokazivacku aritmetiku */


{
int i ;
long ukupno = 0;
for(i = 0; i < n; i++) {
ukupno += *ar; /* dodaje vrednost na ukupno */
ar++; /* pomera pokazivac na sledeci elemenat */
}
return ukupno;
}

Zadatak 20: Napisati program za štampanje niza i množenje elemenata niza konstantnom
vrednošću. Množenje i štmpanje niza impelemntirati pomoću potprograma.
void prikaz_niza(double niz[], int n);
void uvecaj_niz(double broj, double *pok, int vel);

void main()
{
static double dip[VELICINA] = {20.0, 17.66, 8.2, 15.3, 22.22};
prikaz_niza(dip, VELICINA);
uvecaj_niz(2.5, dip, VELICINA) ;
prikaz_niza(dip, VELICINA);
}

void prikaz_niza(double *ar, int n) //*ar je ekvivalentno sa ar[] !!!//


{
int i;
printf("\n") ;
for(i = 0; i < n; i++)
printf("%8.3f ", ar[i]);
printf ("\n");
}

void uvecaj_niz(double mnozi, double *ar)


{
int i;
for(i = 0; i < VELICINA; i++)
ar[i] *= mnozi;
}

13
Rad sa nizovima karaktera
Zadatak 21: Primer rada sa funkcijama za rad sa stringovima (nizovima karaktera).
#include <cstring>
#include <stdio.h>

void main()
{
char rec1[20] = "lep";
char rec2[20] = "dan";
char rec3[20];

printf("%d\n", strlen(rec1));
printf("%d\n", strlen(rec2));
printf("%s\n", strcat(rec1, rec2));
printf("%d\n", strlen(rec1));

strcpy(rec3, rec1);

printf("%s \n %s\n %s\n", rec1, rec2, rec3);


// printf ("%d", i);

printf("%d\n", strcmp(rec1, rec2));


printf("%d\n", strcmp(rec1, rec3));
}

Zadatak 22: Primer za vrednost EOF


#include <cstdio>
int main()
{
printf("Na mom sistemu vrednost za EOF je %d\n\n", EOF);
return 0;
}

Zadatak 23: Razliciti primeri za unosenje i štampanje niza karaktera sa standardnog ulaza:
void main()
{
char recenica[80];
printf("Unesite niz proizvoljnih karaktera:");
gets(recenica);
printf("\nUneli ste niz karaktera:");
puts(recenica); //Stampanje unetih karaktera
printf("\n"); //Prelazak u novi red

printf("Unesite niz karaktera: ");


scanf("%s",&recenica); //scanf cita samo do prvog belog znaka
printf("Prikaz unetog sadrzaja: %s\n",recenica);
}

14
Zadatak 24: Unos i štampanje jednog karaktera
#include<stdio.h>
void main( ) {
char c;
printf("Unesite jedan proizvoljni karakter:");
c = getchar( );
putchar('\n');//Prelazak u novi red
printf("Uneli ste karakter:");
putchar(c);//Stampanje unetog karaktera
putchar('\n');//Prelazak u novi red
}

Zadatak 25: Unos i štampanje karaktera


#include <stdio.h>
void main()
{
int vrednost;
vrednost='A';
printf("%s \nkarakter=%3c \nvrednost=%3d \n","Veliko slovo",
vrednost, vrednost);
vrednost='a';
printf("%s\nkarakter=%3c\nvrednost=%3d\n","Malo slovo",
vrednost, vrednost);
}

15
Zadatak 26: - Program čita jedan karakter i ispisuje ga.
#include <stdio.h>
void main()
{
int c; /* Karakter - obratiti paznju na int */
printf("Unesite jedan proizvoljni karakter:");
c = getchar(); /* cita karakter sa standardnog ulaza */
printf("\nUneli ste karakter:");
putchar(c); /* pise karakter zapamćen u promenljivoj c na standardni izlaz */
putchar('\n'); /* prelazak u novi red */
printf("Ispisuje malo a:");
putchar('a'); /* ispisuje malo a */
printf("\nIspisuje ASCI 97:");
putchar(97); /* ekvivalentno prethodnom */
putchar('\n');/* prelazak u novi red */
}

Zadatak 27: Program učitava i broji karaktera sa ulaza sve dok se ne otkuca znak za kraj
unosa EOF. EOF se može generisati kucanjem Control /Z.
#include <stdio.h>
void main()
{
int ch, i = 0;
while((ch = getchar()) != EOF)
i ++;
printf("%d\n", i);
}

Zadatak 28: Program koristi getchar da učita liniju sa standardnog ulaza stdin, postavlja
takav ulaz u buffer, onda završava string terminacionim karakterom i zatim štampa
string na ekranu.
#include <stdio.h>
void main( void )
{
char buffer[81];
int i, ch;
printf( "Enter a line: " );
/* Read in single line from "stdin": */
for( i = 0; (i < 80) && ((ch = getchar()) != EOF)
&& (ch != '\n'); i++ )
buffer[i] = (char)ch;
/* Terminate string with null character: */
buffer[i] = '\0';
printf( "%s\n", buffer );

16
}

Zadatak 29: Program konvertuje ulazne karaktere u velika slova. Da bi ovo učinili moramo
dodati funkciju toupper iz biblioteke za konverziju karaktera ctype.h
#include <ctype.h> /* For definition of toupper */
#include <stdio.h> /* For definition of getchar, putchar, EOF */

void main()
{
int ch;
while((ch = getchar()) != EOF)
putchar(toupper(ch));
}

Zadatak 30: NCP koji će ispisati na standardni izlaz ukupan broj karaktera standardnog
ulaza do markera kraja, kao i broj prelazaka u novi red. Pretpostaviti da je za ukupan
broj karaktera (zajedno sa enter i blanko) i ukupan broj prelazaka u novi red dovoljan
opseg long promenljivih.
#include <stdio.h>
void main()
{
int znak; /*prihvata znak sa ulaza */
long linije=0 ; /*brojac linija */
long br_znak=0; /*brojac znakova na ulazu */
while ( (znak=getchar() ) != EOF)
{
br_znak++;
if (znak=='\n')
linije ++;
}
printf("Prelazaka u novi red: %ld, karaktera: %ld \n",linije,br_znak);
}

Zadatak 31: Program za prikazivanje tablice ASCII kodova:


#include <stdio.h>
void main()
17
{
char c=' ';
int i;

printf ("\t\tTablica ASCII kodova \n \n");


for (i=0; i<95; i++)
printf("%3d %c ",c+i,c+i);
if (i%19 == 0)
printf("\n");
}

Zadatak 32: Napisati program koji nalazi najduzu unetu liniju sa standardnog ulaza. Nije
poznat ukupan broj linija, ali svaka linija nema vise od 80 karaktera a unos se prekida
unosom karaktera CTRL/Z.
#define MAX_DUZINA_LINIJE 80
void main()
{
char linija[MAX_DUZINA_LINIJE];
char najduza_linija[MAX_DUZINA_LINIJE];
int duzina_linije = 0;
int duzina_najduze_linije = 0;
najduza_linija[0] = '\0';
while( gets(linija) != NULL){
duzina_linije=strlen(linija);
if (duzina_linije > duzina_najduze_linije){
strcpy(najduza_linija, linija);
duzina_najduze_linije = duzina_linije;
}
}
printf("Najduza linija je : %s\n i ona ima %d karaktera
\n\n",najduza_linija, duzina_najduze_linije);
}

18
Zadatak 33: Uraditi program za unos niza karaktera ”Moram da položim drugi kolokvijum
iz Programskih jezika 1” u vektor Niz1. Odštampati ovaj niz karaktera u potpunoj formi,
i izračunati dužinu unetog niza. Iskopirati sadržaj vektora Niz1 u vektror Niz2 i utvrditi
dali su to isti nizovi. Prebrojati koliko praznina (blanko karaktera) ima u nizu Niz1.
void main()
{
int brojznak=0,i=0;
char Niz1[81],Niz2[81];
printf("Unesi clanove niza Niz1, za kraj Ctrl/z/");
while( gets(Niz1)!= NULL) /* Unos se prekida sa Ctrl/z */
continue;

printf("Linija niza Niz1 je : %s\n",Niz1);


printf("\nDuzina niza po broju karaktera je:%d\n",(strlen(Niz1)-1));
strcpy(Niz2,Niz1);
printf("Linija niza Niz2 je : %s\n",Niz2);

if (strcmp(Niz1,Niz2)==0)//Komparacija-uporedjivanje dva niza


printf("Ovo su jednaki NIZOVI!\n");
else printf("Ovo nisu jednaki NIZOVI!\n");

while (Niz1[i]!='\n')
{
if(Niz1[i] == ' ')
brojznak++;
i=i+1;
}
printf("Broj blanko znakova u nizu Niz1 je:%ld \n",brojznak);
}

Zadatak 34: Sastaviti program koji iz skupa unetih karaktera (na primer: ’’Ja sam rodjen
1990. god u 12. mesecu, u petak!’’) izračunava broj unetih slova, brojeva i ostalih
karaktera. Tekst se unosi sa tastature, a program se prekida pritiskom na ctrl+Z
#include<conio.h>
void main( ){
int slovo, broj, ostalo, c;
slovo = broj = ostalo = 0;
while( (c=getchar( )) != EOF )
if( ('A'<=c && c<='Z') || ('a'<=c && c<='z') )
++ slovo;
else if( '0'<=c && c<='9' ) ++broj;
else ++ostalo;
printf("Uneli ste:%d slova, %d brojeva,%d ostalih\n\n", slovo, broj,
ostalo);
}

19
Zadatak 35: Napisati program konvertuje velika u mala slova. Recenica se unosi sa tastature
a program se prekid unošenjem karaktera %.
void main( ) {
char c;
while( (c=getchar( )) != '%' )
if( 'A'<=c && c<='Z' )
putchar(c+'a'-'A');
else
putchar(c);
}

Zadatak 36: Program broji karaktere, brojeve i praznine u tekstu. Završava se unosom %.
void main( )
{
int let, dig, other, c;
let = dig = other = 0;
while( (c=getchar( )) != '%' )
if( ('A'<=c && c<='Z') || ('a'<=c && c<='z') )
++let;
else if( '0'<=c && c<='9' ) ++dig;
else ++other;
printf("%d slova, %d broja, %d ostalih karaktera\n", let, dig,
other);
}

20
Matrice
Zadatak 37: Štampanje elemenata matrice
#include<stdio.h>
#include<math.h>
void main()
{
static int mat[3][3]={{0,1,2},{3,4,5},{6,7,8}};
int i,j;
for(i=0; i<3; ++i)
{
printf("\n");
for(j=0; j<3; ++j)
printf("%d\t",j,mat[i][j]);
}
printf("\n");
}

Zadatak 38: Neka je data kvadratna matrica u formatu:


1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Članove matrice uneti u program kao konstantne celobrojne veličine, a kao izlaz iz programa
predvideti štampanje ove matrice u pokazanom formatu kao polazne matrice i štampanje
nove matrice u istom obliku ali čiji su svi članovi sada pomnoženi skalarom 2.
#include<stdio.h>
#include<math.h>
void main()
{
int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j;
printf("\nPolazna matrica je\n");
for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
printf("%2d ",mat[i][j]);
printf("\n");
}

printf("\nNova matrica je\n");


for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
printf("%2d ",2*mat[i][j]);
printf("\n");
}
}

21
Zadatak 39: Neka je data kvadratna matrica u formatu:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Članove matrice uneti u program kao konstantne celobrojne veličine, a kao izlaz iz programa
predvideti štampanje ove matrice u pokazanom formatu kao polazne matrice i štampanje
nove matrice u istom obliku ali sada unazad od člana a44,a43,a42a41,......,a11.
void main()
{
int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j;
printf("\nPolazna matrica je\n");
for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
printf("%2d ",mat[i][j]);
printf("\n");
}

printf("\nNova matrica je\n");


for(i=3;i>=0; i--)
{
for(j=3;j>=0; j--)
printf("%2d ",mat[i][j]);
printf("\n");
}
}

Zadatak 40: Napisati program na C++ jeziku koji izračunava sumu svih elemenata u
svakom redu pojedinačno, pravougaone matrice [4x4].
22
1 2 3 4
5 6 7 8
A=
9 10 11 12
13 14 15 16
void main()
{
int mat[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int i,j,s=0;

printf("\nPolazna matrica je\n");


for(i=0;i<4; i++)
{
for(j=0;j<4; j++)
printf("%2d ",mat[i][j]);
printf("\n");
}

for(i=0;i<4; i++)
{
printf("\nSuma %d reda je:",i+1);
for(j=0;j<4; j++)
s=s+mat[i][j];
printf("%2d\n",s);
s=0;
}
}

Zadatak 41: NCP koji sa standardnog ulaza učitava 3x3 matricu i ispisuje je na standardni
izlaz tako da centralno polje a[1][1] bude jednako sumi gornjeg levog (a[0][0]) i donjeg
desnog polja (a[2][2]). Pre učitavanja popuniti matricu proizvoljnim vrednostima.
#include <stdio.h>
void main()
{
int a[3][3]; /* deklaracija i inicijalizacija matrice a, može se uraditi
za konkretan primer date matrice*/
int i, j; /*brojaci u ciklusu */

for(i=0; i<3; i++)


for(j=0; j<3; j++)
{
printf("\na[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
printf("\n*******************\n");
23
a[1][1] = a[0][0] + a[2][2]; /* 0 + 22 = 22 */

/*ispis matrice */
for(i=0; i<3; i++)
{
for(j=0; j<3; j++) printf("%d\t", a[i][j]);
printf("\n");
}
}

Zadatak 42: Neka je data kvadratna matrica u formatu:


a11 a12 a13 a14
a 21 a 22 a 23 a 24
a31 a32 a33 a34
a 41 a 42 a 43 a 44
Uneti članove matrice u program kao celobrojne veličine, a kao izlaz iz programa predvideti
štampanje takve matrice u pokazanom formatu kao i štampanje izračunate vrednosti njene
dijagonale a11*a22*a33*a44 urađene preko funkcije.
int d(int mat[4][4])
{
int i,j, rez=0;
for(i=0;i<4;++i)
for(j=0;j<4;++j)
if (i == j)
rez = rez + mat[i][j];
return rez;
}

void main()
{
int mat[4][4];
int i,j;
float dijagonala;
printf("Unesite proizvoljne elemente pravougle matrice:\n");
for(i=0;i<4;++i)
for(j=0;j<4;++j)
24
{
printf("a[%d][%d]=",i,j);
scanf("%d",&mat[i][j]);
printf("\n");
}
printf("\nPolazna matrica je\n");
for(i=0;i<4;++i)
{
for(j=0;j<4;++j)
printf("%3d ",mat[i][j]);
printf("\n");
}

printf ("Vrednost zbira elemenata na glavnoj dijagonali je: %d\n",


d(mat));
}

25
Opšti zadaci
Zadatak 43: Program za odredjivanje da li je godina prestupna ili nije
#include<stdio.h>
#include<math.h>
void main()
{
int godina,ost_4,ost_100,ost_400;
printf("Ukucajte godinu ? ");
scanf("%d", &godina);
ost_4=godina%4;
ost_100=godina%100;
ost_400=godina%400;
if (ost_4 ==0 && ost_100 != 0 || ost_400== 0)
printf("Godina %d je prestupna\n", godina);
else
printf("Godina %d nije prestupna\n", godina);
}

Zadatak 44: Program za odredjivanje srednje vrednosti n celih pozitivnih brojeva -for iskaz
#include<stdio.h>
#include<math.h>
void main()
{
int n,brojac;
float suma =0, x ;
printf("Ukupno brojeva? ");
scanf("%d", &n);
for (brojac=1 ; brojac<=n; ++brojac, suma+=x )
{
printf("Ukucajte %d broj? ",brojac);
scanf("%f",&x);
}
printf("Srednja vrednost ovih brojeva je %f\n", suma/n);
}

Zadatak 45: Program za izracunavanje faktorijela


#include <stdio.h>
#include <math.h>
void main()
{
int i, n;
long fak = 1;
printf("lzracunavanje n!\nUkucajte broj ? ");
scanf("%d", &n);
26
for ( i=1; i<=n; ++i)
fak *= i;
printf("%d! = %ld\n", n, fak);
}

Zadatak 46: Program za izracunavanje prostih aritmetickih izraza u formi operand1


operator operand2
#include <stdio.h>
#include <math.h>
void main()
{
float operand1, operand2;
char op;
printf("Ukucajle lzraz ? \n");
scanf("%f%c%f", &operand1, &op, &operand2);
switch (op)
{
case '+':
printf("%f\n", operand1+operand2);
break;
case '-':
printf("%f\n", operand1-operand2 );
break;
case '*':
printf("%f\n", operand1*operand2 );
break;
case '/':
printf("%f\n", operand1/operand2);
break;
default:
printf("Nepoznat operator\n");
}
}

Zadatak 47: Odredjivanje u ulaznom tekstu broja praznih karaktera, kao i broja znakova:
tacka, zarez, dvotacka i tacka-zarez (naredbe switch i break) za izlaz CTRL/Z.
#include <math.h>
#include <stdio.h>
void main( )
{
int c, prazno=0, interp=0;
while((c=getchar())!=EOF)
switch(c)
{
27
case ' ':
prazno++;
break;
case '.':
case ',':
case ':':
case ';':
interp++;
break;
default:
break;
}
printf("\nBroj praznina: %d", prazno);
printf("\nBroj znakova tacka, zarez, dvotacka i tacka-zarez: %d\n",
interp);
}

28

You might also like