关于c ++:在fscanf中直接将char *转换为std :: string

Directly convert char* to std::string inside fscanf

当使用fscanf读取字符串并将其存储到字符串变量中时,fscanf期望将char*作为格式字符串之后的参数,即,按照我所知,这应该是这样 :

1
2
3
char str[];
std::fscanf(filepointer,"%s
"
,str);

如果我使用的是std::string str而不是char str[],我会收到一个-Wformat警告(很明显),并且该程序因Segnetation fault而崩溃(我不知道为什么,但是我并不感到惊讶)。 除了修复段错误之外,我还可以正确执行此操作,即不接收-Wformat警告。

有没有办法将" x2>转换为std::string进行"内联",即在fscanf的参数列表中,还是我必须创建一个临时的char*变量来存储数据并将其转换为 之后std::string(例如,如此处所述,我看不到将这种方法应用于我的情况的方法)。


从C ++ 17开始,您可以:

1
2
3
4
std::string str(, 0);
fscanf(filepointer,"%s
"
, str.data());
str.resize(strlen(str.c_str()));

但是你不应该。

首先,它没有按照您想要的去做。如果您有类似"Tom Jerry
"
的输入行,它将仅读取"Tom",更糟糕的是,下次您从文件中读取时,它将尝试读取"Jerry"。您应该真正使用fgets()std::istream::getline(),或者更好的是std::getline(file, str)

其次,'\0'char()是C ++字符串中的有效字符。如果您阅读"Tom\0Jerry
"
,则代码将设法读取的实际字符串将包含"Tom\0Jerry",这可能是有效的结果,但是由于该resize(strlen(str.c_str())),它会将其剪切为"Tom"。您可以通过创造性地使用%n格式说明符来缓解这种情况,但是为什么首先会使您的生活复杂化?

第三,C ++字符串输入例程可以在必要时调整字符串的大小。在C函数中,您需要指定一个字符串大小限制,该限制通常是任意的。如果您对格式说明符草率(例如在示例中),这可能导致缓冲区溢出,但是如果您不能正确处理截断的输入的特殊情况,则可能导致逻辑错误。

因此,只需将std::getline(file, str)与C ++流输入一起使用,就可以避免所有这些情况。


可以将std::stringstd::scanf()一起使用,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdlib>   // EXIT_FAILURE
#include <cstdio>    // std::scanf()
#include <cstring>   // std::strlen()
#include <string>
#include <iostream>

int main()
{
    std::string foo(40, '\0');  // fill the string with 40 0s
                                // for pre C++11 please make it 41
    int length = 0;
    if (std::scanf("%39s%n", &foo[0], &length) != 1) {
        std::cerr <<"Input error :(

"
;
        return EXIT_FAILURE;
    }

    foo.resize(length);  // let foo know its own length ^^
    std::cout << foo.length() <<" chars:" << foo << '
'
;
}


如果使用的是C ++,则不应使用C或C样式的函数。尤其是像std::fscanf这样的功能,它会执行不受保护的写入。这是在C ++中正确地从文件读取数据到std::string的方法:在C ++中使用ifstream逐行读取文件


正如您在参考书中所读到的,它应该是:

1
2
3
char str[];
fscanf(filepointer,"%s
"
, str);

因为str是一个数组。在什么是数组衰减中阅读更多内容。

c_str()data(),它们可以为您提供std::string的C字符串。但是,这些函数返回一个常量指针,因此不能在fscanf()中使用(这是一个来自C的函数,因此可以处理C字符串)。

注意:在C ++ 17中,data()具有一个重载,该重载返回一个非恒定指针,因此可以用于内联用法,如下所示:

1
2
3
4
std::string str(10, '\0');               // a string of size 10, null terminated
fscanf(filepointer,"%9s
"
, str.data());
str.resize(strlen(str.data()));          // so that 'str.size()' is correct

Live Demo

但是您实际上应该使用C ++流,例如std::cin而不是C IO函数。

例:

1
2
std::string str;
std::cin >> str;