Conversion from int to c-string (const char*) fails - c++

I fail to convert int to a c-string (const char*):
int filenameIndex = 1;
stringstream temp_str;
temp_str<<(fileNameIndex);
const char* cstr2 = temp_str.str().c_str();
There is no error but cstr2 does not get the expected value. It is initialized with some address.
What's wrong and how can I fix it?

temp_str.str() returns a temporary object which is destroyed at the end of a statement. As such, the address pointed by cstr2 gets invalidated.
Instead, use:
int filenameIndex = 1;
stringstream temp_str;
temp_str<<(filenameIndex);
std::string str = temp_str.str();
const char* cstr2 = str.c_str();
DEMO

temp_str.str() is a temporary string value, destroyed at the end of the statement. cstr2 is then a dangling pointer, invalidated when the array it pointed to was deleted by the string's destruction.
You'll need a non-temporary string if you want to keep hold of a pointer to it:
string str = temp_str().str(); // lives as long as the current block
const char* cstr2 = str.c_str(); // valid as long as "str" lives
Modern C++ also has slightly more convenient string conversion functions:
string str = std::to_string(fileNameIndex);
const char* cstr2 = str.c_str(); // if you really want a C-style pointer
Again, this returns a string by value, so don't try cstr2 = to_string(...).c_str()

Related

How to convert string array to const char **?

I was think something like:
const char * res[cnt];
int i = 0;
for (auto mystring : strings) {
const char * str = mystring.c_str();
res[i++] = str;
}
//then pass res as const char **
But it occurred to me that 'str' is a local variable, the address stored in res could be invalid? What is the right way to do so?
The problem has nothing to do with str, which will be destroyed after iteration, but this doens't mean the char array pointed by it will be destroyed too.
The problem is mystring is declared as by-copy, it'll be destroyed after iteration, then the char arrays returned by c_str get destroyed too. Pointers assigned into res become dangling.
You can change mystring as reference (to const), e.g.
for (auto const & mystring : strings) {
const char * str = mystring.c_str();
res[i++] = str;
}

C++ string to C string

Consider the following piece of code:
void fun (string &str1, string &str2)
{
const char* cstr;
....
if(strlen(cstr = (str1+str2).c_str()) < 15)
{
// here cstr used
}
}
The condition itself works fine, but in the if-condition body cstr contains garbage. Why?
In this expression:
cstr = (str1+str2).c_str()
you are taking a pointer to the temporary string str1 + str2. This temporary dies at the end of the expression, and so you have undefined behaviour when you try to read from cstr inside the if-body.
I'm assuming the string in your C++ code is std::string.
str1 + str2 produces a temporary std::string object. You invoke the c_str() method on it, and you get a C-style string pointer to the data of this temporary std::string object.
When the temporary std::string goes out of scope and is destroyed, the cstr raw C-style pointer is left dangling, pointing to invalid memory.
If you need to work on the concatenated string str1 + str2, I would suggest you safely store it in a non-temporary std::string object, e.g.:
std::string s = str1 + str2;
// Work with s
if (s.length() < 15) {
// Use s here
...
}
Note also that I invoked the std::string::length() method instead of the C function strlen(). You can use the std::string::size() method, as well.
In general, in C++ code, you should use convenient string classes (like std::string), instead of C-style raw string pointers.

convertion from QString to char pointer generates empty string

Here's some test code:
QString qstr_test("TEST");
const char *p = qstr_test.toStdString().c_str();
cout << p << endl;
Nothing is output as p is an empty string.
Here's what I got at debugging:
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::c_str
returns: 0x003bf9d4 "TEST"
p : 0x003bf9d4 ""
It seems p is pointing to the right location but doesn't display the right content.
Why is p empty ?
std::string object is temporary and is destroyed right after c_str() is completed. But std::string owns char* buffer returned by c_str() and this buffer is also destroyed. So your code is incorrect and dangerous. You need to store std::string as long as you use char* buffer:
std::string s = qstr_test.toStdString();
const char* p = s.c_str();
Also it seems pointless to create std::string just to convert it to char*. QString has better methods: toLatin1, toLocal8bit, and toUtf8. Note that returned QByteArray has the same issue that is a common source of mistakes. QByteArray also must be stored if you want to use its buffer.
QByteArray array = qstr_test.toUtf8();
const char* p = array.constData();
I think this method is better because here you specify explicitly the encoding you need to use. And toStdString result depends on QTextCodec::codecForCStrings() current value.

std::string to char*

I want to convert a std::string into a char* or char[] data type.
std::string str = "string";
char* chr = str;
Results in: “error: cannot convert ‘std::string’ to ‘char’ ...”.
What methods are there available to do this?
It won't automatically convert (thank god). You'll have to use the method c_str() to get the C string version.
std::string str = "string";
const char *cstr = str.c_str();
Note that it returns a const char *; you aren't allowed to change the C-style string returned by c_str(). If you want to process it you'll have to copy it first:
std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;
Or in modern C++:
std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
More details here, and here but you can use
string str = "some string" ;
char *cstr = &str[0];
As of C++11, you can also use the str.data() member function, which returns char *
string str = "some string" ;
char *cstr = str.data();
If I'd need a mutable raw copy of a c++'s string contents, then I'd do this:
std::string str = "string";
char* chr = strdup(str.c_str());
and later:
free(chr);
So why don't I fiddle with std::vector or new[] like anyone else? Because when I need a mutable C-style raw char* string, then because I want to call C code which changes the string and C code deallocates stuff with free() and allocates with malloc() (strdup uses malloc). So if I pass my raw string to some function X written in C it might have a constraint on it's argument that it has to allocated on the heap (for example if the function might want to call realloc on the parameter). But it is highly unlikely that it would expect an argument allocated with (some user-redefined) new[]!
(This answer applies to C++98 only.)
Please, don't use a raw char*.
std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*
If you just want a C-style string representing the same content:
char const* ca = str.c_str();
If you want a C-style string with new contents, one way (given that you don't know the string size at compile-time) is dynamic allocation:
char* ca = new char[str.size()+1];
std::copy(str.begin(), str.end(), ca);
ca[str.size()] = '\0';
Don't forget to delete[] it later.
If you want a statically-allocated, limited-length array instead:
size_t const MAX = 80; // maximum number of chars
char ca[MAX] = {};
std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);
std::string doesn't implicitly convert to these types for the simple reason that needing to do this is usually a design smell. Make sure that you really need it.
If you definitely need a char*, the best way is probably:
vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
This would be better as a comment on bobobobo's answer, but I don't have the rep for that. It accomplishes the same thing but with better practices.
Although the other answers are useful, if you ever need to convert std::string to char* explicitly without const, const_cast is your friend.
std::string str = "string";
char* chr = const_cast<char*>(str.c_str());
Note that this will not give you a copy of the data; it will give you a pointer to the string. Thus, if you modify an element of chr, you'll modify str.
Assuming you just need a C-style string to pass as input:
std::string str = "string";
const char* chr = str.c_str();
To obtain a const char * from an std::string use the c_str() member function :
std::string str = "string";
const char* chr = str.c_str();
To obtain a non-const char * from an std::string you can use the data() member function which returns a non-const pointer since C++17 :
std::string str = "string";
char* chr = str.data();
For older versions of the language, you can use range construction to copy the string into a vector from which a non-const pointer can be obtained :
std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();
But beware that this won't let you modify the string contained in str, only the copy's data can be changed this way. Note that it's specially important in older versions of the language to use c_str() here because back then std::string wasn't guaranteed to be null terminated until c_str() was called.
To be strictly pedantic, you cannot "convert a std::string into a char* or char[] data type."
As the other answers have shown, you can copy the content of the std::string to a char array, or make a const char* to the content of the std::string so that you can access it in a "C style".
If you're trying to change the content of the std::string, the std::string type has all of the methods to do anything you could possibly need to do to it.
If you're trying to pass it to some function which takes a char*, there's std::string::c_str().
Here is one more robust version from Protocol Buffer
char* string_as_array(string* str)
{
return str->empty() ? NULL : &*str->begin();
}
// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here
Conversion in OOP style
converter.hpp
class StringConverter {
public: static char * strToChar(std::string str);
};
converter.cpp
char * StringConverter::strToChar(std::string str)
{
return (char*)str.c_str();
}
usage
StringConverter::strToChar("converted string")
For completeness' sake, don't forget std::string::copy().
std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];
str.copy(chrs, MAX);
std::string::copy() doesn't NUL terminate. If you need to ensure a NUL terminator for use in C string functions:
std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];
memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
You can make it using iterator.
std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);
Good luck.
A safe version of orlp's char* answer using unique_ptr:
std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
Alternatively , you can use vectors to get a writable char* as demonstrated below;
//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0');
char* cstring = &writable[0] //or &*writable.begin ()
//Goodluck
This will also work
std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;
No body ever mentioned sprintf?
std::string s;
char * c;
sprintf(c, "%s", s.c_str());

how to copy char * into a string and vice-versa

If i pass a char * into a function. I want to then take that char * convert it to a std::string and once I get my result convert it back to char * from a std::string to show the result.
I don't know how to do this for conversion ( I am not talking const char * but just char *)
I am not sure how to manipulate the value of the pointer I send in.
so steps i need to do
take in a char *
convert it into a string.
take the result of that string and put it back in the form of a char *
return the result such that the value should be available outside the function and not get destroyed.
If possible can i see how it could be done via reference vs a pointer (whose address I pass in by value however I can still modify the value that pointer is pointing to. so even though the copy of the pointer address in the function gets destroyed i still see the changed value outside.
thanks!
Converting a char* to a std::string:
char* c = "Hello, world";
std::string s(c);
Converting a std::string to a char*:
std::string s = "Hello, world";
char* c = new char[s.length() + 1];
strcpy(c, s.c_str());
// and then later on, when you are done with the `char*`:
delete[] c;
I prefer to use a std::vector<char> instead of an actual char*; then you don't have to manage your own memory:
std::string s = "Hello, world";
std::vector<char> v(s.begin(), s.end());
v.push_back('\0'); // Make sure we are null-terminated
char* c = &v[0];
You need to watch how you handle the memory from the pointer you return, for example the code below will not work because the memory allocated in the std::string will be released when fn() exits.
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
return s.c_str(); //BAD
}
One solution is to allocate the memory in the function and make sure the caller of the function releases it:
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
char *ret = new char[s.size()]; //memory allocated
strcpy(ret, s.c_str());
return ret;
}
....
const char* p = fn("some text");
//do something with p
delete[] p;// release the array of chars
Alternatively, if you know an upper bound on the size of the string you can create it on the stack yourself and pass in a pointer, e.g.
void fn(const char*in size_t bufsize, char* out) {
std::string s(psz);
// do something with s
strcpy_s(out, bufsize, s.c_str()); //strcpy_s is a microsoft specific safe str copy
}
....
const int BUFSIZE = 100;
char str[BUFSIZE];
fn("some text", BUFSIZE, str);
//ok to use str (memory gets deleted when it goes out of scope)
You can maintain a garbage collector for your library implemented as
std::vector<char*> g_gc; which is accessible in your library 'lib'. Later, you can release all pointers in g_gc at your convenience by calling lib::release_garbage();
char* lib::func(char*pStr)
{
std::string str(pStr);
char *outStr = new char[str.size()+1];
strcpy(outStr, str.c_str());
g_gc.push_back(outStr); // collect garbage
return outStr;
}
release_garbage function will look like:
void lib::release_garbage()
{
for(int i=0;i<g_gc.size();i++)
{
delete g_gc[i];
}
g_gc.clear();
}
In a single threaded model, you can keep this g_gc static. Multi-threaded model would involve locking/unlocking it.