[C++] while loop + getline() probleem

Pagina: 1
Acties:

  • Denzo
  • Registratie: Augustus 2007
  • Laatst online: 09-11 00:50
Ik heb een programma geschreven dat voor mezelf gebruikt gaat worden als een oefentoets programma. Dit programma leest een .txt bestand in en vraagt dan de vragen.

De structuur van zo'n bestand gaat zo:

code:
1
2
vraag|antwoord
vraag2|antwoord


Enzovoorts.

Nu gebeurt dit allemaal wel correct, maar zodra de laatste vraag is gesteld en beantwoord, gebeurt er niks meer. Dan hangt 'ie in een soort van infinite loop. Dan gebeurt er niks tenzij je weer input geeft, en dat vergelijkt hij met de laatste vraag die gesteld is en dan pas wordt er code gedraait die na de while loop komt. Hier is mijn code:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    string toets;
    cout << "Welkom bij ZelfToets++!" << endl;
    cout << "Typ de bestandsnaam van de toets die je wil maken, bijv. toets.txt\n" << endl;
    cin >> toets;

    string vraag, antwoord, input;
    int vg = 0;
    int v = 0;
    float cijfer;

    ifstream toetsbestand(toets.c_str());

        if (toetsbestand.is_open())
        {
            while (! toetsbestand.eof() )
            {
            getline (toetsbestand,vraag,'|');
            getline (toetsbestand,antwoord);

            cout << "\n" << vraag << endl;
            cout << "\n";
            cin >> input;

                if (input == antwoord)
                {
                    cout << "\nCorrect! Je je antwoord was goed. Het was inderdaad " << antwoord << "!" << endl;
                    vg++;
                }
                else
                {
                     cout << "\nSorry, je had het niet goed. Het goede antwoord was " << antwoord << "." << endl;
                }
                v++;
            }

            toetsbestand.close();

            cout << "Ok, we zijn klaar!" << endl;
            cout << "Je had " << vg << " van de " << v << " vragen goed." << endl;

        }

        else
        {
        cerr << "Deze toets bestaat niet, of het bestand is al in gebruik!";
        }

getchar();
return 0;

}

  • geez
  • Registratie: Juni 2002
  • Laatst online: 25-10 16:40
Schrijf zelf geen C++, maar staat er niet misschien een lege regel onder je laatste vraag?

En kun je het niet oplossen door eerst te kijken of vraag resp. antwoord leeg is? :)

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Kwestie van input altijd controleren. Ga er niet van uit dat de volgende regel altijd vraag|antwoord is, maar controleer dit gewoon. :) Check of | aanwezig en een niet lege vraag en antwoord ingelezen.

Bovendien valt de output bij een lege vraag nu ook niet echt op. Iig tijdens debuggen is het outputten van "Vraag "+v wellicht handig.

[ Voor 25% gewijzigd door Voutloos op 26-05-2008 13:59 ]

{signature}


  • Denzo
  • Registratie: Augustus 2007
  • Laatst online: 09-11 00:50
Nee, onder mijn laatste vraag staat geen lege regel, daar had ik al op gecheckt :)

En die check zal niet helpen, want die zijn toch niet leeg? Ik heb hier over gegoogled, maar er werdt geen antwoord opgegeven. De loop draait gewoon nog een keer, alleen wordt de vraag niet gesteld omdat de volgende lijn end-of-file eigenlijk is. Oh shit, nu heb je toch gelijk. Ik zal eens kijken.

  • Brothar
  • Registratie: Oktober 2000
  • Laatst online: 29-09 21:55

Brothar

meester

Komt het misschien doordat de while-loop éérst de eof leest, en dan nog de bewerkingen wil doen voor dat ie uit de loop stapt ?
Dus dan beter een repeat-until loop gebruiken ?

eagle


  • Denzo
  • Registratie: Augustus 2007
  • Laatst online: 09-11 00:50
Het is opgelost! Even dit stukje code toegevoegd in mijn loop:

C++:
1
2
3
4
            if (vraag.size() == 0)
            {
                break;
            }

  • JaWSnl
  • Registratie: Maart 2007
  • Laatst online: 13-06 15:18
en wat dacht je om aan het einde van het txt bestand op de laatste regel altijd gewoon een andere zin te maken, zoals "EINDE" en als ie die dan tegen komt, dan stopt ie.
of begrijp ik het verhaal verkeerd?

There are only 10 types of people in the world: those who understand binary and those who don't.


  • Denzo
  • Registratie: Augustus 2007
  • Laatst online: 09-11 00:50
Dat kan ook! Maar zoals ik al zei, het is al gefixed. Toch bedankt iedereen!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
JaWSnl schreef op maandag 26 mei 2008 @ 14:03:
en wat dacht je om aan het einde van het txt bestand op de laatste regel altijd gewoon een andere zin te maken, zoals "EINDE" en als ie die dan tegen komt, dan stopt ie.
of begrijp ik het verhaal verkeerd?
Werkt ook, maar je weet toch al dat je geen lege vragen wil stellen.

{signature}


  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 01-11 22:03

leuk_he

1. Controleer de kabel!

http://www.cppreference.com/cppio/all.html
he getline() function is used with input streams, and reads characters into buffer until either:

( * num - 1 characters have been read,)
* a newline is encountered,
* an EOF is encountered,
( * or, optionally, until the character delim is read. The delim character is not put into buffer.)
.....
....
Those using a Microsoft compiler may find that getline() reads an extra character, and should consult the documentation on the Microsoft getline bug.
Zit die MS bug je soms dwars. En hoe zien de laatste bytes van de file er precies uit? Ofwel bevat de laatste regel met antward een newline, en/of een EOF char?)

En anders gewoon je input meer valideren: als hij een lege vraag of antwoord leest loggen en skippen.

/EDIT: lees nu pas dat het al gefix is. :X eerst refreshen, dan 8)7 posten!

[ Voor 4% gewijzigd door leuk_he op 26-05-2008 14:25 ]

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


  • Denzo
  • Registratie: Augustus 2007
  • Laatst online: 09-11 00:50
Zoals ik al zei, het is al gefixed. En ik zit op Linux met Code::Blocks, dus van een MS bug kan geen sprake zijn.

  • Dido
  • Registratie: Maart 2002
  • Laatst online: 18:17

Dido

heforshe

Als ik die post van leuk_he lees, dan lees je du seen EOF na je laatste record. Omdat je aan het begin van je loop test, is je laatste loop altijd met foute data.

De oplossing om elke iteratie die IF in te gaan is een slechte oplossing voor dit probleem (je IF gaat namelijk voor al je vargen af, en alleen bij je EOF heeft hij "nut".

Je kunt je conditie naar het einde van je loop verplaatsen (loop ... until EOF), of je kunt je leesactie naar het einde van je loop verplaatsen. Dan moet je ook initieel lezen (voordat je je loop ingaat).

Wat betekent mijn avatar?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dido schreef op maandag 26 mei 2008 @ 17:01:
Je kunt je conditie naar het einde van je loop verplaatsen (loop ... until EOF)
Gaat natuurlijk niet werken. Het enige verschil is dat je voor de eerste iteratie al niet test op eof, maar daarna blijft het feitelijke punt van testen gelijk.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Voutloos
  • Registratie: Januari 2002
  • Niet online
En die if wegwerken is, aangezien er elke iteratie output is en er zelfs op user input gewacht moet worden, een micro-optimalisatie. Lekker laten staan, overleeft je programma het ook meteen als er ooit per ongeluk een lege regel halverwege het tekstbestand staat.

{signature}


  • Dido
  • Registratie: Maart 2002
  • Laatst online: 18:17

Dido

heforshe

.oisyn schreef op maandag 26 mei 2008 @ 17:06:
Gaat natuurlijk niet werken. Het enige verschil is dat je voor de eerste iteratie al niet test op eof, maar daarna blijft het feitelijke punt van testen gelijk.
Ja, je hebt gelijk. |:(

Er is kennelijk een reden waarom een standaard algoritme in dit soort situaties bestaat :P
code:
1
2
3
4
5
Lees record
Tot EOF
Verwerk record
Lees record
Herhaal

Wat betekent mijn avatar?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dit kan wel:
C++:
1
2
3
4
while (getline (toetsbestand,vraag,'|') && getline (toetsbestand,antwoord))
{
    // bla
}

Overigens vind ik het nog steeds raar dat hij een oneindige loop heeft. Alsof de eof bit nooit wordt gezet oid. Het is waar dat de laatste "vraag" waarbij de EOF optreedt dan wel gesteld wordt terwijl je dat eigenlijk niet wilt, maar de volgende iteratie zou ie er gewoon mee moeten stoppen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Er wordt niet gelooped, maar gewacht op user input als reactie op enkel whitespace. :P

edit:
vandaar ook de hint in m'n 1e post om de vraag (al is het maar tijdens debuggen) te begeleiden met meer dan enkel whitespace

[ Voor 44% gewijzigd door Voutloos op 26-05-2008 17:30 ]

{signature}


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

Oh ja idd ik zie het nu.
Dan hangt 'ie in een soort van infinite loop. Dan gebeurt er niks tenzij je weer input geeft, en dat vergelijkt hij met de laatste vraag die gesteld is en dan pas wordt er code gedraait die na de while loop komt
"soort van infinite loop" |:(. Niets infinites aan :P

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

C++:
1
2
3
4
5
6
try {
   toetsbestand.exceptions(std::ios::failbit);
   ...
 catch (...) {
   // done.
}

;) (of eofbit, maar iha wil je toch ook wel op failbit (en badbit) checken)

[ Voor 23% gewijzigd door Zoijar op 26-05-2008 17:59 ]


  • Denzo
  • Registratie: Augustus 2007
  • Laatst online: 09-11 00:50
Zozo, veel reacties :+

Heeft nou echt niemand gezien dat ik het zelf al gefixt had na aanleiding van geez's zijn post?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je komt zeker niet vaak in PRG? ;)

Overigens is het trouwens handig om op 'leegheid' te testen met empty() ipv size(). Die laatste hoeft namelijk niet altijd O(1) te zijn (bij sommige std::list implementaties is ie O(n)), wat de hele reden is achter het bestaan van empty(). En daarom is het handig om aan te leren om die te gebruiken.

[ Voor 104% gewijzigd door .oisyn op 26-05-2008 19:10 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Denzo
  • Registratie: Augustus 2007
  • Laatst online: 09-11 00:50
Nee niet zo vaak :) Ben ook nog niet heel lang bezig in C++ hoor :)
Pagina: 1