Naputak za kori�tenje tutoriala
�itajte pa�ljivo, i �to je najva�nije sa razumijevanjem,
jer programiranje se ne mo�e na�trebati, mora se razumjeti.
Prije nego �to pro�itate obja�njenja za pojedine primjere,
poku�ajte sami razumjeti za�to je ne�to u tom programu napisano
ba� tako kako je, a ne druga�ije. Zadatke koji se nalaze
u ovom tutorialu svakako probajte sami rije�iti prije nego
�to pogledate rje�enje. Kako gradivo odmi�e ne�e svaki put
biti obja�njen svaki pojedini korak u primjerima programa.
Na kraju kada prou�ite cjeli tutorial svakako sami sebi
stvarajte zadatke, i po mogu�nosti rije�ite ih, preporu�ujem
da se samostalno potrudite pozabaviti sa programiranjem
nekih grafi�kih efekata, kao npr. kretanje neke loptice
preko ekrana i sl, jer �esto se programiranje najbolje nau�i
tek kada se krenu raditi grafi�ki programi.
Ako radite pod win OS-om, tada �ete source k�dove primjera
ili rje�enja najlak�e prebaciti u BorlandC tako da pokrenete
BC u prozoru (ne u full-screenu), te ozna�ite �eljeni k�d,
i stisnete gumb paste u dos-prozoru. Windowsi �e tada opona�aju�i
tipkanje na tipkovnici prenijeti pastani tekst u BC, pri
tome morate paziti da aktivni prozor u BC-u bude source
window. Naravno, sve primjere mo�ete pokretati i u nekom
windows C compileru.
1. Osnovni tipovi podataka
Prvo �u reci za�to je bitno razlikovati tipove podataka:
U C-u svaku varijablu prije nego ju po�nete koristiti, morate
ju deklarirati, to zna�i da odre�ujete kojeg je varijabla
tipa podatka. Da bi uspje�no napisali efikasan program koji
zauzima to�no onoliko memorije koliko je potrebno, da neka
vrijednost u programu slu�ajno ne bi iza�la iz opsega itd,
morate znati osnovne razlike izme�u osnovnih tipova podataka.
Razlika mo�e biti u veli�ini podatka (8bit, 16bit, ...),
druga razlika mo�e biti u predznaku, tj. dali je sa nekim
tipom podatka mogu�e prikazati negativnu vrijednosti ili
nije. Sada �u navesti par osnovnih tipova podataka i osnovne
karakteristike tih tipova:
Int |
16 bit, cjelobrojan, ima predznak, opseg:
-32768 do +32767 |
unsigned
int |
16 bit, cjelobrojan, nema predznak, opseg:
0 do +65535 |
Char |
8 bit, cjelobrojan, odgovara jednom znaku,
ima predznak, opseg ?128 do +127 |
unsigned
char |
8 bit, cjelobrojan, nema predznak, opseg:
0 do +255 |
long
|
32 bit, cjelobrojan, ima predznak, opseg:
-2 147 483 648 do + 2 147 483 647 |
Float |
32 bit, broj sa pomi�nim zarezom (sa ovim
tipom mogu�e je pamtiti decimalni broj), sa predznakom,
opseg: -3.4 *(10 exp -38) do +3.4 * (10 exp +38)
|
1.1 Kako deklarirati varijablu
Varijabla se deklarira tako da se navede oznaka tipa podatka,
te iza te oznake navedemo sva imena varijabli odvojena zarezom
za koje �elimo da budu tog tipa. Na kraju redak mora zavr�iti
sa to�kom-zarez, na primjer:
int
a,b; ->deklariraju se varijable a
i bb
kao tipovi podatka int
float
neki_broj; ->varijabla neki_broj
deklarira se kao tip podatka float
2. Deklaracija funkcija
Dobar stil programiranja je razbiti program na vi�e razli�itih
funkcija, gdje svaka funkcija obavlja neki specifi�ni zadatak.
Op�i oblik funkcije je da prima odre�ene parametre kao ulaz,
a vra�a kao rezultat jednu jedinu veli�inu. Pod pojmom deklaracije
funkcije se podrazumijeva odre�ivanje koje tipove podataka
funkcija prima kao parametar, te koji tip podatka funkcija
vra�a kao rezultat. Op�i oblik deklaracije funkcije je da
se pi�e prvo oznaka tipa podatka koji funkcija vra�a, onda
se pi�e naziv funkcije, te onda u zagradama slijede parametri,
na primjer:
int
mnozi(char a, char b); ->Deklariramo funkciju
mnozi da prima dva tipa podatka char, koje smo nazvali a
i b, te funkcija vra�a kao rezultat podatak tipa int.
2.1 Operator return
Operator return slu�i za vra�anje rezultata. Nema potrebe
o njemu puno govoriti, biti �e sve jasno iz primjera.
2.2 Tip podatka void
Postoje funkcije kojima kao ulaz nije potreban nikakav parametar,
odnosno isto tako postoje funkcije koje ne vra�aju nikakav
rezultat (iako to tada vi�e nije funkcija, ali mi �emo je
zbog jednostavnosti i dalje zvati tako). Da bi se takve
funkcije mogle deklarirati postoji tip podatka void, primjeri
deklaracije upotrebom tipa podatka void:
void
cekaj_tipku(void); ->funkcija cekaj_tipku je deklarirana
tako da niti prima nikakav parametar, niti i�ta vra�a kao
rezultat.
char koja_tipka(void); ->funkcija koja_tipka vra�a podatak
tipa char u kojem je pohranjena ASCII vrijednost pritisnute
tipke na tastaturi, me�utim ova funkcija ni�ta ne prima
kao parametar.
2.3 Funkcija main
Pri pokretanju programa, OS mora znati koju �e funkciju
prvu pokrenuti, za tu svrhu slu�i funkcija main, ona se
po�inje izvr�avati odmah poslije pokretanja programa, drugim
rije�ima svaki C program mora imati funkciju pod nazivom
main. Za po�etak je dovoljno dobro da funkcija main bude
deklarirana kao int main(void), tj. da funkcija main ni�ta
ne prima, a vra�a integer kao rezultat, taj rezultat trebao
bi govoriti o uspje�nosti izvr�avanja programa, ako je program
uspje�no izvr�io zada�u, tada kao rezultat valja vratiti
0, u svim ostalim slu�ajevima, npr. zbog nedostatka memorije
i sl. program treba vratiti kao rezultat vrijednost nejednaku
0, npr. 1.
2.4 Vidljivost varijabli
Varijable mogu biti globalne, ili lokalne, globalne varijable
se deklariraju izvan tijela neke funkcije i kao takve one
su vidljive u svim funkcijama ispod deklaracije, dok se
lokalne varijable deklariraju na po�etku tijela neke funkcije,
te su one vidljive samo unutar te funkcije. Dobar stil programiranja
ka�e da globalne varijable treba izbjegavati kad god je
to mogu�e. Mo�e se dogoditi da u nekoj funkciji deklariramo
neku lokalnu varijablu sa istim imenom kao i neku globalnu
varijablu, tada �e se unutar te funkcije uvijek upotrebljavati
samo lokalna varijabla, te globalnoj varijabli ne mo�emo
pristupiti. Dalje treba napomenuti da se funkcije uvijek
deklariraju izvan tijela neke funkcije, te su one uvijek
vidljive ispod deklaracije.
3. Jednostavan program
U ovom �u odsje�ku prikazati kako napisati jednostavan
program u C-u koji �e ispisati poruku na ekranu. Program
izgleda ovako:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
printf("\nMoj prvi c program!!!! ");
getch();
return
0;
}
Ovaj k�d mo�ete direktno kopirati u Borland C, te izabrati
naredbu RUN i time pokrenuti program.
Obja�njenje k�da: Prva dva reda #include <stdio.h>
i #include <conio.h> neka vas ne zbunjuju previ�e,
dovoljno je znati da ako �elite upotrebljavati funkciju
printf morate imati redak #include <stdio.h> a za
funkciju getch() morate imati #include <conio.h>.
Kako znati koji include morate imati za koju funkciju? Jednostavno,
odete kursorom ispod �eljene funkcije i pritisnete CTRL-F1,
otvorit �e se help u kojem �e izme�u ostalog biti navedeno
koji include trebate za upotrebu te funkcije. Sa tipkom
SHIFT-F1 otvara vam se prozor u kojem su izlistane sve funkcije
koje standardno dolaze sa BORLAND C-om..
redak void main(void) predstavlja deklaraciju funkcije
main, to�ka zarez poslije deklaracije se ne postavlja zato
jer smo sa otvorenom viti�astom zagradom ozna�ili po�etak
tijela funkcije. Tijelo funkcije je k�d koji se treba izvr�avati
kada se ta funkcija pozove. Zatvorenom viti�astom zagradom
ozna�avamo kraj tijela funkcije.
Redak printf("\nMoj prvi c program!!!"); ispisuje
poruku na ekranu, poruka se mora nalaziti unutar navodnika,
znak \n unutar navodnika je specijalni znak koji ozna�ava
novi red, postoje i drugi specijalni znakovi: \\ -> backslash,
\b ->back space, \0 -> null znak...
Redak getch(); �eka dok se ne pritisne tipka, skra�enica
od(get_char), da smo izostavili ovu naredbu tada bi program
pri pokretanju odmah iza�ao iz DOS - prozora, te bi se kontrola
vratila na Borland C, pa korisnik ne stigne vidjeti poruku
pri izvr�avanju ovog programa. Takve situacije se rje�avaju
sa getch() naredbom koja �e zaustaviti program prije samog
zavr�etka, ili mo�ete pritisnuti ALT-F5, da bi pogledali
DOS-prozor.
Vjerojatno ste ve� i sami uo�ili da svaki redak unutar
tijela funkcije main zavr�ava sa to�ka-zarez, to je sintaksa
jezika C, zna�i upamtite da svaki poziv funkcije mora zavr�iti
sa to�ka zarez.
4. Aritmeti�ke i logi�ke
operacije
Postoje �etri osnovne aritmeti�ke operacije: mno�enje,
dijeljenje, zbrajanje, oduzimanje. Svaka od tih operacija
ima svoj simbol: * / + -. Kod logi�kih operacija moramo
razlikovati bitwise logi�ke operacije i obi�ne logi�ke operacije.
Kod obi�nih logi�kih operacija rezultat je uvijek 1 ili
0, tj. ISTINA ili LA�, dok bitwise operatori uspore�uju
zadane varijable bit po bit. Mi se za sada ne�emo baviti
bitwise operatorima.
Simbol za logi�ki I (AND): &&
Simbol za logi�ki ILI (OR): ||
Najbolje �ete nau�iti ako prou�ite slijede�i primjer:
4.1 Jednostavan program
koji zbraja, dijeli, oduzima, mno�i
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
int b1,b2,rez;
b1 = 100;
b2 = 10;
rez
= b1+b2;
printf("Zbrajanje: %d + %d = %d\n",b1,b2,rez);
rez
= b1/b2;
printf("Djeljenje: %d / %d = %d\n",b1,b2,rez);
rez
= b1-b2;
printf("Oduzimanje: %d - %d = %d\n",b1,b2,rez);
rez
= b1*b2;
printf("Mnozenje: %d * %d = %d\n",b1,b2,rez);
getch();
return
0;
}
Obja�njenje programa:
Ovaj program mo�ete direktno kopirati u Borland C, i pokrenuti
ga. Kako i sami vidite za osnovne matemati�ke operacije
nema neke mudrosti, prvo inicijaliziramo po�etne vrijednosti,
redak b1 = 100; stavlja u varijablu b1 vrijednost 100. U
slu�aju bez tog retka vrijednosti varijable b1 bila nepredvidljiva,
nebi bila 0 kao �to mo�da BASIC programeri pretpostavljaju.
Dalje mo�ete uo�iti da se matematika svodi na to da jednostavno
napi�ete matemati�ki izraz i pridru�ite taj izraz znakom
dodjeljivanja (=) nekoj varijabli, npr: rez = b1+b2; zna�i
da u varijablu rez pospremamo zbroj od varijable b1 i b2,
po�to varijabla b1 sadr�i vrijednost 100, a varijabla b2
sadr�i vrijednost 10, vrijednost izraza koja �e se dodijeliti
varijabli rez je 100 + 10 = 110.
Redak koji vas mo�da zbunjuje je printf("Zbrajanje:
%d + %d = %d\n",b1,b2,rez); ,ovim retkom na ekranu
se printa poruka Zbrajanje: 100 + 10 = 110, prou�ite prvi
parametar funkcije printf : "Zbrajanje: %d + %d = %d\n",
prethodno smo spomenuli da je prvi parametar funkcije printf
string koji se treba isprintat na ekran, u slu�aju da �elimo
vrijednosti varijabli printat na ekran moramo se koristiti
specijalnim znakovima unutar tog stringa, ozna�avaju�i na
taj na�in da �elimo printati vrijednost varijable, tako
npr. specijalni znak %d zna�i da na to mjesto �elimo ispisati
broj, poslije prvog parametra onda moramo navoditi varijable
�ije vrijednosti �elimo ispisati na mjestima specijalnih
znakova.
Svakako vam preporu�ujem da se sa gornjim programom malo
poigrate, tj. mijenjajte inicijalne vrijednosti, radite
slo�enije izraze, mijenjajte string unutar printf funkcije
itd. Za slaganje slo�enijih izraza mo�ete se slu�iti i obi�nim
zagradama, npr:
rez = (b1 + b2) * b1;
Osim osnovnih aritmeti�kih operacija postoji jo� nekoliko
zanimljivih aritmeti�kih operatora:
++ operator uve�avanja za jedan, npr k++; uve�ava varijablu
k za 1, ekvivalentno tome je k = k + 1;
-- operator umanjivanja za jedan, npr t--; smanjuje varijablu
t za 1
+= operator dodavanja, npr k+=12; k �e se uve�ati za 12,
ekvivalentno tome je k = k + 12;
-= operator oduzimanja, npr k-=16; k �e se umanjiti za 16,
ekvivalentno tome je k = k - 16;
% operator ostatka cjelobrojnog dijeljenja (modulo), npr:
x = 7%3; x je sada 1;
Ostale operatore potra�ite u HELP-u od Borlanda pod klju�nom
rije�i operators.
4.2 If
operator, ispitivanje uvjeta
Ideja operatora if je da provjeri vrijednost nekog izraza,
i onda na osnovu toga odlu�i dali �e izvr�iti neke naredbe
ili ne. Op�i oblik if operator:
if (izraz) naredba;
Ako je vrijednosti izraza 0 (LA�) tada se naredba ne�e
izvr�it, a ako je izraz bilo koji drugi broj, tada se naredba
bude izvr�ila. Postoje specijalni operatori za provjeru:
== operator jednakosti
!= operator nejednakosti
> operator ve�e od
< operator manje od
>= operator ve�e jednako
<= operator manje jednako
! operator ISTINE ili NEISTINE
Svi ovi operatori u slu�aju istine vra�aju vrijednost 1,
a u slu�aju neistine vra�aju vrijednost 0, npr: izraz 10
== 2 vra�a vrijednosti 0, zato jer je la� da je 10 jednako
2. Naravno umjesto konkretnih brojki mo�ete staviti i varijable,
evo primjer programa u kojemu je sve to prikazano:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
int b1,b2;
printf("\n
Unesi dva broja(b1 b2): ");
scanf("%d %d",&b1,&b2);
if(
b1 > b2) printf("b1 je veci od b2\n");
if(b1
< b2) printf("b2 je veci od b1\n");
if(b1
== b2)
{
printf("b1 jednak b2 ");
b1 = b1 + 10;
printf("...medutim sada b1 postaje za 10 veci i iznosi:
%d\n",b1);
}
getch();
return 0;
}
Obja�njenje programa:
Prvo program ispisuje poruku na ekranu da treba unijeti
dva broja. Funkcija koja omogu�uje unos varijabli sa tastature
je scanf. Prvi parametar funkcije scanf je string koji sadr�i
specijalne znakove koji ozna�avaju koji tip podatka �elimo
unijeti; Gornji primjer unosi dva podatka tipa int, a specijalni
znak za int je kao �to ve� znamo %d. U gornjem primjeru
unosimo dva podatka tipa int, pa je stoga unutar stringa
scanf funkcije dva puta naveden specijalni znak za int.
Parametri koji slijede iza stringa kod scanf funkcije su
pokaziva�i na mjesta u memoriji gdje �elimo pohraniti vrijednosti
unesene sa tipkovnice. Do pokaziva�a na �eljenu varijablu
dolazimo sa znakom & ispred naziva varijable. Nemojte
se sada puno zamarati sa pokaziva�ima, o njima �u kasnije
vise govoriti. Dovoljno je zasada zapamtiti da je u funkciji
scanf potreban znak & uz varijable.
Svakako se sa gornjim primjerom poigrajte mijenjaju�i uvjete
unutar if operatora. Uo�ite da kada �elite da if operator
izvr�i samo jednu naredbu tada nisu potrebne viti�aste zagrade
iza njega, me�utim ako if operator treba izvr�iti vise naredbi
tada obavezno morate sve te naredbe staviti unutar viti�astih
zagrada.
4.3 Upotreba logi�kih operatora
Kada �elite staviti vi�e uvjeta unutar jednog if operatora
tada se mo�ete koristiti logi�kim operatorima, na primjer:
imamo deklariranu varijablu X, i �elimo je pomno�iti sa
dva ako ona iznosi 9 ili 4 ili 5. Taj uvjet bi napravili
ovako:
if(X == 9 || X == 4 || X == 5) X *= 2;
Uo�ite unutar zagrada if operatora logi�ki operator ILI
(||). Gornji izraz zna�i:
Ako je X jednak 2 ili je X jednak 4 ili je X jednak 5, tada
pomno�i x sa 2.
U slijede�em primjeru pretpostavimo da imamo dvije varijable
X i Y, varijabli X �elimo dodati vrijednost varijable Y
samo ako je X > 10 a Y <= 10, ovaj uvjet izveli bi
sa logi�kim operatorom I (&&):
if(X > 10 && Y <= 10) X = X + Y;
Kad bi gornji izraz prevodili na ljudski jezik tada bi prijevod
glasio: Ako je X ve�i od 10 I ako je Y manji ili jednak
10 tada dodaj X-u Y;
Za kraj samo jo� jednom podsjetnik na dva osnovna logi�ka
operatora: I (&&), ILI (||)
5. Petlje
Ideja petlje je da omogu�i izvr�avanje tijela petlje sve
dok se neki uvjet ne ispuni potreban za izlazak iz petlje.
Postoje 2 osnovne vrste petlji: for i do...while.
5.1 For petlja
Op�i oblik for petlje:
for(inicijalni
dio; uvjet; korak)
{
naredbe;
}
Primjer programa sa for petljom:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
int i;
for(i=0;i<5;i++)
{
printf("\nTrenutna vrijednost: %d",i);
}
getch();
return
0;
}
U gornjem programu tijelo petlje �e se izvr�iti 5 puta,
sa vrijednostima varijable i = 0,1,2,3,4. Tijelo petlje
je k�d koji se nalazi unutar viti�astih zagrada for petlje,
u gornjem slu�aju to je jedna printf funkcija koja ispisuje
trenutnu vrijednost varijable i.
Sto se to�no doga�a kod petlje? Kada program ude u gornju
petlju prvo �e postaviti varijablu i na vrijednost 0, zatim
�e se provjeriti dali je uvjet i<5 istinit, ako je uvjet
istinit izvr�iti �e se tijelo petlje, odn. na ekranu �e
se ispisati poruka: Trenutna vrijednost: 0 ,a ako uvjet
nije istinit tada se prekida izvr�avanje petlje, te se program
nastavlja izvr�avati od zatvorene viti�aste zagrade. Poslije
izvr�enja tijela petlje, izvr�it �e se izraz i++, taj izraz
pove�ava varijablu i za 1, nakon toga izvr�avanje se nastavlja
od provjere istinitosti uvjeta i<5, ako je uvjet istinit,
onda �e se u sljede�em izvr�avanju tijela petlje na ekranu
ispisati: Trenutna vrijednost: 1. itd...
Ukratko: Svrha for petlje je omogu�avanje da se neki dio
k�da vi�estruko izvr�i.
5.2 do...while petlja
do...while se upotrebljava kada se treba neki k�d izvr�avati
sve dok uvjet unutar zagrada klju�ne rije�i while() ne postane
istinit, npr. program treba ispitivati koja je tipka pritisnuta
sve dok pritisnuta tipka ne bude tipka 'q'. Op�i oblik do...while
petlje:
do
{
naredbe;
}while(uvjet);
Kratko obja�njenje do...while petlje: Tijelo petlje �e
se izvr�avati sve dok uvjet unutar zagrada kljucne rije�i
while() ne postane istinit.
Primjer programa sa do...while petljom:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
char c;
do
{
printf("\nCekam tipku...");
c = getch();
}while(c
!= 'q');
printf("\nIzasao
sam");
getch();
return
0;
}
Obja�njenje gornjeg programa: Prvo deklariramo varijablu
c kao tip char. Onda program ulazi u do while petlju i ispisuje
poruku Cekam tipku... ,poslije toga program ulazi u funkciju
getch(), za koju od prije znamo da �eka pritisak tipke,
me�utim ta funkcija osim �to �eka pritisak tipke, ona tako�er
vra�a k�d pritisnute tipke, (pogledajte help), taj k�d se
dodjeluje varijabli c, te se onda prelazi na ispitivanje
uvjeta unutar while operatora, uvjet unutar while operatora
ka�e: dali je c nejednak slovu 'q', ako je uvjet istinit
tada �e se izvr�avanje programa nastaviti od klju�ne rje�i
do, tj, ponovno �e se ispisati poruka Cekam tipku...,itd.
sve dok se ne pritisne tipka q, tada �e uvjete unutar zagrada
whila postat neistinit, pa �e se prekinuti izvr�avanje petlje.
Uo�ite da se slovo q nalazi unutar apostrofa ('q'), naime
operatori apostrofa vra�aju ASCII vrijednost znaka unutar
apostrofa, da smo kojim slu�ajem izostavili apostrofe, tada
bi compiler q smatrao kao neku varijablu, te bi prijavio
gre�ku da varijabla q nije definirana..
5.3 break i continue
Ove naredbe djeluju samo unutar for, do...while() i while()
petlje. Naredba break prekida izvr�avanje petlje, a naredba
continue, nastavlja izvr�avanje petlje sa slijede�om veli�inom,
npr:
do{
znak = getch();
if (znak == 'q') break; /*ako je pritisnuta tipka q tada
izlazak iz petlje*/
if (znak < '0' || znak > '9') continue; /*ako pritisnuta
tipka nije broj tada uzmi sljedeci znak (nastavak petlje)
*/
rez
+= (znak - '0'); /*povecaj rez za vrijednost unesenog broja.*/
}while(1);
/*uvjet uvijek istinit, tj. beskonacna petlja*/
Sa zavr�etkom ovog poglavlja, smatram da ste dobili dovoljno
znanja za rje�avanje nekih jednostavnih zadatka, osim sto
�e se kod svakog zadatka definirati problem (ono �to program
mora raditi), navest �u i kratke natuknice kako bi se taj
program mogao rije�iti. Tako�er vam predla�em, da prije
nego sto pro�itate kratke upute, da se poku�ate sami sjetiti
kako rije�iti zadatak. Naravno, va�e rje�enje zadatka mo�da
potrebuje ve�i broj varijabli ili ne koristi funkcije koje
samo naveo u naputku, itd..., glavno da program radi ono
�to tra�i zadatak.
Predla�em vam da zadatak zaista samostalno poku�ate rije�iti,
a za slu�aj da ne uspijete stavio sam na kraju tutoriala
link na stranicu gdje se nalaze rje�enja svih zadataka.
Zadatak 1: Napravite program koji �e unijeti 10 brojeva
sa tipkovnice, te �e na kraju ispisati prosje�nu vrijednost
unesenih brojeva.
Za rje�enje ovog zadatka morat �ete upotrijebiti for petlju,
scanf funkciju za unos brojeva, dvije pomo�ne varijable,
te varijablu u kojoj �ete �uvati ukupni zbroj i printf funkciju
za ispis rezultat.
Zadatak 2: Napravite program koji �e brojati koliko je
korisnik puta pritisnuo tipku na tipkovnici, sve dok ne
unese tipku q, te na kraju ispi�ite broj pritisaka.
Za rje�enje ovog zadatka treba vam: do...while petlja, getch()
funkcija, dvije varijable - jedna pomo�na, jedna u kojoj
�ete brojati, te vam treba printf funkcija za ispis rezultata.
6. Nizovi
Razmislimo kako bi mogli napraviti program koji bi pamtio
unesene brojeve, te na kraju te brojeve ispisao obrnutim
redoslijedom. Ovakav problem rje�avao bi se pomo�u niza.
Pod pojmom niza podrazumijeva se deklaracija neke varijable
tako da ta varijabla ima vi�e �lanova. Npr. deklarirajmo
niz od 10 int varijabli:
int n[10]; -> ovim retkom smo deklarirali niz od 10 varijabli
tipa int. Zna�i niz se deklarira tako da se pored oznake
tipa podatka navede naziv niza, te u uglatima zagradama
navedemo broj �lanova tog niza.
�lanovima niza mo�emo pristupiti pomo�u uglatih zagrada,
npr. ako �elimo u 3 �lan niza ne�to upisati tada bi to izgledalo
ovako: n[2] = 100; Broj 2 unutar uglatih zagrada nije pogre�ka,
ve� svojstvo u C-u da svi nizovi po�inju od indexa nula,
tj. index 0 oznacava 1. �lan, index 1 ozna�ava 2. clan,
index 2 ozna�ava 3. clan itd... To zna�i da ako deklariramo
niz kao int n[10];, onda govorimo compileru da za niz n
predvidi 10 mjesta, pa �e stoga maximalni legalni index
biti 9, tj n[9] je zadnji �lan niza. Za�to sam napisao legalni,
zato jer je mogu�e pristupiti i npr. 153 �lanu tog niza,
ali onda compiler vi�e ne garantira da �e te pristupati
alociranoj memoriji, te �e se u tom slu�aju program vjerojatno
sru�iti. Compiler u ovom slu�aju jedino garantira za indexe
od 0 do 9. QBASIC bi pri pristupaju 153 �lana prijavio pogre�ku,
ali C ni�ta ne prijavljuje, ve� uredno obavlja svoj posao
pa kud puklo da puklo, zbog ovakvih stvari se programskom
jeziku C pove�ava fleksibilnost, ali se smanjuje jednostavnost.
Primjer zadatka sa nizom int-ova, ovaj zadatak �e unijeti
10 brojeva te �e ih na kraju ispisati u obrnutom poretku.
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
int i,b[10];
for(i=0;i<10;i++)
{
printf("\nUnesi broj %d ",i);
scanf("%d",&b[i]);
}
printf("\nIspis
u obrnutom redosljedu: \n");
for(i=9;i>=0;i--)
{
printf("\nUnesi broj %d ",b[i]);
}
getch();
return
0;
}
Obja�njenje programa: Prvo pogledajmo deklaraciju varijabli:
int i,b[10]; ->deklariraju se varijabla i, ovo je pomo�na
varijabla za for petlju, te se deklarira niz od 10 int-ova
pod nazivom b.
U prvoj for petlji se unosi 10 brojeva i spremaju se redom
u b[0], b[1], b[2]...b[9]. U drugoj for petlji ispisuju
se onda brojevi b[9],b[8]....b[0], uo�ite u drugoj for petlji,
na�in na koji je ta petlja inicijalizirana da bi brojala
od 9 do 0.
Zadatak 3: Napravite program koji �e unositi brojeve sa
tipkovnice sve dok se ne unese broj 0, tada sve unesene
brojeve ispi�ite obrnutim redoslijedom. Predvidite maximalno
100 unesenih brojeva.
Naputak za rje�enje: Izme�u ostalog trebat �e vam niz od
100 int-ova, do...while petlja, for petlja.
7. Pokaziva�i ili pointeri
Pokaziva�i su tipovi podataka koji pokazuju na neku varijablu,
ono o �emu pokaziva�i fizi�ki vode ra�una je memorijska
adresa podatka na koji pokazuju, to zna�i da su svi pokaziva�i
jednake duljine, u DOS-u svi pokaziva�i su 16 bitni, me�utim
razlikuju se po tome na koju vrstu podatka pokazuju. Na
primjer mo�ete deklarirati pokaziva� koji pokazuje na int-ove,
mo�ete deklarirati pokaziva� koji pokazuje na char-ove itd...
Deklaracija pokaziva�a vr�i se zvjezdicom ispred naziva
pokaziva�a, npr;
int *pi; /*varijabla pi je deklarirana kao pokaziva� na
int*/
float *mh /*varijabla mh je deklarirana kao pokaziva� na
float*/
Svrha pokaziva�a je da bi se podaci izme�u funkcija mogli
prenositi preko pokaziva�a, tj. umjesto da se po�alju nekoj
funkciji sve vrijednosti nekog niza, jednostavno se po�alje
samo pokaziva� na po�etni �lan toga niza.
Tako�er mo�ete pristupati vrijednosti na koji pointer pokazuje,
to se opet �ini sa operatorom zvjezdice, npr: ako je deklariran
pokaziva� int *k; tada mo�emo na mjestu gdje taj pointer
pokazuje upisati vrijednost 100 na sljede�i na�in: *k =
100; Ako vam se ovo �ini zbunjuju�im, opustite se, to zbilja
jest zbunjuju�e dok vam jednom ne sjedne.
Operatorom & ispred neke varijable dolazimo do adrese
gdje se ta varijabla u memoriji nalazi. Upotrebom ovog operatora
mo�emo neki pokaziva� usmjeriti da pokazuje na neku to�no
odre�enu varijablu.
Primjer upotrebe pokaziva�a:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
int x,*p;
p = &x; /*preusmjeri p tako da pokazuje na x*/
printf("\nUnesi
broj ");
scanf("%d",&x);
printf("\nUneseni
broj je: %d",*p);
getch();
return
0;
}
Ono �to je bitno uo�iti kod ovog programa je da na kraju
kada se ispisuje rezultat ne pristupa se unesenom broju
preko varijable x, ve� preko pokaziva�a p koji je prethodno
preusmjeren da pokazuje na varijablu x.
7.1 pokaziva�i i nizovi
Pokaziva�i i nizovi su u C-u usko povezani, zato jer je
svaki niz zapravo pokaziva� na alociranu memoriju, alocirana
memorija znaci da je to dio memorije koji je operacijski
sustav dodjelio nasem programu, te operacijski sustav garantira
da tu memoriju ne�e dodijeliti niti jednom drugom programu.
Zna�i kod deklaracije niza int b[100]; OS alocira 100 mjesta
za int varijablu, te pokaziva� b preusmjeri da pokazuje
na 0 clan tog niza. Slikovito bi to izgledalo ovako:
U gornjoj slici vidimo da pokaziva� *b pokazuje na 0 �lan
niza od 100 int-ova. Kod deklaracije int b[100]; nama nije
mogu�e mijenjati mjesto na koje b pokazuje, to, se zove
stati�ki alocirana memorija koja se uvijek nalazi na istom
mjestu i stalne je veli�ine. Me�utim postoji druga stvar
koju mo�emo napraviti, a to je da neki drugi pokaziva� preusmjerimo
recima na 20 �lan od niza b, to bi izgledalo ovako: int
b[100],*p; p = &b[20]; Onda �e p[0] imati jednaku vrijednost
kao b[20]. Prika�imo to programom:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
int i,b[20], *p;
p = &b[5];
for(i=0;i<20;i++)
{
b[i] = i;
}
printf("\nIspis
niza p i niza b");
for(i=0;i<20;i++)
{
printf("\nb[%2d] = %2d, p[%2d] = %2d",i,b[i],i,p[i]);
}
getch();
return
0;
}
Svakako ovaj program kompajlirajte i pokrenite, te prou�ite
izlaz na ekranu. Na po�etku se deklariraju varijable i,
niz b od 20 int-ova, pokaziva� na int *p. U sljede�em koraku
p se preusmjeri da pokazuje na 6 �lan niza b. To se naravno
posti�e operatorom &. U prvoj for petlji inicijalizira
se niz, tako da se u svaki �lan niza upi�e vrijednost njegovog
indeka, tj. b[0] �e imati vrijednost 0, b[1] imat �e vrijednost
1,... U drugoj for petlji ispisuju se oba dva niza od indeksa
0 do indeksa 20, posto p pokazuje na 6 �lan od niza b, a
6 �lan niza b sadr�i vrijednost 5, pa �e se zbog toga za
p[0] ispisati 5. Slikovito bi to otprilike ovako izgledalo:

Ako poku�amo pristupiti �lanu p[20], a znamo da je p = &b[5],
tada mo�emo zaklju�iti da je p[20] = b[25], a u deklaraciji
smo predvidjeli samo 20 �lanova u nizu b, pa �e onda p[20]
zasigurno pokazivati na ne�to nealocirano, odnosno p[20]
�e sadr�avati nepredvidljivu vrijednost, a to se vidi ako
se pokrene gornji program. Nemojte se pla�iti da �ete tako
sru�iti DOS, naime pri operaciji �itanju pod DOS-om nema
straha, problemi bi mogli nastati kada bi po�eli pisati
po tu�oj memoriji.
Uo�ite da u printf funkciji kao specijalni znak nije upotrijebljen
%d ve� %2d, razlika je u tome �to %2d predvi�a uvijek 2
mjesta za ispis tog broja, %3d, predvi�alo bi 3 mjesta itd...
7.2 dinami�ko alociranje
memorije
Pojam dinami�kog alociranja memorije znaci da program za
neki niz alocira onoliko memorije koliko mu je potrebno,
na primjer ako �elimo neku tekstualnu datoteku u�itati u
memoriju, tada �emo prvo zatra�iti od DOS-a informaciju
o tome koliko je ta datoteka duga�ka, te �emo na osnovu
toga alocirati potreban broj byteova, i tek �emo onda tu
datoteku u�itati u alociranu memoriju.
Funkcija koja slu�i za alociranje memorije: malloc, ova
funkcija prima kao parametar broj byteova koliko �elimo
alocirati, a kao rezultat vra�a pokaziva� na nulti byte
alocirane memorije. Poslije �to nam alocirana memorije vise
ne treba mo�emo ju osloboditi funkcijom free. Funkcija free
kao parametar prima pokaziva� na memoriju koju �elimo osloboditi
(dealocirati).
Napi�imo program koji �e prvo zatra�iti broj brojeva koliko
ih �elimo unijeti, tada �e program alocirati memoriju, u
koju �e onda unijeti zadani broj brojeva. Na ekranu program
mora ispisati brojeve tako da su svaka dva susjedna �lana
zamijenjena, npr �lan 1 i �lan 2 su zamijenjeni itd...
#include
<stdio.h>
#include <conio.h>
#include <stdlib.h>
int
main(void)
{
int temp,i,*b,brmax;
printf("\nUnesi
maximalan broj brojeva: ");
scanf("%d",&brmax);
b
= (int *) malloc(brmax * sizeof(int)); /*alokacija*/
if(b
== NULL) /*dali je alokacija bila uspjesna*/
{
printf("\nNedovoljno memorije!");
getch();
return; /*izlaz iz programa*/
}
for(i
= 0; i<brmax;i++)
{
printf("\nUnesi broj %d: ",i);
scanf("%d",&b[i]);
}
for(i=1;i<brmax;i+=2)
{
temp = b[i];
b[i] = b[i-1];
b[i-1] = temp;
}
printf("\nRezultat:\n");
for(i=0;i<brmax;i++)
{
printf("\n b[%2d]: %5d",i,b[i]);
}
free(b);
/*oslobodi memoriju*/
getch();
return
0;
}
Gornji program ne donosi ni�ta posebno novo jedino, �to
se ovdje dinami�ki alocira potrebna memorija za uneseni
niz, pa �u jedino redak b = (int *) malloc(brmax * sizeof(int));
podrobnije pojasniti. Funkcija malloc kao parametar prima
broj bytova koliko �elimo alocirati, mi �elimo alocirati
brmax integera, da bi saznali koliko byteova zauzima jedan
integer koristimo se operatorom sizeof, u njegove zagrade
stavimo tip podatka od kojeg �elimo saznati njegovu veli�inu
u byteovima, odnosno u gornjem slu�aju stavimo sizeof(int).
Sada veli�inu sizeof(int) pomno�imo sa brmax, i onda smo
dobili potreban broj bytevoa za brmax integera.
Funkcija malloc �e vratiti kao rezultat pokaziva� void *.
Pokaziva� void * ne pokazuje niti na jedan tip podatka,
on je jednostavno pokaziva� na neku memorijsku lokaciju.
Da bi void * pokaziva� pretvorili u int* pokaziva� potrebno
je staviti u zagrade poslije znaka dodjelivanja tip podatka
u koji �elimo void * prevesti. Ako funkcija malloc nije
uspjela alocirati potreban broj bytova, tada kao rezultat
vraca NULL pointer.
Uo�ite da u gornjem primjeru imamo jedan novi include: #include
<stdlib.h>, to je zbog funkcija malloc i free.
Na kraju programa oslobodimo alociranu memoriju pomo�u funkcije
free.
Napomena: Nad ponterima mo�ete vr�iti isto aritmeti�ke
operacije, tj mo�ete uve�avati pokaziva� da pokazuje npr.
na sljede�u memorijsku lokaciju. Tako npr. dobili bi isti
rezultat kada bi pristupali p[4] ili *(p+4), za�to ?, Zato
jer p[4] pokazuje za �etri mjesta udaljeniju lokaciju od
p[0], a p == &p[0], pa uve�avanjem p za 4 mo�emo do�i
opet do istog mjesta. U bytovim gledano pointeri na int
kod uve�anja za jedan u stvari se uve�a za 2 byta zato jer
je int duljine dva byta.
p[ ] | 0 | 1 |
2 | 3 | 4 | 5 | 6 |
p +0 +1 +2 +3 +4 +5 +6
8.
Stringovi
Stringovi su u C-u nizovi char-ova gdje zadnji character
u tom nizu ima vrijednost 0, koji ozna�ava kraj tog stringa.
Zna�i zapamtite da svaki string zavr�ava sa vrijedno��u
0 '\0'. Stringu se naravno pristupa preko pokaziva�a na
char. U k�du deklariramo stringove na slijede�i na�in:
char *str = "Ovo je neki string";
�to se zapravo doga�a kod ovakve deklaracije, compiler napravi
pokaziva� na char *str, zatim pogleda duljinu stringa "Ovo
je neki string", te alocira potrebnu duljina znakova
+ 1, dodatni znak slu�i za null znak, koji dolazi na kraju
tog niza charctera. Kada je compiler alocirao potreban broj
byteova, tada spremi tekst stringa u taj alocirani dio memorije,
i na kraju preusmjeri pokazivac *str da pokazuje na nulti
�lan alociranog niza.
Unos stringova sa tipkovnice. Za unos stringa sa tipkovnice
postoje dva na�ina, gets() funkcija i scanf() funkcija,
nedostatak scanf() funkcije je da onemogu�uje unos stringa
koji sadr�i razmake, te kod razmaka prekida unos stringa,
gets() funkcija nema taj nedostatak. Zna�i upamtite, da
kada �elite unositi stringove koji �e mo�da sadr�avati razmake,
tada obavezno morate koristit funkciju gets().
Sljede�e na �to morate obratiti pa�nju je da kad koristite
ove funkcije morate pretpostaviti maximalnu duljina unesenog
stringa, a ako slu�ajno korisnik unese dulji string od predvi�enog,
tada postoji mogu�nost da se sru�i OS. Predvi�anje maximalne
duljine unesenog stringa zna�i da alocirate odre�en broj
bytova memorije (npr 150), te uneseni string spremite u
tu alociranu memoriju. Ako bi korisnik slu�ajno natipkao
vi�e od 149 znakova, tada bi se moglo ne�to nepredvidljivo
dogoditi. Primjer unosa stringa te njegovog ispisa:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
char p[150];
printf("\n\nUnesi string: ");
gets(p);
printf("\nUneseni
string je: %s",p);
getch();
return
0;
}
Prvo sto program napravi je da stati�ki alocira 150 char-ova
(==150 bytova) , to je redak char p[150]; Poslije alokacije
ispi�e se poruka na ekranu za unos stringa, te se izvr�avanjem
funkcije gets prelazi na unos stringa, funkcija gets prima
kao parametar char pokaziva� na mjesto u memoriji gdje �elimo
unijeti string. Poslije unosa stringa, taj isti string ponovno
ispisujemo sa printf funkcijom i klju�nim znakom %s.
Naravno mo�emo i dinami�ki alocirati string sa funkcijom
malloc, onda bi char p[150]; zamjenili sa
char *p;
p = (char *) malloc(150);
Unos stringa sa funkcijom scanf izgleda ovako:
scanf("%s",p);
Uo�ite da sada kod scanf funkcije nismo koristili &p,
ve� samo p, to je zato jer funkcija scanf prima pokaziva�e
na mjesta u memorije gdje �elimo pohraniti unesenu veli�inu,
a po�to je p pokaziva� tada nebi imalo smisla stavljati
&p. Me�utim umjesto p mogli smo staviti &p[0], tj.
pokaziva� na nulti �lan niza p.
8.1 Odre�ivanje duljine
stringa
Za operacije nad stringovima postoji mno�tvo standardnih
funkcija, pogledajte u helpu pod klju�nom rije�i string.h,
me�utim mi �emo za vje�bu napraviti funkciju koja odre�uje
duljinu stringa, prisjetimo se prvo da svaki string zavr�ava
sa vrijedno��u 0, onda se prisjetimo da je do...while petlja
ko_stvorena za pretragu:
#include
<stdio.h>
#include <conio.h>
#include <stdlib.h>
int
dulj_str(char *p); /*deklaracija funkcije dulj_str, prima
kao parametar pokazivac na char, a vraca int*/
int
main(void)
{
char *s;
int duljina;
s
= (char *) malloc(1000);
printf("\n
Unesi string: ");
gets(s);
duljina
= dulj_str(s); /*poziv funkcije dulj_str*/
printf("\nDuljina unesenog stringa je %d",duljina);
getch();
return
0;
}
int
dulj_str(char *p)
{
int rez;
rez = 0;
do{ /*radi*/
rez ++; /*povecaj duljinu*/
}while(p[rez] != 0); /*dali smo dosli do null znaka, ako
ne nastavi*/
return
rez;
}
Prvo razmislimo dali �e ovaj program davati uvijek to�an
rezultat, odgovor je negativan. Naime funkcija dulj_str
ne�e dati to�an rezultat ako je string duljine 0 (stru�ni
naziv za string duljine 0 je 'null - string'), da bi to
ispravili postoji jedan brzi i jednostavni na�in, mo�ete
u inicijalizaciji funkcije dulj_str postaviti da rez bude
-1. Drugi na�in bio bi upotreba while() petlje umjesto do...while().
Zadatak 4: Napravite program koji �e unijeti string, te
u memoriji generirati novi string, koji je obrnut od unesenog,
na kraju �e ispisati oba stringa, npr: Uneseno: Zemlja,
izlaz: Zemlja aljmeZ.
Naputak za rje�enje zadatka: Kao prvo trebat �e vam neka
funkcija za saznavanje duljine stringa, mo�ete napisati
svoju vlastitu, a mo�ete koristiti i strlen(), koja se nalazi
u datoteci string.h. Nadalje �ete morati alocirati memoriju
za novi string sa funkcijom malloc, te okretanje stringa
�ete obaviti u for petlji.
9. Vi�edimenzionalni nizovi
i vi�estruki pokaziva�i
Kada �elimo neke podatke �uvati u obliku neke tabele, tada
je potrebno neku varijablu deklarirati kao vi�edimenzionalni
niz:
int s[50][20]; ->deklaracija dvodimenzionalnog niza sa
50 * 20 integera
char j[50][20][100]; ->deklaracija trodimenzionalnog
niza sa 50 * 20 * 100 karaktera
Kao �to vidite iz gornjih primjera, vi�edimenzionalni niz
se deklarira tako da se dodaju uglate zagrade, gdje broj
uglatih zagrada odre�uje dimenziju tog niza, a unutar uglatih
treba upisati broj elemenata u toj dimenziji. Pristupanje
nekom �lanu nekog elementa vr�i se na slijede�i na�in:
s[5][9] = 100; /*element 5,9 poprima vrijednost 100*/
Varijabla iz gornjeg primjera je dvostruki pokaziva� na
int: int **s; a varijabla j je trostruki pokaziva� na char:
char ***j;
Niz int *s[50]; je niz pokaziva�a na int, a niz char j **[50];
je niz dvostrukih pokaziva�a na char. Kako �to vidite ovdje
smo unijeli novi pojam: dvostruki pokaziva� tj. pokaziva�
na pokaziva�.
Pokaziva� na pokaziva� zapravo nije ni�ta drugo nego obi�an
pokaziva� na mjesto u memoriji, s razlikom da ne pokazuje
na neku varijablu, nego pokazuje na neki drugi pokaziva�,
deklarira se s dvije zvijezdice ispred naziva pokaziva�a,
npr: char **pp;. Pokaziva� na pokaziva� se koristi kod dvodimenzionalnih
nizova, npr. ako �elimo u memoriju na zgodan na�in �uvati
neku tabelu brojeva sa 20 kolona i 50 redaka, tada postoje
dva na�ina da deklariramo datu tabelu, stati�ki i dinami�ki.
U slu�aju kada imamo vi�edimenzionalne nizove tada se stati�ka
i dinami�ka alokacija razlikuju. Kod dinami�ke alokacije
tabela �e zauzimati vi�e memorije nego stati�ki alocirana
tabela, razlog je u tome da kod stati�ke alokacije compiler
alocira jedan komad memorije koji on onda sam pretvara u
dvije dimenzije. Stati�ka alokacija se vrsi tako da se veli�ina
niza ozna�i odmah pri deklaraciji datog niza: npr: int s[50][20];
Konkretno, za tabelu od 20 * 50 integera compiler bi alocirao
20 * 50 * 2byte = 2000byteova. Tako bi prvih 50 *2bytova
predstavljalo mjesta nulte kolone, drugih 50 * 2bytova predstavljalo
bi mjesta prve kolone itd. Za�to sve ovo mno�imo sa dva
byta, zato jer je pod DOS-om veli�ina integera to�no 2 byte
(16 bit).
Prije nego �to odredimo koliko bi dinami�ka alokacija ovakvog
niza zauzimala memorije, potrebno je objasniti kako ovaj
niz dinami�ki alocirati: Prvo moramo deklarirati neku varijablu
kao dvostruki pokaziva� na int: int **k;. Sada moramo alocirati
memoriju za 50 pokaziva�a na int, te **k preusmjeriti da
pokazuje na tu memoriju:
k = (**int) malloc( 50*sizeof(int*) ); Unutar zagrada malloc
funkcije nalazi se izraz koji izra�unava potreban broj bytova
za 50 pokaziva�a na int. Sada moramo alocirati 50 puta po
20 int varijabli, te svaki taj alocirani blok preusmjeriti
da na njega pokazuje jedan od pokaziva�a iz niza pokaziva�a
*k[50]; To �emo napraviti for petljom, kona�an izgled k�da
u kojem se dinami�ki alocira dvodimenzionalni niz integera
glasi:
int
i,**k;
k = (int **) malloc(50 * sizeof(int *));
for(i=0;i<50;i++)
{
k[i] = (int *) malloc(20 * sizeof(int )); /*Unutar for petlje
se za svaki pokazivac alocira po 20 int-evo*/
}
Sada mo�emo izra�unati koliko dinami�ka alokacija niza
50 * 20 integera zauzima bytova memorije. Prvo svaki pokaziva�
pod dos-om je veli�ine 2byta, mi smo alocirali 50 pokaziva�a
= 100bytova, plus 50 * 20 * 2 bytea = 2100 bytova.
slikovito stati�ka i dinami�ka alokacija izgledaju ovako:

Vjerodostojnost gornje slike mo�ete provjeriti tako da
ispisujete sa funkcijom printf uz pomo� specijalnog znaka
%p, memorijsku lokaciju na koju pokaziva� pokazuje. Kod
stati�ke alokaciju pri ispisu s i &s[0], dobit �ete
jednaku vrijednost, dok �ete kod dinami�ke alokacije pri
ispisu k i &k[0] dobiti razli�ite rezultate.
Napi�imo program koji �e stati�ki alocirati mjesta za tabelu
od 4*5 integera, a sa tastature �e unijeti u tabelu samo
prva 3*4 �lana, tako da �e rubna mjesta ostat nepopunjena.
Vrijednosti za rubno mjesta izra�unaj tako da zbroji� sva
4 prethodna mjesta u retku, odnosno sva 3 prethodna mjesta
u stupcu.
Npr: uneseno je:
1
2 3 4
2 3 4 1
4 1 1 2
Rezulzat:
1
2 3 3 9
1 3 4 1 9
4 1 1 2 8
6 6 8 6 27
Source programa:
#include
<stdio.h>
#include <conio.h>
int
main(void)
{
int tabela[4][5],i,t;
for(i=0;i<4;i++)
{
for(t=0;t<5;t++)
{
if(i==3 || t==4)
{
tabela[i][t] = 0; /*ako i,t pokazuju na rubno mjesto
tada mjesto i,t postavi u nulu*/
continue; /* nastavi sa sljedecim mjestom*/
}
printf("\nUnesi clan %d %d: ",i,t);
scanf("%d",&tabela[i][t]); /*Unos vrijednosti
na mjesto i,t*/
}
}
/*u
sljedeceoj dvostrukoj for petlji racunaju se rubna mjesta
*/
for(i=0;i<3;i++)
{
for(t=0;t<4;t++)
{
tabela[ 3][ t] += tabela[ i][ t]; /*u najdonjem retku u
trenutnoj koloni dodaj trenutnu vrijdenost */
tabela[ i][ 4] += tabela[ i][ t]; /*u najdesnijoj koloni
u aktivnom retku dodaj trenutnu vrijednost */
}
}
/*u
slijedecoj dvostrukoj for petlji ispusuje se ukupna tabela
*/
for(i=0;i<4;i++)
{
printf("\n"); /*ako je novi red prijedi u novi
red*/
for(t=0;t<5;t++)
{
printf("%4d",tabela[i][t]);
}
}
getch();
return
0;
}
U gornjem primjeru smo koristili stati�ku alokaciju. Svakako
se gornjim programom poigrajte, te mu mijenjajte dimenzije
itd itd.
Sada �emo napisati program koji �e prvo unijeti broj stringova
koje korisnik �eli unijeti, tada �e program unositi string
po string, i za svaki string alocirati to�no onoliko mjesta
koliko je za taj string potrebno. Zna�i alokacija �e se
izvesti dinami�ki. Na kraju program treba sve stringove
obrnutim redoslijedom ispisati na ekran.:
#include
<stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
int
main(void)
{
char **str, privstr[250]; /*deklaracija dvostrukog pokazivaca
**str
i privremeng stringa za unos */
int brStr,i,len;
printf("\nUnesi broj stringova: ");
scanf("%d",&brStr); /* u varijablu brStr pohranjuje
se broj stringova*/
str
= (char **) malloc(brStr * sizeof(char *)); /* alokacija
od brStr
pokazivaca na char*/
for(i=0;i<brStr;i++)
{
printf("\nUnesi %d. string: ",i+1);
scanf("%s",privstr);
len = strlen(privstr); /*odredivanje duljine unesenog stringa*/
str[i]
= (char *) malloc(len + 1); /*alokacija potrebnog broja
bytova za uneseni string */
strcpy(str[i],privstr); /*kopiranje privremenog stringa
u memoriju
alociranu za uneseni string */
}
for(i=brStr-1;i>=0;i--)
{
printf("\n%s",str[i]); /*ispis*/
}
getch();
return
0;
}
Zadatak 5: Napravite program koji �e prvo unijeti veli�inu
kvadratne tabele brojeva, tada �e program dinami�ki alocirati,
datu tabelu i unijeti brojeve u svaki �lan tabele, na ekranu
�e program ispisati sve �lanove tabele po dijagonalama Npr:
velicina:
3
unesi 1 1: 1
unesi 1 2: 2
unesi 1 3: 3
unesi 2 1: 4
unesi 2 2: 5
unesi 2 3: 6
unesi 3 1: 7
unesi 3 2: 8
unesi 3 3: 9
ispis:
dijagonala1: 3
dijagonala2: 2 6
dijagonala3: 1 5 9
dijagonala4: 4 8
dijagonala5: 7
Naputak: Za rje�enje ovog zadatka trebat �e vam dvostruku
pokaziva� na int, morat �ete dinami�ki alocirati niz integera,
te �ete sa for petljama ispisivati dijagonale.
10. Strukture
Struktura je na�in da razli�ite varijable nekako grupiramo,
npr, ako �elimo pamtiti koordinate od 100 to�aka, te svaka
ta to�ka ima svoj naziv u obliku stringa, tada bi morali
imati 3 niza, niz za y koordinate int y[100]; niz za x koordinate
x[100];, te niz stringova char *naziv[100]; Da bi nekako
mogli grupirati te razli�ite podatke, postoje strukture,
novodefiniranoj strukturi mo�emo dati naziv koji �elimo,
te je ta struktura onda postala korisni�ki definirani tip
podatka:
typedef
struct
{
int x,y;
char *naziv;
}TOCKA;
Struktura TOCKA je sada definirana kao novi tip podatka,
da sumiramo, stvaranje novog tipa podatka se vr�i tako da
se pi�u klju�ne rije�i typedef struct te onda u viti�astim
zagradama navedu varijable koje ta struktura treba sadr�avati,
poslije zatvorene viti�aste zagrade onda upisujem naziv
koji �elimo dati datoj strukturi, i obavezno to�ka zarez
na kraju definicije. Postoji jo� jedan na�in definiranja
korisni�ke strukture, kojim se sada ne�emo baviti.
Deklariranje niza od 100 varijabli tipa TOCKA, vr�imo analogno
kao i kod osnovnih tipova podataka, dakle TOCKA t[100];
deklarirat �e niz od 100 varijabli tipa TOCKA, odnosno to�nije,
deklarirat �e pokaziva� TOCKA *t , koji �e preusmjeriti
da pokazuje na 100 * sizeof(TOCKA) alociranih bytova.
Pristupanje �lanovima niza TOCKA ovisi o tome dali pristupamo
preko pokaziva�a ili preko konkretne varijable, ako deklariramo
varijablu to na slijede�i na�in TOCKA to; tada toj varijabli
mo�emo vrijednost x postaviti na 100 ovako: to.x = 100;,
naziv joj mo�emo preusmjeriti ovako: to.naziv = "Naziv
neke tocke";. Zna�i zapamtite, �lanovima konkretne
strukture se pristupa preko operatora to�ke (.). Ako imamo
ne�to ovako:
TOCKA *to;
to = (TOCKA *) malloc( sizeof(TOCKA) );
to -> x =100;
to -> y = 110;
to -> naziv = "Ovo je drugi naziv";
Dakle kada pristupamo preko pokaziva�a na neki �lan neke
strukture, tada se koristimo operatorom ->.
Napravimo program koji �e generirati 10 razli�itih to�aka
te ih u tekstualnom modu prikazati na ekranu (upozorenje
ovaj program koristi funkciju gotoxy() koja nije uklju�ena
u C standard, tako da ovaj program bez modifikacije mo�da
ne�e raditi na nekim drugim compilerima osim na BC-u:
#include
<stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
typedef
struct /*deklaracija novog tipa podatka*/
{
int x,y; /*sadrzi dvije int varijable x i y*/
char *naziv; /*i pokaziva na char*/
}TOCKA;
void
iscrtaj_tocku(TOCKA *tp); /*deklaracija funkcije*/
int
main(void)
{
TOCKA t[10]; /*staticka deklaracija niza od 10 varijablu
tipa TOCKA*/
char priv_str[100]; /*privremeni string*/
int i,len; /*pomocne varijable*/
clrscr();
/*brisanje ekrana*/
for(i
=0;i<10;i++) /*petlja od 0 do 9*/
{
t[i].x = rand() % 80 +1; /*postavi slucajnu vrijednost u
opsegu od 1 do 80 u x*/
t[i].y = rand() % 20 +1;
sprintf(priv_str,"%d,%d",t[i].x,t[i].y);
/*pisi u string naziv tocke*/
len = strlen(priv_str); /*odredu duljinu naziva tocke*/
t[i].naziv = (char *) malloc(len+1); /*alociraj memoriju
potrebnu za
spremanje naziva */
strcpy(t[i].naziv,priv_str); /*kopiraj naziv u alociranu
memoriju*/
}
for(i=0;i<10;i++)
{
iscrtaj_tocku(&t[i]); /*prosljedivanje funkciji iscrtaj_tocku
pokazivac
na strukturu TOCKA, koju zelimo iscrtati */
}
getch();
return
0;
}
void
iscrtaj_tocku(TOCKA *tp)
{
gotoxy(tp->x,tp->y);
/*pristupanje preko pokazivaca vrijednostima x i y, te
pomocu funkcije gotoxy postaviti kursor na
zeljene koordinate*/
printf("%s",tp->naziv);/*ispis naziva tocke
na trenutnu poziciju kursora*/
}
Uo�imo u gornjem programu da smo prvo stvorili novi tip
podatka i nazvali ga TOCKA. Onda smo deklarirali funkciju
iscrtaj_tocku, koja prima kao parametar, pokaziva� na podatak
tipa TOCKA, u main funkciji onda stati�ki alociramo niz
od 10 varijabli tipa TOCKA, te x,y �lanove svake te varijable
u for petlji postavimo na neki slu�ajni broj unutar opsega
koordinata ekrana, funkcija koju je upotrijebljena za dobivanje
slu�ajnog broja zove se rand(); za svaku to�ku onda jo�
napravimo i naziv te to�ke, koji se sastoji od koordinata
te to�ke, za to smo koristili funkciju sprintf, ta funkcija
pona�a se identi�no kao i printf funkcija, samo �to ova
ispisuje rezultat u string, a printf ispisuje rezultat na
standardni izlaz (ekran), zbog toga sprintf ima jedan dodatni
parametar: pokaziva� na char, u kojeg �e ta funkcija upisati
�eljeni string.
Valja jo� uo�iti kako se u funkciji iscrtaj_tocku pristupa
pojedinim �lanovima varijable tipa TOCKA, preko operator
->. Dalje uo�ite prednost da u funkciju iscrtaj_tocku
nismo morali proslje�ivati tri varijable (x,y,naziv), ve�
samo jednu (TOCKA), daljnja prednost proslje�ivanje preko
pokaziva�a na strukturu je da je br�e od proslje�ivanja
cijele strukture, te ima jo� jedna prednost proslje�ivanja
pokaziva�a, u tom slu�aju vrijednosti izvorne strukture
mogu se preko tog pokaziva�a direktno mijenjati.
Zadatak 6: Napravite program sa strukturom UCENIK koja
�e sadr�avati ime, prezime, ocjene i prosjek. Ocjene trebaju
biti niz integera i broj ocjena je za svakog u�enika jednak.
Prvo program treba unijeti koliko u�enika treba postoji,
zatim program mora unijeti broj ocjena za svakog u�enika,
zatim redom program unosi za svakog u�enika podatke i ra�una
prosjek, na kraju program treba ispisati sve u�enike poredane
po prosjeku.
Upute: Prosjek neka bude float, ocjene neka budu pokaziva�
na int, ime, prezime neka budu pokaziva� na char, Najjednostavniji
algoritam za sortiranje koji mo�ete upotrijebiti zove se
metoda razmjene, kod tog algoritma stavite dvije petlje
jednu u drugu i uspore�ujete svaki sa svakim, ako je prosjek
iz vanjske petlje ve�i od onog iz unutarnje, tada ih zamjeni.
11. #include i #define
U op�enitom slu�aju: Pomo�u #include<dat.h> govorite
compileru da uzme izvornu datoteku dat.h te da je ubaci
na mjesto gdje se nalazi include, i tek onda neka po�ne
compilirati. Na primjer, ako datoteke dat.h i mojprg.c izgledaju
ovako:
dat.h:
int
mnozi(char a,char b)
{
return a*b;
}
mojprg.c:
#include
<dat.h>
int main(void)
{
printf("\nUmnozak: %d",mnozi(2,3));
return
0;
}
Compiler datoteku mojprg.c vidi kao:
int
mnozi(char a,char b)
{
return a*b;
}
int main(void)
{
printf("\nUmnozak: %d",mnozi(2,3));
return
0;
}
Kada se include datoteka navodi sa znakovima <> tada
�e compiler zadanu datoteku poku�ati prona�i u standardnom
include direktoriju, me�utim kada radimo svoje vlastite
include datoteke, tada ih mo�emo pozivati i sa navodnicima,
npr:
#include "c:\bc\mojinc.h"
Pomo�u naredbe #define mo�emo nekoj vrijednosti dati neko
simboli�ko ime, te kasnije mo�emo to simboli�ko ime upotrebljavati
u k�du, a compiler �e umjesto imena stavljati na to mjesto
vrijednost tog simboli�kog imena. Npr:
#define
MAX_X 640
definirana je konstanta MAX_X, sa vrijedno��u 640, kasnije
u k�du mo�emo tu konstantu koristiti, npr:
if(x
> MAX_X)return 0; Umjesto broj�anih vrijednosti
mo�ete konstantama pridru�ivati i stringove, �ak i funkcije,
itd... Prednost upotrebe konstanti je u tome da ih lako
mo�ete mijenjati, te ne morate prelaziti cijeli k�d svaki
put kada neku specifi�nu vrijednost mijenjate.
12. Stvari
koje zbog jednostavnosti nisam spominjao
Kada BORLANDC barata sa ekstenzijom .CPP tada on program
tretira kao C++ program, dok ekstenzija .C odgovara C programu.
U C/C++ tip podatka int nije uvijek 16bitne duljine, ve�
njegova duljina ovisi od compilera do compilera, pod 16bitnim
DOS-ovim compilerima integer je duljine 16, me�utim pod
32bitnim DOS-ovim compilerima kao npr. DJGPP int je duljine
32 bita, u MS VISUAL C-u int je tako�er 32 bita.
U C-u nije potrebno void * pointer pretvarati u �eljeni
oblik, kao �to smo to radili tijekom tutoriala, dok je u
C++ to itekako potrebno, me�utim C-u ne smeta, tako da sam
za svaki slu�aj uvijek pisao i tu pretvornu.
Gdje god sam koristio izraze da compiler ne�to alocira,
ili ne�to drugo radi, to nije sasvim to�no, naime compiler
samo stvara potreban k�d koji �e alocirati, ili to ne�to
drugo raditi, a procesor ra�unala je tek onaj koji �e zaista
to i napraviti (izvr�iti).
Pointer u DOS-u ne mora uvijek biti duljine 2 byte, postoje
far pointeri koji su uvijek 4byta veli�ine, a kada radite
u LARGE memorijskom modelu tada se svi pointeri far pointeri.
KRAJ
Do�li smo do kraja ovog kratkog putovanja kroz porgramski
jezik C, vjerujem da ste ne�to nau�ili, ali isto tako sam
siguran da imate mnoga pitanja za koja ovdje ne mo�ete na�i
odgovor. Zato vam preporu�ujem da si nabavite neku knjigu
ili si na�ete osobnog 'gurua' koji �e odgovarati na va�a
pitanja. I nemojte odustati kod prvog problema na koji naletite.
Podsjetio bih vas samo na jo� jednu sitnicu, da mi po�aljete
mail sa svojim dojmovima na vinko_kojundzija@yahoo.com.
Hvala.
Rjesenja zadataka.