【问题标题】:Why does the function find of C++ stl string sometimes go wrong sometime go right?为什么C++ stl字符串的find函数有时会出错有时会正确?
【发布时间】:2020-09-06 14:18:14
【问题描述】:

我正在尝试在 Ubuntu 16.04(GCC&G++ 5.4 和 CMake 3.5.1)中使用 C++ 读取文件。 测试文件(名为 123.txt)只有一行字,就像这样:

Reprojection error: avg = 0.110258   max = 0.491361

我只想得到avg 错误和max 错误。我的方法是获取一条线并将它们放入std::string 并使用string::find。我的代码很简单,就像这样:

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

int main()
{
    FILE *fp = fopen("123.txt", "r");
    char tmp[60];
    string str;
    fgets(tmp, size_t(tmp), fp);
    fclose(fp);
    cout << tmp << endl;
    str = tmp;
    cout << str.size() << endl;
    size_t avg = str.find("avg");
    size_t max = str.find("max");
    cout << avg << endl;
    cout << max << endl;
}

我可以使用g++ 编译成功。但我遇到了一个奇怪的问题。

当我第一次在命令中运行它时,它会得到正确的结果:

Reprojection error: avg = 0.110258   max = 0.491361

52
20
37

如果我再次运行代码,有时会出错,就像这样:

p
2
18446744073709551615
18446744073709551615

“p”是乱码,不能在命令中正确显示。我不擅长 C++,对此感到困惑。有没有人可以说点什么?谢谢!

【问题讨论】:

  • 始终检查来自fopen("123.txt", "r") 调用的返回,以确保文件已成功打开。
  • 我非常怀疑size_t(tmp) 不是编译错误。
  • tmp 没有以零终止,因此您的程序具有未定义的行为。
  • @molbdnilo,令人惊讶的是它不是,它产生一个随机数,但没有警告也没有错误。
  • 您可能想改写memset(tmp, 0, sizeof(tmp)); fgets(tmp, sizeof(tmp)-2, fp);size_t(tmp) 所做的是将 tmp 开始的地址转换为 size_t 并将其传递给 fgets。该地址可能是一个非常大的数字,您可能会丢弃堆栈。

标签: c++ string stl ubuntu-16.04


【解决方案1】:

表达式

fgets(tmp, size_t(tmp), fp);

格式不正确,size_t(tmp) 将无法按预期工作,您需要sizeof(tmp)

您获得的52 值是因为fgets 消耗了\n 字符,这也被计算在内,实际上字符串中有51 字符以空格计数。

也就是说,在这种情况下,您可以使用更好的 C++ 工具来替换您正在使用的 C 工具,fopen 可以使用 fstream 替换库,fgets 可以替换为getline

类似:

#include <iostream>
#include <string>
#include <fstream>

int main()
{
    std::ifstream fp("123.txt"); //C++ filestream

    if (fp.is_open()) {//check for file opening errors

        std::string str;
        std::getline(fp, str); //C++ read from file
        fp.close();
        std::cout << str << std::endl;
        std::cout << str.size() << std::endl;
        size_t avg = str.find("avg");
        size_t max = str.find("max");
        std::cout << avg << std::endl;
        std::cout << max << std::endl;
    }
    else{
        std::cerr << "Couldn't open file";
    }
}

请注意,我不使用using namespace std;,这是有原因的,这不是一个好习惯,您可以查看this thread了解更多详细信息。

【讨论】:

  • 我多么讨厌 std::cout,在 99% 的情况下,我在编写 C++ 代码时仍然更喜欢 printf。 gist.github.com/bkaradzic/2e39896bc7d8c34e042b
  • @Konrad 这里的问题不是std::cout,它已经被OP使用,真正的问题是行读取和文件打开,尽管你的链接有一个有趣的观点,我有时,可以分享,在这种情况下我不同意,我相信std::getlinestd::ifstream实际上比他们的C同行更好。至于std::cout,真正的无偏分析:stackoverflow.com/a/20238349/6865932
  • 我知道。我只是想知道你的意见。我同意 std::getline 和 std::ifstream。我刚刚评论过,所以也许 OP 将来会更喜欢使用 printf,或者其他不需要使用 &lt;&lt; 运算符的东西,例如 spdlog ;),这样写和读起来会更容易、更舒服。其他语言通常提供像print 这样更好、更优雅的东西,例如生锈
  • @Konrad,这是一个很好的评论,我确实根据它改变了我的答案,我真的不想传递你不能混合 C 和 C++ 的信息,如果一个 C 工具对于给定任务更好,我鼓励使用它,printf 是一个非常好的例子,尽管我不会说 99% 的时间 :)
猜你喜欢
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 1970-01-01
  • 2012-09-29
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多