带有%s和std::string的sprintf会发出胡言乱语

sprintf with %s and std::string gives gibberish

本文关键字:胡言乱语 sprintf string std 带有      更新时间:2023-10-16

在以下代码中:

#include <string>
using namespace std;
int main(){
    char command[300];
    string stringz = "mystringy";
    sprintf(command,"echo "something with a string %s" ", stringz);
    system(command);
    return 0;
}

为什么输出

something with a string 8�

而不是预期的

something with a string mystringy

一个愚蠢的问题,但我找不到答案。

printf的"%s"修饰符采用char*,而不是std::string

你可以写:

sprintf(command,"echo "something with a string %s" ", stringz.c_str());

它为std::string的内容提供了一个const char*。这显示了sprintf的一个主要弱点——没有类型检查!

sprintf格式的%s需要一个C字符串,这是一个以0结尾的char数组,而不是std::string

stringz.c_str()和由于C++11&stringz[0]stringz.data()是获取std::string所持有的C字符串的几种方法。

要添加Deduplicator答案,请尝试放置

sprintf(command,"echo "something with a string %s" ", stringz.c_str());

你应该做好准备。

这是因为sprintf需要一个char *作为扩展%s令牌的参数。它会像一样工作

sprintf(command,"echo "something with a string %s" ", stringz.c_str());

它将字符串的"char *"版本传递给sprintf

它之所以显示这些奇怪的字符,是因为整个std::string对象被复制到sprintf的堆栈帧中。然后,接受可变数量参数的sprintf会查看自己的堆栈空间,并假设它要找到的是char *,但实际上是一些垃圾,这些垃圾是将字符串数据重新解释为char *产生的,当它被取消引用时,它会进入该序列。如果你运气不好的话,还不如分手。

首先不应该使用sprintf。这是C++,而不是C。std::string以一种非常自然的方式支持级联,使用+运算符,就像在其他一些编程语言中一样:

#include <string>
int main(){
    std::string stringz = "mystringy";
    std::string command = "echo "something with a string " + stringz + "" ";
    system(command.c_str());
    return 0;
}

如果您坚持使用char-像sprintf这样的数组函数,请使用stringz.c_str()。事实上,这也是system的要求。但请注意,我的示例是如何仅在最后可能的情况下转换字符串的。

您可以使用:

sprintf(command,"echo "something with a string %s" ", stringz.c_str());

注意,%s采用C字符串,而不是std::string

更好地使用iostreams:

string stringDemo("MYSTRING");
std::cout << stringDemo << "n";