使用 scanf 读入 std::string
Read into std::string using scanf
正如标题所说,我很好奇是否有办法使用 scanf 读取C++字符串。
我知道我可以读取每个字符并将其插入应得的字符串中,但我想要这样的东西:
string a;
scanf("%SOMETHING", &a);
gets()
也不起作用。
提前感谢!
这可以工作
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
gets()
的情况!使用gets()
总是错误的,它从 C11 中删除并从 C++14 中删除。
scanf()
不支持任何C++类。但是,您可以将scanf()
的结果存储到std::string
中:
编者注:以下代码是错误的,如注释中所述。查看Patato,Tom和Daniel Trugman的答案,了解正确的方法。
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
我不完全确定以scanf()
为单位指定缓冲区长度的方法以及参数的顺序(参数&str[0]
和str.size()
可能需要反转,并且我可能缺少格式字符串中的.
(。请注意,生成的std::string
将包含一个终止 null 字符,并且不会更改其大小。
当然,我只会使用if (std::cin >> str) { ... }
但这是一个不同的问题。
问题解释:
您可以使用 scanf
填充std::string
的基础缓冲区,但 (!( 托管std::string
对象将不知道更改。
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
输出:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
那么,这里发生了什么?对象std::string
不知道未通过导出的官方 API 执行的更改。
当我们通过底层缓冲区写入对象时,数据会发生变化,但字符串对象不知道这一点。
如果我们要将原始调用:token.reseve(64)
替换为 token.resize(64)
,一个更改托管字符串大小的调用,结果会有所不同:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
输出:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
再一次,结果是次优的。输出正确,但大小不正确。
溶液:
如果您确实要执行此操作,请按照以下步骤操作:
- 调用
resize
以确保缓冲区足够大。使用最大长度的#define
(请参阅步骤 2 以了解原因(:
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
- 使用
scanf
,同时使用"宽度修饰符"限制扫描字符串的大小并检查返回值(返回值是扫描的令牌数(:
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
- 以安全的方式将托管字符串大小重置为实际大小:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
下面的代码片段有效
string s(100, ' ');
scanf("%s", s.c_str());
这里没有长度限制的版本(在输入长度未知的情况下(。
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
出于性能考虑,getchar
肯定比scanf
快,std::string::reserve可以预先分配缓冲区以防止频繁的重新分配。
您可以构造一个适当大小的 std::string 并读取其底层字符存储:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
对 str.resize(( 的调用至关重要,否则 std::string 对象的长度将不会更新。感谢丹尼尔·特鲁格曼指出这一点。
(为字符串保留的大小与传递给scanf
的宽度没有一个错误,因为自 C++11 以来,保证 std::string 的字符数据后跟一个空终止符,因此有空间容纳 size+1 个字符。
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string
- cppcheck在const std::string[]上引发警告
- 将std::string传递给WriteConsole API
- 为std::string的某个索引赋值
- std中有类似find_last_of的函数,而string中没有
- 使用 std::string () const 函数启动线程或未来
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 如何更改大小(std::string)
- std::string 的对象真的可以移动吗?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 无法从 std::string 中提取C++ Unicode 符号
- std::string 构造函数如何处理固定大小的 char[]?
- 确切地说,如何解释 std::getline(stream, string) 函数在C++中填充的字符串
- C++:考虑C++ std::string 中双引号 (") 的字面含义,而不使用反斜杠 (\)
- 'int main(int, int, std::__cxx11::string, std::__cxx11::string)'只需要零或两个参数 [-Wmain]
- C++ 在列表和列表之间选择返回类型<<string>std::p air<string,string>>
- std::string, std::wstring and UTF8
- uan inplace replacement of std::string/std::wstring?
- #define Glib::string std:wstring
- 从 std::string & std::wstring 中获取 char 整数值
- BSTR转换为std::string(std::wstring),反之亦然