need a c-string format of toString()
If you just need to convert the output of toString(), you can use
const char* s = toString().c_str();
Note that c_str simply returns a pointer to the underlying character storage of the string. So you do need to be careful to not get a pointer to the string and then having that string go out of scope, in which case the pointer may or may not still point to valid memory. Your function currently is returning a string (I'm guessing your code has using namespace std) which means a C++ string object.
If you don't absolutely need C strings, I would recommend using C++ strings, since they are more current and just easier to work with. However, if for reasons somewhere else in the code you do need a C string, your function should look like
char* toString() {
// formatting your output
}
Because all a C string is is a null terminated ('\0') array of char, and an array is equivalent to a pointer to the first element, so that's where char* comes from.
Because of that, something needs to “own” the memory of that character array, and that something needs to have a “lifetime” that is at least as long as the scope you need it for. If you make a function that returns a raw char * you should make sure that the pointer is to either a:
- static string literal
- a dynamically allocated string with the
newoperator that you then make sure todeletelater.
In either case, C++ stringstreams could make formatting your output far more intuitive. You will need #include <sstream> and then some googling will steer you in the right direction. This solution also works if you need a C string, because C++ strings have a method called c_str() that converts C++ strings into C strings (null terminated array of characters):
#include <string>
#include <sstream>
using namespace std;
string toString() {
stringstream ss; // these are so useful!
if (*d != 1) {
// this probably isn't the exact formatting you are looking for,
// but stringstreams can certainly do it if you research a bit!
ss << *n << *d;
}
else {
ss << *n;
}
return ss.str();
}
void function_that_needs_c_string(const char * c);
int main() {
function_that_needs_c_string(toString().c_str());
}
Answer from Aposhian on Stack OverflowVideos
I've been programming in this language forever and I still don't know how to put stuff in those parentheses!
Does anyone know of a quick reference guide for all the things you can pass to ToString? specifically for formatting numbers?
Hello all! I have a strange requirement to fulfill, and I was not able to find a proper solution for all use cases. So, the PO wants to display the measured double typed data with 5 useful digits (with possible decimal places as well). I tried the obvious F5 and G5 format strings, but they are not good for all scenarios.
For the following inputs the expected outputs are: 1.2345 -> "1.2345" 2099.1547 -> "2099.2" 1234.567 -> "1234.6" 0.000605 -> "0.0006" 0.0000001 -> "0.0"
Thanks for your help in advance!
Because in a format string, the # is used to signify an optional character placeholder; it's only used if needed to represent the number.
If you do this instead: 0.ToString("0.##"); you get: 0
Interestingly, if you do this: 0.ToString("#.0#"); you get: .0
If you want all three digits: 0.ToString("0.00"); produces: 0.00
More here
You can use the numeric ("N") format specifier with 2 precision as well.
Console.WriteLine((13.1).ToString("N2")); // 13.10
Console.WriteLine((14).ToString("N2")); // 14.00
Console.WriteLine((22.22).ToString("N2")); // 22.22
Remember this format specifier uses CurrentCulture's NumberDecimalSeparator by default. If yours is not ., you can use a culture that has . as a NumberDecimalSeparator (like InvariantCulture) in ToString method as a second parameter.
I know I ask a lot of questions on here. Unfortunately I am learning all this on my own with not even a single peer to talk to so I hope you all understand. I really need some help understanding the ToString method as it seems to be used frequently. I have read all over the web, essentially, the same text book response when someone asks this question. "ToString returns the the class or data specific to the class" which I understand but at the same time I dont. for instance, the following code is in my book ( condensed it a little but im sure you get the idea)...
public class Time
public override string ToString()
{
return string.Format("{0}:{1:D2}:{2:D2} {3}",
((hours == 0 || hours == 12) ? 12 : hours % 12),
minutes, seconds, (hours > 12 ? "AM" : "PM"));
}I get that when you input values in the new variable that you assign for time the ToString Method can be used to display those values in a specific format.
ex. Time time = new Time();.... time.SetTime( 13,27, 24) will display as 1:27:24 PM.
What I dont get is why ToString? why "return string.Format"? couldn't we just call this method DisplayTime() and say return string(.....)?
Why is it specifically only ToString that is used here and what is the purpose of the .Format? More to the point, why use .Format instead of Console.Write?
Use sprintf. (This is NOT safe, but OP asked for an ANSI C answer. See the comments for a safe version.)
int sprintf ( char * str, const char * format, ... );
Write formatted data to string Composes a string with the same text that would be printed if format was used on printf, but instead of being printed, the content is stored as a C string in the buffer pointed by str.
The size of the buffer should be large enough to contain the entire resulting string (see snprintf for a safer version).
A terminating null character is automatically appended after the content.
After the format parameter, the function expects at least as many additional arguments as needed for format.
Parameters:
str
Pointer to a buffer where the resulting C-string is stored. The buffer should be large enough to contain the resulting string.
format
C string that contains a format string that follows the same specifications as format in printf (see printf for details).
... (additional arguments)
Depending on the format string, the function may expect a sequence of additional arguments, each containing a value to be used to replace a format specifier in the format string (or a pointer to a storage location, for n). There should be at least as many of these arguments as the number of values specified in the format specifiers. Additional arguments are ignored by the function.
Example:
// Allocates storage
char *hello_world = (char*)malloc(13 * sizeof(char));
// Prints "Hello world!" on hello_world
sprintf(hello_world, "%s %s!", "Hello", "world");
If you have a POSIX-2008 compliant system (any modern Linux), you can use the safe and convenient asprintf() function: It will malloc() enough memory for you, you don't need to worry about the maximum string size. Use it like this:
char* string;
if(0 > asprintf(&string, "Formatting a number: %d\n", 42)) return error;
log_out(string);
free(string);
This is the minimum effort you can get to construct the string in a secure fashion. The sprintf() code you gave in the question is deeply flawed:
There is no allocated memory behind the pointer. You are writing the string to a random location in memory!
Even if you had written
char s[42];you would be in deep trouble, because you can't know what number to put into the brackets.
Even if you had used the "safe" variant
snprintf(), you would still run the danger that your strings gets truncated. When writing to a log file, that is a relatively minor concern, but it has the potential to cut off precisely the information that would have been useful. Also, it'll cut off the trailing endline character, gluing the next log line to the end of your unsuccessfully written line.If you try to use a combination of
malloc()andsnprintf()to produce correct behavior in all cases, you end up with roughly twice as much code than I have given forasprintf(), and basically reprogram the functionality ofasprintf().
If you are looking at providing a wrapper of log_out() that can take a printf() style parameter list itself, you can use the variant vasprintf() which takes a va_list as an argument. Here is a perfectly safe implementation of such a wrapper:
//Tell gcc that we are defining a printf-style function so that it can do type checking.
//Obviously, this should go into a header.
void log_out_wrapper(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void log_out_wrapper(const char *format, ...) {
char* string;
va_list args;
va_start(args, format);
if(0 > vasprintf(&string, format, args)) string = NULL; //this is for logging, so failed allocation is not fatal
va_end(args);
if(string) {
log_out(string);
free(string);
} else {
log_out("Error while logging a message: Memory allocation failed.\n");
}
}