Pitäis tuommoinen tehdä. Mistä johtuu että 1.kohta ei toimi allaolevassa koodissa?
#include <iostream.h> #include <conio.h> void kysy_nimi(char &numero) { void clrscr(); cout << "Anna uuden asiakkaan nimi: "; cin >> numero; return; } void kysy_nro(long int &numero) { void clrscr(); cout << "Anna uusi asiakastunnus: "; cin >> numero; return; } void tulosta_nro(const long int &numero) { void clrscr(); cout << "Numero: " << numero; getch(); return; } void muuta_nro(long int &numero) { void clrscr(); cout << "Anna uusi numero: "; cin >> numero; return; } void poista_nro(long int &numero) { void clrscr(); numero = 0; return; } int main () { int valinta = 0; long int numero = 0; while ( valinta != 6) { void clrscr(); cout << "Tilaustenkäsittelyjärjestelmä" << endl << endl; cout << "1. Anna uuden asiakkaan nimi" << endl; cout << "2. Anna asiakastunnus" << endl; cout << "3. Tulosta asiakastunnus" << endl; cout << "4. Muokkaa tunnusta" << endl; cout << "5. Poista " << endl; cout << "6. Lopeta" << endl << endl; cout << "Valintasi: "; cin >> valinta; if (valinta == 2) kysy_nro(numero); if (valinta == 3) tulosta_nro(numero); if (valinta == 4) muuta_nro(numero); if (valinta == 5) poista_nro(numero); } return 0; }
Mod.edit: lisätty kooditagit, käyttöä suositellaan, jotta koodista saa selvää.
Mod. edit: koodi muokattu mukavammin luettavaan kuosiin ja sisennetty loogisesti. Kannattaa itsekin opetella kirjoittamaan koodia siististi, niin on muiden mukavampi auttaa.
Onpas hassua koodia...
- mikä "void clrscr();"? Mit tuo void tekee tuossa? (lisäksi conio.h ei ole ihan standardia, vältä sen käyttöä)
- häh, eihän sulla edes ole riviä "if (valinta == 1) ..."
-
lainaus:
cout << "Anna uuden asiakkaan nimi: "; cin >> numero;
Mitä häh, eihän nimi ole numero.
Opettelepa ensiksi kutsumaan funktioita oikein. void clrscr();
on ruma, jätä void pois. Se ei myöskään ole standardia (conio.h ei ole), yritä olla käyttämättä sitä.
Niinikään myös iostream.h on vanhentunut, pitää olla iostream sellaisenaan ja std-nimiavaruus:
#include <iostream> // Joko aina näin std::cout << "Moi!" << std::endl; // Tai ohjelman alkuun tällainen using namespace std;
Varmaankin auttaisi, jos laittaisit vastaavan if-lauseen main-funktioon. Myöskin suosittelen vaikkapa std::string-tyyppiä tai edes char-taulukkoa yhden merkin (char) sijaan.
Ilman tuota conio juttua tämä ei toimi... Siistin vähän koodia eikä se vieläkään toimi.
#include <iostream.h> #include <conio.h> void kysy_nimi(char &nimi) { cout << "Anna uuden asiakkaan nimi: "; cin >> nimi; return; } void kysy_nro(long int &numero) { cout << "Anna uusi asiakastunnus: "; cin >> numero; return; } void tulosta_nro(const long int &numero) { cout << "Numero: " << numero; getch(); return; } void muuta_nro(long int &numero) { cout << "Anna uusi numero: "; cin >> numero; return; } void poista_nro(long int &numero) { numero = 0; return; } int main () { int valinta = 0; long int numero = 0; char nimi = 0; while ( valinta != 6) { cout << "Tilaustenkäsittelyjärjestelmä" << endl << endl; cout << "1. Anna uuden asiakkaan nimi" << endl; cout << "2. Anna asiakastunnus" << endl; cout << "3. Tulosta asiakastunnus" << endl; cout << "4. Muokkaa tunnusta" << endl; cout << "5. Poista " << endl; cout << "6. Lopeta" << endl << endl; cout << "Valintasi: "; cin >> valinta; if (valinta == 1) kysy_nimi(nimi); if (valinta == 2) kysy_nro(numero); if (valinta == 3) tulosta_nro(numero); if (valinta == 4) muuta_nro(numero); if (valinta == 5) poista_nro(numero); } return 0; }
Mod. edit: lisätty taas kooditagit! Menepä jo vähitellen lukemaan keskustelun ohjeita. Lisäksi koodia siistitty, jotta sitä helpommin lukee.
Suosittelen, että luet jo äsken annetut ohjeet. Nimi ei mahdu yhteen char-muuttujaan, niitä pitää olla taulukollinen. Paras vaihtoehto on, kuten jo aiemmin sanoin, std::string. Kannattaa korjata tuo iostream-otsikon käyttötapa, kuten aiemmin neuvoin. Poistamalla getch-funktion pääsee eroon conio.h:sta, tilalle kelpaa vaikkapa getchar, vaikka eipä tuolla sellaistakaan pitäisi tarvita.
Aina kannattaisi myös kertoa, millä tavalla koodi ei toimi. "Ei toimi" ei oikein kerro mitään, ja kun ei tiedä, millaista virhettä pitäisi etsiä, ei välttämättä oikein kiinnosta sitä etsiä.
#include <iostream.h> void kysy_nimi(std::string &nimi) { cout << "Anna uuden asiakkaan nimi: "; cin >> nimi; return; } void kysy_nro(long int &numero) { cout << "Anna uusi asiakastunnus: "; cin >> numero; return; } void tulosta_nro(const long int &numero) { cout << "Numero: " << numero; return; } void muuta_nro(long int &numero) { cout << "Anna uusi numero: "; cin >> numero; return; } void poista_nro(long int &numero) { numero = 0; return; } int main () { int valinta = 0; long int numero = 0; char nimi = 0; while ( valinta != 6) { std::cout << "Tilaustenkäsittelyjärjestelmä" << std::endl; std::cout << "1. Anna uuden asiakkaan nimi" << std::endl; std::cout << "2. Anna asiakastunnus" << std::endl; std::cout << "3. Tulosta asiakastunnus" << std::endl; std::cout << "4. Muokkaa tunnusta" << std::endl; std::cout << "5. Poista " << std::endl; std::cout << "6. Lopeta" << std::endl; std::cout << "Valintasi: "; cin >> valinta; if (valinta == 1) kysy_nimi(nimi); if (valinta == 2) kysy_nro(numero); if (valinta == 3) tulosta_nro(numero); if (valinta == 4) muuta_nro(numero); if (valinta == 5) poista_nro(numero); } return 0; }
Eli tällä tavalla vai? Nyt visual c++ antaa 20 virhettä...
#include <iostream> #include <string> //... void kysy_nimi(std::string &nimi) getline(cin >> ws, nimi); // Ei pakko, mutta ehkä parempi idea kuin cin >> nimi //... int main() std::string nimi; // char nimen tilalle
Lisäksi vielä void-funktiot eivät tarvitse returnia loppuun.
En kyllä ymmärrä mihin kohtaan nuo tulevat?
Jaa, 20 virhettä: enpä viitsi ryhtyä arvuuttelemaan, kun täällä ei näy yhtäkään. :-)
Nuo Metabolixin
paikkaukset tulevat ihan niihin kohtiin, joissa koodissasi mainitaan nimi
-muuttuja tai -viittaus.
Sellainen lisävinkki vielä, että syötteen lukemisen onnistuminen kannattaa aina tarkistaa. Pääohjelmasi jää pahaan kuolemankieppiin, jos sille numeron sijasta tarjoaakin jonkin kirjaimen. Yksinkertaisimmillaan asia korjautuu näin:
std::cin >> valinta; if (std::cin.fail()) break;
Virhelippu ei nollaudu itsestään, eli joskus voi olla hyödyllistä kirjoittaa että std::cin.clear();
.
Yleensä tuollaisten (pääohjelman) if
-hässäköiden sijasta pannaan switch
.
Muuten, kyllähän tuo kysy_nimi
-funktio toimi alkuperäisessä versiossakin - nimi sitten vain oli vain yhden merkin mittainen. :-)
Olikos noilla void clrscr()
-riveillä jonkinlainen vaikutus alkuperäisessä versiossa? Ne nimittäin eivät ole funktion kutsuja vaan funktion (turhia) esittelyitä.
koo, liki 20 virhettä saa jo siitä, että ei ole std kunnossa. Se valittaa jokaisesta std::-kohdasta, kun ei ole oikeaa otsikkoa.
pele1977, niissähän lukee, mihin ne tulevat.
Eipä tainnut olla void cl... jutulla merkitystä...
Mod. edit: taas sama pätkä. :/
Virheitä edelleen 20. Äh hajoo kohta pää ku olen niin tyhmä ohjelmoinnissa! Eli missä vielä vika?
Virheilmoituksista: Näin on, mutta pointti on siinä, että avustamisen kannalta esimerkiksi ensimmäisen (ja toisen) sisältö on se avainjuttu, ei kokonaismäärä. :-)
C:\Olio ohjelmointi\Projekti\VALIKKO.CPP(6) : error C2065: 'nimi' : undeclared identifier
C:\Olio ohjelmointi\Projekti\VALIKKO.CPP(6) : error C2501: 'getline' : missing storage-class or type specifiers
Siinä pari ekaa erroria. Metabolix: mitä tarkoitat otsikoilla?
Eikö nuo muuttujat tulisi määritellä mainin ulkopuolella, jos niitä haluaa käyttää muissakin funktioissa?
Mod. edit: taas melkein sama pätkä. :/
Tältä se nyt näyttää ja tosiaan 20 virhettä vielä.
Pele, rauhoitus nyt hetkeksi äläkä pastea jatkuvasti tuota samaa koodia, niin käydään rauhassa läpi tuo kaikki.
Ensinnäkin, pois se iostream.h ja sen tilalle pelkkä iostream, kuten tuossa jo edellä neuvottiin.
Toiseksi, mikä tuo getline on heti niiden jälkeen? Se pitää olla jonkin funktion sisällä.
Kolmanneksi, seuraavalta funktiolta puuttuu nimi ja muutkin määrittelyt. Vähän aikaa sitten ne vielä olivat sinulla siinä.
En tunne C++:aa kovin tarkasti, joten joku muu saa kertoa, miten nimiavaruuksien ym. kanssa pitää toimia, mutta korjaa nyt nuo ensin.
Ota koodin alusta #include <iostream.h>
pois. Laita alkuun:
#include <iostream> #include <string> using namespace std;
Nyt sinun ei tarvistse kirjoittaa joka cin
in, cout
in, string
in ja endl
:n eteen std::
.
P.S. Joku voisi selvittää minullekin, mitä niin pahaa tuossa using namespace
ssa on, että kaikkien luokkien ja olioiden eteen pitää nimiavaruusmäärittely kirjoittaa erikseen. Näyttääkö se vain komeammalta?
Määkin kuulisin mielelläni argumentteja using namespacesta (puolesta ja vastaan), linkit kelpaa oikein hyvin. En nyt näin äkkiseltään löytäny Googlella mitään kivaa.
Blaze kirjoitti:
Määkin kuulisin mielelläni argumentteja using namespacesta (puolesta ja vastaan), linkit kelpaa oikein hyvin. En nyt näin äkkiseltään löytäny Googlella mitään kivaa.
http://www.parashift.com/c -faq-lite/coding-standards.html#faq-27.5
hunajavohveli kirjoitti:
Eikö nuo muuttujat tulisi määritellä mainin ulkopuolella, jos niitä haluaa käyttää muissakin funktioissa?
Joo, mutta tässä niitä on kyllä tarkoitus käyttää ihan parametreina ja viittauksina, mikä on yleensä parempi kuin globaalit muuttujat.
Nimiavaruudet ovat sitä varten, ettei koodarin muuttuja-, funktio- ja tyyppinimet törmäile muiden koodareitten, kirjastojen tai standardikirjastojen käyttämien nimien kanssa. Pienissä projekteissa on oikeastaan aina yks hailee, miten asioita tehdään, mutta isommissa kuvioissa törmäyksiä saattaakin sattua, varsinkin jos koodijutut pohjautuvat englantiin.
C-tyylisesti nimien törmäyksiä vältetään sillä, että esimerkiksi kaikki abc-kirjastossa olevat funktiot nimetään vaikkapa tyyliin abcTamaFunktio
ja abcTuoFunktio
. Tätä on käytetty C++:ssakin, homma toimii samaan malliin tyyppien ja muuttujienkin nimissä.
Seuraava veto on käyttää luokkia, joista ei ole tarkoituskaan luoda olioita ja jossa on vain staattisia funktioita.
struct abc { static int tamaFunktio(); static void tuoFunktio(); class yksLuokka { /* ... */ }; };
Noihin kun viittaa, niin syntaksi vaatii aina luokan nimen abc::
. Tähän malliin homma toimii Javassakin (siellä tosin jengi aina sössöttää hienommasta oliosuuntautuneisuudesta, vaikka tässäkin nyt nimenomaan tehdään asia olioiden kannalta just väärin).
Nimiavaruus muistuttaa tuota luokka-static-viritystä, mutta siinä on yritetty ratkaista se varsinainen ongelma eikä vääntää oliojuttuja oliottomiin asioihin (antamalla static
-sanalle lisämerkityksiä). Kylkiäisinä on tullut sitten uusia toimintoja (esimerkiksi aliasointi ja using-määrittelyt) ja kimurantteja sääntöjäkin (nimien lookup). EDIT: Uusi piirre on myös nimettömät nimiavaruudet. Nimiavaruudet on myös tapa saada jotkut template-jutut järkevästi toimimaan.
Kun sanotaan using namespace std;
vesitetään koko juttu standardikirjastojen osalta. Pikkujutuissa tällä ei ole väliä. Nimiavaruudet ovat hyvä juttu kun tehdään koodausta large scale. Voi tietenkin ajatella, että aloittaa pienesti vesittämällä nimiavaruusjutut ja vaihtaa sitten "isolle", jos ja kun tarvetta on. Mutta silloin jos ja kun tarvetta sitten ilmaantuu, onkin oikeastaan jo myöhäistä ja joutuu tavalla tai toisella tekemään turhaa työtä. Siksipä itse kirjoittelen ihan kiltisti std::
sitä ja std::
tätä ihan alusta saakka, aika vähällä siinä tuntuu pääsevän.
#include <iostream> #include <string> using namespace std; void kysy_nimi(string &nimi) getline(cin >> ws, nimi); { cout << "Anna uuden asiakkaan nimi: "; string nimi; } void kysy_nro(long int &numero) { cout << "Anna uusi asiakastunnus: "; cin >> numero; } void tulosta_nro(const long int &numero) { cout << "Numero: " << numero; } void muuta_nro(long int &numero) { cout << "Anna uusi numero: "; cin >> numero; } void poista_nro(long int &numero) { numero = 0; } int main () { int valinta = 0; long int numero = 0; string nimi; while ( valinta != 6) { cout << "Tilaustenkäsittelyjärjestelmä" << endl; cout << "1. Anna uuden asiakkaan nimi" << endl; scout << "2. Anna asiakastunnus" << endl; cout << "3. Tulosta asiakastunnus" << endl; cout << "4. Muokkaa tunnusta" << endl; cout << "5. Poista " << endl; cout << "6. Lopeta" << endl; cout << "Valintasi: "; cin >> valinta; if (valinta == 1) kysy_nimi(nimi); if (valinta == 2) kysy_nro(numero); if (valinta == 3) tulosta_nro(numero); if (valinta == 4) muuta_nro(numero); if (valinta == 5) poista_nro(numero); } return 0; }
Back to sorvin ääreen. Eli nyt tulee enää kaksi virheilmoitusta:
error C2146: syntax error : missing ';' before identifier 'getline'
fatal error C1004: unexpected end of file found
Mitäs nuo nyt meinaavat?
void kysy_nimi(string &nimi)
getline(cin >> ws, nimi);
Tuo koodin pätkä on kai ongelman ydin. Itse ihmettelen mikä tuo ws oikein on?
Tuo getline
on nyt aivan väärässä paikassa. Funktion koodi sijoitetaan aina lohkoon, joka tietysti seuraa välittömästi funktion nimeä ja parametreja:
PALUUARVON_TYYPPI funktio(PARAMETRIN_TYYPPI parametri1, PARAMETRIN_TYYPPI parametri2) { // koodi tähän return PALUUARVO; }
kysy_nimi
on siis funktio ja nimi
sen parametri (tyyppiä viittaus std::string
-tyyppiseen olioon). getline
n on tarkoitus lukea käyttäjän syöttämää tekstiä tällaiseen olioon, johon funktiota kutsuttaessa annetaan viittaus.
Se siis loogisesti sijoitetaan koodissa syöttöpyynnön (cout << "Syötä nimi: ";
) jälkeen. Nyt getline
on C:n syntaksin vastaisessa paikassa, mistä kääntäjä tietysti omalla epäsuoralla tavallaan valittaa. Sen sijaan että kysy_nimi
-funktiossa yrittäisit lukea mitään, määrittelet uuden nimi
-nimisen string
-olion.
Ei kannata yrittää kirjoittaa koodia, josta ei itse ymmärrä mitään.
Jos tämä on ensimmäinen tai toinen C++ -ohejlmasi, siinä on aivan liikaa funktioita, viittauksia ja string
-olioita. Tuon ohjelman voi aivan hyvin toteuttaa ilman yhtään aliohjelmaa.
Yhä edelleenkin voi ennen kaikkea ajatella kaikessa rauhassa ja lukea annetut ohjeet. Sanoin näin:
getline(cin >> ws, nimi); // Ei pakko, mutta ehkä parempi idea kuin cin >> nimi
Tämä nähdäkseni aika selvästi tarkoittaa, että tuota ei ole pakko käyttää mutta se voi olla parempi kuin cin >> nimi
, mistä voi varmaankin päätellä, että tuo pitäisi laittaa juuri kyseisen rivin paikalle. Lisäksi omin silmin voi todeta, että tuo on funktiokutsu, jolloin tuo kuuluu, kuten os sanoi, lohkon sisään.
Jos jokin ihmetyttää, sitä voi itsekin etsiä vaikkapa Googlella ja löytää cppreference.com-sivustolta selostuksen asiasta. Lukemalla >>-operaattorilla ws:ään saa poistettua tietovirrasta alussa olevat tyhjät kuten välit ja turhat rivinvaihdot. Näin getline pääsee aloittamaan siitä, mistä teksti alkaa, ja saa varmasti siis luettuakin jotakin.
niin sitä ei ole pakko käyttää mutta kun errorit lisääntyy vaikka kuinka paljolla...
No mikähän nyt vielä oli virheenä?
pele1977, kääntäjän antamien virheiden määrällä ei ole niinkään väliä. Yksi puuttuva merkki koodissa voi tuottaa vaikka sata käännösvirhettä.
Ensimmäisen funktion määrittelyn pitäisi näyttää tältä:
void kysy_nimi(string &nimi) { cout << "Anna uuden asiakkaan nimi: "; getline(cin >> ws, nimi); }
Lisäksi koodissa on lyöntivirhe (Rivi 63):
scout << "2. Anna asiakastunnus" << endl; // pitäisi olla "cout" eikä "scout"
Aihe on jo aika vanha, joten et voi enää vastata siihen.