Samy Dressel
Samy Dressel

Reputation: 143

C++ std::sort function gets not finished?

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:

enter image description here

My question now is why this is happening?

Thanks for you help

Upvotes: 0

Views: 309

Answers (3)

Killzone Kid
Killzone Kid

Reputation: 6240

My question now is why this is happening?

Because your scores are compared as strings and not as ints. 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 strings in the above example are converted to ints 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

Jive Dadson
Jive Dadson

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

Tripp Kinetics
Tripp Kinetics

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

Related Questions