Home

About me

C-Tutorial Hrvatski

C-tutorial examples

Electronics

Funny stuff

Links

 

 

 

 

 

   
C Tutorial na hrvatskom


Autor: Vinko Kojund�ija
Godina prvog objavljivanja: 1999
Zadnja izmjena: 10.3.2005
Email: vinko_kojundzija@yahoo.com
Home page: http://www.oocities.org/vinko_kojundzija/
Opis: Tutorial je namjenjen u�enju programskog jezika C, te su sadr�ane i neke najosnovnije upute za rad sa BORLAND C-om 3.X

Sad�aj

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.

 

 





 

 

 

 

 

 

 

 

 

 
Vinko Kojundzija (c) 2005