【问题标题】:How does the C++ sort function work when using a custom comparator?使用自定义比较器时,C++ 排序功能如何工作?
【发布时间】:2020-10-22 12:10:59
【问题描述】:

免责声明:自从我编写任何 C/C++ 以来,已经过去了大约 5 年。我通常用python编写代码。

我有一个字符串向量,我想以某种方式(按长度)排序,所以我编写了自己的比较器函数:

bool sortSubstrs(string a, string b)
{
    if (a.length() > b.length()) { return true; }
    else { return false; }
}

我最初有一个错误,所以我输入了一个打印语句(是的,我知道我应该使用 ide,但我很懒,只使用 vim):

bool sortSubstrs(string a, string b)
{
    cout << a.length() + " " + b.length() << endl;
    if (a.length() > b.length()) { return true; }
    else { return false; }
}

我预计它会打印 ab 的长度,但它会打印一堆看似“随机”的东西,来自堆栈的早期(我猜)。

这是一个完整的、最小的重现示例:

sort_words.cpp:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

vector<string> to_vector(char* filename) // read from file and put into a vector
{
    vector<string> karray;
    FILE *ifile = fopen(filename, "r");
    int ch;
    int idx = 0;
    string s1 = "";

    while( EOF != (ch=getc(ifile)))
    {
        if ('\n' == ch)
        {
            karray.push_back(s1);
            s1 = "";
        } else {
            string s2(1,ch);
            s1 = s1 + s2;
        }
    }
    fclose(ifile);
    return karray;
}

bool sortSubstrs(string a, string b)
{
    cout << a.length() + " " + b.length() << endl;
    if (a.length() > b.length()) { return true;}
    else { return false;}
}

void sort_words(char* filename){
    vector<string> wordArray;
    wordArray = to_vector(filename);

    sort(wordArray.begin(), wordArray.end(), sortSubstrs);
    wordArray.erase(unique(wordArray.begin(), wordArray.end()), wordArray.end());

    //print out the sorted array
    for (unsigned n=0; n < wordArray.size(); n++) {cout << wordArray.at(n) << "\n";}
}

int main(int argc, char *argv[])
{
    if (FILE *ifile = fopen(argv[1], "r")){
        fclose(ifile);
        sort_words(argv[1]);
    } else {
        cout << "file doesn't exist" << endl;
        return 1;
    }
}

还有一个 input.txt 文件:

sh
zsh
bash

使用 g++(在 centos7 上运行 4.8.5)编译没有错误: g++ sort_words.cpp -o sort_words

运行./sort_words input.txt 会给出以下输出:

ile doesn't exist
e doesn't exist
bash
zsh
sh

我认为可能存在/可读文件的主要签入以某种方式搞砸了,所以我重写了它:

int main(int argc, char *argv[]) { sort_words(argv[1] }

但是使用相同的输入文件重新编译和运行会得到这个输出:

ector::_M_insert_aux
tor::_M_insert_aux
bash
zsh
sh

使用更长的输入文件只会以类似的模式打印出更多这些“损坏”的字符串。那么,到底发生了什么?我的记忆有点模糊,但我知道大多数排序算法都是递归的(看起来 C++ 使用混合递归排序方法:Wikipedia: sort (C++)),但无论如何递归都发生在 within排序函数和(我认为)排序函数无法访问内存中的其他函数。

使用自定义比较器是否会显着改变排序功能的工作方式?我的理解是,在 sort 函数内部,它只会调用自定义函数而不是默认的 > 或

【问题讨论】:

  • 离题,但您的比较器可能会占用const string&amp;
  • 顺便说一句,你为什么使用fopen()getc(),而不是使用std::ifstreamstd::getline()?此外,您的比较器应该通过 const 引用而不是值来获取 strings。
  • @RemyLebeau 老实说,我真的很生疏。 8 年前我在大学上过一门 C++ 课程,然后很快就忘记了一切,所以我现在只是在拼凑一些东西。不过感谢您的建议!
  • sortSubstrs 可以更经济地编码为return a.length() &gt; b.length();

标签: c++ string sorting recursion vector


【解决方案1】:

这与排序无关。这一行是错误的:

cout << a.length() + " " + b.length() << endl;

应该是:

 cout << a.length() << " " << b.length() << endl;

作为 C++ 中与 C 的遗物和兼容性,字符串字面量具有 C 数组类型,即 " " 的类型为 char[2]。再次作为 C relic C 数组类型衰减为指针。所以a.length() + " " 只是指针运算。不是你想要的。

出于好奇,当我使用 + 时会发生什么?

指针算术。您将指针从" " 的开头移动 a.length() 元素。使指针 1 超出原始数组会导致未定义行为。

这里有一个更好的例子来说明:

const char str[7] = "abcdef";

str + 2
// is equivalent with:
&str[0] + 2
// and is a pointer pointing to the 'c' letter from the array

str + 10
// is equivalent with:
&str[0] + 10
// and is a pointer pointing outside the array
// this is Undefined Behavior

【讨论】:

  • 我不敢相信我花了这么长时间!谢谢你抓住那个。出于好奇,当我使用 + 时会发生什么?
  • 抱歉,我一定错过了您的编辑 - 感谢您的解释。有趣的是,当我第一次看到输出时,我认为这一定是指针问题,但设法说服自己它一定是别的东西......
  • @asdf 指针很有趣 :)。添加了一个更好的示例来说明指针算法的含义。
猜你喜欢
  • 2020-11-20
  • 2011-11-01
  • 2022-01-05
  • 2018-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-13
  • 1970-01-01
相关资源
最近更新 更多