如何将一个 std::string 和一个 int 进行拼接操作

775

我以为这很简单,但它却有些困难。如果我有

std::string name = "John";
int age = 21;

如何将它们合并为一个字符串"John21"


1
Herb Sutter在这个主题上有一篇很好的文章:"Manor Farm的字符串格式化程序"。他涵盖了Boost::lexical_caststd::stringstreamstd::strstream(已弃用)以及sprintfsnprintf的比较。 - Fred Larson
让我补充一下:我尝试了 'str = "hi"; str += 5; cout << str;',但没有看到任何效果。结果发现这调用了 operator+=(char) 并添加了一个不可打印的字符。 - daveagp
25个回答

1347
按字母顺序排列:
std::string name = "John";
int age = 21;
std::string result;

// 1. with Boost
result = name + boost::lexical_cast<std::string>(age);

// 2. with C++11
result = name + std::to_string(age);

// 3. with FastFormat.Format
fastformat::fmt(result, "{0}{1}", name, age);

// 4. with FastFormat.Write
fastformat::write(result, name, age);

// 5. with the {fmt} library
result = fmt::format("{}{}", name, age);

// 6. with IOStreams
std::stringstream sstm;
sstm << name << age;
result = sstm.str();

// 7. with itoa
char numstr[21]; // enough to hold all numbers up to 64-bits
result = name + itoa(age, numstr, 10);

// 8. with sprintf
char numstr[21]; // enough to hold all numbers up to 64-bits
sprintf(numstr, "%d", age);
result = name + numstr;

// 9. with STLSoft's integer_to_string
char numstr[21]; // enough to hold all numbers up to 64-bits
result = name + stlsoft::integer_to_string(numstr, 21, age);

// 10. with STLSoft's winstl::int_to_string()
result = name + winstl::int_to_string(age);

// 11. With Poco NumberFormatter
result = name + Poco::NumberFormatter().format(age);

  1. 安全但慢,需要 Boost(仅头文件),支持大多数平台。
  2. 安全,需要 C++11(to_string() 已包含在 #include <string> 中)。
  3. 安全且快速,需要编译 FastFormat,支持大多数平台。
  4. (同上)
  5. 安全且快速,需要 the {fmt} library,可以编译或者使用头文件模式,支持大多数平台。
  6. 安全但慢且冗长,需要标准 C++ 的 #include <sstream>
  7. 脆弱(必须提供足够大的缓冲区),快速且冗长;itoa() 是非标准扩展,不保证适用于所有平台。
  8. 脆弱(必须提供足够大的缓冲区),快速且冗长,不需要任何东西(是标准 C++),支持所有平台。
  9. 脆弱(必须提供足够大的缓冲区),可能是最快的转换方法,冗长,需要 STLSoft(仅头文件),支持大多数平台。
  10. 相对安全(在单个语句中不使用多个 int_to_string() 调用),快速,需要 STLSoft(仅头文件),仅支持 Windows。
  11. 安全但慢,需要 Poco C++,支持大多数平台。

19
除了你提供的一个链接之外,你基于什么来发表你对表现的评论? - JamieH
5
这几乎是你整个声誉来自于一个答案!!你真是个幸运的家伙;) 我认为8是标准C(当然也包括C ++),但可能值得区分。 - noelicus
3
如果您使用Arduino,您也可以使用String(number) - Machado
2
我可能会添加snprintf,而不是sprintf。 - rjhcnf
1
当答案需要按字母顺序排列时,你就知道这是一个好答案了。=) - cs1349459
显示剩余4条评论

315

C++11中,你可以使用std::to_string,例如:

auto result = name + std::to_string( age );

same as before. - gumuruh

91
如果你有Boost库,你可以使用boost::lexical_cast<std::string>(age)将整数转换成字符串。
另一种方法是使用stringstreams。
std::stringstream ss;
ss << age;
std::cout << name << ss.str() << std::endl;

第三种方法是使用C库中的sprintfsnprintf

char buffer[128];
snprintf(buffer, sizeof(buffer), "%s%d", name.c_str(), age);
std::cout << buffer << std::endl;

其他海报建议使用 itoa。这不是标准函数,因此如果您使用它,则代码将无法移植。有些编译器不支持它。


请注意,snprintf不能保证字符串以空字符结尾。以下是确保其正常工作的一种方法:<pre> char buffer[128]; buffer[sizeof(buffer)-1] = '\0'; snprintf(buffer, sizeof(buffer)-1, "%s%d", name.c_str(), age); std::cout << buffer << std::endl; </pre> - Mr Fooz
我的倾向是从不使用sprintf,因为这可能导致缓冲区溢出。如果名称非常长,则上面的示例是一个很好的例子,使用sprintf将是不安全的。 - terson
请注意,snprintf与您提到的itoa一样,同样不是标准的C++。它来自于C99。 - Johannes Schaub - litb
@terson:我在答案中没有看到sprintf的出现,只有snprintf - David Foerster

84
#include <iostream>
#include <sstream>

std::ostringstream o;
o << name << age;
std::cout << o.str();

3
这很好,BYT头文件是 sstream。 - landerlyoung

59
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string itos(int i) // convert int to string
{
    stringstream s;
    s << i;
    return s.str();
}

以下内容来自http://www.research.att.com/~bs/bs_faq2.html,仅供参考。


但是s是一个栈变量,调用itoss的内存将被释放。s应该从堆中分配,并在使用后进行free,对吗? - kgbook
1
即使字符串对象已经超出作用域,按值返回也是可以的。https://dev59.com/W2865IYBdhLWcg3wHK3u#3977119 - kgbook
链接已损坏:“页面未找到”。 - Peter Mortensen

35

这是最简单的方法:

string s = name + std::to_string(age);

10
这是一个 C++11 之后的解决方案! - YamHon.CHAN

29
如果您使用的是C++11,您可以使用std::to_string
示例:
std::string name = "John";
int age = 21;

name += std::to_string(age);

std::cout << name;

输出:

John21

3
在VC++2010中,它将是name += std::to_string(static_cast<long long>(age));,你可以在此处查看链接 - neonmate
@neonmate 用 name += std::to_string(age + 0LL); 怎么样? - chux - Reinstate Monica
很棒的解决方案。谢谢。 - Shofiullah Babor

18

我认为最简单的答案是使用sprintf函数:

sprintf(outString,"%s%d",name,age);

1
snprintf 可能会有些棘手(主要是因为在某些情况下它可能不包含空字符),但我更喜欢这种方式,以避免 sprintf 缓冲区溢出的潜在问题。 - terson
3
当你在sprintf函数的格式字符串中使用%s来代替std::string类型时,某些编译版本可能会出现错误,但并非全部版本都会出错(这是未定义的行为),而且结果可能会受到字符串长度(SSO)的影响。因此,请使用.c_str()函数来解决该问题。 - MSalters
1
加上 sprintf 存在缓冲区溢出的风险,因此可能会导致代码注入。 - Jean-François Fabre

15
#include <string>
#include <sstream>
using namespace std;
string concatenate(std::string const& name, int i)
{
    stringstream s;
    s << name << i;
    return s.str();
}

11

在C++20中,您将能够执行以下操作:

auto result = std::format("{}{}", name, age);

同时,您可以使用{fmt}库std::format是基于该库的:

auto result = fmt::format("{}{}", name, age);

声明:本人是{fmt}库和C++20 std::format的作者。


(说明:该段内容为免责声明,作者为某个库和标准的创作者)

嗨@vitaut,fmt::format支持动态输入字符串吗?例如:fmt::format(variable,name,age) - Nguyen Manh
1
需要在 fmt 8.x 中使用 fmt::runtime 将动态格式字符串包装起来。 - vitaut
嗨@vitaut,如何让代码与数字配合工作:store.push_back(fmt::arg("1", "pi"));,这也会抛出异常fmt::vformat("{1} = {2}",store) - Nguyen Manh
嗨@vitaut,我能否使用fmt :: format与SYSTEMTIME t;一起使用? fmt :: format(“ {}”,t);请给我一个例子。谢谢! - Nguyen Manh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接