用scanf读取C++字符串

Vla*_*eru 20 c c++ string

正如标题所说,我很好奇是否有办法用scanf读取C++字符串.

我知道我可以读取每个char并将其插入到deserved字符串中,但我想要的是:

string a;
scanf("%SOMETHING", &a);
Run Code Online (Sandbox Code Playgroud)

gets() 也行不通.

提前致谢!

Pat*_*ato 28

这可以工作

char tmp[101];
scanf("%100s", tmp);
string a= tmp;
Run Code Online (Sandbox Code Playgroud)

  • 我不知道我可以使用char []初始化C++字符串..非常感谢!:) (5认同)
  • 它可以工作。它也可能有未定义的行为,因为这里的 `tmp` 的内容可能未初始化。切勿在不检查其返回值的情况下使用 `scanf`。 (5认同)

Die*_*ühl 17

没有任何情况gets()可以使用!使用它总是错误的gets(),它从C11中删除并从C++ 14中删除.

scanf()不支持任何C++类.但是,您可以将结果存储scanf()std::string:

std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我不能完全肯定,指定在缓冲区lenght的方式scanf()及顺序的参数去(有机会的参数&str[0]str.size()需要予以转回,我可能会丢失一个.格式字符串).请注意,结果std::string将包含终止空字符,并且不会更改其大小.

当然,我会使用,if (std::cin >> str) { ... }但这是一个不同的问题.

  • 对于`scanf`,`*`*supresses*赋值,它并不意味着将下一个参数作为字段宽度. (4认同)
  • “*我不完全确定在 scanf() 中指定缓冲区长度的方式以及参数的顺序*” - 简单:您根本无法做到。`scanf` 不支持长度参数。此代码不起作用。 (3认同)
  • 它应该是 `scanf("%99s", &str[0]))`,因为 `scanf()` 不允许在运行时使用 `*` 指定字段宽度,而 `printf()` 允许. 此外,`scanf()` 用`0` 终止符对读入的内容进行后缀,因此需要读取比`str` 大小少的几分之一。 (2认同)

Dan*_*man 5

问题解释:

std::string您可以填充using的底层缓冲区scanf,但是(!)托管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;
Run Code Online (Sandbox Code Playgroud)

输出:

Managed string:  (size = 0)
Underlying buffer: Daniel (size = 6)
Run Code Online (Sandbox Code Playgroud)

那么,这里发生了什么? 该对象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;
Run Code Online (Sandbox Code Playgroud)

输出:

Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Run Code Online (Sandbox Code Playgroud)

结果再次不是最优的。输出是正确的,但大小不正确。

解决方案:

如果您确实想这样做,请按照下列步骤操作:

  1. 致电resize以确保您的缓冲区足够大。使用 a#define作为最大长度(请参阅步骤 2 以了解原因):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Run Code Online (Sandbox Code Playgroud)
  1. 使用scanfwhile 使用“宽度修饰符”限制扫描字符串的大小并检查返回值(返回值是扫描的标记数量):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Run Code Online (Sandbox Code Playgroud)
  1. 以安全的方式将托管字符串大小重置为实际大小:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
Run Code Online (Sandbox Code Playgroud)