【问题标题】:How to convert char* array into std::string如何将 char* 数组转换为 std::string
【发布时间】:2013-08-26 08:47:10
【问题描述】:

我声明了一个 char * 数组 char *excluded_string[50] = { 0 };

稍后excluded_string 数组的每个元素都会得到一个单词。现在我想把它转换成字符串,这样我就可以用空格分隔所有单词了。

std::string ss(excluded_string); 给出错误:

`server.cpp:171:32: error: no matching function for call to ‘std::basic_string::basic_string(char* [50])’ 和大的棘手解释!

【问题讨论】:

  • 我不太符合 c++ 但不应该是一个字符数组到字符串?否则,您必须在循环中取消引用每个字符,或者在添加到字符串之前取消引用,您不会这样做吗?!
  • @Zaibis 他有一个char *数组,基本上就是一个字符串数组
  • 是的,所以如果想通过保留治疗来转换它,他应该尽可能地将其转换为 std::string *,他不必这样做吗?
  • std::string 可以从 char * 构造,因此 M M. 的解决方案可以将 char * 隐式构造为 std::string 并附加到单个 std::字符串

标签: c++


【解决方案1】:

我声明了 char * array char *excluded_string[50] = { 0 };

稍后 ex_str 数组的每个元素都得到一个单词。现在我想把它转换成字符串,这样我就可以用空格分隔所有单词了。

将其转换为单个字符串:

char *excluded_string[50] = { 0 };
// excluded_string filled in the meantime
std::ostringstream buffer;  // add #include <sstream> at the top of 
                            // the file for this
for(int i = 0; i < 50; ++i)
    buffer << excluded_string[i] << " ";
std::string result = buffer.str();

编辑:几点说明:

  • 如果可能,不要直接连接字符串:这会创建和销毁大量对象并执行大量不必要的分配。

  • 如果您的代码有严格的效率要求,请考虑预先分配/保留结果,以确保一次性分配而不是重复分配。

  • 如果您连接字符串,请考虑使用运算符 += 而不是 + 和 =。

编辑 2:(回答 cmets)

如果 + 和 = 而不是 += 会怎样?

以下是连接字符串的两种备选方案的分辨率(s += s1 + s2 vs s += s1; s += s2):

  • 使用 = 和 +:

代码:

std::string ss;
for (int i=0; i<50; i++)
    ss += std::string(excluded_string[i]) + " ";

等效代码(在对象构造和分配方面):

std::string ss;
for (int i=0; i<50; i++)
{
    // ss += std::string(excluded_string[i]) + " ";
    std::string temp1(excluded_string[i]); // "std::string(excluded_string[i])"
    std::string temp2 = temp1 + " "; // call std::string operator+(std::string, char*)
    ss += temp2; // call std::string::operator +=(std::string)
}
  • temp1 每次迭代创建一次;
  • temp2 是为连接运算符创建的
  • 第二个临时附加到 ss。

两个临时对象都创建数据的副本(分配缓冲区、复制数据、释放缓冲区)。

  • 使用 += 两次:

代码:

std::string ss;
for (int i=0; i<50; i++)
{
    ss += excluded_string[i]; // call std::string::operator +=(char*)
    ss += " "; // same as above
}
  • std::string::operator += 被调用两次;它分配空间(如有必要),将字符串的当前内容复制到新分配的空间,然后在分配的缓冲区末尾复制新数据。

  • 单个预分配空间:

预先分配/保留结果以确保一次分配

std::size_t total_length = 0;
for(int i = 0; i < 50; ++i)
    total_length += std::strlen(excluded_strings[i]); // assumes argument is not null
std::string ss;
ss.reserve(total_length + 51); // reserve space for the strings and spaces between
for (int i=0; i<50; i++)
{
    ss += excluded_string[i]; // calls std::string::operator +=
    ss += " "; // same as above
}

在这种情况下,operator+= 不会在内部分配空间,只是在开头(单个操作)。这仍然有点慢,因为您对字符串进行了两次迭代 (0->49) 并对每个字符串进行了两次迭代(一次计算长度,一次将其复制到 ss)。

如果您的 exclude_string 是一个 std::vector,它会更有效,因为计算字符串长度不会迭代每个字符串,而只是迭代向量)。

【讨论】:

  • 非常感谢!如果 + 和 = 而不是 += 会怎样?您在这里想说的是:“预先分配/保留结果以确保单个分配而不是重复分配。”
  • @utnamistim:你太棒了!
【解决方案2】:

可能的解决方案

由于您小心地将指向 c_str 的指针数组初始化为 0,我们可以使用该知识仅添加实际分配的单词:

另外,您需要先基于原始 c_str 构建一个 std::string,然后才能使用串联 operator+

std::string stringResult;

for (int i=0; i!=50; ++i)
    if(excluded_string[i])
    {
        stringResult.append(std::string(excluded_string[i]) + " ");
    }

有关原始错误的详细信息

excluded_string 对象的类型是由 50 个指向 char 的指针组成的静态数组。您的代码将所有指向 char 的指针初始化为 0。 指向 char 的指针可以称为 C 字符串,或者更简洁地称为 c_str

C++ STL 为您提供std::string 类,其中several constructors are defined。其中一个采用 c_str(即指向 char 的指针)来初始化字符串(迂腐地,将其转换为指向 const char 的指针,这是此表达式中的隐式转换)。
这个构造函数是我们在编写时在解决方案中使用的构造函数:

std::string(excluded_string[i])

但正如您所见,没有构造函数采用 c_str 数组,这正是编译器错误告诉您的内容。

编辑:措辞,感谢Lightness Races in Orbit评论。 (cast 其实意思是显式转换)。

【讨论】:

  • c_str 是 std::string 的成员函数,而不是 C 字符串的名称
  • 学究式地,绝对没有“隐式强制转换”这样的东西。
【解决方案3】:
#include <iostream>
#include <string.h>
#include <algorithm>
#include <vector>
#include <sstream>
#include <iterator>
using namespace std;

int main()
{
char *arr[10] = {0};
for(int i = 0; i < 10; i++)
    arr[i] = "wang";

ostringstream str;
copy(arr, arr+10, ostream_iterator<string>(str, " "));
cout<<str.str()<<endl;
}

【讨论】:

    【解决方案4】:

    尝试循环:

    std::string ss;
    
    for (int i=0; i < 50; i++)
        ss += std::string(excluded_string[i]) + " ";
    

    您的代码在最好的情况下会将第一个字符串放入ss

    【讨论】:

    • 我认为首先找到 c 字符串的长度并预分配 std 字符串并执行第二次传递将不会重新分配,并且内存已经从strlen.
    猜你喜欢
    • 2012-09-03
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多