3

I declared a char * array char *excluded_string[50] = { 0 };

Later each element of excluded_string array gets one word. Now I want to convert it into string so that I can have all words seperated by space.

std::string ss(excluded_string); gives error:

`server.cpp:171:32: error: no matching function for call to ‘std::basic_string::basic_string(char* [50])’ and large tricky explaination!

valiano
  • 16,433
  • 7
  • 64
  • 79
user123
  • 5,269
  • 16
  • 73
  • 121
  • I'm not that conform with c++ but shouldnt be iit an char Array to string? otherwise you had to dereference each char in a loop or some kind of before adding to string, wouldnt you ahve to?! – dhein Aug 23 '13 at 10:29
  • 2
    @Zaibis he has an array of char *, which is basically an array of strings – Matthew Mcveigh Aug 23 '13 at 10:31
  • Yeah, so if want to convert it by keeping the treatment he should convert it into an std::string * as if thats possible, wouldnt he have to? – dhein Aug 23 '13 at 10:33
  • std::string can be constructed from a char * so M M.'s solution does the trick where the char * is implicitly constructed into a std::string and appended to a single std::string – Matthew Mcveigh Aug 23 '13 at 10:35
  • Take a look at [http://stackoverflow.com/questions/1833447/a-good-example-for-boostalgorithmjoin](http://stackoverflow.com/questions/1833447/a-good-example-for-boostalgorithmjoin) if you can use boost. – indeterminately sequenced Aug 23 '13 at 10:38

4 Answers4

12

I declared char * array char *excluded_string[50] = { 0 };

Later each element of ex_str array gets one word. Now I want to convert it into string so that I can have all words seperated by space.

To convert it into a single string:

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();

Edit: A few notes:

  • if possible, do not concatenate strings directly: that will create and destroy a lot of objects and perform lots of unnecessary allocations.

  • if your code has stringent efficiency requirements, consider allocating/reserving the result beforehand to ensure a single allocation instead of repeated allocations.

  • if you concatenate strings, consider using operator += instead of + and =.

Edit 2: (answering comments)

What if + and = instead of +=?

Here's the resolution of the two alternatives for concatenating strings (s += s1 + s2 vs s += s1; s += s2):

  • Using = and +:

code:

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

Equivalent code (in terms of objects constructed and allocations):

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 is created once per iteration;
  • temp2 is created for the concatenation operator
  • the second temporary is appended to ss.

Both temporaries create a copy of the data (allocate buffer, copy data, deallocate buffer).

  • Using += twice:

code:

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 += is called twice; It allocates space (if necessary), copies current contents of the string to newly allocated space, then copies new data at the end of the allocated buffer.

  • single pre-allocated space:

allocating/reserving the result beforehand to ensure a single allocation

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
}

In this case, operator+= doesn't allocate space internally, just at the beginning (a single operation). This is still a bit slow, because you iterate over the strings twice (0->49) and over each string twice (once to compute length, once to copy it to ss).

If your excluded_string were a std::vector instead, it would be more efficient because computing the strings lengths would not iterate each string, just the vector).

utnapistim
  • 26,809
  • 3
  • 46
  • 82
  • thank a lot! What if + and = instead of +=? what you want to say here : " allocating/reserving the result beforehand to ensure a single allocation instead of repeated allocations." – user123 Aug 23 '13 at 15:17
  • @utnamistim: You are awwsome! – user123 Aug 23 '13 at 18:17
3

Possible solution

Since you took care to initialize your array of pointers to c_str to 0, we can use that knowledge to only add actually allocated words :

Also, you need to first build a std::string based on the original c_str before you can use the concatenation operator+.

std::string stringResult;

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

Details about the original error

The type of your excluded_string object is a static array of 50 pointers to char. All pointers to char being initialized to 0 by your code. A pointer to char can be referred as a C string, or more concisely c_str.

C++ STL gives you the std::string class, for which several constructors are defined. One of them taking a c_str (i.e. a pointer to char) to initialize the string (pedantically, converting it to a pointer to const char, which is an implicit conversion in this expression).
This constructor is the one we use in the solution when we write:

std::string(excluded_string[i])

But as you can see, there is no constructor taking an array of c_str, which is exactly what you compiler error's tells you.

EDIT : Wording, thanks to Lightness Races in Orbit comment. (cast meaning in fact explicit conversion).

Ad N
  • 7,930
  • 6
  • 36
  • 80
2
#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;
}
BlackMamba
  • 10,054
  • 7
  • 44
  • 67
1

Try a loop:

std::string ss;

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

You're code in the best situation will put first string in ss.

masoud
  • 55,379
  • 16
  • 141
  • 208
  • I think it would be more optimal to first find the length of the c string and preallocate the std string and do a second pass that will append without reallocation, and the memory would already be brought in cache from strlen. – dtech Aug 23 '13 at 10:35