Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » const char *? -- more n00bisms

This thread is locked; no one can reply to it. rss feed Print
 1   2   3 
const char *? -- more n00bisms
Michael Jensen
Member #2,870
October 2002
avatar

how do you give a char* back from a function?

right now, I'm building a string, and returning .c_str() -- but the string is disposed as the function ends, and c_str comes back as garbage.

I could malloc the data myself, but I don't want the end-programmer to have to free it. I could declare a "static char msg[8000];" or something in my class, but that's kind of ineffecient, and allows my classes memory to get mangled if the end-programmer wanted to mangle it.

How does this const work in regards to this? does it solve my problem? How do I use it?

TeamTerradactyl
Member #7,733
September 2006
avatar

If you create a std::string inside of your function, and then you return its .c_str(), you should simply be able to use:

const char *theFunction(void)
{
   string myString;
   myString = "Groovy, baby!";
   return (myString.c_str());
}

That will copy "myString" into a specific address, which you will be able to address when the function returns. However, I'm not certain if simply <b>char theFunction() would work or if you need to declare the <b>char pointer a const: <b>const char theFunction().

Milan Mimica
Member #3,877
September 2003
avatar

You're returning a pointer to the member of the locally instanced class. The object will be deleted on function exit and so will object members. That won't work.

There is nothing wrong if the end-programmer has to free() the returned memory. Just document that.

TeamTerradactyl
Member #7,733
September 2006
avatar

Well, if you want to do it that way...

char *theFunction(void)
{
   string myString = "Groovy!";
   char *theResult = new char[myString.size()];
   return theResult;
}

This results in a new without the matching delete, so like Milan said, you'd have to document that the end-programmer will have to free that memory.

Michael Jensen
Member #2,870
October 2002
avatar

tt, as milan says, your first example doesn't work -- it's what I tried, then I realized what was happening, not good. The second example, yeah, I could allocate it and return it, but that kind of sucks... oh well, maybe I'll just use a private static member.

Milan Mimica
Member #3,877
September 2003
avatar

Heh, not quite. You're returning an uninitialized memory block. Here is the right way to do this dumb function:

char *theFunction(void)
{
   std::string myString = "Groovy!";
   return strdup(myString.c_str());
}

Now you have to free() the memory. It is important to note whether to use free() or delete to free the memory.

IMO, the better way to do it is to avoid C strings at all, if possible.

Runesabre
Member #7,573
August 2006
avatar

Does it have to return a value? If not, you could try:

void theFunction(string& thestring)
{
   thestring = "Groovy, baby!";
}

Or perhaps...

const char* theFunction(string& thestring)
{
   thestring = "Groovy, baby!";
   return thestring.c_str();
}

Declaring a static can work for certain situations but will produce invalid results if the return value changes for multiple callers:

const char* theFunction(void)
{
   static string thestring = "Groovy, baby!";
   return thestring.c_str();
}

_______________
Runesabre
Connecting People through Inspiring Interactive Entertainment
Enspira Online

Michael Jensen
Member #2,870
October 2002
avatar

Quote:

Heh, not quite. You're returning an uninitialized memory block.

It was just an example... anyway strdup is easier.

What I've decided to do, is that the class will keep an internal pointer to the string it returns, and upon disopsale, or a request for a new string, it frees the old one.

edit: Yeah, it has to return it, I'm attempting to write a virtual function that overloads a base class function (unsucessfully) -- or I'd just return a string. I do like that static version though.

edit: ack, all bad -- all bad. -- multiple callers == death.

Milan Mimica
Member #3,877
September 2003
avatar

Your class can keep a std::string so that you don't have to bother with realocating the string. You just return .c_str() of the internal string.

Michael Jensen
Member #2,870
October 2002
avatar

Quote:

Your class can keep a std::string so that you don't have to bother with realocating the string. You just return .c_str() of the internal string.

:: smacks forehead ::

Kibiz0r
Member #6,203
September 2005
avatar

Or you can always use std::strings and only convert to c-style strings when you really need to...

Goalie Ca
Member #2,579
July 2002
avatar

In standard c++ there is a type of pointer that knows who owns it and when it can delete itself (when the owner goes out of scope). It is called auto_ptr. Note: there can only be one owner at a time. Otherwise it works like a regular pointer.

http://www.gotw.ca/publications/using_auto_ptr_effectively.htm

-------------
Bah weep granah weep nini bong!

Michael Jensen
Member #2,870
October 2002
avatar

Quote:

Or you can always use std::strings and only convert to c-style strings when you really need to...

but that's what I AM doing.

auto pointers you say? I'll have to take a look at that.

ImLeftFooted
Member #3,935
October 2003
avatar

The solution to this problem is to stop using MSVC and start using GCC. MSVC just sucks like that.

Michael Jensen
Member #2,870
October 2002
avatar

Quote:

The solution to this problem is to stop using MSVC and start using GCC. MSVC just sucks like that.

I use both -- the problem occurs in both also and has nothing to do with MSVC versus GCC.

ImLeftFooted
Member #3,935
October 2003
avatar

char buf[256];

sprintf(buf, "%s", string("test").c_str());

buf[255] = 0;

printf("%s", buf);

Assuming above is the issue you're talking about I've run into it and dealt with it.

In my tests MSVC seems to print out garbage, while gcc does what you'd hope for.

Possibly you tried this on a version of gcc more immature then mine?

I'm using gcc version 3.4.2 (mingw-special)

**Fixed print_r to be printf (man I've done too much php coding lately :o ).

On a complete tangent, I've found this issue very annoying:

int i;
istringstream("5") >> i;
printf("%d", i);

Earlier versions of gcc can't handle this code.. The workaround is to name the instance of istringstream. I find this work-around very ugly :(.

Milan Mimica
Member #3,877
September 2003
avatar

Quote:

buf[255] = 0;

try buf[255] = '\0';

edited: replaced / with \.

EDIT (again): I see, that's not the issue here.

ImLeftFooted
Member #3,935
October 2003
avatar

Thats exactly the same, but requires three extra hard to reach key strokes. :-X

Quote:

EDIT (again): I see, that's not the issue here.

Yeah thats just a check so MSVC doesn't crash when it tries to output the string. Not really the point of the excerise, just a cleaning operation.

Below, Baf said:

4? I only count 3 extra strokes. :-X

You post too fast :P.

BAF
Member #2,981
December 2002
avatar

4? I only count 3 extra strokes. :-X

Milan Mimica
Member #3,877
September 2003
avatar

So the problem is that sprintf() doesn't put '\0' at the end, or is printf() ignoring it for some reason?

ImLeftFooted
Member #3,935
October 2003
avatar

The issue up for debate is what

string("test").c_str()

Gives you. GCC is proclaimed to give you what you'd hope for. MSVC is proclaimed to give you garbage data.

BAF
Member #2,981
December 2002
avatar

You should use snprintf anyway. But I guess that setting the last thing to zero is a fix in case you overflow the string or hit the end, or something. I vaguely recall having to do something similar at one time, but I've since moved to less primitive, more civilized languages, so I forgot why I had to do such an ugly thing.

[edit]
Why would you want to have something like that? If it was anonymous, it could go out of scope at anytime, leaving that c_str() dangling.

Milan Mimica
Member #3,877
September 2003
avatar

what was i thinking ::)

ImLeftFooted
Member #3,935
October 2003
avatar

Quote:

Why would you want to have something like that? If it was anonymous, it could go out of scope at anytime, leaving that c_str() dangling.

Clean code can handle possible situations it will go into. In this respect GCC's string::c_str has cleaner code then MSVC's string::c_str as far as handling edge cases goes.

Things like this make me like GCC better then MSVC. You'd think this is a rarely used edge case, but I use this functionality all the time.

Goalie Ca
Member #2,579
July 2002
avatar

Aah when digging around in the c++ reference i noticed something.

.c_str() returns a null terminated c-string version. It does not need to be "freed" it says.
.data() returns a const char* to first character in the string.

See the difference? .data's is not likely to go out of scope (unless the string resizes and gets moved around in memory).

I wonder how much work it would be to make these thread safe and if that factored into the decision to have a seperate c_str() from data().

Clearly these differences give flexibility to implementation. Microsoft must've interpreted a standard in the microsoft way again.

-------------
Bah weep granah weep nini bong!

 1   2   3 


Go to: