Pregunta

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!

¿Fue útil?

Solución

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.

Otros consejos

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;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top