1

我不明白如何sscanf()在 C++ 中使用来读取文件。

我正在开发一个程序,它从一个文件中读取三个跑步者的名字,以及他们的五个最佳时间。我想平均每个跑步者的时间,并说出谁是最好的跑步者。我在使用文件 IO 时遇到了绝对的困难。

Cplusplus.com 帮助了一些人,但并没有真正说明如何读取、将 char*(名称)与浮点数(时间)分开等。在其他地方,我无法逃避过于技术性的行话和解释。

一位朋友向我展示了这段代码片段来解释。

while(file>>str) {
    sscanf (str.c_str(),"%d",&myint);
}    

有人介意向我解释它是如何阅读的吗?

4

5 回答 5

5

使用sscanf()被认为有点老派,但可能非常有益并且值得掌握。我认为您正在寻找类似的东西:

sscanf(input, "%s %f", name, &time);

input文件中的一行在哪里。一些基础知识是%s针对基本字符串和%f浮点数的。

享受编程的开始;随着您获得经验,它只会变得更好。

于 2012-08-11T00:17:08.987 回答
1

scanf 如果与 printf 相反。

“sscanf”中的第一个“s”表示它扫描一个字符串。“fscanf”扫描文件,“scanf”扫描标准输入。

格式与 printf 相同。

如果将sprintf(s, "%d x", 5)“5 x”打印到 s中,sscanf("5 x", "%d x", &n)则将 5 放入 n 中。它总是与 printf 相反。

例外是%s%s在 printf 中打印每个字符串。printf("%s", str); 将打印 str,无论 str 中有什么。在scanf中,%s是一个词。单词是没有空格的东西。所以读a%s只会读一个词。

sscanf(str, "%d", &a);表示 str 的格式为“%d”(单个十进制数),并且您正在将此数字转换为 a (因为 &a 是第二个参数)。

举个例子

int a,b,c,d;
sscanf("10,20,30,40", "%d,%d,%d,%d", &a, &b, &c, &d);

将导致 a = 10, b = 20, c= 30, d = 40。每个 %d 将读取到下一个参数,并且每个将读取一个十进制数。

于 2012-08-11T00:49:52.107 回答
1

总体而言,该sscanf()函数用于在描述要在字符串中找到的值的格式字符串的指导下,将(C)字符串转换为程序变量中的一系列值。

剖析引用的代码:

while (file >> str)
{
    sscanf(str.c_str(), "%d", &myint);
}

我们可以假设这file是一个输入流并且str是一个字符串。循环在每次迭代时将输入中的while一个“单词”读取到字符串中,其中“单词”是一系列非空白字符,可能前面有一系列空白字符。

示例中的sscanf()语句具有三个参数和一个被忽略的返回值(后果自负)。第一个参数是 C 风格的字符串,因此读取的单词通过str.c_str()调用转换为 C 字符串。第二个参数是一个格式字符串,它告诉字符串sscanf()中期望的内容。在这种情况下,%d转换说明符指示十进制整数。第三个参数是指向相应类型的指针,转换后的值将存储在其中。通常,一个格式字符串可以包含多个转换说明符,并且每个分配的转换说明符都需要一个指针参数(您可以通过抑制分配来跳过数据)。

from的返回值sscanf()是成功分配转换的次数。在这种情况下,您应该检查是否完成了一次转换。

这是一个基于您的示例的工作微型程序:

#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>

static void read_stuff(std::istream &file)
{
    std::string str;
    while (file >> str)
    {
        std::cout << "IN: <<" << str << ">>" << std::endl;
        int myint;
        if (sscanf(str.c_str(), "%d", &myint) != 1)
        {
            std::cerr << "Oops: sscanf() failed" << std::endl;
            std::exit(1);
        }
        std::cout << "GOT: " << myint << std::endl;
    }
}

int main()
{
    read_stuff(std::cin);
    return(0);
}

假设您键入输入行:123 234 345 abc. 然后程序产生:

IN: <<123>>
GOT: 123
IN: <<234>>
GOT: 234
IN: <<345>>
GOT: 345
IN: <<abc>>
Oops: sscanf() failed

请注意,如果您正在处理的名称包含名字和姓氏,可能带有中间名首字母和 5 个数字(都在一行上),那么您可能需要一个不同的过程。您可能会使用getline()读取整行,然后尝试使用sscanf()(或者您可能会使用 astringstream来代替)解析它。当然,您必须在线处理少于 5 个数字。I/O 总是很棘手,尤其是当您也必须处理错误数据时(并且生产质量代码总是必须准备好处理错误数据)。

于 2012-08-11T00:55:41.720 回答
1

基本上,您在 sscanf 函数的第二个参数中指定字符串格式,用占位符替换要解析的变量。

比如说,您知道您的文件包含以下几行:

Father bought 8 bottles of rum on day 1.  
Father bought 11 bottles of rum on day 2.  
Father bought 5 bottles of rum on day 3.  
Father bought 19 bottles of rum on day 4. 

除了每天的瓶子数量之外,您不关心该字符串中的任何内容。您修复不更改的部分,即“父亲当天买了瓶朗姆酒”,并为要从字符串中提取的部分指定占位符。

您的代码将如下所示:

int nDay, nBottles;
sscanf(str.c_str(), "Father bought %d bottles of rum on day %d", &nBottles, &nDay);
cout << "Day: " << nDay << ", bottles: " << nBottles << endl;

% 之后的符号仅指定该部分将被解析为的变量类型。d这里的意思是十进制。

于 2012-08-11T00:57:33.963 回答
0

只需使用sscanf(str.c_str(), "%d", &myint)而不是sscanf(str, "%d", &myint).

我看到其他人解释过sscanf,但我认为你的问题有点不同。

sscanf是一个 C 函数,但您可以在 C++ 中使用它,因为 C++ 包含 C。sscanf基本上需要一个字符串,按照您将显示的方式对其进行划分,然后将这些部分分配给变量。但是在C中并没有这样的东西string。正因为如此,sscanf它的参数char*就是char pointer与它基本做同样的工作string

在 C++ 中,您应该使用c_str()函数转换stringchar pointer.

于 2013-11-16T19:47:25.257 回答