Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++ ja NULL

Sivun loppuun

Firia [24.03.2010 13:14:21]

#

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!";

Megant [24.03.2010 13:30:01]

#

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 == "")

Metabolix [24.03.2010 13:32:42]

#

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.

Firia [25.03.2010 07:33:13]

#

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ä...

Chiman [25.03.2010 12:16:41]

#

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ää.

JussiR [25.03.2010 12:22:28]

#

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

temu92 [25.03.2010 13:10:45]

#

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ä :)

Jokotai [25.03.2010 14:52:41]

#

Omaperäinen sisennys mutta ei siinä mitään vikaa ole ;)

Metabolix [25.03.2010 15:05:24]

#

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.

Jokotai [26.03.2010 15:16:31]

#

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.

Chiman [26.03.2010 15:27:32]

#

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.

jalski [26.03.2010 15:40:47]

#

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();
}

eq [26.03.2010 22:28:44]

#

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()) ;-))

Mazzimo [26.03.2010 23:34:56]

#

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

eq [27.03.2010 00:21:58]

#

Että ihan referenssiä... Kyllä, jälkimmäinen kappale oli täysin puolivakavissaan kirjoitettu, vaikka siitä nyt tulikin kuivakka ja tarkoitustaan ajatellen pitkähkökin.

Firia [05.04.2010 14:06:07]

#

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!";
	}

os [05.04.2010 17:23:10]

#

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.

Metabolix [05.04.2010 17:51:27]

#

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.

Firia [05.04.2010 18:09:02]

#

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.

os [05.04.2010 18:15:34]

#

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.

Firia [05.04.2010 18:17:27]

#

ok kiitos, kokeillaan

hetkonen.. ja toimii! kiitos!


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta