Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: cin.getline ja string?

Sivun loppuun

vehkis91 [05.02.2008 20:13:18]

#

mulla on tässä koodissa pieni ongelma...

#include <cstdlib>
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>


using namespace std;

fstream tiedosto;

 string nimi;
 char ika[4];

// ...

cin.getline(nimi, 20)  // Tässä ongelma ohjelma ei anna mun laittaa tohon
cout<<endl;            //   mitään arvoa, vaan hyppää sen yli...

// ...

void NimenLuku()     //jostain syystä sammuu kun tätä funktiota kutsuu...
{
 cout<<endl;
 tiedosto.open("Ihmiset.dat", ios::in);
 cout<<tiedosto.rdbuf();
 tiedosto.close();
}

(Mod. Edit. koodic-tagi C++-koodille ja vähän järkeä siihen pastettavan koodin määrään.)

Metabolix [05.02.2008 20:16:41]

#

char taulu[20];
cin.getline(taulu, sizeof(taulu)); /* char* ja luku (streamsize) */

string str;
getline(cin, str); /* istream ja string */

Lisäksi sinulta puuttuu puolipiste.

vehkis91 [05.02.2008 20:22:25]

#

ok kiitos...

vehkis91 [06.02.2008 19:17:35]

#

Mulla ei vieläkään toimi tuo getline(cin,nimi)? Se hyppää aina sen yli seuraavaan cin käskyyn...

Ja jostain syystä funktio kutsu NimenLuku()-funktioon sammuttaa ohjelman?


Tässä päivitetty koodi:

#include <cstdlib>
#include <iostream>
#include <string>
#include <fstream>


using namespace std;

void menu();
void menu2();
void NimenLisays();
void NimenLuku();
void NimenPoisto();


fstream tiedosto;

 string nimi;
 char ika[4];


int main(int argc, char *argv[])
{
    menu();
    return EXIT_SUCCESS;
}

void menu()
{
 char vaihtoehto[2];
 cout<<endl;
 cout<<"MENU"<<endl;
 cout<<endl;
 cout<<"(M)uokkaa nimi(a)"<<endl;
 cout<<"(L)ue nimi(a)"<<endl;
 cout<<"(S)ulje ohjelma"<<endl;
 cout<<endl;
 cout<<"--> ";
 cin>>vaihtoehto;
  while(1)
  {
  if(vaihtoehto[1]!='\0')
   {
    cout<<endl;
    cout<<"Valinassa saa olla vain yksi kirjain!!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto;
    continue;
   }
  if(vaihtoehto[0]=='m'|vaihtoehto[0]=='l'|vaihtoehto[0]=='s')
   {
    break;
   }
  if(vaihtoehto[0]!='m'|vaihtoehto[0]!='l'|vaihtoehto[0]!='s')
   {
    cout<<"Valinnan pitaa olla m, l tai s!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto;
    continue;
   }
  }
  switch(vaihtoehto[0])
  {
   case 'm':
        menu2();
        break;
   case 'l':
        NimenLuku();
        break;
   case 's':
        cout<<endl;
        cout<<"Ohjelma suljetaan..."<<endl;
        exit(1);
        break;
  }
}

void menu2()
{
char vaihtoehto2[2];
 cout<<endl;
 cout<<"(L)isaa nimi"<<endl;
 cout<<"(P)oista kaikki nimet"<<endl;
 cout<<"(M)enu"<<endl;
 cout<<endl;
 cout<<"--> ";
 cin>>vaihtoehto2;
   while(1)
  {
  if(vaihtoehto2[1]!='\0')
   {
    cout<<endl;
    cout<<"Valinassa saa olla vain yksi kirjain!!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto2;
    continue;
   }
  if(vaihtoehto2[0]=='l'|vaihtoehto2[0]=='p'|vaihtoehto2[0]=='m')
   {
    break;
   }
  if(vaihtoehto2[0]!='l'|vaihtoehto2[0]!='p'|vaihtoehto2[0]!='m')
   {
    cout<<"Valinnan pitaa olla l, p tai m!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto2;
    continue;
   }
  }

  switch(vaihtoehto2[0])
  {
   case 'l':
        NimenLisays();
        break;
   case 'p':
        NimenPoisto();
        break;
   case 'm':
        menu();
        break;
  }
}

void NimenLisays()               //Lisää nimen ja iän tiedostoon
{
tiedosto.open("Ihmiset.dat", ios::out|ios::app);
 if(tiedosto.good())
  {
   cout<<endl;
   cout<<endl;
   cout<<"Anna nimi: ";
   getline(cin,nimi);
   cout<<endl;
   cout<<"Anna ika: ";
   cin>>ika;
   tiedosto<<nimi<<" "<<"n "<<"ika on "<<ika<<" "<<"v."<<endl;
   tiedosto.close();
   cout<<endl;
   cout<<"Palaan takaisin valikkoon..."<<endl;
   menu2();
  }
 else
  {
   cout<<endl;
   cerr<<"Tedoston avaaminen epaonnistui!!!"<<endl;
   menu2();
  }
}

void NimenLuku()             //Lukee nimet ja iät tiedostostosta
{
 cout<<endl;
 tiedosto.open("Ihmiset.dat", ios::in);
 if(tiedosto.good())
 {
  cout<<tiedosto.rdbuf();
  tiedosto.close();
 }
 else
 {
  cout<<endl;
  cerr<<"Nimien luku epaonnistui!!!!"<<endl;
  menu();
 }
}

void NimenPoisto()           //Poistaa nimet ja iät tiedostosta
{
 tiedosto.open("Ihmiset.dat", ios::out | ios::trunc);
 if(tiedosto.good())
  {
   cout<<"Kaikki nimet poistettu!"<<endl;
   menu2();
  }
 else
 {
  cout<<endl;
  cerr<<"Nimien poisto epaonnistui!"<<endl;
  menu2();
 }
}

(Mod. Edit. Edelleenkin koodic-tagi C++-koodille. Koodin määrän kanssa voisit yhä käyttää järkeä, nyt en jaksa edes karsia. Ärsyttävää ruveta tuolta etsimään sitä getlineä ja muita ongelmakohtia.)

WinC [06.02.2008 20:44:33]

#

Ennen getline(cin,nimi); riviä täytyy kutsua cin.ignore(); (esim. cin.ignore(256,'\n'); ) puskurin "tyhjentämiseksi", koska siellä lymyilee ilkeä '\n' merkintä, jonka takia getline() luulee syötteen jo annetuksi.

Nimenluku funktio lopettaa ohjelman koska onnistuneen tiedostonlukemisen jälkeen ei enään kutsuta valikkoa (ainostaan epäonnistunut tiedostonluku jatkaa ohjelman suorittamista tällähetkellä)

Gaxx [06.02.2008 20:59:17]

#

vehkis91 kirjoitti:

Mulla ei vieläkään toimi tuo getline(cin,nimi)? Se hyppää aina sen yli seuraavaan cin käskyyn...

Ohjelmasi ei hyppää getlinen yli vaan cin:virrassa sattuu olemaan rivinvaihto, jolloin getline lukee siihen rivinvaihtoon asti. Tällöin luettu sisältö on "ei mitään".

Miksi siellä virrassa sitten on tuo rivinvaihto? No siksi, koska "cin <<" ei poista rivinvahtoja(eikä mitään muutakaan tyhjää tilaa).

Esimerkki:
cin << komento;
getline(cin, nimi);
cin << ika;

Käyttäjä syöttää komennon(vaikka m) ja painaa enteriä. Tällöin virrassa on "m\n" eli kirjain m ja rivinvaihto. Nyt cin lukee kirjaimen m, mutta jättää virtaan rivinvaihdon "\n". Sitten tulee getlinen vuoro joka katsoo, että jahas, virrasta löytyy rivinvaihto "\n", joten luetaanpas siihen asti. getline palauttaa "ei mitään" ja poistaa rivinvaihdon virrasta. Sitten cin << ika suoritetaan totuttuun tapaan.

vehkis91 kirjoitti:

Ja jostain syystä funktio kutsu NimenLuku()-funktioon sammuttaa ohjelman?

Kokeile laittaa menu()-funktion switch-rakenne while-silmukan sisään. Siellä on aika monta muutakin ajatusvirhettä, mutta en nyt jaksa ruveta niitä kaikkia rustailemaan tähän.

Sitten vielä sellainen juttu, että älä suunnittele ohjelmiasi tähän tapaan:

int peli() {
   // pelataan...

   menu(); // palataan menuun
}

int menu() {
   // hoidetaan menua...

   while(1) {
      peli();
      if(halutaan_lopettaa)
         exit(1);
   }

   // ...
}

int main() {
   menu();

   return 0;
}

Eli suunnittele ohjelmasi siten, että pystyt lopettamaan sen ilman exit-käskyä. Voit pitää exit-käskyä yhtä pahana asiana, kuin goton käyttöä.

Esimerkki:

int peli() {
   // pelataan...

   return 0;                   // tästä palataan peli-funktiota kutsuneeseen funktioon, kutsukohtaan (*)
}

int menu() {
   // hoidetaan menua...

   while(1) {
      peli();                  // täällä kutsuttiin (*), eli tähän palataan

      if(halutaan_lopettaa)
         break;
   }

   // ...
   return 0;
}

int main() {
   menu();

   return 0;
}

vehkis91 [06.02.2008 22:27:41]

#

ok, tuo on vain harjoitus, joten en ole pahemmin sitä suunnitellut, eikä se ole myöskään valmis... ;)

Edit:
Muutan ohjelman teidän neuvvojen mukaisiksi, koska olette enemmän ohjelmoineet, nii olette luultavasti oikeassa. Ja haluan oppia kunnolla ohjelmoimaan.

tgunner [06.02.2008 23:27:35]

#

Gaxx kirjoitti:

Eli suunnittele ohjelmasi siten, että pystyt lopettamaan sen ilman exit-käskyä. Voit pitää exit-käskyä yhtä pahana asiana, kuin goton käyttöä.

Itse suosin käyttämääsi ohjelmointitekniikkaa, mutta ihan mielenkiinnon puolesta haluaisin vähän perustelua tälle väittämälle.

Megant [06.02.2008 23:35:53]

#

No silloin saa esimerkiksi muistin vapautettua ja muita samanlaisia asioita tehtyä helpommin ja siistimmin ainakin minusta.

Gaxx [07.02.2008 09:46:13]

#

tgunner kirjoitti:

Gaxx kirjoitti:

Eli suunnittele ohjelmasi siten, että pystyt lopettamaan sen ilman exit-käskyä. Voit pitää exit-käskyä yhtä pahana asiana, kuin goton käyttöä.

Itse suosin käyttämääsi ohjelmointitekniikkaa, mutta ihan mielenkiinnon puolesta haluaisin vähän perustelua tälle väittämälle.

Varmasti suurin syy tällä väittämälleni on se, että meidän yliopiston ohjelmistotekniikan laitos kieltää sen käytön kokonaan c++:ssa. Se on sitten jokaisen oma mielipide, selkeyttääkö sen käyttämättä jättäminen ohjelmaa, minusta ainakin. Lisäksi ilman exit-käskyä on mahdoton toteuttaa ohjelmaa, joka lopetettaisiin hallitusti, jos funktioista ei koskaan palata. Kysyjän lähettämässä koodissa funktioista ei palata, vaan niitä kutsutaan uudelleen, joka aiheuttaa jossain vaiheessa pinomuistin loppumisen.

koo [07.02.2008 11:16:52]

#

tgunner kirjoitti:

Gaxx kirjoitti:

Eli suunnittele ohjelmasi siten, että pystyt lopettamaan sen ilman exit-käskyä. Voit pitää exit-käskyä yhtä pahana asiana, kuin goton käyttöä.

Itse suosin käyttämääsi ohjelmointitekniikkaa, mutta ihan mielenkiinnon puolesta haluaisin vähän perustelua tälle väittämälle.

exit-FUNKTIO on paha C++:ssa, koska se lopettaa ohjelman kutsumatta normaaliin tapaan kaikkien olioiden destruktoreita. Ainoastaan globaalien ja staattisten olioiden destruktorit ajetaan. Käyttöjärjestelmä voi kyllä tehdä lopullisen siivouksen, mutta joskus ei ole sellaista käyttistä ja oliot voivat hallita sellaisiakin resursseja, joita käyttiksen siivous ei kata.

Funktiokutsun sijasta voi ihan yksinkertaisesti heittää poikkeuksen, niin hoituu siivous automaattisesti. Poikkeuksen voi vielä catchata mainissa, jos haluaa vaikka antaa virheilmoituksen tai palauttaa jonkun tietyn statuskoodin.

Goto-hyppykäsky voi olla pahasta, jos hypyt sotkevat muuttujien näkyvyysalueita. Gotolla pystyy helposti tekemään todella vaikeaselkoista koodia. Mutta ei goto ihan niin paha ole kuin mitä yleensä kuulee puhuttavan.

tgunner [07.02.2008 13:24:07]

#

^Veikkaanpa, että yrität returnata void-funktiosta.

öö, ihanassa kunnossa tämä ajan käsite? Vehkiksen vastaus on näköjään yhden alempana :)

vehkis91 [07.02.2008 14:33:47]

#

Mulla ei toimi oikein noilla return 0 - käskyllä...

Gaxx [07.02.2008 16:44:46]

#

Eli selventääkseni tqunneria, void funktio palaa, kun funktion lohko loppuu. Se ei palauta mitään arvoa, eli mitään return-käskyä ei tarvita. Jos kuitenkin haluat palata kesken funktion(vaikka jokin virhetilanne), voit kirjoittaa pelkästään "return;".

Pekka Karjalainen [07.02.2008 18:48:18]

#

Tuo keskinäinen rekursio onkin jännä juttu. Sitä voi testata tällä yksinkertaisella C-ohjelmalla.

#include <stdio.h>

void a (unsigned int);
void b (unsigned int);

void a (unsigned int count) {
  if (count % 10000 == 0)
    printf ("Recursive calls: %d\n", count);
  b (count + 1);
}

void b (unsigned int count) {
  if (count % 10000 == 0)
    printf ("Recursive calls: %d\n", count);
  a (count + 1);
}


int main (void) {
  a (0U);
  return 0;
}

MinGW-kääntäjällä tehty exe tulosti luvut 0 - 120000 (kymmenentuhannen välein), kun käänsin ilman optimointia. Sen verran oli siis pinomuistia käytössä oletuksena. Mutta mitä tapahtuu, kun teen näin:

C:\temp>gcc recu.c -foptimize-sibling-calls -o recu2.exe

C:\temp>recu2.exe
Recursive calls: 0
Recursive calls: 10000
Recursive calls: 20000
Recursive calls: 30000
Recursive calls: 40000
... (jatkuu vaikka kuinka pitkään)

Keskinäinen rekursio toimiikin nyt rajoituksetta. Voitte itse kokeilla tätä millä tahansa gcc:n versiolla, jossa tuo optimointilippu on käytössä. Sen sijaan muissa kääntäjissä homma ei ehkä pelitä mitenkään, koska tätä optimointia ei taata kielen standardissa.

Vehkiskin joutuu kyllä opettelemaan jonkin virallisesti hyväksytyn tavan tehdä tuon ohjelmansa, koska eräät tahot suhtautuvat hyvin kielteisesti loppurekursion käyttöön.

Metabolix [07.02.2008 19:38:35]

#

Tokihan monenlainen on mahdollista, kun pannaan kääntäjä tekemään temppujaan. Esimerkiksi tämänhetkisen putkapostin (nro 20) rekursiivinen ratkaisu muuttuikin GCC:n -O2-lipulla jonkinlaiseksi iteraatioksi, joka ei käytä lainkaan pinomuistia alunperin sisäkkäisissä kutsuissa. Tuossa Kopeekan tapauksessa optimointi perustunee siihen, että koska a-funktion viimeinen asia on b-funktion kutsuminen, kääntäjä muuttaakin kutsun hypyksi, jolloin b-funktio suoritetaan suoraan a-funktion jatkona. Sama tapahtuu tietysti toisinkin päin. Ainakin minun GCC-versioni kuitenkin vaati tämän toteuttamiseen jostakin syystä myös -O-lipun. Tällaisesta optimoinnista tulee "mahdoton", jos funktioiden parametrien koko ei täsmää eli jos parametreja on esimerkiksi eri määrä. ("Mahdoton", koska toki on mahdollista tehdä funktiosta kaksi eri versiota, joista toinen on luotu rekursiota ajatellen ja toinen suoraan kutsuttavaksi. Tuskin mikään kääntäjä kuitenkaan ryhtyy tällaiseen touhuun, Assembly-ohjelmoija ehkä.)

Ohjelmointitapana tuo toistuva kutsuminen ei ole olennaisesti goto-sotkua parempi selkeydeltään, ja haittapuolena on tuo muistinkäyttö.

Pekka Karjalainen [07.02.2008 21:03:56]

#

Ennen kuin hylkäämme koko ajatuksen, pohditaan hieman. Mitä mieltä Metabolix olisi kielestä, jossa ei olisi yhtään iteratiivista rakennetta? Ei while-silmukoita tai foreja, eikä edes gotoa.

Sen sijaan kielen määritelmä takaisi, että kääntäjän on tehtävä toimiva loppukutsuoptimointi jokaisessa mahdollisesssa tilanteessa, jolloin kaikki toistorakenteet voisi ilmaista rekursiivisina funktioina. Toimivuutta lisäisi, jos funktioita voisi määritellä sisäkkäin, mikä ratkaisisi suluissa mainitun funktioversio-ongelman kätevästi.

Kielestä tekisi joustavamman, jos siinä funktiot olisivat ns. ensimmäisen luokan kansalaisia, eli niitä voisi sijoittaa muuttujiin, välittää toisiin funktioihin parametreina ja palauttaa funktioista arvoina. Eihän ole mitään erityistä syytä tehdä funktiosta erilaista tietotyyppiä kuin luku tai merkkijono, jos ei tarvitse.

Mitä ajatuksia tällainen ohjelmointikieli herättäisi lukijoissa? Luottaisitteko ihmisen ohjelmointitaitoihin, jos hän olisi joskus ohjelmoinut tällaisella kielellä?

Pekka Karjalainen [08.02.2008 12:48:53]

#

Harmi, ettei kukaan vastannut. Olisi ollut niin juoni kieli ohjelmoida tuollainen, mutta ei kai se sitten voi toimia ^^.

Taidanpa lopettaa Putkan lukemisen toistaiseksi, kun tahtoo mennä trollauksen puolelle. Heip.

Tzaeru [08.02.2008 13:01:24]

#

Kopeekka kirjoitti:

Ennen kuin hylkäämme koko ajatuksen, pohditaan hieman. Mitä mieltä Metabolix olisi kielestä, jossa ei olisi yhtään iteratiivista rakennetta? Ei while-silmukoita tai foreja, eikä edes gotoa.

Sen sijaan kielen määritelmä takaisi, että kääntäjän on tehtävä toimiva loppukutsuoptimointi jokaisessa mahdollisesssa tilanteessa, jolloin kaikki toistorakenteet voisi ilmaista rekursiivisina funktioina. Toimivuutta lisäisi, jos funktioita voisi määritellä sisäkkäin, mikä ratkaisisi suluissa mainitun funktioversio-ongelman kätevästi.

Kielestä tekisi joustavamman, jos siinä funktiot olisivat ns. ensimmäisen luokan kansalaisia, eli niitä voisi sijoittaa muuttujiin, välittää toisiin funktioihin parametreina ja palauttaa funktioista arvoina. Eihän ole mitään erityistä syytä tehdä funktiosta erilaista tietotyyppiä kuin luku tai merkkijono, jos ei tarvitse.

http://en.wikipedia.org/wiki/Haskell_(programming_language)

Tarpeeksi lähellä :)

Deewiant [08.02.2008 13:20:00]

#

Tai ylipäätään kaikki funktionaaliset ohjelmointikielet, nehän ovat kaikki pohjimmiltaan tuollaisia, kuin Kopeekka kuvaili.

vehkis91 [08.02.2008 15:50:45]

#

Tässä koodi tällä hetkellä...

#include <cstdlib>
#include <iostream>
#include <string>
#include <fstream>


using namespace std;

int menu();
int menu2();
int NimenLisays();
int NimenLuku();
int NimenPoisto();


fstream tiedosto;

 string nimi;
 char ika[4];


int main(int argc, char *argv[])
{
    menu();
    return EXIT_SUCCESS;
}

int menu()
{
 char vaihtoehto[2];
 cout<<endl;
 cout<<"MENU"<<endl;
 cout<<endl;
 cout<<"(M)uokkaa nimi(a)"<<endl;
 cout<<"(L)ue nimi(a)"<<endl;
 cout<<"(S)ulje ohjelma"<<endl;
 cout<<endl;
 cout<<"--> ";
 cin>>vaihtoehto;
  while(1)
  {
  if(vaihtoehto[1]!='\0')
   {
    cout<<endl;
    cout<<"Valinassa saa olla vain yksi kirjain!!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto;
    continue;
   }
  if(vaihtoehto[0]=='m'|vaihtoehto[0]=='l'|vaihtoehto[0]=='s')
   {
    switch(vaihtoehto[0])
     {
      case 'm':
        menu2();
        break;
      case 'l':
        NimenLuku();
        break;
      case 's':
        cout<<endl;
        cout<<"Ohjelma suljetaan..."<<endl;
        return 0;
        break;
     }
    break;
   }
  if(vaihtoehto[0]!='m'|vaihtoehto[0]!='l'|vaihtoehto[0]!='s')
   {
    cout<<"Valinnan pitaa olla m, l tai s!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto;
    continue;
   }
  }
}

int menu2()
{
char vaihtoehto2[2];
 cout<<endl;
 cout<<"(L)isaa nimi"<<endl;
 cout<<"(P)oista kaikki nimet"<<endl;
 cout<<"(M)enu"<<endl;
 cout<<endl;
 cout<<"--> ";
 cin>>vaihtoehto2;
   while(1)
  {
  if(vaihtoehto2[1]!='\0')
   {
    cout<<endl;
    cout<<"Valinassa saa olla vain yksi kirjain!!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto2;
    continue;
   }
  if(vaihtoehto2[0]=='l'|vaihtoehto2[0]=='p'|vaihtoehto2[0]=='m')
   {
    switch(vaihtoehto2[0])
     {
      case 'l':
        NimenLisays();
        break;
      case 'p':
        NimenPoisto();
        break;
      case 'm':
        menu();
        break;
     }
    break;
   }
  if(vaihtoehto2[0]!='l'|vaihtoehto2[0]!='p'|vaihtoehto2[0]!='m')
   {
    cout<<"Valinnan pitaa olla l, p tai m!!!"<<endl;
    cout<<endl;
    cout<<"--> ";
    cin>>vaihtoehto2;
    continue;
   }
  }
}

int NimenLisays()               //Lisää nimen ja iän tiedostoon
{
tiedosto.open("Ihmiset.dat", ios::out|ios::app);
 if(tiedosto.good())
  {
   cout<<endl;
   cout<<endl;
   cout<<"Anna nimi: ";
   cin.ignore(256,'\n');
   getline(cin,nimi);
   cout<<endl;
   cout<<"Anna ika: ";
   cin>>ika;
   tiedosto<<nimi<<" "<<"ika: "<<ika<<" "<<"v."<<endl;
   tiedosto.close();
   cout<<endl;
   cout<<"Palaan takaisin valikkoon..."<<endl;
   menu2();
  }
 else
  {
   cout<<endl;
   cerr<<"Tedoston avaaminen epaonnistui!!!"<<endl;
   return 0;
  }
}

int NimenLuku()             //Lukee nimet ja iät tiedostostosta
{
 tiedosto.open("Ihmiset.dat", ios::in);
 if(tiedosto.good())
 {
  cout<<endl;
  cout<<tiedosto.rdbuf();
  tiedosto.close();
  menu();
 }
 else
 {
  cout<<endl;
  cerr<<"Nimien luku epaonnistui!!!!"<<endl;
  return 0;
 }
}

int NimenPoisto()           //Poistaa nimet ja iät tiedostosta
{
 tiedosto.open("Ihmiset.dat", ios::out | ios::trunc);
 if(tiedosto.good())
  {
   cout<<"Kaikki nimet poistettu!"<<endl;
   menu2();
  }
 else
 {
  cout<<endl;
  cerr<<"Nimien poisto epaonnistui!"<<endl;
  return 0;
 }
}

Päärynämies [08.02.2008 17:25:34]

#

Mitä meidän nyt pitäisi tuolla koodilla tehdä? Päivitellä omissa pienissä mielissämme?

vehkis91 [08.02.2008 18:13:27]

#

vaikka... ;)

Metabolix [08.02.2008 22:02:35]

#

Opettelehan nyt vähän itse. Tutki vaikka aputulostuksilla, millä rivillä ohjelma kaatuu, ja mieti sitten, miksi niin käy.

Virheesi taitaa olla se, että et sulje tiedostoa koskaan. Avoimeen tiedosto-olioon ei voi avata uutta tiedostoa. Järkevintä olisi käyttää jokaisessa funktiossa omaa tiedosto-oliota, joka sitten sulkeutuisi itsestään funktion lopussa. Samalla sinulla olisi loistava syy (suorastaan tarve) luopua huonosta ohjelmointitavastasi ja siirtyä funktioihin, jotka myös päättyvät.

Onnistuit kehittämään esimerkkitapauksen siitä, miksi globaaleja muuttujia ei pitäisi käyttää tarpeettomasti. Tästedes voisimmekin linkittää tähän aiheeseen, kun asiasta tulee keskustelua.

Kopeekka kirjoitti:

Mitä mieltä Metabolix olisi kielestä, jossa ei olisi yhtään iteratiivista rakennetta?

Kelpaahan se, mutta C(++) ei ole tuollainen, joten siltä ei voi odottaa tuollaista toimintaa.


Sivun alkuun

Vastaus

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

Tietoa sivustosta