Miten seuraavan koodin voi korvata for -lauseella?
int arvauksia =0; boolean löytyi=false; do { arvauksia++; System.out.println("Arvauksesi: "); int arvaus= lukija.nextInt(); löytyi = binHae(luvut, arvaus); if (!löytyi) System.out.println("Väärin. Uusiks:"); } while (!löytyi);
binHae on binäärihaku, kun taas luvut on taulukko numeroita.
For -lauseen keskimmäinen osa hämää minua. En tiedä, mitä laittaisin rajaksi (X) tuohon kohtaan. Esimerkiksi:
for(arvauksia=0; arvauksia < X; arvauksia++)
Javassa for -silmukan keskellä oleva ehto saa olla myös tyhjä, jolloin silmukka menee läpi aina ja ikuisesti, jollei sitä keskeytä silmukan sisällä.
Toki voihan tuohon laittaa ehdoksi saman mikä sinulla on while -silmukassa.
Valmista koodia en tähän kirjoita.
Ei kannata yrittää minusta vääntää for rakennetta, koska do-while toimii ihan hyvin tuossa. Mistä muuten ajatus for-rakenteen käyttöön? Jotenkin voisi ajatella, että haluat rajoittaa arvausmäärään johonkin tiettyyn määrään, mutta senkin voit helposti toteuttaa nykyisessä versiossa laittamalla vertailun
while(arvauksia <= maksimi);
Vai onko sinusta nykyisessä rakenteessa jotakin aivan kamalan hankalaa tehdä?
Tämä olisi mielestäni lähinnä alkuperäistä do-silmukkaa:
for (arvauksia = 0; !löytyi; arvauksia++)
Siis for-silmukan keskimmäisen lausekkeen ei tarvitse olla muotoa a < b.
Mutta edelleen onko mielekästä lähteä muuttamaan ihan hyvää ja rakenteellisesti oikeaa kontrollirakennetta toiseksi ilman perusteluja? for on kuitenkin tarkoitettu minusta selkeästi rajatulle joukolle tapahtumia, kun taas while suoritetaan kunnes ehto ei ole tosi ja do-while muutoin samoin, mutta ainakin kerran.
Veikkaan, että kyseessä on koulutehtävä, ja siksi muutos.
Nykyinen rakenne on näppärä. For -lauseke on minusta hieno, minkä takia halusin sitä käyttää.
Kiitos vastauksista!
Stroustrup kirjoitti muistaakseni kirjassaan "C++ -ohjelmointi", että do-while -silmukka on potentiaalinen virheiden lähde, sillä silmukka suoritetaan ainakin kerran. Mutta huolellisella ohjelmoinnilla ei kyseisessä silmukassa pitäisi olla mitään vikaa. Itse en ole do-whileä käyttänyt omissa ohjelmissani kertaakaan lukuun ottamatta yliopiston ohjelmointikurssin laskaritehtäviä, joissa sitä oli pakko käyttää. Suunnittelen silmukat aina toisin.
Eikös melkein jokainen toistorakenne voi jäädä ikuiseen silmukkaan, jos toistoehto suunniteltu väärin, vai ymmärsinkö pointtisi väärin? Millä tavalla do-while on virhealtiimpi? Minusta tässä tapauksessa do-while on perusteltu toistorakenne, ja ilmeisen hyvin toteutettukin, vaikka toisaalta turha arvauksia laskuri onkin silmukassa.
Jokainen toistorakenne voi jäädä ikuiseen silmukkaan. Luin vaan kirjasta suosituksen ja aloin noudattamaan sitä sen kummemmin miettimättä asiaa enempää. Kukin koodatkoon omalla tyylillään.
Teuro kirjoitti:
Eikös melkein jokainen toistorakenne voi jäädä ikuiseen silmukkaan, jos toistoehto suunniteltu väärin, vai ymmärsinkö pointtisi väärin?
Nähdäkseni Jaskan pointti oli, että do-while suoritetaan aina vähintään kerran. Jos siis on mahdollista, että sitä ei pitäisi suorittaa kertaakaan (esim. joukon läpikäynti jos joukko voi olla tyhjä), niin joudutaan sisällyttämään do-while if:n sisään. Toisaalta silloin on järkevämpää käyttää toistorakennetta, jossa tarkistus tehdään ennen suoritusta ja joka voidaan täten suorittaa myös 0 kertaa. Eli esim. while (ehto) { koodi }
Heräsi muutama kysymys tuosta Antin koodista.
1. Voiko for-silmukan keskiosassa käyttää eri muuttujaa kuin ekassa tai kolmannessa osassa myös muille tyypeille kuin boolean?
2. Voiko seuraavaa koodia for-silmukan keskiosassa:
!muuttuja
kirjoittaa yhtälö- tai epäyhtälömuotoon. Tuo muoto hämää minua.
Mutta eikös silloin ole käytetty juurikin väärää ohjausrakennetta, jos on mahdollista, että tutkittava tietorakenne onkin tyhjä. Tällöin for / while puolustaa paikkaansa.
Ymmärsin toki pointin nyt. Turha tästä kai enempää on jauhaa, koska asia selvisi ilmeisesti myös aloittajalle.
hevonen kirjoitti:
1. Voiko for-silmukan keskiosassa käyttää eri muuttujaa kuin ekassa tai kolmannessa osassa myös muille tyypeille kuin boolean?
Totta kai voi. Ainoa mikä for-loopissa keskiosassa on olennaista on, että sen saa tulkittua totuusarvoksi (todeksi tai epätodeksi). Se, mitä koodia siinä yhteydessä mahdollisesti suoritetaan ei ole olennaista.
for(a;b;c) { d; }
voitasiin kirjoittaa yhtä hyvin (joskin a:n näkyvyydessä taitaa olla ero)
a; while(b) { d; c; }
hevonen kirjoitti:
Tuo muoto hämää minua.
Millä tavalla?
Teuro kirjoitti:
Mutta eikös silloin ole käytetty juurikin väärää ohjausrakennetta, jos on mahdollista, että tutkittava tietorakenne onkin tyhjä.
Kyllä. Olettaisinkin että ideana on että do while -rakennetta ei tulisi käyttää oletusarvoisesti vaan ainoastaan kun on tarkkaan harkittu että se on parempi kuin while.
Grez kirjoitti:
Ainoa mikä kääntäjää kiinnostaa on, että se saa tulkittua sen todeksi tai epätodeksi.
Tämä selvensi asiaa.
Eli
!muuttuja
tarkoittaa vain, että suoritetaan for ehtoa niin kauan, kunnes se on tosi.
Kiitos!
hevonen kirjoitti:
Heräsi muutama kysymys tuosta Antin koodista.
1. Voiko for-silmukan keskiosassa käyttää eri muuttujaa kuin ekassa tai kolmannessa osassa myös muille tyypeille kuin boolean?
2. Voiko seuraavaa koodia for-silmukan keskiosassa:
!muuttujakirjoittaa yhtälö- tai epäyhtälömuotoon. Tuo muoto hämää minua.
1. Ensimmäinen osa for-silmukasta on varattu muuttujien alustusta varten ja se suoritetaan aina tasan yhden kerran. Toinen osa on ehtolause (eli mitä tahansa, minkä paluuarvo on true tai false) ja silmukan sisältö suoritetaan, jos tämä on tosi. Kolmas osa suoritetaan aina jokaisen kierroksen lopussa, jonka jälkeen tarkistetaan taas onko toistoehto vielä voimassa.
2. muuttuja == false tai muuttuja != true ajaisivat saman asian. Yleensä on kuitenkin selkeää käyttää !muuttuja.
Tuossa grezin esimerkissä myös näkyvyysalue saadaan samaksi lisäämällä yhdet aaltosulut näin (on täysin sallittua luoda aaltosuluin eroteltuja koodilohkoja, vaikkei aaltosulun edessä olisikaan mitään avainsanaa):
{ a; while(b) { d; c; } }
grez kirjoitti:
Kyllä. Olettaisinkin että ideana on että do while -rakennetta ei tulisi käyttää oletusarvoisesti vaan ainoastaan kun on tarkkaan harkittu että se on parempi kuin while.
whilen ja do-whilen välillä on yksi selvä ero: do-whilen sisällä oleva koodi suoritetaan aina vähintään yhden kerran, koska ehto tarkistetaan aina lohkon lopuksi, toisin kuin whilessä, missä se tarkistetaan heti ensimmäisenä.
Esimerkiksi seuraavissa hieman tekaistuissa esimerkeissä ero tulee toivottavasti esille.
int luku = arvoToinenLuvuista(-1, 1); do { System.out.println("anna luku"); luku = lueLuku(); } while (luku >= 0);
ja
int luku = arvoToinenLuvuista(-1, 1); while (luku >= 0) { System.out.println("anna luku"); luku = lueLuku(); };
tekevät täsmälleen saman, jos muuttuja luku sattuu saamaan alussa arvon 1. Jos se taas sattuu saamaan arvoksi -1, niin ensimmäinen kyselee silti lukuja kunnes saa nollaa pienemmän, jälkimmäinen taas ei kysy käyttäjältä lukua lainkaan, koska ehto oli alunperinkin epätosi.
Kiitos Sami!
Sain lopulta koodin tehtyä - teidän ansiosta. Vastaus siis on:
boolean löytyi=false; for(int arvauksia=0; !löytyi; arvauksia++) { System.out.println("Arvauksesi: "); int arvaus= lukija.nextInt(); löytyi = binHae(luvut, arvaus); if (löytyi==false) System.out.println("Väärin. Uusiksi."); else { arvauksia++; System.out.println("Oikein! Tarvitsit yhteensä "+arvauksia+" arvausta."); } } }
Sami kirjoitti:
whilen ja do-whilen välillä on yksi selvä ero: do-whilen sisällä oleva koodi suoritetaan aina vähintään yhden kerran
Niin, en pysty oikein tulkitsemaan tuota Jaskan kommenttia muuten, kuin että tuo on potentiaalinen virheiden lähde, jos koodari ei huomioi tuota tosiasiaa. Vai voiko Jaskan kommentin mielestäsi tulkita muulla tavalla?
Kyseessä ei siis ollut oma mielipiteeni. Oma mielpiteeni on, että virhelähde on näppimistön ja tuolin välissä.
Hevonen kirjoitti:
Vastaus siis on:
Miksi arvausten määrää kasvatetaan kahdella per looppi?
Grez: kyllä se arvausten määrä kasvaa vain yhdellä - kokeilin. :) Lopussa vain else loopissa on tuo +1 arvausten määrään, koska lähtöarvo oli 0.
Hupsista, mun moka. Katsoin vaan nopeasti että siellä oli arvauksia++ kaksi kertaa. Eikö lähtöarvoksi olisi ollut järkevämpää pistää 1?
Omaan silmään seuraava näyttäisi selkäemmältä:
int arvauksia=1; System.out.println("Arvauksesi: "); while (!binHae(luvut, lukija.nextInt())) { System.out.println("Väärin. Uusi arvauksesi: "); arvauksia++; } System.out.println("Oikein! Tarvitsit yhteensä "+arvauksia+" arvausta.");
Tuon ei ole tarkoitus olla mikään mallisuoritus, varmaan monien mielestä tuo on sekavampi. Pistimpähän nyt kuitenkin.
Grez kirjoitti:
Niin, en pysty oikein tulkitsemaan tuota Jaskan kommenttia muuten, kuin että tuo on potentiaalinen virheiden lähde, jos koodari ei huomioi tuota tosiasiaa. Vai voiko Jaskan kommentin mielestäsi tulkita muulla tavalla?
Tätä tarkoitin.
Stroustrup kirjoitti:
Minun kokemukseni mukaan do-lause on virheiden ja sekaannusten lähde. Tämä johtuu siitä, että sen runko suoritetaan kerran ennen ehdon testaamista. Jotta runko toimisi oikein, ehdon on oltava hyvin lähellä toteutumista jo silmukan ensimmäisellä kierroksella. Olen yllättävän usein havainnut, että ehto ei ole ollut voimassa joko ohjelmaa kirjoittaessa ja testatessa tai myöhemmin, kun edeltäviä lauseita on muutettu. Minusta ehdon pitäisi olla alussa, jotta sen näkee heti, ja siksi yritän välttää do-lauseita.
Näin siis Bjarne Stroustrup kirjassaan C++ -ohjelmointi.
Aihe on jo aika vanha, joten et voi enää vastata siihen.