【问题标题】:C++ std::sort function gets not finished?C++ std::sort 函数没有完成?
【发布时间】:2018-10-03 14:08:54
【问题描述】:

我目前正在为游戏设置高分部分,但由于 std::sort 函数的奇怪行为,我遇到了一个非常奇怪的问题。

我在 C++ 中的 RAD Studio 10.2 (Embarcadero IDE) 中完成所有工作。

所以他是我的代码:

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;

}

编译器/链接器没有错误,一切正常。 字符串数组被正确填充等等。

但它没有排序。

为了给你看问题,我做了一个截图——在左边你可以看到带有分数的txt文件;右边可以看到排序算法后的输出:

我现在的问题是为什么会这样?

感谢您的帮助

【问题讨论】:

  • 它确实排序。如果你想按数字排序,你应该使用数字类型。
  • 如果以前没有人告诉过您,请查看我们的页面minimal complete examples。不要发布数据的屏幕截图,将其硬编码到您的示例中。
  • 我错了,在发帖几秒后删除了我的评论。
  • 当我在示例中的 txtfile 中有 5 个分数并输出分数 [4] 时,输出为 5 = 我的 txtfile 中的第五项。
  • @SamyDressel 您有 5 个分数和 2 个“空”行,它们都是 std::string 的有效值。检查count的值

标签: c++ arrays string sorting


【解决方案1】:

我现在的问题是为什么会这样?

因为您的分数是以strings 而不是ints 进行比较的。因为“3”大于“25”

std::cout << std::boolalpha << (std::string("3") > std::string("25")) << std::endl; // true

幸运的是,您可以将自定义比较器(或 lambda)传递给 std::sort 以使其行为符合您的要求:

#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;
    }
}

上例中比较的strings 转换为ints 再比较,得到desired sorting order

35
25
5
4
3

请注意,我不同意你的其余代码,我认为你应该重新考虑实现,因为使用std::vector&lt;std::string&gt; 来完成你的任务会更容易、更安全、更高效。

【讨论】:

  • asked why Jive downvoted your answer (虽然我不知道你为什么认为 Jive 是负责任的;他的回答同样可能引起了对这个问题的关注,并且随后的访问者被否决了),我至少可以给你投反对票的一个原因(我没有,但这是一个足够大的错误,有些人可能会)。在您的字符串比较演示中,您比较了一对 C 风格的字符串,而不是 std::string,并且该比较的结果并不总是 true...
  • ...因为 C 风格的字符串比较指针地址(从技术上讲,比较不是都指向同一个数组内的指针是未定义的行为 IIRC,但实际上,它可以在所有具有平坦内存的机器上正常工作楷模)。因此,如果支持"3" 的数据存储在支持"25" 的数据之前的二进制文件中,则结果为假,如果存储在之后,则为真(这可能因编译器而异,甚至使用相同的重新编译编译器)。您需要 std::string("3") &gt; "25" 或(使用 C++14+ 和 using namespace std::literals"3"s &gt; "25"s 才能按预期工作。
  • @ShadowRanger 很公平,有效的观点,我更正了,谢谢。在没有解释的情况下值得一票否决吗?我个人会留下评论,让发帖人回应。根据谁投反对票,假设我有无可辩驳的证据是谁做的。
  • 是的,我不相信在不解释的情况下对错误投反对票(总的垃圾答案,与其说是不准确不如令人困惑,在没有解释的情况下投反对票,我会在不解释的情况下投反对票其他人解释了他们的反对意见,我同意),当我反对并解释时,我会在问题解决后撤回他们(如果我稍后注意到),但是是的,没有理由为孤立的、硬的-发现错误。也就是说,我刚刚习惯了偶尔出现的虚假的、无法解释的反对票;我重新审视自己,然后耸耸肩继续前进。
【解决方案2】:

欢迎使用 C++。由于您想按等级列出数字,请将它们读作int 而不是string。忘记运营商new。如果有的话,你几年都不需要它。使用像 std::vector 这样的标准容器,它可以透明地处理内存分配和解除分配。

#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;
}

【讨论】:

  • 你能告诉我你拒绝我的答案的原因吗?
  • 谢谢你——这对我帮助很大。它给了我一个了解 C++ 和容器的理由:D 在我的大学用 C++ 开发软件的一年模块中,没有人提到过向量之类的东西。这很可悲:D
  • 确实很悲伤,但很典型。几十年来一直致力于使 C++ 易于实现。教导学生做事的方式不仅容易出错,而且在现实世界的代码审查中是完全不可接受的。 youtu.be/YnWhqhNdYyk
【解决方案3】:

怎么样:

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);

如果需要,您可以使用 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;

以后别忘了delete [] targetScores

【讨论】:

  • delete 数组的内存,因为您正在分配它。复制这段代码会导致内存泄漏。
  • @PetarVelev 或者你知道...使用 std::vector
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多