Heips!
Ongelmana on tällä kertaa NULL-valuen käyttö...kyseinen esimerkkiohjelma toimii muilta osin, mutta se ei ymmärrä (valinta==NULL) kohtaa. ohjelman pitäisi siis tulostaa tuo "nimi puuttui,yritä uudelleen", jos käyttäjä ei syötä mitään muuta kuin komennon (ei valintaa).. keksittetkö korjausehdotuksia? esim. while-silmukalla tms...osoittimia ei saisi tässä kohtaa käyttää (harjoitus)... Kiitosta!
#include<iostream> #include<string> using namespace std; void main(void) { string marja, valinta, komento; cout<<"Anna komento ja marjan laatu\n"; cin>>komento; if (komento=="marja") { cin>>valinta; if (valinta==NULL) cout<<"Nimi puuttui, yrit\x84 uudelleen\n!"; else if (valinta=="mansikka") cout<<"onhan meillä mansikoita!"; else if (valinta=="mustikka") cout<<"onhan meillä mustikoita!"; else if (valinta=="vattu") cout<<"vadelmiakin on!"; else cout<<"ei sellaista marjaa ole!"; } else cout<<"Tuntematon komento, yrit\x84 uudelleen!";
NULL tarkoittaa C++:ssa samaa asiaa kuin 0, mutta sen kanssa vertaamisen sijasta ilmeisesti haluat katsoa onko valinta tyhjä string. Se onnistuu vaikkapa kirjoittamalla
if(valinta == "")
Et voi kuitenkaan >>-operaattorilla lukemalla saada tyhjää tekstiä, koska kyseinen operaattori odottaa aina, että käyttäjä syöttää yhden tai useampia merkkejä. Jos haluat lukea rivin, käytä funktiota std::getline. (Muista kuitenkin, että edellinen >>-lukeminen on lopettanut heti sanan loppuun, jolloin kyseisen rivin lopussa oleva enter on vielä lukematta.)
Toiston saa tosiaan tehtyä while-silmukalla (tai do-while-silmukalla). Ratkaisu on niin yksinkertainen, että varmaan keksit sen itsekin. Hyviä esimerkkejä silmukasta on luultavasti kurssisi materiaalissa sekä paikallisen C++-opassarjan 3. osassa.
Olet sisentänyt koodisi todella kummallisesti. Jatkon kannalta suosittelen jotain selkeämpää tapaa. Hyviä esimerkkejä on mm. yllä mainitsemassani oppaassa.
Kiitos vinkeistä! Eiköhän tämä tästä lähde sujumaan...
ps.sisennykset on tehty opettajan toivomusten mukaan, en sitten tiedä onko ne käytännöllisiä...
Firia kirjoitti:
ps.sisennykset on tehty opettajan toivomusten mukaan, en sitten tiedä onko ne käytännöllisiä...
Luultavasti olet ymmärtänyt opettajan toivomukset hieman väärin. Voisit näyttää aloitusviestin koodia hänelle ja kysyä onko sisennys sellainen kuin pitää.
Itse sisensin joskus if-lausekkeet juuri samalla tavalla ja opettaja ei tykännyt. Se ei tykännyt myöskään tabilla sisentämisestä vaan välilyönnillä.. hmm
En tajua miks pitäisi välilyöntejä käyttää sisentämiseen. Monissa tekstieditoreissa kun kuitenkin pystyy itse valitsemaan kuinka pitkänä (lue: montako välilyöntiä) tab-merkki näytetään. Lisäksi välilyönnin rämppääminen, että saadaan esim. 4 välilyönnin sisennys alkaa pitemmän päälle ottamaan päähän ja sisennyksen lyhentäminen vaatii saman verran painalluksia (noh joo sanotaan ny että monissa editoreissa pystyy kyllä tabulaattorinkin laittamaan välilyönteinä).
Ei ehkä oleellisin asia nykypäivänä enää, mutta myös se että tiedostokoko kasvaa vrt. 1 tavun tab vs. 4 tavua välilyöntejä :)
Omaperäinen sisennys mutta ei siinä mitään vikaa ole ;)
Jokotai kirjoitti:
Omaperäinen sisennys mutta ei siinä mitään vikaa ole ;)
Onpas. Muista kohdista voidaan vielä neuvotella, mutta on ehdottomasti epäloogista sisentää nuo if-lauseet siten, että else-lohko on aina entistä sisempänä. Koodista syntyy kuva, että if (valinta==NULL)
on ensimmäinen ehto, jonka toteutuessa jatketaan muihin tarkistuksiin, vaikka todellisuudessa asia on juuri päinvastoin.
Veikkaan, että tuo opettajan haluama sisennys menisi näin:
if (valinta == NULL) cout << "Nimi puuttui, yrit\x84 uudelleen\n!"; else if (valinta == "mansikka") cout << "onhan meillä mansikoita!"; else if (valinta == "mustikka") ...
Selkeyden vuoksi suosittelen lisäksi välien jättämistä operaattorien (kuten == ja <<) ympärille, kuten yllä tein. Itse en pidä tuosta aaltosulkujen asettelusta, mutta se nyt ei ole katastrofaalinen ongelma. Sen sijaan main-funktion tyyppi void sekä toinen void-sana main-funktion parametrilistan paikalla panee epäilemään opettajan pätevyyttä, kun kuitenkin kyseessä on C++ eikä C. Oikea main-funktio on jompikumpi näistä:
int main(); int main(int argc, char** argv); // char** argv <=> char* argv[]
Mikäli opettaja vaatii väkisin void-sanaa jommassakummassa kohdassa, käske lukea C++:n standardia. Ohjelman main-funktiosta sanotaan seuraavaa:
lainaus:
It [the
main
function] shall have a return type of type int, – – All implementations shall allow both of the following definitions of main:int main() { /* ... */ }and
int main(int argc, char* argv[]) { /* ... */ }
Parametrilistan void-sana taas on peräisin C:stä, jossa sillä oli todellistakin merkitystä. C++ sallii sen varmaankin lähinnä yhteensopivuussyistä, mutta muuta merkitystä sillä ei ole:
lainaus:
The parameter list (void) is equivalent to the empty parameter list.
Oikeastaan if-else if-else rakenteen sisennys on looginen. Jos ehto toteutuu suritetaan koodi ja hypätään seuraavien kohtien yli.
Ilman jossia ei ole muutoin jossia tai muutointa.
Jokotai kirjoitti:
Oikeastaan if-else if-else rakenteen sisennys on looginen.
Tiettyä logiikkaa tuossa on, mutta siltikin yhtenäisyys puuttuu, koska uloimmat if ja else ovat keskenään samalla tasolla, toisin kuin sisemmät vastaavat.
Joka tapauksessa tuo on erittäin epäsuositeltava sisennystapa, koska vakiintunut käytäntö on aivan toisenlainen.
Jokotai kirjoitti:
Oikeastaan if-else if-else rakenteen sisennys on looginen. Jos ehto toteutuu suritetaan koodi ja hypätään seuraavien kohtien yli.
Ilman jossia ei ole muutoin jossia tai muutointa.
Alkuperäisen viestin sisennys ei kyllä ole kovin looginen, puhumattakaan luettavuudesta.
Alla olevissa kahdessa eri vaihtoehdossa sisennykset ja aaltosulut ovat molemmissa loogisemmat, kuin alkuperäisessä viestissä.
if(valinta == NULL) { do_stuff(); } else if(valinta == "mansikka") { do_stuff(); } else { do_stuff(); }
tai
if(valinta == NULL) { do_stuff(); } else if(valinta == "mansikka") { do_stuff(); } else { do_stuff(); }
jalski kirjoitti:
Alla olevissa kahdessa eri vaihtoehdossa sisennykset ja aaltosulut ovat molemmissa loogisemmat, kuin alkuperäisessä viestissä.
Kyllä aloitusviestin aaltosuluissa on selkeä ja pitävä logiikka, joten on väärin väittää että jokin erilainen tapa olisi vain henkilökohtaisten mieltymysten vuoksi "loogisempi". Ei, en välttämättä käyttäisi kyseistä tyyliä ikinä, mutta en tosin sen enempää sinunkaan omiasi.
(Oikea tapahan olisi tietysti kuin tuo jälkimmäinen, sillä erotuksella, että else {
kirjoitetaan edeltävän lohkon päättävän aaltosulun perään – tai aaltosulut jätetään kokonaan pois. Myös, koska if
ei ole funktio, sitä ei kirjoiteta yhteen sulkeiden kanssa – ja if-else-rakennetta on turha kirjoittaa jos joka tapauksessa tehdään sama asia (do_stuff()) ;-))
Oikea on sanana hieman suhteellinen käsite. Se riippuu nimittäin täysin siitä, mitä konventiota käytetään. Tässäpä referenssiä: http://en.wikipedia.org/wiki/Coding_conventions tai http://en.wikibooks.org/wiki/C _Programming/Code_Style
Että ihan referenssiä... Kyllä, jälkimmäinen kappale oli täysin puolivakavissaan kirjoitettu, vaikka siitä nyt tulikin kuivakka ja tarkoitustaan ajatellen pitkähkökin.
no tästähän syntyi mielenkiintoinen keskustelu.. :)
täytyy tosiaan katsella noita sisennyksiä, parempi kait opetella vakiintunut hyvä tapa kuin se mitä opettaja kertoilee..
tuosta void keskustelusta vielä..käytämme sekä void main(void)-tapaa että int main() tapaa.Kukaan ei ole onnistunut selvittämään,miksi välillä käytetään toista ja välillä toista.. :/
Ja tässä vielä tämä sama yritelmä...ongelmana on nyt se, ettei kääntäjä salli muutosta tyypistä int tyypiksi char..missä kohtaa nyt mennään metsään..???
#include<iostream> #include<string> using namespace std; int main() { string marja, valinta, komento; cout<<"Anna komento ja marjan laatu\n"; cin>>komento; if (komento=="marja") { cin.ignore(1); cin.get(valinta); if (valinta == "") cout<<"Nimi puuttui, yrit\x84 uudelleen\n!"; else if (valinta=="mansikka") cout<<"onhan meillä mansikoita!"; else if (valinta=="mustikka") cout<<"onhan meillä mustikoita!"; else if (valinta=="vattu") cout<<"vadelmiakin on!"; else cout<<"ei sellaista marjaa ole!"; } else cout<<"Tuntematon komento, yrit\x84 uudelleen!"; }
Myös jälkimmäinen teksti kuuluu lukea näin
cin >> valinta; // yksi sana
tai näin
getline( cin, valinta ); // monta sanaa
"Nimi puuttuu" -vaihtoehto kannattaa unohtaa kokonaan, koska yllä olevat tavat lukea tekstiä sulkevat tämän automaattisesti pois. void main(void)
on jotain takavuosien epämääräistä epästandardia C++:ssaa, jota ei kuulu käyttää. Sen sijaan main-funktion loppuun kuuluu laittaa return-lauseke.
os kirjoitti:
"Nimi puuttuu" -vaihtoehto kannattaa unohtaa kokonaan, koska yllä olevat tavat lukea tekstiä sulkevat tämän automaattisesti pois.
Ei suinkaan. Jälkimmäinen tapa (getline-funktio) lukee vain yhden rivin, joka voi olla myös tyhjä.
Jos näitä kahta tapaa käyttää sekaisin, pitää olla tarkkana, koska >>-lukemisen jälkeen getline-funktio palauttaa tyypillisesti tyhjän rivin. Tämä johtuu siitä, että >>-operaattori ei lue riviä loppuun asti vaan pysähtyy lukemansa sanan loppuun, jolloin rivin loppua merkitsevä tieto jää vielä odottamaan.
os kirjoitti:
Sen sijaan main-funktion loppuun kuuluu laittaa return-lauseke.
C++ sisältää kummallisen poikkeuksen, että main-funktion lopussa return-lausetta ei tarvita, vaan tämä funktio palauttaa automaattisesti nollan. Kannattaa ehkä kuitenkin totutella return-lauseeseen, jottei se sitten unohdu toisista funktioista.
joo,ongelma onkin juuri siinä, että tuon getline-funktion kanssa en saa ohjelmaa toimimaan...(lukee ilmeisesti char-muotoon tai jotain) ja sitten tulee yhteensopivuusongelmia. >>-operaattoria käyttäen sain ohjelman toimimaan lukuunottamatta NULL-kohtaa.cin kun odottaa aina jotakin syötettä eikä hyväksy pelkkää tyhjää. kokeilin myös ottaa tiedon talteen taulukkoon (marja[15]), mutta siinä ongelmana oli taas taulukon sisällön vertailu merkkijonoon (esim."mustikka").
Tehtävän yksi ideoista oli käsitellä tapausta jossa syöte on tyhjä (mutta komento ok). Ilman sitähän tämä ohjelma toimii ihan ok.
Katso, että käytät sopivaa versiota getline
-komennosta. string
-olioita luetaan funktiolla getline
, jota käytetään näyttämälläni tavalla. cin::getline
-metodi, jota ilmeisesti olet käyttänyt, on eri asia ja soveltuu tähän huonommin.
EDIT: Metabolix on kuitenkin oikeassa getline
-funktion käytön suhteen. Sen paluuarvo voi olla myös tyhjä merkkijono ja "edeltävien" whitespace-merkkien kanssa pitää olla tarkkana. Neuvoin tämän siis väärin.
ok kiitos, kokeillaan
hetkonen.. ja toimii! kiitos!
Aihe on jo aika vanha, joten et voi enää vastata siihen.