1

I am trying to write a function to convert a std::string to char* . The first one I have written was this:

char* $ (string str)
{
    char* cstr;
    const unsigned int length=str.size();
    cstr=new char[1000];
    for(int i=0;i<length;i++)
        cstr[i]=str[i];
    cstr[length]=0;
    return cstr;
}

But the problem was the memory leak: let's suppose that I do this:

char* cstr;
string str1("hello"),str2("hello2");
cstr=$(str1);
cstr=$(str2);

There is a memory leak in this case.The first allocated string is not reachable but it's reference is lost. So I made the same using static:

char* $ (string str)
{
    static char cstr[1000];
    const unsigned int length=str.size();
    for(int i=0;i<length;i++)
        cstr[i]=str[i];
    cstr[length]=0;
    return cstr;
}

But the problem now is that the static char fields are accessible:

char* cstr;
string str("hello");
cstr=$(str);
$(str)[5]='!';

This is possibile, the 6th character is modified and so also the C-style string pointed by cstr is modified.

Using const:

const char* $ (string str)
{
    static char cstr[1000];
    const unsigned int length=str.size();
    for(int i=0;i<length;i++)
        cstr[i]=str[i];
    cstr[length]=0;
    return cstr;
}

The problem is that a char pointer is not compatible with a const char pointer, so I can't do this:

string str("hello");
char* cstr;
cstr=$(str);

But I can only use a const char pointer. What I would do is to have a function which the return value could be placed only as right operand, but not as left operand of an assignment.How could this be done?

I tried to do this:

char* toCharArray(string& str)
{
    std::unique_ptr<char>p(new char[1000]);
    char* temp=p.get();
    for(unsigned int i=0;i<str.size();i++)
    {
        *temp=str[i];
        temp++;
    }
    return p.get();
}

But the problem is still there, I don't see the difference between this and the other solution I posted using static.Since a code like this:

char* cstr;
string str("hello");
cstr=toCharArray(str);
toCharArray(str)[0]='o';
cout << cstr;

Modifies the string (prints "oello"). Problem still not solved.

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
  • 8
    You've written a function called `$`? – Oliver Charlesworth Feb 23 '12 at 12:48
  • 4
    "There is a memory leak in this case.The first allocated string is not reachable but it's reference is lost." your function cannot protect the client code from being an idiot. If you want protection from leaks you use `std::string`, if you work with `char *` you know that if you are not careful you may leak. The only other solution is to return a smart pointer to `char *` (specifically, one for arrays, otherwise it will call `delete` instead of `delete[]`). – Matteo Italia Feb 23 '12 at 12:53
  • What do you want to do with `cstr`? Maybe your problem could be solved in a more clever way. For example using const_cast` to remove the `const` from `str.c_str()`? – jofel Feb 23 '12 at 13:04
  • To free up memory automatically, you could use [`auto_ptr`](http://en.wikipedia.org/wiki/Auto_ptr) or `shared_ptr`. – jofel Feb 23 '12 at 13:07
  • possible duplicate of [Convert std::string to const char* or char*](http://stackoverflow.com/questions/347949/convert-stdstring-to-const-char-or-char) – PlasmaHH Feb 23 '12 at 13:13
  • 2
    @jofel: `auto_ptr` is deprecated, and can only manage a single object, not an array. `unique_ptr` is ideal for this, if your compiler supports it. – Mike Seymour Feb 23 '12 at 13:20
  • @MikeSeymour Thanks for pointing this out. The boost library offers [shared_array](http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_array.htm) which can be used for array. – jofel Feb 23 '12 at 13:41

5 Answers5

2

You can prevent memory leaks by returning the allocated array as either std::unique_ptr<char[]> or std::vector<char>; both will release the memory if they are reassigned or go out of scope.

You can get a char* pointer to the contents as ptr.get() or &vec[0] respectively.

By the way, since the length is known, the array length really should be length+1, not 1000. Fixed-sized buffers are an overrun waiting to happen. Also, $ is not a portable name for a function.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Just a question: with length declared const, will length+1 give compiler error variable length array or not? – supertopi Feb 23 '12 at 13:28
  • @supertopi: That's fine - declaring something `const` doesn't stop you using its value, and that's all you're doing if you use it in `new char[length+1]` or `std::vector v(length+1)`. – Mike Seymour Feb 23 '12 at 13:35
1

You need to create a new char * and copy the contents of the std::string over it.

You can use strcpy.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
1

http://www.cplusplus.com/reference/string/string/c_str/

Look at the example, specifically:

char * cstr, *p;

string str ("Please split this phrase into tokens");

cstr = new char [str.size()+1];
strcpy (cstr, str.c_str());
0

I don't see why you're surprised by the memory leak. If you're making a copy of something, you've got to put it somewhere.

You can either put all the copies in the same place (running a risk of overflow, and putting the onus of taking a proper copy on the client, or they run the risk of unexpected corruption), or you do the allocation (they still have to do the freeing, but at least they don't have to copy), or you get them to pass a buffer and a size into your function.

And seriously, $ as a function name?

Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
  • A name function shall be significative, I think that $ gives an idea of what you're doing like when you use $ in assembly to get a register value. I'll change the name because, like Seymour said in the above post, it isn't portable. – Ramy Al Zuhouri Feb 23 '12 at 13:50
  • Have you read the full question? I used a static array of char. – Ramy Al Zuhouri Feb 23 '12 at 15:15
  • yes I did. I your first sample you used malloc/new. A static array of char has other problems (for instance, what if the string is longer than 1k? what if the client doesn't duplicate the string and refers to it later after someone else has used that function) – Tom Tanner Feb 23 '12 at 17:05
-3

What about str.c_str()? Or strdup(str.c_str()) if you want a copy.

James M
  • 18,506
  • 3
  • 48
  • 56