Ciklična programska struktura je ona kod koje se koraci mogu izvršiti više puta. Slično kao kod razgranate strukture, vrlo lako se može desiti da ne znamo koje će vrednosti korisnik uneti, ili čak koliko će ih biti.

Ogroman broj zadataka koje rešavamo u programiranju zahteva da se podatak za podatkom obrađuje na isti način. To sa stanovišta algoritma znači da se jedni isti koraci ponavljaju više puta. Kao što smo se upoznali sa različitim tipovima grananja, sada ćemo se upoznati sa nekoliko tipova ciklusa. Svim koracima kojima definišemo cikluse zajedničko je to što imaju "vraćanje unazad". Na taj način "vraćaju" izvršavanje programa nekoliko koraka unazad čime se pravi ciklus ili petlja.

Svako ponavljanje ciklusa, naziva se iteracija. Koraci unutar ciklusa su uvek isti, ali vrednosti sa kojima se radi se menjaju. To je u stvari i poenta rada sa ciklusima.

Ciklusi se mogu kombinovati sa svim programskim strukturama. To znači da možemo imati grananja unutar ciklusa ili cikluse unutar grananja.

Kako ciklus funkcioniše?

Sećate se razgranatih programa i koraka u kome smo "račvali" izvršenje programa na dve grane? E, sad zamislite da se izvršenje programa ne deli na dve mogućnosti, već se vraća unazad. Korak koji definiše ciklus, takođe sadrži izraz logičkog tipa, odnosno uslov. Pitanje koje se postavlja više nije "ako je (tačno)...", već "dok je (tačno), ponavljaj to-i-to". Sve što smo ranije pisali za uslove u razgranatim algoritmima važi i ovde. To znači da možemo zadati i kompleksne uslove.

Ovo su takozvani uslovni ciklusi.

Dakle, da zaključimo: sve dok je odgovor na pitalicu unutar koraka ciklusa, "da", ciklus će se ponavljati. To znači da do kraja ciklusa dolazimo kada uslov više nije zadovoljen. Tada se nastavlja sa normalnim izvršavanjem koraka koji dolaze posle ciklusa.

Ovo nas dovodi do jedne važne stvari:

Da bi uslov koji je u nekoliko iteracija bio zadovoljen, odjedanput prestao da važi, mora doći do neke promene. Nosioci vrednosti u našim algoritmima su promenljive. Kroz ciklus, ta vrednost može (i treba) da se menja - posebno onih promenljivih koje učestvuju u uslovu. Praktično, čeka se "kap koja je prelila čašu", da bi se ciklus završio.

Mesto provere uslova

Uslov može da se proverava na početku ili na kraju ciklusa. Tako razlikujemo ciklus sa preduslovom i ciklus sa postuslovom. Možda vam se čini da je svejedno da li proveravamo uslov pre ili posle "tela" ciklusa, ali  postoji jedna jako bitna razlika.

Kod ciklusa sa preduslovom, može da se desi da uslov već na početku ne bude zadovoljen. Tako je moguće da se ciklus ne izvrši ni jednom. Sa druge strane, kod ciklusa sa postuslovom, ciklus mora da se izvrši jednom, da bi uopšte došlo do provere uslova i odluke da li će se ciklus ponavljati.

U praksi ćete birati ciklus koji vam više odgovara za trenutni problem:

ciklični algoritam sa preduslovom

ciklični algoritam sa postuslovom

Ciklični algoritam - brojački

while

do ... while

for

(dokle god je uslov ispunjen,
izvršavaće se telo ciklusa)

(prvo jednom odradi telo ciklusa,
pa onda proveri da li je uslov ispunjen,
i ako jeste ispunjen,
nastavlja da se ponavlja telo ciklusa,
dokle god je uslov ispunjen)

(ovde znamo koliko će se puta ponoviti )

while(uslov)
{
/* telo ciklusa /*
}

do {
/* telo ciklusa */
}while(uslov);

primer:

for(i=0;i<100;i++)
{
/* telo ciklusa */
}



Objašnjenje uslovnih ciklusa, i kako se koriste:


while  ( ciklus sa preduslovom )

ciklični algoritam sa preduslovom

Ovako izgleda ciklus koji se može izvršiti jednom, ni jednom ili više puta. Primećujete da se uslov proverava na početku. Ako je zadovoljen (vrednost true), izvršiće se iteracija ciklusa.

To znači da ako uslov nije zadovoljen već pri prvoj proveri, ceo ciklus se preskače - neće se izvršiti ni jedanput. Ovaj uslov se proverava svaki put na "ulasku" u iteraciju i sve dok je zadovoljen, naredbe ciklusa će se ponavljati.

Sintaksa naredbe while je:

    while (uslov){
	blok naredbi;
    }

Prvo se proverava ispunjenje zadatog uslova, ukoliko je uslov ispunjen, izvršava se blok naredbi i ide se ponovo na proveru uslova. Ukoliko uslov nije ispunjen izlazi se iz while petlje i nastavlja sa izvršavanjem naredbi posle while naredbe. Ovde možemo zaključiti da se blok naredbi u while-u ne mora izvršiti ni jednom. Uslov while naredbe je logičkog tipa !

Pre ulaska u petlju vrši se inicijalizacija promenljivih koje će biti korišćene bilo u uslovu, bilo u telu petlje. U telu petlje se mora nalaziti kod koji će baratati sa promenljivama koje formiraju uslov za ostanak u petlji. Na primer:

C: C++:
   int i=1;
   while(i<=10){
    printf("%d",i);
    i++;
   }
   int i=1;
   while(i<=10){
    cout<<i<<endl;
    i++;
   }

u ovom deli koda kao rezultat se štampaju brojevi od 1 do 10 na standardni izlaz.

U slučaju inicijalizacije promenljive i sa bilo kojim brojem većim od 10 petlja se ne bi izvršavala i na izlazu ne bismo dobili ništa.



do...while ( Ciklus sa postuslovom )

ciklični algoritam sa postuslovom

Ovakav ciklus će se izvršiti bar jednom ili više puta. Uslov se sada nalazi na kraju ciklusa, kao "ventil" koji određuje da li će izvršavanje ciklusa "skočiti" nazad na telo ciklusa, ili će se ciklus završiti.

Zbog toga se čak iako uslov nije zadovoljen pre ciklusa, telo ciklusa izvrši bar jednom, pre nego što dođe do provere.

Sintaksa naredbe do..while je:

   do{
      blok naredbi;
   }while(uslov)

Naredba se izvršava tako što se prvo izvrši blok naredbi, nakon čega se proverava ispunjenost uslova. Ukoliko je ispunjen uslov, ponovo se izvršava blok naredbi, ukoliko uslov nije ispunjen izlazi se iz petlje i nastavlja se sa izvršavanjem naredbi koje su navedene posle do..while naredbe. Osnovna razlika između naredbi while i do..while je što će se kod naredbe do..while blok naredbi sigurno izvršiti barem jednom.

Posmatrajmo sada zadatak da treba učitati broj koji je deljiv sa tri i dok korisnik ne unese takav broj ponovo ispisujemo isti zahtev. Ovakav zadatak je najbolje implementirati korišćenjem do..while naredbe:


C: C++:
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int broj;
    do{
        printf("unesite broj deljiv sa tri: \n");
        scanf("%i", &broj);

    }while(broj%3!=0);

    printf("%i / 3 = %i", broj, broj/3);
    return 0;
}
#include <iostream>
using namespace std;

int main()
{
    int broj;
    do{
        cout<<"unesite broj deljiv sa tri: "<<endl;
        cin>>broj;

    }while(broj%3!=0);

    cout<<broj<<" / "<<"3 = "<< broj/3<<endl;
    return 0;
}
Zbog prirode do..while naredbe korisniku će se zahtev ispisati barem jednom, nakon učitavanja broja proverava se uslov, a to je da broj nije deljiv sa tri, ako je ovaj uslov ispunjen, znači da nismo učitali dobar broj i izvršava se sledeća iteracija do..while naredbe, ako uslov nije ispunjen, znači da je učitan broj deljiv sa tri i završava se izvršavanje do..while naredbe.



naredba for ( Brojački ciklus )

Kada u programu računar stigne do uslovnog ciklusa, uglavnom je to situacija kada ne može da se zna koliko će se puta ciklus izvršiti. Dakle, ciklus će se "vrteti" sve dok je uslov zadovoljen, nepoznat broj puta.

Međutim, često se u programu zna (ili se može izračunati) broj ponavljanja ciklusa. To su npr. situacije kada u programu postoji informacija o broju elemenata niza ili se od korisnika unapred traži da unese maksimalan broj ponavljanja. Tada je mnogo optimalnije koristiti brojački ciklus.

Ovaj ciklus funkcioniše na pricipu brojačke promenljive, koja ima definisanu početnu i krajnju vrednost. U jednom koraku se objedinjuje postavljanje početne vrednosti, provera da li je dostignuta krajnja vrednost i računanje nove vrednosti brojača.

Ciklični algoritam - brojački

Brojački ciklus se u različitim programskim jezicima optimizuje na različite načine, ali gotovo uvek je njegovo izvršavanje brže od običnog uslovnog ciklusa.

naredba for

Sintaksa for naredbe je

   for(inicijalizacija; uslov; inkrementacija){
	blok naredbi
   }

Prvo se izvrši inicijalizacija, i zatim se proverava uslov. Ukoliko je njegova vrednost tačna, ulazi se u blok naredbi koji je naveden u petlji. Kada se izvrše sve naredbe izvršava se inkrementacija i tok programa se vraća na ponovno ispitivanje uslova. Opisani proces se ponavlja sve dok je ispunjen uslov. Ako uslov nije ispunjen izlazi se iz petlje i nastavlja se sa izvršavanjem naredbi koje su navedene posle for petlje. Deo za inkrementaciju ne mora uvek da znači povećanje vrednosti neke promenljive za jedan, to može da bude proizvoljno povećanje ili smanjenje vrednosti promenljive, a najčešće se menja vrednost promenljive koja se pojavljuje u uslovu.

Ako bismo posmatrali problem izračunavanja zbira svih parnih brojeva u intervalu od nula, do nekog zadatog broja n, ovaj zadatak bi se mogao jednostavno implementirati korišćenjem for naredbe.


xxxxxxxxxxx
C: C++:
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i, n;
    int zbir = 0;
    printf("Unesite broj n:\n");
    scanf("%i", &n);
    for(i=0; i<=n; i+=2){
        zbir +=i;
    }
    printf("Zbir parnih brojeva od 0 do %d je %d.", n, zbir);
    return 0;
}
#include <iostream>
using namespace std;

int main()
{
    int i, n;
    int zbir = 0;
    cout<<"Unesite broj n:"<<endl;
    cin>>n;
    for(i=0; i<=n; i+=2){
        zbir +=i;
    }
    cout<<"Zbir parnih brojeva od 0 do ";
cout<<n<< " je "<< zbir<<endl; return 0; }
Na početku definišemo sve potrebne promenljive, to je promenljiva n koja predstavlja ulazni podatak, promenljiva i koji će se koristiti kao brojač u for petlji i promenljiva zbir u kojoj će se akumulirati zbir u toku izvršavanja petlje. Promenljivoj zbir na početku dodeljujemo vrednost 0, a u for petlji ćemo joj dodavati parne brojeve.

Nakon što korisnik unese broj n ulazi se u for petlju koja u delu za inicijalizaciju postavlja vrednost brojača na nula, uslov za izlazak iz petlje je da smo došli do broja n (u obzir uzimamo samo brojeve koji su manji ili jednaki sa n), a u delu za inkrementaciju brojač povećavamo za dva, jer se traže samo parni brojevi. U for petlji je navedena jedna naredba koja trenutni zbir povećava za brojač i koji će u svakoj iteraciji for petlje imati sledeći parni broj u intervalu od 0 do n.


Dodatak (ovo nismo radili na sekciji, ali bi bilo dobro da se zna): 


break i continue

Postoje dve ugrađene naredbe koje mogu da promene tok izvršavanja petlji i mogu se koristiti u kombinaciji sa bilo kojom od tri navedene naredbe ponavljanja.

Prva je naredba break, koja prekida proces izvršavanja petlje, a druga je naredba continue koja prekida izvršavanje jedne iteracije petlje.


break

Ako se toku izvršavanja petlje u određenoj grani pozove naredba break, na tom mestu se prekida izvršavanje petlje i prelazi se na sledeću naredbu posle petlje.


Primer: Zadatak sa učitavanjem broja koji je deljiv sa 3 koji smo prethodno uradili korišćenjem do..while naredbe može se implementirati korišćenjem while petlje i naredbe break:

#include <iostream>
using namespace std;

int main()
{
    int broj;
    while(1){
        cout<<"unesite broj deljiv sa tri: "<<endl;
        cin>>broj;
        if(broj%3==0)
            break;
    }
    cout<<broj<<" / 3 = "<< broj/3<<endl;
    return 0;
}

Ovde smo izabrali da napravimo beskonačnu petlju (uslov za naredbu while je uvek tačan), ali čim dobijemo odgovarajući broj izlazimo iz petlje naredbom break i program nastavlja sa naredbom posle while-a, odnosno ispisuje rezultat deljenja unetog broja sa 3.


continue

Naredba continue ne prekida celu petlju već trenutnu iteraciju:

Kada se u toku izvršavanje petlje u nekoj grani programa naiđe na naredbu continue, prekida se izvršavanje trenutne iteracije, odnosno preskaču se naredbe u bloku naredbi 2 i tok izvršavanja programa vraća se na ispitivanje uslova za sledeću iteraciju petlje (for, while ili do..while). Ukoliko je uslov ispunjen, izvršava se sledeća iteracija petlje.

Naredba continue se može iskoristiti u implementaciji programa koji sabira 10 brojeva koji se unose preko konzole, ali izostavlja negativne brojeve.

# include <iostream>
using namespace std;

int main()
{
int i;
double broj, suma = 0.0;
for(i=1; i <= 10; ++i){
cout<<"Unesite broj " << i<<": ";
cin>>broj;
// ako korisnik unese negativan broj, preskacemo ga
if(broj < 0.0){
continue;
}
suma += broj;
}
cout<<"Suma = "<<suma<<endl;
return 0;
}

Imamo for petlju koja će imati deset iteracija, u svakoj iteraciji učitavamo broj preko konzole i ako je unet negativan broj naredbom continue prelazimo na sledeću iteraciju, odnosno preskačemo naredbu koja sabira uneti broj sa trenutnom sumom.


Mrtva petlja

Mrtva petlja je ciklus koji ne može da se zaustavi. Zove se još i beskonačni ciklus. To je situacija kada je uslov za ponavljanje ciklusa uvek zadovoljen, tako da ciklus nikada ne dođe do svog kraja.

Ovo je u 99% slučajeva rezultat greške programera. Moguće je da smo pogrešili u uslovu tako da on uvek vraća isti rezultat, ili u samom ciklusu ako zaboravimo da promenimo vrednosti promenljivih koje bi dovele do kraja ciklusa, ili to uradimo pogrešno.

Postoje i retke situacije kada želimo da napravimo beskonačni ciklus. Na primer, zatrebaće nam ako pravimo animaciju koja treba neprestano da se "vrti". Takođe može da se desi i da je uslov za izlazak iz ciklusa toliko kompleksan, da je programeru lakše da na više mesta unutar ciklusa zada nasilni prekid. Međutim, ovo se ne smatra "dobrom programerskom praksom".

Ako želimo da napravimo beskonačan ciklus, najjednostavniji način je uslovni ciklus sa uslovom true. To je svakako uslov koji je uvek ispunjen.

! ! ! DA NE BISTE ZAGLAVILI PROGRAM, POTRUDITE SE DA U NEKOM MOMENTU BUDE MOGUĆE MAKAR AKTIVIRATI NAREDBU break DA BISTE IZAŠLI IZ BESKONAČNE PETLJE ! ! !

Last modified: Saturday, 5 December 2020, 8:20 PM