tags:

views:

353

answers:

3

If i pass a char * into a function. I want to then take that char * convert it to a std::string and once I get my result convert it back to char * from a std::string to show the result.

  1. I don't know how to do this for conversion ( I am not talking const char * but just char *)
  2. I am not sure how to manipulate the value of the pointer I send in.

so steps i need to do

  1. take in a char *
  2. convert it into a string.
  3. take the result of that string and put it back in the form of a char *
  4. return the result such that the value should be available outside the function and not get destroyed.

If possible can i see how it could be done via reference vs a pointer (whose address I pass in by value however I can still modify the value that pointer is pointing to. so even though the copy of the pointer address in the function gets destroyed i still see the changed value outside.

thanks!

+13  A: 

Converting a char* to a std::string:

char* c = "Hello, world";
std::string s(c);

Converting a std::string to a char*:

std::string s = "Hello, world";
char* c = new char[s.length() + 1];
strcpy(c, s.c_str());

// and then later on, when you are done with the `char*`:
delete[] c;

I prefer to use a std::vector<char> instead of an actual char*; then you don't have to manage your own memory:

std::string s = "Hello, world";
std::vector<char> v(s.begin(), s.end());
v.push_back('\0'); // Make sure we are null-terminated
char* c = &v[0];
James McNellis
yea but in the latter case when you use c_str() it is returning a const char * not a char *
@user295030: `c_str()` does indeed return a `const char*`; the second parameter to `strcpy` (the source string) is of type `const char*`. If you only need a `const char*`, then there's no need to do this, and you can just use the result of `c_str()`.
James McNellis
s.c_str() returns a const char*, which is why he's copying it into the char* called c. In your function, you would then return c.
crimson_penguin
You also wouldn't have to manage your memory if you declared the C array on the stack.
wilhelmtell
@wilhelmtell: True, but that would violate one of the OP's requirements ("return the result such that the value should be available outside the function and not get destroyed"). It also has the disadvantage that you have to guess at compile time how big it needs to be. Often that's fine; other times it's not.
James McNellis
@James you can still do with the stack if you take the pointer as a parameter or if the pointer is outside the scope of the function (class member? global?).
wilhelmtell
+1  A: 

You need to watch how you handle the memory from the pointer you return, for example the code below will not work because the memory allocated in the std::string will be released when fn() exits.

const char* fn(const char*psz) {
    std::string s(psz);
    // do something with s
    return s.c_str();   //BAD
}

One solution is to allocate the memory in the function and make sure the caller of the function releases it:

const char* fn(const char*psz) {
    std::string s(psz);
    // do something with s
    char *ret = new char[s.size()]; //memory allocated
    strcpy(ret, s.c_str());
    return ret;
}
....
const char* p = fn("some text");
//do something with p
delete[] p;// release the array of chars

Alternatively, if you know an upper bound on the size of the string you can create it on the stack yourself and pass in a pointer, e.g.

void fn(const char*in size_t bufsize, char* out) { 
    std::string s(psz);
    // do something with s
    strcpy_s(out, bufsize, s.c_str()); //strcpy_s is a microsoft specific safe str copy
}
....
const int BUFSIZE = 100;
char  str[BUFSIZE];

fn("some text", BUFSIZE, str);
//ok to use str (memory gets deleted when it goes out of scope)
hamishmcn
A: 

You can maintain a garbage collector for your library implemented as std::vector<char*> g_gc; which is accessible in your library 'lib'. Later, you can release all pointers in g_gc at your convenience by calling lib::release_garbage();

char* lib::func(char*pStr)
{
  std::string str(pStr);
  char *outStr = new char[str.size()+1];
  strcpy(outStr, str.c_str());
  g_gc.push_back(outStr); // collect garbage
  return outStr;
}

release_garbage function will look like:

void lib::release_garbage()
{
   for(int i=0;i<g_gc.size();i++)
   {
       delete g_gc[i];
   }
   g_gc.clear();
}

In a single threaded model, you can keep this g_gc static. Multi-threaded model would involve locking/unlocking it.

Pankaj
This is _very_ dangerous; storing bare pointers in a container is almost always a bad idea, because it is very difficult to ensure exception safety. (See here for alternatives: http://stackoverflow.com/questions/2558134/2558152#2558152). In addition, the code in your answer has a critical bug: it uses mismatched `new[]` and `delete`.
James McNellis
that's a great thread. Thanks for pointing out about delete[].
Pankaj
And with this you can't even "garbage collect" on demand because some pointers could be in use. You can only do it safely when your application exits, which makes it useless since memory allocated is released when your application exits anyway.
Blindy