如何从单个字符创建一个字符串?

178

我有一个单个的 char 值,现在需要将它转换成 std::string。请问怎么做?

我知道如何反过来,从 std::string 对象中获取 char: 只需要在适当的位置对字符串进行索引即可。例如: str[0] 将检索字符串中的第一个字符。

但是如何进行相反的操作呢?我想要这样的效果:

char c = 34;
std::string s(c);

...但这并不起作用(字符串始终为空)。

9个回答

255
您可以使用以下任何一种或全部方式来从单个字符创建一个std::string

  • std::string s(1, c);
    
    std::cout << s << std::endl;
    
  • std::string s{c};
    
    std::cout << s << std::endl;
    
  • std::string s;
    s.push_back(c);
    
    std::cout << s << std::endl;
    

17
最简单的方法是: string s = string() + 'a'; 这行代码的意思是创建一个空字符串,并在其后面添加字符'a'。 - doctorram
16
更短的方法是 string s = {c};string s({c});string s{c};。链接 https://ideone.com/eFZTFY - Remy Lebeau
我认为@RemyLebeau的解决方案在你需要创建一个字符串并将其作为参数传递给函数的情况下,在一行中完成最佳。 - Nicholas Obert

100

std::string有一个接受数字和字符的构造函数。该字符将重复给定次数。因此,您应该使用:

std::string str(1, ch);

20
这是正确的答案。但我不喜欢这个构造函数的原因是我不常使用它,以至于记不住参数的顺序。如果参数位置颠倒了,它仍然可以编译通过。 - Fred Larson
3
@Fred Larson,当然,这正是我尝试这种解决方案时所发生的事情。 - pythonic metaphor
4
对于一个字符数组,@Maxim,请使用带指针和字符数的构造函数。在你的情况下,使用std::string(x, 3) - Rob Kennedy
1
嗯,是的,@Maxim。这个类提供了多个构造函数。我的观点是我们应该根据任务选择正确的构造函数。 - Rob Kennedy
4
参数的顺序很糟糕。为什么不允许一个字符和没有计数参数呢? - Jonny
显示剩余5条评论

12

你可以尝试使用stringstream。以下是一个示例:

#include <sstream>
#include <string>

std::stringstream ss;
std::string target;
char mychar = 'a';
ss << mychar;
ss >> target;

这个解决方案是可行的,但是使用stringstream(<sstream>)并不是必要的,因为它会在项目中包含整个库,从而减慢编译过程。尽量避免将不必要的依赖项包含到您的项目中。 - Cristian
我认为那是一种过于复杂而非“简单”的解决方案。话虽如此,问题本身可能过于简化,在其他情况下使用字符串流可能更合适(当其他类型要插入到该字符串中时)。 - Clifford

11

这个解决方案将适用于您拥有的任何char变量数量:

char c1 = 'z';
char c2 = 'w';
std::string s1{c1};
std::string s12{c1, c2};

4

您仍然可以使用接受两个迭代器的字符串构造函数:

char c = 'x';
std::string(&c, &c + 1);

更新:

詹姆斯和GMan提出了一个好问题。我在免费下载的Derek M. Jones的《新C标准》中搜索“指针超过”时,第一个命中的结果是:

如果表达式P指向数组对象的一个元素,而表达式Q指向同一数组对象的最后一个元素,则指针表达式Q+1与P相比较大...即使Q+1并不指向数组对象的任何元素...

在分段体系结构中,将指针递增超过段的末尾会导致地址从该段的末尾回绕到该段的开头(通常为地址零)。如果在这样的段内分配了数组,则实现必须确保数组之后有足够的空间,以便存在一个超过末尾地址的地址,或者使用其他实现技术来处理此情况(例如,如果所使用的段是指针表示的一部分,则可能会分配一个特殊的超过末尾段值)...

C关系运算符模型使得对象的指针可以像数组对象的索引一样处理。两个不是更大对象的子对象的索引之间的关系比较很少有任何意义,标准也未定义指针的支持。某些应用程序确实需要利用存储中不同对象的相对位置信息。然而,委员会认为这种用法不足以具有足够的通用性,无法指定定义行为的模型...

大多数实现在指针类型的任何值操作之前都不执行检查。大多数处理器使用与算术类型相关的指令来执行涉及指针类型的关系比较。对于使用分段存储器体系结构的处理器,指针值通常使用两个组件表示,即段号和该段内的偏移量。这种表示的一个后果是,有许多好处可以将对象的存储分配在单个段内(即,对象的存储不跨越段边界)。其中之一是优化涉及某些关系运算符的生成机器代码的情况,该运算符仅需要检查段偏移量组件。这可能会导致p>= q为false,但p> q为true,当p和q指向不同的对象时。


3
这严格可行吗?你能把一个标量对象当作一个单元素数组处理,然后使用指向该数组结尾后一位的指针吗? - James McNellis
2
当然。一个元素的数组和一个标量具有相同的布局和对齐方式。事实上,sizeof(element)被定义为元素对齐的倍数,因此在数组元素之间没有填充。 - Maxim Egorushkin
2
@Maxim:我们怎么知道呢?一个指向数组末尾的指针是有效的(虽然不能被解引用),但我不认为一个指向元素末尾的指针是有效的,就像@James所说的那样。 - GManNickG
3
@Maxim:以“常识”为依据的论述等同于“因为我这么认为、希望如此,并且应该是这样”的说法,并不能使其成立。不,这并不是“常识”,否则James和我也不会提出疑问了。我真的怀疑这个回答已经定义了行为。 - GManNickG
8
§5.7/4 "对于这些运算符,指向非数组对象的指针与指向长度为一的数组的第一个元素的指针行为相同"。可以。 - Cheers and hth. - Alf
显示剩余3条评论

3

这在gcc C++ 4.9.2上起作用(http://ideone.com/f3qhTe)。

#include <iostream>
using namespace std;

int main() {
    // your code goes here
    std::string test;

    test = (char) 76;
    test += (char) 77;
    test += (char) 78;
    test += (char) 79;

    std::cout << "test contains: " << test << std::endl;
    return 0;
}

3
在大多数情况下,你只需使用{ch}
std::string s = {ch}; // works
infix.push({ch}); // works

这里使用了std::stringstd::initializer_list构造函数。


1
我不太懂Java,但是在C++中,最接近于ch + ""的可能是std::string{} + ch。请注意,""不是std::string,您无法为基本类型重载运算符,因此ch + ""不可能产生std::string
然而,std::string{} + ch涉及到两个字符串。我想编译器可以优化临时变量,但是从一个字符构造一个字符串是完全可以的:std::string(1,ch)
对于std::string的其他构造函数,请参考https://en.cppreference.com/w/cpp/string/basic_string/basic_string

0

你可以将一个字符串设置为一个字符。

#include <iostream>
#include <string>

using namespace std;

int main()
{
   string s;
   char one = '1';
   char two = '2';
   s = one;
   s += two;
   cout << s << endl;
}

./测试
12


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