[ Riga019 @ 23.10.2012. 17:27 ] @
Kako u programu staviti da se po obavljenom zadatku ponavlja main funkcija ?

Code:
#include <stdio.h>

// Napisati program koji odredjuje da li je uneti broj paran ili neparan.

main()
{
      int x;
      printf("Unesi broj :\n");
      scanf("%i",&x);
      if(x%2==0)
      printf("PARAN");
      else
      printf("NEPARAN");
      scanf("%i");
}


Znači ... Primer : Ukucam broj 23, program ispiše da je taj broj NEPARAN. I kako odmah posle toga opet pokrene tu main funkciju, tj. da opet ispiše da se unese broj i da ponovo ako ukucam primer 24, ispise da je PARAN ?

Mislim da sam bio jasan. :D
[ maksvel @ 23.10.2012. 17:29 ] @
Ne treba ti još jedan main, stavi petlju, na primer while i neka vrti, dok se ne unese broj "za izlaz iz petlje", na primer nula.
Npr:
Code (c):


main()
{
      int x;
while(1)
{    
      printf("Unesi broj (za izlaz unesi 0) :\n");
      scanf("%i",&x);
     if(x==0)
          break;
      if(x%2==0)
      printf("PARAN\n");
      else
      printf("NEPARAN\n");

}
     
}
 

Petlja radi non-stop (while (1)), dok se ne unese nula, kada prestaje.

[Ovu poruku je menjao maksvel dana 23.10.2012. u 18:43 GMT+1]
[ chaami @ 23.10.2012. 23:59 ] @
A možeš i bez petlje
Code:

#include <stdio.h>

int main()
{
    int x;
    {
        printf("Unesi broj (za izlaz unesi 0) :\n");
        scanf("%i",&x);
        if(x%2==0) printf("PARAN\n");
        else printf("NEPARAN\n");
    }
    return x==0 ? x:main();
}

čisto da se malo bolje upoznaš sa C jezikom.
[ Mihajlo Cvetanović @ 24.10.2012. 10:07 ] @
Treba imati u vidu da rekurzivno pozivanje funkcije mora da ima neki kraj, to jest ne može funkcija da se u nedogled poziva rekurzivno. Postoji fizičko ograničenje pozivnog steka, i kad program nesputanim rekurzivnim pozivima dođe do kraja steka onda program "puca". Ovde upravo imamo takav slučaj, kada bi neki korisnik bio dovoljno zaludan da koristi program dovoljno dugo, nikad ne unevši nulu.
[ Goran Arandjelovic @ 24.10.2012. 12:39 ] @
A i bez obzira što je mali program, nije baš "lepo" pozivati rekurzivno main funckiju.
[ chaami @ 24.10.2012. 13:57 ] @
@Mihajlo neće se stek nikad popuniti jer ga return prazni od predhodne funcije tako da možeš do penzije da unosiš brojeve (uključi debug i videćeš da je uvek samo jedna funkcija na steku).

@Goran upravo zato i jeste "lepo" jer rekurziju koristimo bukvalno kao goto ;)
[ Mihajlo Cvetanović @ 24.10.2012. 14:14 ] @
Stek će se u jednom trenutku napuniti. Stek se ne prazni kad se pozove return, nego kad se taj return izvrši, a u ovom slučaju da bi se izvršio potrebno je da se prvo ponovo pozove main, u krug. Možeš da probaš, napravi tekstualni fajl sa par miliona jedinica, po jedna u redu, i izvrši ovaj program preusmeravajući standardni ulaz da ide preko tog fajla, proba.exe < mnogo_jedinica.txt, i vidi šta će se desiti.

Ili, uključi debug i videćeš da je mnogo funkcija na steku.
[ chaami @ 24.10.2012. 15:02 ] @
Mihajlo, ne mogu da tvrdim za MS kompajler (voleo bi da neko proveri jer me od njih ništa ne bi čudilo) ali što se GCC tiče stek se definitivno prazni. Onog trenutka kad kompajler kao povratni rezultat neke funkcije ima drugu funkciju automatski prestaje potreba za pozivnom funkcijom i ona se briše. Ne pričam ti ništa napamet. Sve sam proverio sa debugerom, kao što sam ti i rekao u prethodnom postu. Uostalom, povedi se zdravom logikom, što bi kompajler čuvao funkciju za kojom je prestala potreba.

EDIT: evo ga jednostavan primer. Imamo 1000 milijardi pozivanja funkcije main i u svakoj pravimo lokalnu promenljivu c.
Code:

#include <stdio.h>
int x,y;
int main()
{
    int c;
    ++y;
    c=y;
    if (c>1000000){y=0;++x;printf("%d\n", x);}
    return x==1000000 ? x:main();
}


[Ovu poruku je menjao chaami dana 24.10.2012. u 16:29 GMT+1]

[Ovu poruku je menjao chaami dana 24.10.2012. u 16:29 GMT+1]
[ Mihajlo Cvetanović @ 24.10.2012. 15:33 ] @
A dobro, to je ono što zovu tail call optimization. Na to sam zaboravio. U ovom slučaju je moguće napraviti kod tako da se ne troši stek, ali to nije moguće u svakoj rekurziji.
[ Nedeljko @ 26.10.2012. 11:23 ] @
chaami, nisi u pravu. Stek se itekako puni i puca, a program ti nije dobar. Na početku izvršavanja x i y sadrže đubre (često nulu, ali ne uvek), tako da ti program ima nedefinisano ponašanje. Osim toga, ne znam da li si ga probao, ali kod mene puca (Ubuntu 11.04, gcc/g++ 4.6.3). Stavio sam da se x i y inicijalizuju na nulu.

Probao sam ovaj program:
Code (cpp):

int counter = 1000000;

int main() {
    return --counter == 0 ? 0 : main();
}

Rezultat je

Segmentation fault (core dumped)


Isti rezultat daje ovaj program:
Code (cpp):

int main() {
    return main();
}
[ Mihajlo Cvetanović @ 26.10.2012. 11:51 ] @
Možda treba da se uključi odgovarajuća optimizacija, O3 valjda.
[ Nedeljko @ 26.10.2012. 14:02 ] @
U pravu si. Izgleda da sa njom radi.
[ chaami @ 26.10.2012. 21:18 ] @
Definitivno je potrebna ili O2 ili O3 optimizacija ... eto, a ja sam bio ubeđen da se to podrazumeva. U svakom slučaju, sa O2 optimizacijom svaka funcija može da poziva samu sebe bez opasnosti da će zatrpati stek.
Što se neinicijalizovanih globalnih i statičkih promenljivih tiče, one se isto kao i globalni pointeri smeštaju u .bss segment. Loader programa, odnosno sam OS bi morao da popuni bss segment sa nulama. ISO C standard takođe kaže da će sve neinicijalizovane globalne i statičke promenljive biti postavljene na 0.


[Ovu poruku je menjao chaami dana 26.10.2012. u 22:32 GMT+1]
[ Mihajlo Cvetanović @ 27.10.2012. 23:43 ] @
E vidiš, ovo sad nije tačno, da s optimizacijom svaka funkcija može da poziva samu sebe bez opasnosti po stek. Samo funkcije koje imaju "tail call", ili mogu da se preslože tako da imaju tail call, mogu da se organizuju tako da ne troše stek. Ako posle rekurzivnog poziva funkcije postoji još nešto bitno da se radi u funkciji, onda kompajler ne može da ukloni stek, jer mu stek treba da bi uradio to drugo što je bitno. Pišem napamet, i mrzi me da testiram, ali ko je znatiželjan nek proveri da li sledeći kod puca:

Code:
int proba(int x)
{
  int result = x == 0 ? 0 : proba(x);
  return result + (result ? 1 : -1);
}


Malo sam ga zakomplikovao da prevarim eventualni analizator koda. Pozvati funkciju s bilo kojim parametrom osim nule.
[ chaami @ 28.10.2012. 06:47 ] @
Da ... moja greška. Napisao sam "svaka funkcija može da poziva sebe" umesto "svaka funkcija na izlazu može da poziva sebe". Ukoliko stavimo return funkcija() imaćemo beskonačnu petlju.
[ X Files @ 28.10.2012. 11:01 ] @
Iskreno, nikad u životu mi nije palo na pamet da pozovem main() iz main()-a :)


Off:
Sećam se mojih prvih programa, na interpreterskom BASIC-u, na jednom domaćem računaru. Često sam imao izraze tipa (radilo se o nekoj bazi podataka):
Code:

...
100 FOR I=1 TO N
110 IF A$(I)=N$ THEN GOTO 500
120 NEXT I
130 REM nastavak, kada se potroši i poslednji "I" (sa brisanjem adrese linije 110, gde je trebalo kod da se vrati), ali se to uglavnom nikada nije dešavalo, jer je izlazak uvek bio ranije
140 GOTO 10

500 REM Neka obrada sa poznatim indeksom I
...


Šta se dešavalo?
Posle izvesnog vremena VIDEO MEMORIJA (izgled ekrana), koja je bila realizovana samo kao kontinualnih 8KB celokupne linearne memorije, je počela da pri vrhu ima neke čudne tačkice. E te tačkice su bile neočišćeni parovi bajtova x broj dolazaka na linije tipa koda koji sam naveo. Ukratko STEK se prelivao na deo koji je pripadao VIDEO MEMORIJI.

[ maksvel @ 28.10.2012. 12:09 ] @
- Kakve su ti to mrlje po monitoru?
- Naše plate, kolega.
[ Nedeljko @ 28.10.2012. 13:00 ] @
@X Files

Jesi li imao krme (C64) ili najbolji računar u istoriji, savršenstvo bez mane (ZX Spectrum, 48K)? Mojne samo da mi kažeš da si koristio amSMRAD.
[ X Files @ 28.10.2012. 14:07 ] @
Heh :) Koristio sam sve koje si naveo, i još neke starije i novije, a ovo o čemu sam pričao, odnosilo se na ORAO 102:
http://hr.wikipedia.org/wiki/Orao_(računalo)
Mora se ručno dodati desna zagrada. Inače gde li se izgubiše genijalci tog doba: http://rep.hr/vijesti/tehno-i-...leb-i-orao-su-moje-djelo/2335/

Obrati pažnju na ovaj deo sa linka:
Citat:

Memorijska mapa [uredi]
0000 - 03FF - nulti blok (1K)
0400 - 5FFF - korisnički RAM (23K)
6000 - 7FFF - video RAM (8K)

8000 - 9FFF - sistemske lokacije (8K)
A000 - AFFF - proširenje (1K)
B000 - BFFF - DOS (1K)
C000 - DFFF - BASIC ROM (8K)
E000 - FFFF - sistemski ROM (8K)


Dakle, radilo se o prelazu iz segmenta "korisnički RAM" ka segmentu "video RAM". Ali ja to tada nisam kapirao. Kasnije, kada sam se zainteresovao za 6502 asemblere, sa zakašnjenjem sam skapirao šta je bio uzrok.

Video RAM je činilo 8KB, rezolucije 256x256 piksela (podeljeno sa 8 bitova=8192bajta), bez boja, samo crno belo. Idealno projektovano za eksperimente. Zato se sve u vezi grafike prilično brzo izvršavalo za tih 1MHz.

[ Nedeljko @ 28.10.2012. 14:10 ] @
A, pa to je bio .

[Ovu poruku je menjao Nedeljko dana 28.10.2012. u 17:40 GMT+1]
[ Boyka @ 28.10.2012. 17:56 ] @
Citat:
chaami:
@Mihajlo neće se stek nikad popuniti jer ga return prazni od predhodne funcije tako da možeš do penzije da unosiš brojeve (uključi debug i videćeš da je uvek samo jedna funkcija na steku).

@Goran upravo zato i jeste "lepo" jer rekurziju koristimo bukvalno kao goto ;)


goto je u stvari jedna rekurzivna metoda sa get, set parametrima...
[ Nedeljko @ 28.10.2012. 18:02 ] @
Nije. Probaj da isprogramiraš izračunavanje vrednosti matematičkih izraza sa zagradama bez rekurzije. Može bez rekurzije, ali ti treba stek, koji predstavlja fundamentalnu razliku između rekurzije i goto naredbe.
[ Goran Arandjelovic @ 29.10.2012. 18:46 ] @
Meni samo nije jasno zašto bi neko morao da se oslanja na bilo kakvu vrstu optimizacije koja nije invarijantna. To je jednostavno loše u 90% slučajeva. U preostalih 10%, onaj ko to radi, vrlo dobro zna šta radi ili nema blage veze šta radi. Za rekurziju UVEK treba definisati bazni slučaj, a ne oslanjati se na tail recursion optimizaciju. To je isto kao kada bi neko hteo da broji kopije nekog objekta u statičkoj promenljivoj njegove klase koju bi inkrementirao u copy konstruktoru recimo... Neko je postavljaču teme ponudio rešenje sa while petljom koje smatram mnogo boljim neko rekurzivno pozivanje main-a, ma koliko optimalno bilo...
[ Boyka @ 29.10.2012. 19:44 ] @
@Nedeljko mislio sam za petlje, kontam da su petlje u stvari neke rekurzivne metode?

Evo i sa goto, krenuo i ja sa c, pa cisto da vidim da li znam ista :lol:
Code (c):

int main()
{
pocetak:
     int x;
     printf("Unesi broj (za izlaz unesi 0) :\n");
     scanf("%i",&x);
     if(x%2==0) printf("PARAN\n");
     else printf("NEPARAN\n");
     while(x!=0)
     {
          goto pocetak;
     }
}
 
[ Nedeljko @ 30.10.2012. 12:50 ] @
Citat:
Goran Arandjelovic: Za rekurziju UVEK treba definisati bazni slučaj, a ne oslanjati se na tail recursion optimizaciju.

Kakve veze ima rekurzija sa optimizacijom? Rekurzija je svođenje složenih slučajeva na proste u nekom broju koraka, pri čemu se rešavaju neposredno. Štaviše, rekurzija po pravilu daje manje efikasna rešenja od iterativnih.

Primer: Izračunavanje elemenata Fibonačijevog niza:
Code (cpp):
int fib_recursive(int k)
{
    if (k == 1 || k == 2) {
        return 1;
    } else if (k > 2) {
        return fib_recursive(k - 1) + fib_recursive(k - 2);
    } else {
        throw("error");
    }
}

int fib_iterative(int k)
{
    if (k < 1) {
        throw("error");
    }

    int a0 = 0, a1 = 1;

    for (int i = 1; i < k; ++i) {
        int t = a0 + a1;

        a0 = a1;
        a1 = t;
    }

    return a1;
}

Rekurzivna funkcija se računa u eksponencijalnom vemenu i linearnom prostoru (računajući nagomilavanje steka), a iterativno u linearnom vremenu i konstantnom prostoru. Za iterativno rešenje je lako proceniti složenost. Rekurzija uvek izbacuje rezultat 1 kada se slučaj ne svodi na prostiji, tako da će se sve svesti na sabiranje jedinica. Primera radi

fib(5)=fib(4)+fib(3)
=(fib(3)+fib(2))+(fib(2)+fib(1))
=((fib(2)+fib(1))+1)+(1+1)
=((1+1)+1)+(1+1)

Ko ne veruje, može da ubaci brojače i dobiće da je broj sabiranja koji se obavi za izračunavanje fib(k) tačno fib(k)-1, a broj neposrednih izračunavanja tačno fib(k). No, poznato je da Fibonačijev niz eksponencijalno brzo raste, tako da je vreme izvršavanja eksponencijalno. Korišćeni prostor je linearan, jer za k>2 nema rekurzivnih spustova koji su duži od k-2 (argument se uvek smanjuje za 1), a postoji rekurzivni spust dužine k-2 (u izračunavanju fib(k) se koristi izračunavanje od fib(k-1) u čijem se izračunavanju koristi fib(k-2) itd.).

Kada rekurziju treba koristiti? Skoro nikad. Ako ne postoji potreba za gomilanjem steka, to treba rešiti petljom. Sledeći primer pronalazi prvi član neopadajućeg niza koji nije manji od date vrednosti:
Code (cpp):
int binary_search(double value, double array[], int size)
{
    int left = 0, right = size;

    while (left < right) {
        int mid = (left + right) >> 1;

        if (array[mid] < value) {
            left = ++mid;
        } else {
            right = mid;
        }
    }

    return left;
}

Kada se stek gomila, a nemamo kontrolu koliko može da se gomila, ni slučajno ne koristiti rekurziju, već ako je algoritam baš prirodno rekurzivan, onda simulirati rekurziju korišćenjem dinamičkog steka (flood fill, rešavanje lavirinta itd). Nju treba koristiti samo u slučaju da se stek gomila do neke kontrolisane granice, a takvi slučajevi su retki (razna balansirana stabla, minimaks algoritam za igranje igara kao što je šah itd).
[ Nedeljko @ 30.10.2012. 12:52 ] @
Boyka, ne valja ti program. Hajde, proveri ga i ispravi. Neće se izvšiti petlja više od jedanput.
[ Goran Arandjelovic @ 30.10.2012. 15:27 ] @
Citat:
Nedeljko:
Kakve veze ima rekurzija sa optimizacijom? Rekurzija je svođenje složenih slučajeva na proste u nekom broju koraka, pri čemu se rešavaju neposredno. Štaviše, rekurzija po pravilu daje manje efikasna rešenja od iterativnih.


Ako bi malo bolje čitao, ne bi me takvu glupost ni pitao samo da bi trolovao, ali avaj, da se nadovežem:
Pošto ne mora da bude poznato koliko će rekurzivnih poziva biti, u nekom trenutku može da se prepuni stek, pa sam zato pomenuo da ne treba računati na optimizaciju koja će "obrisati" f-ju, tj. eleminisati pravljenje novih stek frejmova.
[ Nedeljko @ 30.10.2012. 16:26 ] @
Sad sam izguglao "tail recursion optimisation". No, kakve to ima veze sa nedefinisanjem baznih slučaja? Bazne slučajeve moraš da imaš, osim ako želiš beskonačnu rekurziju.
[ Goran Arandjelovic @ 30.10.2012. 16:49 ] @
Čekaj, sad ti je jasnije šta sam rekao ili ne? Pošto brzo menjaš svoje odgovore pa nisam stigao da pročitam.

Code:

void func()
{
    // ...
    func();
}

int main()
{
    func();
}


Ovo je beskonača rekurzija koja će prepuniti stek, ali ako se uključi O2/O3 optimizacija, onda neće. Takođe, ako je optimizacija isključena, može se desiti da se stek napuni pre svođenja na bazni slučaj. Je l' sad jasnije ili ne? A mogao si i ranije da izguglaš šta znači tali recursion optimizacija pre nego što saspeš kako ne razumeš šta sam napisao.
[ Nedeljko @ 30.10.2012. 17:30 ] @
Takvu beskonačnu rekurziju kakvu si naveo, ti nikada ne bi napisao u kodu. Je li tako? E, ako je tako, čemu uopšte komentarisanje takvih "tehnika"? Korišćenje beskonačne rekurzije umesto beskonačne petlje je za momentalan otkaz. Takođe, i dalje ne vidim vezu sa nedefinisanjem baznih slučajeva.

Kada rekurziju treba koristiti, napisao sam. Vrlo retko, a kada se koristi, uvek treba da postoji izlaz iz rekurzije. Nije bitno samo da se direktno reše bazni slučajevi, već i da se ostali slučajevi zaista svode na bazne. Primer:
Code (cpp):

int fib(int k)
{
    if (k < 1) {
        throw("error");
    }

    if (k == 1) {
        return 1;
    }

    return fib(k - 1) + fib(k - 2);
}

Ovaj kod je pogrešan jer baca izuzetak za sve ulaze različite od 1. Džaba definisanje baznih slučajeva, ako se ostali ne svode na njih.
[ Goran Arandjelovic @ 30.10.2012. 18:47 ] @
Aman čoveče, čitaj šta pišem, a batali ono o čemu ne pišem.

Code:

int fact(int n)
{  
    if(n <= 1)
        return 1;
    
    return(n * fact(n - 1));
}


Dakle, najprostija rekurzivna funkcija koju bi neko mogao da napiše ovako, zar ne?
Za dovoljno veliko n, poziv ove f-je može teoretski da napuni stek i program puca, a ako je optimizacija uključena na kraju ćeš samo dobiti pogrešan rezultat zbog prekoračenja.
Šta ti dalje nije jasno?
[ Nedeljko @ 30.10.2012. 20:24 ] @
Nije mi jasno zašto se nerviraš. OK, isprva nisam proverio šta je optimizacija repa rekurzije, posle sam video. OK.

Što se ovog programa tiče, testirao sam ga i radi, ali nemam pojma kako. Koliko vidim, nakon izračunavanja rezultat mora da se pomnoži sa n, koje nije isto kroz sve pozive po dubini, tako da mi nije najasnije kako može da ne gomila stek, ali ga ne gomila.
[ chaami @ 31.10.2012. 00:25 ] @
@Nedeljko evo ga primer koji će i sa optimizacijom da puni stek.

Code:

float fun(float n)
{
    if(n <= 1)
        return 1;
    return n/fun(n-1);
}


Kod množenja je svejedno sa koje strane računamo dok kod deljenja nije, tako da u ovom slučaju nema ništa od optimizacije.

Izgleda da nisam bio u pravu kad sam tvrdio da ako na izlazu funcija pozove samu sebe da nema opasnosti od pretrpavanja steka :)

@Goran Za O3 optimizaciju znam da često možemo imati više štete nego koristi ukoliko neznamo šta radimo. Inline funkcije koje ta optimizacija pravi često mogu da naprave glomazne objekte koji uveliko premašuju instrukcijski keš. Interesuje me zašto smatraš da je O2 optimizacija loša stvar. Voleo bi da mi daš neki konkretan primer. Ovaj primer koji si naveo mi baš i nije jasan.Koliko vidim u praksi ćemo čak i sa 64-bitnim intidžerom i sa optimizacijom i bez nje dobiti pogrešan rezultat već sa 26. Ukoliko pretpostavimo da imamo neku imaginarnu mašinu sa neograničenim intidžerom u tom slučaju će program bez optimizacije zaista pući kod velikog unosa. Program sa optimizacijom neće pući već će bez obzira na veličinu unosa dati tačan rezultat. Ukoliko čak i dođe do situacije koju si naveo imaćemo dva potpuno neupotrebljiva programa (koje su napravili loši programeri).
[ Goran Arandjelovic @ 31.10.2012. 13:02 ] @
@chaami
Ma primer koji sam naveo je samo veštački i ne baš realan, zauzima malo prostora na steku u jednom pozivu f-je, tako da ni posle tih graničnih 26 (overflow granica) rekurzivnih poziva stek sigurno neće biti popunjen, ali samo kažem da postoji mogućnost da se stek popuni pre svođenja na bazni slučaj. Nisam rekao da je O2 optimizacija loša samo sam u trenutku zaboravio da li je inlajnovanje u okviru O2 ili O3. Nego, evo ga jedan primer, a vrlo brzo ćeš da pogodiš koja optimizacija može da prouzrokuje neočekivane rezultate.

Code (cpp):

struct A
{
    A() {}
    A(const A &a) { ++count; }

    static int count;
};

int A::count = 0;

A func1()
{
    A ret;
    // ...
    return(ret);
}

void func2(A arg)
{
    // ...
}

int main()
{
    A obj;
    func2(obj);
    func2(func1());

    cout << A::count;

    return(0);
}
 


U tom smislu sam govorio kako treba biti upoznat sa optimizacijama koje se uključuju, a ne da neko lupi bilo šta pa se posle češe po glavi.
[ kosta90s @ 31.10.2012. 17:20 ] @
Code (c):
main()
{
      int x;
while(1)
{    
      printf("Unesi broj (za izlaz unesi 0) :\n");
      scanf("%i",&x);
     if(x==0)
          break;
      if(x%2==0)
      printf("PARAN\n");
      else
      printf("NEPARAN\n");

}
     
}

Zasto koristis break kad ne moras? Licno smatram da break treba izbegavati.
Evo mog nacina
Code (c):

#include <stdio.h>

int main(void)
{
      int x=1;
      while(x!=0)
      {    
           printf("Unesi broj (za izlaz unesi 0) :\n");
           scanf("%d",&x);
           if(x%2!=0)
           {
                printf("NEPARAN\n");
           }
           else if(x!=0)
           {
                printf("PARAN\n");
           }
      }
      return(0);  
}


[Ovu poruku je menjao kosta90s dana 31.10.2012. u 18:38 GMT+1]
[ Boyka @ 31.10.2012. 17:38 ] @
Citat:
Nedeljko:
Boyka, ne valja ti program. Hajde, proveri ga i ispravi. Neće se izvšiti petlja više od jedanput.


Meni odlicno radi care...
[ Goran Arandjelovic @ 31.10.2012. 17:55 ] @
Tebi program "odlično" radi, ali hajde malo razmisli, da li bi bilo razlike da si umesto while-a stavio if?
[ Nedeljko @ 31.10.2012. 18:14 ] @
Niko da mi objasni kako radi ona funkcija za faktorijel bez nagomilavanja steka.

Boyka, tvoj program odlično radi, ali šta radi? Probaj da ga jednom pokreneš i da uneseš nekoliko brojeva.
Citat:
kosta90s: Zasto koristis break kad ne moras? Licno smatram da break treba izbegavati.

Zašto smatraš da ga treba izbegavati?
[ kosta90s @ 31.10.2012. 18:30 ] @
@Nedeljko
Citat:
Zašto smatraš da ga treba izbegavati?


Zato sto se upotrebom naredbe break narusava strukturiranost koda.

[Ovu poruku je menjao kosta90s dana 31.10.2012. u 21:31 GMT+1]
[ Boyka @ 31.10.2012. 18:31 ] @
Citat:
Goran Arandjelovic:
Tebi program "odlično" radi, ali hajde malo razmisli, da li bi bilo razlike da si umesto while-a stavio if?


Nepotrebni while definitivno :)

@Nedeljko
@Goran

Je'l mozete samo da skoknete do teme http://www.elitesecurity.org/t456741-0#3190852 moj poslednji post, zanima me gde to gresim u C-u, program odlicno radi u C# i zavrsio sam ga za 2-3 minuta, ali u C nemam pojma, jer sam treci dan u C jeziku, bas me zanima gde sam pogresio.
[ Nedeljko @ 31.10.2012. 21:50 ] @
Citat:
kosta90s: Zato sto se upotrebom naredbe break narusava strukturiranost koda.

goto naredba se ne koristi zato što se ne za kako je program došao do neke linije (što rezultira smanjenom čitljivošću koda), što sa break naredbom nije slučaj. Prvi put čujem da se break naredba izbegava.
[ Nedeljko @ 31.10.2012. 22:09 ] @
Boyka,

to što ti radiš je ispis niza u obrnutom redosledu, a ne obrtanje niza. Rezultat obrtanja niza je niz koji ima isti sadržaj, samo u obrnutom redosledu.

Recimo, ako si imao niz n dužine 3 sa članovima n[0]=2, n[1]=7 i n[2]=5, onda rezultat treba da bude niz k iste dužine, kod koga bi bilo k[0]=5, k[1]=7 i k[2]=2. Ti elementi ne moraju uopšte da se ispisuju, već da se formira taj novi niz ili da stari dobija takav sadržaj. Nakon toga, ako hoćeš možeš i da ih ispišeš.
[ kosta90s @ 01.11.2012. 06:22 ] @
Citat:
Nedeljko:
Citat:
kosta90s: Zato sto se upotrebom naredbe break narusava strukturiranost koda.

goto naredba se ne koristi zato što se ne za kako je program došao do neke linije (što rezultira smanjenom čitljivošću koda), što sa break naredbom nije slučaj. Prvi put čujem da se break naredba izbegava.



poincare.matf.bg.ac.rs/~filip/p1i/p1.pdf

106 strana

Citat:
Koriscenjem naredbe break se narusava strukturiranost koda, te moze da
ugrozi rezonovanje o njemu. Kod koji koristi naredbu break uvek se moze
napisati i bez nje, medutim koriscenje naredbe break moze da poboljsa citljivost.



62 strana u pdf (61 na strani)

http://www.singipedia.com/atta...chmentid=2640&d=1316604339

Citat:
Naredbe break i continue u programima treba koristiti samo kada su zaista neophodne, jer narušavaju strukturiranost programa.



Secam se i predavanja kad je profa pominjao da break treba izbegavati. Naravno, u switch naredbi je OK koristiiti break.

Naredba goto se izbegava zbog spageti koda, tj kao sto si rekao, smanjuje citljivost.


[Ovu poruku je menjao kosta90s dana 01.11.2012. u 07:37 GMT+1]

[Ovu poruku je menjao kosta90s dana 01.11.2012. u 07:44 GMT+1]
[ Boyka @ 01.11.2012. 08:41 ] @
Citat:
Nedeljko:
Boyka,

to što ti radiš je ispis niza u obrnutom redosledu, a ne obrtanje niza. Rezultat obrtanja niza je niz koji ima isti sadržaj, samo u obrnutom redosledu.

Recimo, ako si imao niz n dužine 3 sa članovima n[0]=2, n[1]=7 i n[2]=5, onda rezultat treba da bude niz k iste dužine, kod koga bi bilo k[0]=5, k[1]=7 i k[2]=2. Ti elementi ne moraju uopšte da se ispisuju, već da se formira taj novi niz ili da stari dobija takav sadržaj. Nakon toga, ako hoćeš možeš i da ih ispišeš.


aha nisam razumeo, pa to je jos lakse..
[ Nedeljko @ 01.11.2012. 09:10 ] @
kosta90s

Nemoj da se ljutiš, ali Univerzitet Singidunum nije nikakav autoritet nikome. Za goto naredbu postoji čuveni članak o tome zašto je opsana i odgovor Donalda Knuta na to situacijama gde goto povećava čitljivost koda. U tom članku je argumentovano zbog čega goto smanjuje čitljivost koda i to je razlog koji sam naveo. Taj razlog otpada kod break naredbe, a drugi razumni razlozi nisu navedeni.
[ kosta90s @ 01.11.2012. 10:00 ] @
Ne studiram ni na jednom od ova dva faxa(Singidunum, Matematicki ), tako da necu ulaziti u to kakav je kvalitet nastave na tim fakultetima (uostalom, drzava stoji iza svake diplome).Nemam razloga da se ljutim :) Student sam jedne Visoke skole u vlasnistvu drzave. Postoji problem kod koriscenja break-a jer npr ako imas dugacku petlju i koristis break, postoji mogucnost da jedan deo koda koji si zeleo da se izvrsi , ne izvrsi, jer si greskom stavio ispod break-a.
Pogotovo je to vidljivo ako se iz petlje izlazi na vise mesta.

Uostalom mozes da proguglas "why not to use break statement"

P.S. Nadam se da se ne ljutis. ;) Ti imas jedna, a ja druga saznanja, tehnike.

[Ovu poruku je menjao kosta90s dana 01.11.2012. u 11:33 GMT+1]
[ maksvel @ 01.11.2012. 10:21 ] @
Vrlo dobar odgovor, upravo sa prvog Google searcha:
Citat:
Dogmatic adherence to strict guidelines sometimes does preclude the most elegant solutions. "Rules of Thumb" are not "Laws" for a reason.
[ mmix @ 01.11.2012. 10:29 ] @
Citat:
maksvel: Vrlo dobar odgovor, upravo sa prvog Google searcha:


+1.
Suvise puta sam video ljude da se vise trude da zadovolje formu nego da funkcionalno rese problem.
[ Mihajlo Cvetanović @ 01.11.2012. 10:30 ] @
Malo mi je čudna ta logika, "X ne valja, jer ako se pogrešno koristi onda dolazi do neželjenih rezultata". Break instrukcija nije ljuta, senjor, godinama je koristim i ne smeta mi.
[ kosta90s @ 01.11.2012. 10:41 ] @
Zasto bi nekom smetao kod koji je pun goto naredbi, ako taj kod koji je napisan radi?
Zasto je zabranjeno da vozim 120 km na sat tamo gde je ogranicenje 60, ako znam da necu nikog ubiti?

Stos je u tome da se sanse za gresku smanje. Zato i postoje neka pravila...


[Ovu poruku je menjao kosta90s dana 01.11.2012. u 11:51 GMT+1]
[ Shadowed @ 01.11.2012. 10:48 ] @
Citat:
kosta90s: Postoji problem kod koriscenja break-a jer npr ako imas dugacku petlju i koristis break, postoji mogucnost da jedan deo koda koji si zeleo da se izvrsi , ne izvrsi, jer si greskom stavio ispod break-a.


Tim rezonom, nista nije dobro koristiti :)
[ Mihajlo Cvetanović @ 01.11.2012. 10:53 ] @
Problem nije kad kompajler čita kod, nego kad ga čita čovek. Drugi čovek mora da potroši nepotrebno mnogo vremena da se snađe u kodu. Čak i onaj ko je pisao kod posle dva meseca više ne može da ga čita tako lako, kao što ga je čitao onda kad je napisan. Proživeo sam to, i verovatno svaki programer to mora da proživi da bi shvatio poentu. U ozbiljnom projektima isplati se da potrošiš malo više vremena prilikom pisanja koda tako da učiniš kod čitljivijim, i lakšim za izmene. Izmene su neumitne. Ovo je bila opšta priča koja nema veze sa break instrukcijom.

Špageti kodovi pravljeni sa goto skokovima su stvar prošlosti, Fortrana i Cobola, i vremena "tvrdih muškaraca". Niko više tako ne programira. Povremeni goto tu i tamo neće pokvariti kod, a može čak i da doprinese čitljivosti. E sad, break instrukcija je još korisnija od goto instrukcije, i lakša za praćenje, i break, bar po meni, ne treba izbegavati.
[ Ivan Dimkovic @ 01.11.2012. 10:53 ] @
Smetace mu ako bude morao da radi na njemu, zato sto je kod pun goto naredbi manje citljiv.

A gde je kod manje citljiv, to povecava sanse da osoba koja bude radila na njemu u buducnosti nece razumeti sta se zaista desava.

To povlaci neke druge posledice, koje opet ne zelis u svom softverskom proizvodu. Nece se nista desiti ako koristis goto komande odjednom, na kraju krajeva - u C/C++ mozes da pises kod tako da ga niko drugi osim tebe nece razumeti, pa ni to nije "zabranjeno" :-) Samo nije dobra praksa.

Problem sa break naredbom je sasvim drugaciji - zapravo, nije problem sa break naredbom uopste vec sa potencijalnim korisnicima iste koji ne razumeju potpuno sve implikacije break/continue komandi na kod u kome ce se potencijalno nalaziti. Ali to se da resiti nekim dobrim kursom programiranja.
[ Boyka @ 01.11.2012. 11:22 ] @
Citat:
kosta90s:
Ne studiram ni na jednom od ova dva faxa(Singidunum, Matematicki ), tako da necu ulaziti u to kakav je kvalitet nastave na tim fakultetima (uostalom, drzava stoji iza svake diplome).Nemam razloga da se ljutim :) Student sam jedne Visoke skole u vlasnistvu drzave. Postoji problem kod koriscenja break-a jer npr ako imas dugacku petlju i koristis break, postoji mogucnost da jedan deo koda koji si zeleo da se izvrsi , ne izvrsi, jer si greskom stavio ispod break-a.
Pogotovo je to vidljivo ako se iz petlje izlazi na vise mesta.

Uostalom mozes da proguglas "why not to use break statement"

P.S. Nadam se da se ne ljutis. ;) Ti imas jedna, a ja druga saznanja, tehnike.

[Ovu poruku je menjao kosta90s dana 01.11.2012. u 11:33 GMT+1]


Visoka Poslovna? pitam, mozda si mi kolega lol
[ kosta90s @ 01.11.2012. 14:09 ] @
Citat:
Visoka Poslovna? pitam, mozda si mi kolega lol

Nije u pitanju Visoka Poslovna. ;)
[ plague @ 01.11.2012. 16:10 ] @
@kosta90s, break nije nikakav bauk i treba ga koristiti. Evo primera pisanog slobodnijom sintaksom cisto da svi mogu da razumeju o cemu pisem:
Code (csharp):

List<Control> AllControls = Page.GetAllControls().ToList();
WantedControl result = null;
foreach(Control currentControl in AllControls)
{
     if(currentControl is WantedControl)
     {
          result = currentControl;
          break;
     }
}
 


Ovde seces foreach petlju cim ti nadje kontrolu zeljenog tipa jer nema potrebe da se dalje vrsi pretraga ako ti treba samo prvi element koji ispunjava uslov.

Obrnuto, bez break, morao bi cak da se postaras da ne dodje do sledeceg dodeljivanja ako ti treba samo prvi rezultat. Pritom tako pisan kod bi po meni bio za nijansu necitljiviji.
[ Nedeljko @ 01.11.2012. 18:01 ] @
Citat:
kosta90s: Uostalom mozes da proguglas "why not to use break statement"


Evo, proguglao sam i našao ovo na stackoverflow-u (koga inače cenim):

http://stackoverflow.com/quest...ice-to-use-break-in-a-for-loop

Neko je pitao i svi su se složili da nema ničeg lošeg u korišćenju break naredbe.
[ kosta90s @ 01.11.2012. 20:17 ] @
Citat:
plague:
@kosta90s, break nije nikakav bauk i treba ga koristiti. Evo primera pisanog slobodnijom sintaksom cisto da svi mogu da razumeju o cemu pisem:
Code (csharp):

List<Control> AllControls = Page.GetAllControls().ToList();
WantedControl result = null;
foreach(Control currentControl in AllControls)
{
     if(currentControl is WantedControl)
     {
          result = currentControl;
          break;
     }
}
 


Ovde seces foreach petlju cim ti nadje kontrolu zeljenog tipa jer nema potrebe da se dalje vrsi pretraga ako ti treba samo prvi element koji ispunjava uslov.

Obrnuto, bez break, morao bi cak da se postaras da ne dodje do sledeceg dodeljivanja ako ti treba samo prvi rezultat. Pritom tako pisan kod bi po meni bio za nijansu necitljiviji.


Potpuno je meni jasna break naredba. Retko je upotrebljavam jer obicno nemam potrebe za njom.

Code (csharp):

List<Control> AllControls = Page.GetAllControls().ToList();
WantedControl result = null;
foreach(Control currentControl in AllControls)
{
     if(currentControl is WantedControl && result == null)
     {
          result = currentControl;
     }
}
 

Svestan sam da bi tvoj kod bio brzi jer ne bi morao da izlista sve kontrole.
Taj kod pretpostavljam (slabo poznajem c#) bi mogao drugacije da se napise, da se foreach zameni sa obicnom for ili while petljom,sto bi omogucilo izlazak iz petlje cim nadje element bez upotrebe break-a.

Mislim da smo skrenuli u dubok off.
Nek svako koristi ono sto njemu najvise odgovara i prija.

[Ovu poruku je menjao kosta90s dana 01.11.2012. u 21:29 GMT+1]
[ plague @ 01.11.2012. 20:47 ] @
Naravno da moze, ali to ubrzo postaje ruzno jer ti treba resenje i za slucaj da ne postoji trazena kontrola. Uslov je da izadje cim nadje kontrolu.
Znaci bez break bi nekako ovako isao while:
Code (csharp):

int index = 0;
while(result == null && index < AllControls.Count)
{
     if(AllControls[index] is WantedControl)
          result = currentControl;
     index++;

}
 

Za for:
Code (csharp):

for(int index = 0; result == null && index < AllControls.Count; index++)
     if(AllControls[index] is WantedControl)
          result = currentControl;
 


Ne zna se koji je lepsi. :]
[ peromalosutra @ 02.11.2012. 09:37 ] @
Malo off topica .. u php-u break prima parametar koji oznacava iz koliko konteksta treba da se iskoci. Korisno je ponekad, npr. za izlazak iz dvostruke petlje, ali generalno je uzas za pratiti. :)
[ llux @ 24.11.2012. 07:16 ] @
Tesko bez "continue".
Na primer kako biste vi prepravili sledeci kod a da ne poremeti ili izadje iz programa.
Ovo je parce koda mog prvog Iks Oksa:

Code (cpp):
void PocetakIgre() {

    while(igra)
{
PrikaziTablu();

cout<<"Gde zelite da postavite "<<znak<<'?'<<endl<<"(OD 1-9)\n";

 int brojPolja;
cin>>brojPolja;

   if(!cin)
    {
cin.clear();
 string garbage;
cin>>garbage;
 system("cls");
   cout<<"GRESKA! POKUSAJTE PONOVO\n";
continue;
 }

if(brojPolja<1||brojPolja>9)
 {
system("cls");
 cout<<"TO POLJE NE POSTOJI\n";
continue;
}

if(tabla[brojPolja]=='X' || tabla[brojPolja]=='O')
  {
system("cls");
 cout<<"TO POLJE JE ZAUZETO\n";
continue;
 }

   tabla[brojPolja]=znak;
++BrojacPoteza;
 system("cls");
ProveraPobede();

 if(znak=='X')znak='O';
  else znak='X';
 }

 }

Ako korisnik unese nesto pogresno ja jednostavno moram da ga vratim da ponovi.



[Ovu poruku je menjao llux dana 24.11.2012. u 08:37 GMT+1]

[Ovu poruku je menjao llux dana 24.11.2012. u 08:37 GMT+1]
[ Nedeljko @ 24.11.2012. 13:10 ] @
Sve si to umesto sa continue mogao da rešiš sa else. Međutim, continue naredba nije opasna.
Code (cpp):

while(igra) {
     PrikaziTablu();
     cout << "Gde zelite da postavite "<<znak<<'?'<<endl<<"(OD 1-9)" << endl;

     int brojPolja;
     
     cin >> brojPolja;

     if (!cin) {
          cin.clear();
          string garbage;
          cin >> garbage;
          system("cls");
          cout << "GRESKA! POKUSAJTE PONOVO\n";
     } else if (brojPolja < 1 || brojPolja > 9) {
          system("cls");
          cout << "TO POLJE NE POSTOJI\n";
     } else if (tabla[brojPolja] == 'X' || tabla[brojPolja] == 'O') {
          system("cls");
          cout << "TO POLJE JE ZAUZETO\n";
     } else {
          tabla[brojPolja]=znak;
          ++BrojacPoteza;
          system("cls");
          ProveraPobede();

          if (znak == 'X') {
               znak = 'O';
          } else {
               znak = 'X';
          }
     }
}
 

Meni se lično više sviđa tvoje rešenje sa continue.