1

I'm trying to read in a line of the file, print out parts of the line, and repeat the process for the next line of the file.

but it doesn't work properly, when I push the output to cmd line it becomes apparent that the while loop is never exitting.

I also tried the same process just using getline() instead, but I have the same problem, it just reads and re-reads the file infinitely.

Here is my code:

fstream scores;
scores.open("scores.txt");
string playerName;
string playerScore;
int i = 0;

while (scores >> playerName >> playerScore && i < 8) {
    int line = i * 40;
    int rank = i + 1;

    // testing
    cout << rank << " " << playerName << " " << playerScore << "\n";

    char plRank[1];
    sprintf(plRank, "%i", (rank));
    char plName[8];
    sprintf(plName, "%s", "Name");
    char plScore[8];
    sprintf(plScore, "%s", "score");

    DrawScreenString(GAX1 + 20, GAY1 + 120 + line, plRank, 0x505050, pBody);
    DrawScreenString(GAX1 + 320, GAY1 + 120 + line, plName, 0x505050, pBody);
    DrawScreenString(GAX1 + 570, GAY1 + 120 + line, plScore, 0x505050, pBody);
    i++;
}
scores.close();

Here is an extract from the cmd line output.

1 Edward 100
2 Jodi 80
3 Tom 50
4 Emma 40
1 Edward 100
2 Jodi 80
3 Tom 50
4 Emma 40
1 Edward 100
2 Jodi 80
3 Tom 50
4 Emma 40
1 Edward 100
2 Jodi 80
3 Tom 50
4 Emma 40
1 Edward 100
2 Jodi 80
3 Tom 50
4 Emma 40
1 Edward 100
2 Jodi 80
3 Tom 50
4 Emma 40
1 Edward 100
2 Jodi 80
3 Tom 50
4 Emma 40
...

this is what the scores.txt file cotains

Edward 100
Jodi 80
Tom 50
Emma 40

Any suggestions of why it infinitely loops or fixes would be greatly appreciated!

stell1315
  • 153
  • 1
  • 2
  • 9

2 Answers2

1

I also tried the same process just using getline() instead, but I have the same problem, it just reads and re-reads the file infinitely.

You should have shown us the std::getline code which doesn't work. Using std::getline is certainly the preferred solution here. Did you, by any chance, use the member function instead of the free-standing function which works with std::string? sprintf and arrays are the wrong tools for this task.

Here's what you should do:

  1. Read whole lines with the free-standing std::getline function.
  2. Use std::getline's returned std::ifstream itself in the loop condition (it will work due to operator overloading).
  3. Tokenize each line after reading it. Did you consider what would happen in your program if a player has two first names? Shouldn't this at least result in a meaningful error message?
  4. Use std::string's c_str member function to safely pass strings to DrawScreenString.

Example:

std::string line;
while (std::getline(scores, line) && (i < 8))
{
    std::vector<std::string> const tokens = tokenize(line);
    // ...

    DrawScreenString(GAX1 + 20, GAY1 + 120 + line, tokens[0].c_str(), 0x505050, pBody);
    // and so on
}

The remaining interesting question is how to write the tokenize function:

std::vector<std::string> tokenize(std::string const &line)
{
    // ?
}

Perhaps Boost Tokenizer can help you. But you could also just use std::string's member functions like find and substr.

Just to give you an idea:

std::vector<std::string> tokenize(std::string const &line)
{
    std::vector<std::string> result;

    std::string::size_type const pos_first_space = line.find(" ");
    if (pos_first_space == std::string::npos)
    {
        // error, no space found
    }
    std::string const first_token = line.substr(0, pos_first_space);
    result.push_back(first_token);

    // ...

    return result;
}

The point is: separate reading a line from tokenizing a line.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • Thankyou for the help, I'll give this a go. Sorry I din't explain, the current use of sprintf is completely unnecessary, I plan to make use of them later once I had ironed out the infinite re-reading of the file. – stell1315 Mar 28 '14 at 19:35
1

This code should work quite well. You can easily modify it for your other purposes and/or use different means for output. I have also made slight modifications, note:

I recommend not using stream.open(), but rather a constructor as shown. The stream is closed implicitly, no need for stream.close()

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

// reads name, score entries from text file

int main()
{
    std::ifstream scores("scores.txt");
    std::string line {""};
    int lineNr {1};
    while(std::getline(scores, line))
    {
        std::stringstream stream(line);
        std::string name;
        int score;
        if(stream >> name >> score)
            std::cout << lineNr << ' ' << name << ' ' << score << '\n';

        else
            std::cerr << "Error: invalid score entry in line " << lineNr << ".\n";

        ++lineNr;
    }
}
smoothware
  • 898
  • 7
  • 19
  • Thanks: I tried implementing your code, but I get the same issue, It just reads and re-reads the file continuously.. – stell1315 Mar 28 '14 at 19:29
  • I used a textfile "scores.txt" with the content `Edward 100 Jodi 80 Tom 50 Emma 40 fail err corrupt line Adam 20` and I cannot reproduce your error. Did you use _exactely_ the same code, or combine it with other things? – smoothware Mar 28 '14 at 19:43
  • I literally copied and pasted your code, did your file have a new line after each player and their respective score? – stell1315 Mar 28 '14 at 19:47
  • Yes, it does. Which things have you tried outputting for debug information? E.g. try outputting the lineNr and maybe line each time around the loop or so... – smoothware Mar 28 '14 at 19:52
  • lineNr output's as expected, everything outputs as you expect until it reads to the bottom of the file, and then rather than stopping it just rereads the file – stell1315 Mar 28 '14 at 19:56
  • If you really used exactely this code with nothing else and still get the "reading over and over" error, I cannot help you. My knowledge ends here. Maybe some problem with the streamstate or line-endings, I don't know... – smoothware Mar 28 '14 at 20:09
  • ok, thank-you very much for your help, I'll keep working at it – stell1315 Mar 28 '14 at 20:23
  • Looking back at this code, it is bad because it doesn't check for he file actually being opened: "if (!scores) { */ error */ } – smoothware Sep 12 '16 at 09:58