Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Tilaustenkäsittelyjärjestelmä

Sivun loppuun

Aloittelija2 [19.06.2006 16:35:03]

#

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.

sooda [19.06.2006 16:57:52]

#

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.

Metabolix [19.06.2006 16:59:00]

#

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.

Aloittelija2 [20.06.2006 11:42:53]

#

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.

Metabolix [20.06.2006 11:52:10]

#

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

Aloittelija2 [20.06.2006 12:04:28]

#

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

Metabolix [20.06.2006 12:14:17]

#

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

Aloittelija2 [20.06.2006 12:27:07]

#

En kyllä ymmärrä mihin kohtaan nuo tulevat?

koo [20.06.2006 12:33:38]

#

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

Metabolix [20.06.2006 12:36:30]

#

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.

Aloittelija2 [20.06.2006 12:40:22]

#

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?

koo [20.06.2006 12:43:01]

#

Virheilmoituksista: Näin on, mutta pointti on siinä, että avustamisen kannalta esimerkiksi ensimmäisen (ja toisen) sisältö on se avainjuttu, ei kokonaismäärä. :-)

Aloittelija2 [20.06.2006 12:46:52]

#

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?

hunajavohveli [20.06.2006 12:48:32]

#

Eikö nuo muuttujat tulisi määritellä mainin ulkopuolella, jos niitä haluaa käyttää muissakin funktioissa?

Aloittelija2 [20.06.2006 12:49:49]

#

Mod. edit: taas melkein sama pätkä. :/

Tältä se nyt näyttää ja tosiaan 20 virhettä vielä.

hunajavohveli [20.06.2006 12:53:02]

#

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.

os [20.06.2006 13:08:33]

#

Ota koodin alusta #include <iostream.h> pois. Laita alkuun:

#include <iostream>
#include <string>

using namespace std;

Nyt sinun ei tarvistse kirjoittaa joka cinin, coutin, stringin ja endl:n eteen std::.

P.S. Joku voisi selvittää minullekin, mitä niin pahaa tuossa using namespacessa on, että kaikkien luokkien ja olioiden eteen pitää nimiavaruusmäärittely kirjoittaa erikseen. Näyttääkö se vain komeammalta?

Blaze [20.06.2006 14:00:19]

#

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.

Deewiant [20.06.2006 14:17:09]

#

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

koo [20.06.2006 15:41:09]

#

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.

Aloittelija2 [26.06.2006 10:41:53]

#

#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?

os [26.06.2006 12:23:00]

#

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). getlinen 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.

Metabolix [26.06.2006 12:37:02]

#

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.

Aloittelija2 [26.06.2006 14:44:01]

#

niin sitä ei ole pakko käyttää mutta kun errorit lisääntyy vaikka kuinka paljolla...

Metabolix [26.06.2006 14:48:34]

#

No mikähän nyt vielä oli virheenä?

os [26.06.2006 15:39:04]

#

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"

Sivun alkuun

Vastaus

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

Tietoa sivustosta