Bartlomiej Lewandowski
Bartlomiej Lewandowski

Reputation: 11190

Saving to an array of strings from file

Basically, i want to read highscores from a file and check if the user has scored enought points to be on the scoreboard. I'm trying to do it like this:

string initials[10];
int scores[10];

//load txt
ifstream highscores("highscores.txt");
if(highscores.is_open())
{
   while(highscores.good())
   {
    for(int x=0;x<10;x++)
    {
        getline(highscores,initials[x],' '); 
        highscores >> scores[x];
    }
   }

    }

the initials are only 3 chars long, so i could implement a 2 dim. array but i wanted to try it with strings. It shows that i mad one string of size 10. How should i write it so it will work with 10 arrays instead of 1? (I know i could make 10 arrays naming them from array1.. to 10, looping through them sound much better. The highscores file is just a set of 10 initialas AAA,BBB etc. and some scores.

Example of highscores.txt:

AAA 5000
BBB 4000
CCC 3000

Upvotes: 0

Views: 205

Answers (3)

jfs
jfs

Reputation: 414835

There are two tasks:

  • add a new user score if it is high enough

    // Add a new score (score => name pair); pop the lowerest score and return it
    template <class Map> typename Map::value_type
    add_score_if(Map& scores, typename Map::value_type new_score) {
      scores.insert(new_score);
      // pop the lowerest score
      auto it = scores.begin();
      typename Map::value_type lowerest(*it);
      scores.erase(it);
      return lowerest;
    }
    

    add_score_if() pops the lowerest score thus if new_score is not high enough it won't stay in the score table i.e., the content of the scores will be the same before/after add_score_if() in this case.

  • load scores from the file

    // Load scores (score => name pairs) from input stream
    // where each line is: name score
    // Return whether all scores have been loaded
    template <class Istream, class Map> bool
    load_scores(Istream& in, Map& scores) {
      std::string name; int score;
      while (in >> name >> score) scores.insert(std::make_pair(score, name));
      return in.eof(); //XXX ignore errors at eof
    }
    

Program

#include <iostream>
#include <map>

template<class Map> void
dump_scores(std::ostream& out, const Map& scores) {
  for (auto it = scores.rbegin(); it != scores.rend(); ++it)
    out << it->second << ' ' << it->first << '\n';
}

int main() {
  // load scores
  std::multimap<int, std::string> scores;
  if (! load_scores(std::cin, scores)) {
    std::cerr << "error: not all scores have been loaded\n";
    return 1;
  }
  std::cout << "Before:\n";
  dump_scores(std::cout, scores);

  // add new score
  add_score_if(scores, std::make_pair(4000, "AAA"));
  std::cout << "\nAfter:\n";
  dump_scores(std::cout, scores);
}

Example

$ g++ -std=c++0x *.cc && printf "AAA 5000\nCCC 3000\nBBB 4000" | ./a.out
Before:
AAA 5000
BBB 4000
CCC 3000

After:
AAA 5000
AAA 4000
BBB 4000

Upvotes: 1

Arunmu
Arunmu

Reputation: 6901

Got your question after re-reading it :)

1. string str[10] as you mentioned does not create an array of 10 strings as strings are created on heap not on stack.

If you want to create an array of strings to put your data to..then it should be char * name[10]; and every time you read a line and get the first 3 characters you do new char[3] (you gotta store it in char * right ??).

Else, to be more efficient and depending upon your data, you can create a char arr[30] and do the alignment of 3 bytes for reading all by yourself.

Now, you can make your life much easier by using the STL containers..

vector < map < string,int > > arr; arr.reserve(10);

The advantages are many: 1) No memory management to be done by you.

2) Use of iterators to loop through.

3) And there wont be much difference in performance also if you compare it with my first method.

Upvotes: 0

hmjd
hmjd

Reputation: 122011

Use std::map to hold initials and associated score. For example:

int main()
{
    // Map is keyed by initials.
    std::map<std::string, int> scores;

    std::ifstream in("highscores.txt");
    if (in.is_open())
    {
        for (;;)
        {
            std::string line;
            std::getline(in, line);

            if (!in.good())
            {
                break;
            }

            const size_t space_idx = line.find(' ');
            if (std::string::npos != space_idx)
            {
                // The initials are everthing before the space.
                // Score everything after the space.
                scores[line.substr(0, space_idx)] =
                    atoi(line.substr(space_idx + 1).c_str());
            }
        }
        in.close();
    }

    // Check who has achieved required score.
    for (std::map<std::string, int>::iterator i = scores.begin();
         i != scores.end();
         i++)
    {
        if (i->second > 3500)
        {
            std::cout << i->first << "\n";
        }
    }
    return 0;
}

Upvotes: 1

Related Questions