34

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!

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
user295030
  • 393
  • 1
  • 3
  • 7
  • 1
    "convert it back to char * from a std::string to show the result." - why can't you show the result when it's a string? Should be able to do std::cout << my_string; – crimson_penguin Apr 01 '10 at 22:23
  • 1
    this is an interface i have to work with. so although I use string whenever I can if an interface requires char * then that is what I have to use. the function output parameter is a char *...and that is what I have to work with – user295030 Apr 01 '10 at 22:29
  • 3
    In that case, the interface should say something about memory management. I say "should" because it *might* not - some interfaces are poorly specified, fact of life. Whenever you return a pointer from a function, you need to say who is responsible for allocating the data that's pointed to, how long it remains valid, and who is responsible for freeing it (if applicable). If you can work that out, you can figure out how to return an appropriate pointer value. – Steve Jessop Apr 01 '10 at 22:39
  • well, i am just writing a test app which will be allocating the memory for the pointer (so whoever uses the interface will be the one managing the pointer). My actual function will just take in 2 param and one of them needs to return a char * value. SO i am doing this int he spirit of testing my lib that i will be sending. – user295030 Apr 02 '10 at 16:24

3 Answers3

51

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
  • 348,265
  • 75
  • 913
  • 977
  • 1
    yea but in the latter case when you use c_str() it is returning a const char * not a char * – user295030 Apr 01 '10 at 22:26
  • @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 Apr 01 '10 at 22:32
  • 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 Apr 01 '10 at 22:41
  • You also wouldn't have to manage your memory if you declared the C array on the stack. – wilhelmtell Apr 02 '10 at 00:12
  • @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 Apr 02 '10 at 03:49
  • @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 Apr 02 '10 at 06:19
  • I know that this thread was written long time ago. Just one point about converting a `std::string` to a `char*`. Using `strncpy` may be sometimes safer than using `strcpy` as stated here http://stackoverflow.com/questions/1258550/why-should-you-use-strncpy-instead-of-strcpy. The syntax with strncpy would be `strncpy(c, s.c_str(), s.length()+1);` – user9869932 Oct 12 '15 at 23:17
  • You can remove const ness by using const cast. char *str = const_cast(s.c_str()); – sitaram chhimpa Sep 14 '17 at 07:01
1

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
  • 7,843
  • 10
  • 41
  • 46
-1

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
  • 34
  • 2
  • 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 Apr 02 '10 at 03:26
  • that's a great thread. Thanks for pointing out about delete[]. – Pankaj Apr 02 '10 at 03:32
  • 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 Aug 01 '10 at 03:02