Я сейчас настраиваю часть рекордов для игры, и у меня очень странная проблема из-за странного поведения функции std :: sort.
Я делаю все это в RAD Studio 10.2 (Embarcadero IDE) на C++.
Итак, это мой код:
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;
}
Я не получаю ошибок от компилятора / компоновщика, и все должно работать нормально. Строковый массив заполняется правильно и так далее.
Но это не сортировка.
Чтобы показать вам проблему, я сделал снимок экрана - слева вы видите текстовый файл с оценками; справа вы можете увидеть результат после алгоритма сортировки:
Теперь у меня вопрос: почему это происходит?
Спасибо за помощь
Если вам этого раньше не говорили, загляните на нашу страницу на минимальные полные примеры. Не публикуйте снимок экрана с данными, жестко закодируйте его в своем примере.
Я ошибся и удалил свой комментарий через несколько секунд после публикации.
Когда у меня, как в примере, 5 оценок в моем txt-файле и результаты вывода [4], на выходе получается 5 = пятый элемент в моем txt-файле.
@SamyDressel у вас есть 5 оценок и 2 «пустые» строки, которые являются действительными значениями для std::string. Проверить значение count





Как насчет чего-то вроде:
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
My question now is why this is happening?
Потому что ваши оценки сравниваются как string, а не как int. Из-за этого «3» больше, чем «25».
std::cout << std::boolalpha << (std::string("3") > std::string("25")) << std::endl; // true
К счастью, вы можете передать 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;
}
}
Сравниваемые string в приведенном выше примере преобразуются в int, а затем сравниваются, что дает желаемый порядок сортировки.
35
25
5
4
3
Обратите внимание, что я не согласен с остальной частью вашего кода, и я думаю, вам следует переосмыслить реализацию, так как было бы намного проще, безопаснее и эффективнее использовать std::vector<std::string> для вашей задачи.
Вы спросил, почему Jive отклонил ваш ответ (хотя я понятия не имею, почему вы считаете, что Джайв виноват; с равной вероятностью его ответ привлек внимание к этому вопросу, и последующий посетитель проголосовал против), и я могу назвать вам по крайней мере одну причину для отрицательного голоса (я не , но это достаточно большая ошибка, и некоторые могут). В вашей демонстрации сравнения строк вы сравнивали пару строк в стиле C, а не std::string, и результат этого сравнения не всегда будет true ...
… Потому что строки в стиле C сравнивают адреса указателей (технически сравнение указателей, которые не указывают на один и тот же массив, является неопределенным поведением IIRC, но на практике оно работает предсказуемо на всех машинах с плоскими моделями памяти). Таким образом, если данные, поддерживающие "3", хранятся в двоичном файле до данных, поддерживающих "25", то результат будет ложным, а если он будет сохранен после, он верен (и это может варьироваться между компиляторами или даже перекомпилировать с одним и тем же компилятором). Для нормальной работы вам понадобится std::string("3") > "25" или (с C++ 14 + и using namespace std::literals) "3"s > "25"s.
@ShadowRanger Достаточно честно, правильная точка зрения, и я исправил ее, спасибо. Стоит ли отрицательный голос без объяснения причин? Я лично оставил бы комментарий и дал бы автору ответить. Что касается того, кто проголосовал против, допустим, у меня есть неопровержимые доказательства того, кто это сделал.
Да, я не верю в отрицательное голосование за ошибки без объяснения (полный мусор ответы, которые не столько неточны, сколько сбивают с толку, получайте отрицательные голоса без объяснения, и я буду отрицать, не объясняя, если кто-то другой объяснил свой отрицательный голос, и я согласен) , и когда я сделаю отрицательный голос и объясню, я отзову их, когда проблема будет исправлена (если я заметлю это позже), но да, нет никаких оснований для тихого отрицательного голоса для отдельных, трудно обнаруживаемых ошибок. Тем не менее, я только что привык к случайным необъяснимым ложным голосам против; Я перепроверяю себя, затем пожимаю плечами и продолжаю.
Добро пожаловать в 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
Это действительно сортировка. Если вы хотите выполнить числовую сортировку, вам следует использовать числовой тип.