I am trying to convert an int to a cstring. I've decided to read the int into a regular string via stringstream, and then read the string into a char array. The following seems to be working, but I'm wondering if I'm just getting lucky with my compiler. Does the code seem sound? Thanks!
int zip = 1234;
char zipString[30];
stringstream str;
str << zip;
str >> zipString;
cout << zipString;
You can get a C++ std::string from the stream's str() function, and an immutable C-style zero-terminated string from the string's c_str() function:
std::string cpp_string = str.str();
char const * c_string = cpp_string.c_str();
You might be tempted to combine these into a single expression, str.str().c_str(), but that would be wrong; the C++ string will be destroyed before you can do anything with the pointer.
What you are doing will work, as long as you're sure that the buffer is large enough; but using the C++ string removes the danger of overflowing the buffer. In general, it's best to avoid C-style strings unless you need to use an API that requires them (or, in extreme circumstances, as an optimisation to avoid memory allocation). std::string is usually safer and easier to work with.
Unless you have a specific reason that you need an array of char instead of a standard string, I'd use the latter. Although it's not strictly necessary in this case, I'd also normally use a Boost lexical_cast instead of explicitly moving things through a stringstream to do the conversion:
std::string zipString = lexical_cast<std::string>(zip);
Then, if you really need the result as a c-style string, you can use zipString.c_str() to get that (though it's still different in one way -- you can't modify what that returns).
In this specific case it doesn't gain you a lot, but consistent use for conversions on this general order adds up, and if you're going to do that, you might as well use it here too.
The std::string's c_str() member function returns a const char* (aka a C-style string).
std::string str = "world";
printf("hello, %s", str.c_str());
Related
I am now using C++ to program a robot using PROS. Pros has a print function, which is taking in a const char*. Now, I'm using lvgl to create my own screen, and I want to replicate the print function. Like the printf() functions, I want it to include variadic params to do the %d effect (so it converts all the %? to the corresponding values). The problem now is about the conversions between functions. I wanted to make a convert function to convert a string and the variadic params into a complete string. I need to input is a string which is like "hey" and I'm unsure what the type name should be. I need to be able to get size, search in it for %ds but I need the function to return a const char* to pass onto the lvgl to pring on the screen. I am having a bad time trying to convert a string into an const char* for the out put of the convert function.
Also, I tried using the input type as a char*, and when I input a string like "hello" is says a error [ISO C++11 does not allow conversion from string literal to 'char ' [-Wwritable-strings]]. But instead, when is use a const char, the error disappears. Anyone knows why?
Thanks everyone for your kind help!
char* and const char* are two flavours of the same thing: C-style strings. These are a series of bytes with a NUL terminator (0-byte). To use these you need to use the C library functions like strdup, strlen and so on. These must be used very carefully as missing out on the terminator, which is all too easy to do by accident, can result in huge problems in the form of buffer-overflow bugs.
std::string is how strings are represented in C++. They're a lot more capable, they can support "wide" characters, or variable length character sets like UTF-8. As there's no NUL terminator in these, they can't be overflowed and are really quite safe to use. Memory allocation is handled by the Standard Library without you having to pay much attention to it.
You can convert back and forth as necessary, but it's usually best to stick to std::string inside of C++ as much as you can.
To convert from C++ to C:
std::string cppstring("test");
const char* c_string = cppstring.c_str();
To convert from C to C++:
const char* c_string = "test";
std::string cppstring(c_string);
Note you can convert from char* (mutable) to const char* (immutable) but not in reverse. Sometimes things are flagged const because you're not allowed to change them, or that changing them would cause huge problems.
You don't really have to "convert" though, you just use char* as you would const char*.
std::string A = "hello"; //< assignment from char* to string
const char* const B = A.c_str(); //< call c_str() method to access the C string
std::string C = B; //< assignment works just fine (with allocation though!)
printf("%s", C.c_str()); //< pass to printf via %s & c_str() method
I am new to C++, and haven't quite grasped all the concepts yet, so i am perplexed at why this function does not work. I am currently not at home, so i cannot post the compiler error just yet, i will do it as soon as i get home.
Here is the function.
const char * ConvertToChar(std::string input1, std::string input2) {
// Create a string that you want converted
std::stringstream ss;
// Streams the two strings together
ss << input1 << input2;
// outputs it into a string
std::string msg = ss.str();
//Creating the character the string will go in; be sure it is large enough so you don't overflow the array
cont char * cstr[80];
//Copies the string into the char array. Thus allowing it to be used elsewhere.
strcpy(cstr, msg.c_str());
return * cstr;
}
It is made to concatenate and convert two strings together to return a const char *. That is because the function i want to use it with requires a const char pointer to be passed through.
The code returns a pointer to a local (stack) variable. When the caller gets this pointer that local variable doesn't exist any more. This is often called dangling reference.
If you want to convert std::string to a c-style string use std::string::c_str().
So, to concatenate two strings and get a c-style string do:
std::string input1 = ...;
std::string input2 = ...;
// concatenate
std::string s = input1 + input2;
// get a c-style string
char const* cstr = s.c_str();
// cstr becomes invalid when s is changed or destroyed
Without knowing what the error is, it's hard to say, but this
line:
const char* cstr[80];
seems wrong: it creates an array of 80 pointers; when it
implicitly converts to a pointer, the type will be char
const**, which should give an error when it is passed as an
argument to strcpy, and the dereference in the return
statement is the same as if you wrote cstr[0], and returns the
first pointer in the array—since the contents of the array
have never been initialized, this is undefined behavior.
Before you go any further, you have to define what the function
should return—not only its type, but where the pointed to
memory will reside. There are three possible solutions to this:
Use a local static for the buffer:
This solution was
frequently used in early C, and is still present in a number of
functions in the C library. It has two major defects: 1)
successive calls will overwrite the results, so the client code
must make its own copy before calling the function again, and 2)
it isn't thread safe. (The second issue can be avoided by using
thread local storage.) In cases like yours, it also has the
problem that the buffer must be big enough for the data, which
probably requires dynamic allocation, which adds to the
complexity.
Return a pointer to dynamically allocated memory:
This works well in theory, but requires the client code to free
the memory. This must be rigorously documented, and is
extremely error prone.
Require the client code to provide the buffer:
This is probably the best solution in modern code, but it does
mean that you need extra parameters for the address and the
length of the buffer.
In addition to this: there's no need to use std::ostringstream
if all you're doing is concatenating; just add the two strings.
Whatever solution you use, verify that the results will fit.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Splitting a string in C++
char *strtok(char *s1, const char *s2)
How can I convert a string to a char* as required by strtok? I did
for (string line; getline(sourceFile, line);) {
tokens = strtok(line.c_str(), " {};");
}
Where sourceFile is an ifstream (sourceFile.open(filepath.c_str());)
I am getting:
argument of type "const char *" is incompatible with parameter of type "char *"
As others have said, you probably want to use something other than strtok.
However, to do what you are asking (and you probably shouldn't):
for (string line; getline(sourceFile, line);) {
char* line_cstr = strdup(line.c_str());
char* token = strtok(line_cstr, " {};");
while ((token = strtok(NULL, " {};")) != NULL) {
//code
}
free(line_cstr);
}
If you do something like this:
char fp[40]; // or some reasonable size
strcpy( fp, filepath.c_str()); // fp is not a const char* like c_str() returns
You should be able to use strtok() against fp.
But you might want to consider a more C++ way of splitting strings.
As Jonathan Leffler's comment explains, strtok actually modifies the buffer in place to terminate successive tokens. That's great for speed - saves copying each token out to some other memory area while still giving you convenient access to it as a separate NUL-terminated sequence. It's an interesting question whether it's legitimate to use strtok on a std::string instance - certainly, the c_str() member returns a const char* because you're not meant to write over parts of that buffer. But, as long as you don't have an empty string (for which it'd give undefined behaviour), you can get a char* to the first element with &line[0]. Having done that, you can mutate the string, but only at offsets [0]..[size()-1]... it's not guaranteed to be NUL terminated the way the c_str()-returned buffer is, and precisely because of that the &line[0]-returned buffer may not be suitable for use by strtok. You could append a NUL (i.e. line += '\0' - NUL is legal std::string content), but it would make the code a bit hackish and harder to maintain, and you might need to remove the NUL afterwards if you're planning to use the original value for anything.
If you really want to use strtok, seems best to copy the data to a separate writable NUL-terminated buffer first. For example:
char* p = strdup(line.c_str());
... use strtok on p ...
free(p);
You could use alloca(), a smart pointer, a std::vector<char> to minimise potential for memory leaks. (I don't see any particular reason to prefer C++ new and delete for the above - you're using strtok anyway, but if you've smart-pointer libraries that expect it go for it).
All that said, finding another mechanism - like those in boost - is a better option. I'm guessing alternatives like that are discussed in the link chris posted in a comment under your question....
I have the function below in a file called WiServer.h for Arduino.
GETrequest(uint8* ipAddr, int port, char* hostName, char* URL);
Now the problem is I need to concatenate an int value (setting1) to the char* URL parameter like the below for example.
"twittermood.php?status=sendTweet&setting1="+setting1
I get an error:
invalid conversion from const char* to char*
How do I fix it?
You've gotten decent generic C++ advice, but for the special case of Arduino on an 8-bit AVR microcontroller I think you need platform-specific advice:
The Arduino runtime provides a String object. Your question is probably covered by these examples.
Because of the very limited RAM space on Arduino it is common to use special attributes to put constant strings in flash (essentially ROM) which requires different instructions to access. AVR code built with GCC is typically built on top of AVR Libc which has support for operating on a mix of constant strings and RAM strings. You must be explicit in your code and choose the right operations. This requires at least a basic understanding of how C strings work and how pointers work. I'm not sure how much of this cleverness is automatically provided by the Arduino String, but without this cleverness all of your string constants will end up copied into RAM at boot and will take up those precious bytes all the time.
If RAM space becomes a problem or you are working on an AVR application that does extensive string manipulation you need to learn how to use the mix of PGM Space operations (string functions that can work on read-only strings in flash) and regular C-style RAM-based string operations.
Use std::string, rather than C strings. Use string streams, rather than trying to concatenate non-string values to strings:
std::ostringstream oss;
oss << "twittermood.php?status=sendTweet&setting1=" << setting1;
use(oss.str()); // or use(oss.str().c_str());
If that API really needs a non-const string (given that it doesn't even take the length of the string, I suppose it's just a buggy API disregarding const), copy the string to a buffer and pass that:
const std::string& str = oss.str();
std::vector<char> buffer(str.begin(), str.end());
buffer.push_back('\0');
GETrequest(addr, port, &buffer[0], c);
As for what really happens when you do what you do:
"twittermood.php?status=sendTweet&setting1=" is an rvalue of the type char[43], which implicitly converts to const char*, a pointer to the first character. To that you add an integer, by this forming a new pointer of the type const char* pointing to some more or less random memory location. I suppose you try to pass this as the char* to your API function, for which the const would have to be dropped.
A C++ compiler, however, will never implicitly drop a const — for your own good.
Use a std::string, not a char*, for this sort of work. A char* in C is extremely basic and if you're not familiar with how C works, very easy to use wrong.
If you need to use char*, look into strcpy, strcat and snprintf. But these functions are very dangerous in a novice's hands and can lead to memory corruption and crashing.
You can use an ostringstream for this:
#include <sstream>
// ...
std::ostringstream os;
os << "twittermood.php?status=sendTweet&setting1=" << setting1;
GETrequest(addr, port, hostname, os.str().c_str());
Use std::string instead of char* and maybe a std::stringstream for your concatination. But first about your errors:
Your problem is that "twittermood.php?status=sendTweet&setting1=" will get you a const char*, which can't be implicitely converted to a char*. If you are really sure that GETrequest doesn't try to change the value of its URL parameter, you can use const_cast<char*>(...) on your const char* variable to cast away the constness. However, do this only if you are absolutely sure it won't be changed (don't lie to the compiler about constness (or anything really)).
Even if you do that "twittermood.php?status=sendTweet&setting1="+setting1 won't do what you think it does. As I said your string constant will give you a const char*, which doesn't have any knowledge about string operations. So adding an intto it won't concat that int to the string, but instead do some pointerarithmetic, so if you are lucky and your int was small enough you get only a part of the URL, otherwise you will address something completely different.
Posting C solution for completeness:
const char ctext[] = "twittermood.php?status=sendTweet&setting1=";
char text[sizeof(ctext) + 20];
snprintf(text, sizeof(text), "%s%i", ctext, setting1);
std strings and streams are much nicer/safer to use.
In a recent question, I learned that there are situations where you just gotta pass a char* instead of a std::string. I really like string, and for situations where I just need to pass an immutable string, it works fine to use .c_str(). The way I see it, it's a good idea to take advantage of the string class for its ease of manipulation. However, for functions that require an input, I end up doing something like this:
std::string str;
char* cstr = new char[500]; // I figure dynamic allocation is a good idea just
getstr(cstr); // in case I want the user to input the limit or
str = cstr; // something. Not sure if it matters.
delete[] cstr;
printw(str.c_str());
Obviously, this isn't so, uh, straightforward. Now, I'm pretty new to C++ so I can't really see the forest for the trees. In a situation like this, where every input is going to have to get converted to a C string and back to take advantage of string's helpful methods, is it just a better idea to man up and get used to C-style string manipulation? Is this kind of constant back-and-forth conversion too stupid to deal with?
In the example you give, you can generally read a line into a std::string using the std::getline function: http://www.cplusplus.com/reference/string/getline/
Of course this doesn't do everything that a curses library does. If you need a non-const char* so that some C function can read into it, you can use a vector<char>. You can create a vector<char> from a string, and vice-versa:
std::string a("hello, world");
std::vector<char> b(a.begin(), a.end());
// if we want a string consisting of every byte in the vector
std::string c(b.begin(), b.end());
// if we want a string only up to a NUL terminator in the vector
b.push_back(0);
std::string d(&b[0]);
So your example becomes:
std::vector<char> cstr(500);
getnstr(&cstr[0], 500);
printw(&cstr[0]);
Most std::string::c_str() implementations (if not all of them) simply return a pointer to an internal buffer. No overhead whatsoever.
Beware however that c_str() returns a const char*, not a char*. And that the pointer will become invalid after the function call. So you cannot use it if the function does anything like writing back into the passed string or makes a copy of the pointer.