Reputation: 143
im currently setting up the highscore-part for a game and I have a very weird problem because of the weird behaviour of the std::sort function.
Im doing the whole thing in RAD Studio 10.2 (Embarcadero IDE) in C++.
So he is my code:
std::string Line;
int count = 0;
int i = 0;
ifstream File("Highscore.txt");
if(File.is_open())
{
while(getline(File, Line))
{
count += 1;
}
File.close();
}
ifstream ReadFile("Highscore.txt");
if(ReadFile.is_open())
{
string *scores = NULL;
scores = new string[count];
while(getline(ReadFile, Line))
{
scores[i] = Line;
i += 1;
}
ReadFile.close();
std::sort(scores, (scores+count));
UnicodeString Uscores1 = scores[0].c_str();
UnicodeString Uscores2 = scores[1].c_str();
UnicodeString Uscores3 = scores[2].c_str();
UnicodeString Uscores4 = scores[3].c_str();
UnicodeString Uscores5 = scores[4].c_str();
LScore1->Caption = Uscores1;
LScore2->Caption = Uscores2;
LScore3->Caption = Uscores3;
LScore4->Caption = Uscores4;
LScore5->Caption = Uscores5;
}
I get no errors from the compiler/linker and everything work should fine. The string array gets filled correctly and so on.
But its not sorting.
To show the problem to you I made a screenshot - on the left you can see the txtfile with the scores; on the right you can see the output after the sorting algorithm:
My question now is why this is happening?
Thanks for you help
Upvotes: 0
Views: 309
Reputation: 6240
My question now is why this is happening?
Because your scores are compared as string
s and not as int
s. Because of that "3" is greater that "25"
std::cout << std::boolalpha << (std::string("3") > std::string("25")) << std::endl; // true
Luckily you can pass a custom comparator (or lambda) to the std::sort
to make it behave just as you want:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
const int count = 5;
std::string scores[count] = { "35","25","3","4","5" };
// TWEAKED SORT
std::sort(scores, scores + count, [](std::string const &s1, std::string const &s2)
{
return std::stoi(s2) < std::stoi(s1);
});
// TEST
for (auto const &s : scores)
{
std::cout << s << std::endl;
}
}
The compared string
s in the above example are converted to int
s and then compared, resulting in the desired sorting order.
35
25
5
4
3
Please note that I do not agree with the rest of your code and I think you should rethink the implementation, as it would be much easier, safer and more efficient to use std::vector<std::string>
for your task.
Upvotes: 0
Reputation: 17036
Welcome to C++. Since you want to list numbers by rank, read them as int
not string
. Forget about operator new
. You will not need it for years, if ever. Use standard containers like std::vector
, which take care of the memory allocation and de-allocation transparently.
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
int main() {
using namespace std;
vector<int> scores;
{
ifstream inp("Highscore.txt");
int next;
while (inp >> next) {
scores.push_back(next);
}
}
sort(scores.begin(), scores.end());
for (auto s : scores) {
cout << s << '\n';
}
return 0;
}
Upvotes: 3
Reputation: 5449
How about something like:
int i = 0;
int * scoresInteger = NULL;
scoresInteger = new int[count];
for(i = 0; i < count; i++)
{
scoresInteger[i] = std::stoi(scores[i]);
}
std::sort(scoresInteger, scoresInteger + count);
If you need to, you can convert the integers back into strings using targetStrings[i] = std::to_string(scoresInteger[i])
.
string * targetScores = NULL;
targetScores = new std::string[count];
for(i = 0; i < count; i++)
{
targetScores[i] = std::to_string(scoresInteger[i]);
}
delete [] scoresInteger;
scoresInteger = NULL;
Don't forget to delete [] targetScores
later.
Upvotes: 0