// OBS 1 - "getText()" must return "const char*"
// OBS 2 - The "get" methods return integers
// C style
// The text is correctly formated here, but, as tempString goes out of scope,
// "result" points to an undefined position, so the caller of "getText()"
// will get garbage
const char* C_Clock::getText() {
char tempString[9];
_snprintf( tempString, 9, "%02d:%02d:%02d", getHours(), getMinutes(), getSeconds() );
const char* result = tempString;
return result;
}
// C++ style
// This style suffers from the same thing as the C style, plus the fact that I
// don't know how to force the values to be formated as "hh:mm:ss"
const char* C_Clock::getText() {
std::ostringstream tempString;
tempString << getHours() << ":" << getMinutes() << ":" << getSeconds() << std::ends;
return tempString.str().c_str();
}
🔒 Locked
Problems returning string
Advertisement
Original Post
Hello! CONTEXT: I'm using Visual C++ 6 and I'm trying to format some text (and return it). The text in question is the current time (hh:mm:ss format), that must be stored in the records file to keeps track of how much the user has played. PROBLEM: I've tried two different implementatios for the same method, in C and in C++ styles (none actually works :( ). Please, read the code below to a better understanding: QUESTION: Could you point me the right way to go? It would be better yet if you point me BOTH ways (C and C++)... Thanks a lot! // lb edit - added a title
const char* C_Clock::getText() { char tempString[9]; _snprintf( tempString, 9, "%02d:%02d:%02d", getHours(), getMinutes(), getSeconds() ); const char* result = tempString; return result;}The variable tempString is a local variable so it loses validity once the function returns. You'll need to allocate it from the heap or reference a global variable instead. If you allocate the variable from the heap, don't forget to deallocate it when it's no longer used.
Quote:
Original post by Sneftel
Why not return a std::string instead of a char*?
Yes, I could do that and use "c_str()" to pass the value to the XML library I'm using, but I'm really interest on how to solve the problem using "const char*".
Can you help me?
Quote:
The variable tempString is a local variable so it loses validity once the function returns. You'll need to allocate it from the heap or reference a global variable instead. If you allocate the variable from the heap, don't forget to deallocate it when it's no longer used.
Could you give some example? Is it not possible to do all the job (allocation and deallocation) inside "getText()" and return only the interesting thing to the caller?
Thanks a lot!
As LessBread said, tempString is a local stack variable and will be done away with when the function exits. However, you still set result to point at it. If you want to set result to point to tempString and have it work properly, you need to allocate tempString on the heap so it's not destroyed when the function exits.
Or, you could use Sneftel's expert advice of using std::string rather than const char*.
Or, you could use Sneftel's expert advice of using std::string rather than const char*.
I don't think there's any real "good" way to return a char *. The way a some libraries do it, is they have you pass in a char * and its length, modify that, and return the same pointer you passed in. It's two extra parameters to send, but you get the functionality of returning a c-style string.
Quote:
Original post by nilkn
Or, you could use Sneftel's expert advice of using std::string rather than const char*.
I think this is the way to go. I'll forget the "const char*" thing for now ;)
The easy way to use a character pointer here is to make your buffer static, so that it isn't on the stack.
There are two problems with this however:
1) It isn't safe in a multithreading environment.
2) The result of a previous call shouldn't be used after the function is called again, as the new result will overwrite the old one.
You could also allocate memory to avoid those problems, but then you'd have to free it when you were done with it. If you write something natural like cout << clock.getText(), then you've just managed to create a memory leak.
You can avoid all those problems by just using std::string.
There are two problems with this however:
1) It isn't safe in a multithreading environment.
2) The result of a previous call shouldn't be used after the function is called again, as the new result will overwrite the old one.
You could also allocate memory to avoid those problems, but then you'd have to free it when you were done with it. If you write something natural like cout << clock.getText(), then you've just managed to create a memory leak.
You can avoid all those problems by just using std::string.
Quote:
Original post by bjle
I don't think there's any real "good" way to return a char *. The way a some libraries do it, is they have you pass in a char * and its length, modify that, and return the same pointer you passed in. It's two extra parameters to send, but you get the functionality of returning a c-style string.
Similar to the "printf" family, right? Better go with std::string :)
Thanks!
Guys, could you help me on formating the text on the C++ style example (so I can completely get rid of C character arrays)? Otherwise I'll end up with a C and C++ hibrid solution :(
Thanks a lot!
Thanks a lot!
// Example #1#include <string>std::string C_Clock::getText() { char tempString[9]; _snprintf(tempString, 9, "%02d:%02d:%02d", getHours(), getMinutes(), getSeconds()); return tempString;}// Example #2#include <string>#include <sstream>std::string C_Clock::getText() { std::stringstream stream; stream.fill('0'); stream.width(2); stream << getHours() << ':'; stream.width(2); stream << getMinutes() << ':'; stream.width(2); stream << getSeconds(); return stream.str();}Quote:
Original post by smart_idiot
*** Source Snippet Removed ***
Wow, thanks a lot, Idiot ;) I think I'll stay with the #1 solution.
Quote:
Original post by MajinMusashi
Could you give some example? Is it not possible to do all the job (allocation and deallocation) inside "getText()" and return only the interesting thing to the caller?
What I would have done is probably made the string variable (tempString) a member of the clock class, named "displayText" or similar. This way the memory for the string would be allocated as part of the object and thus deallocated when object is destroyed. And that would make getText more of an update method, updating the text in the display string when called.
Quote:
Original post by LessBread
What I would have done is probably made the string variable (tempString) a member of the clock class, named "displayText" or similar. This way the memory for the string would be allocated as part of the object and thus deallocated when object is destroyed. And that would make getText more of an update method, updating the text in the display string when called.
Agreed, LessBread. The resulting code now is:
// displayText is now a member of the clock class (char displayText[9])const char* C_Clock::getText() { _snprintf( displayText, 9, "%02d:%02d:%02d", getHours(), getMinutes(), getSeconds() ); return displayText;}Thanks a lot!
Do clients of the class really need to be able to check hours/minutes/seconds directly? I would assume that normally one only wants to tell a clock to advance/retreat, and then check the current time as a whole. Accessors don't really help internally and one shouldn't add more to external interfaces than necessary.
Also, for outputting stuff, the C++ idiom is to accept a stream reference and return it back, rather than implementing a toString() (as Java would call it):
Oh, and std::ends is not called for when using the current standard library version of stringstream (it is in, NOT , or anything else).
Also, for outputting stuff, the C++ idiom is to accept a stream reference and return it back, rather than implementing a toString() (as Java would call it):
ostream& Clock::display(ostream& os) const { // Another useful thing is knowing how to do the formatting 'manually' return os << hours / 10 << hours % 10 << ':' << minutes / 10 << minutes % 10 << ':' << seconds / 10 << seconds % 10;}ostream& operator<<(ostream& os, const Clock& c) { return c.display(os);}// Now you can do:Clock noon(12, 0, 0);noon.display(cout);// Or more idiomatically:cout << noon;Oh, and std::ends is not called for when using the current standard library version of stringstream (it is in
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement