Convert str to char* issue - c++

I need to convert a Str to char* but I sometimes lose a part of the string.
For example:
str: "/Users/seb/Pictures/Photos/20141009 - Aulani - Hawaii/20141009_083318_Richtone(HDR).jpg"
char*: /Users/seb/Pictures/Photos/20141009 - Aulani - Hawaii/20141009_083318_Ri
I'm using the code below:
void TreeWidget::CopyFilesFromLocal(QStringList pathList, QTreeWidgetItem * item) {
QString fileelt;
uint32_t Folder_id = INVALID;
MyTreeWidget* myItem = dynamic_cast<MyTreeWidget*>(item);
uint32_t destination_id = myItem->mtp_item_id;
item->setExpanded(true);
qDebug() << "**************************************";
qDebug() << "Send to PULS Start";
qDebug() << "Start of Loop to copy files";
foreach(fileelt, pathList) {
char *txt = NULL;
// char *isFileName = NULL;
qDebug() << "str: " << fileelt;
txt = strdup(m_device.convertQStr2char(fileelt));
qDebug() << "char*: " << txt;
Here is the api I use.
char *PulsDeviceMngr::convertQStr2char(QString str) {
return const_cast<char*>(std::string(str.toUtf8().constData() ).c_str());
}
Any idea ?

The pointer you return form convertQStr2char points to the internal buffer of the temporary std::string which is destroyed after the return. You thus use a dangling pointer and have undefined behavior.
Note that changing the data pointed to by std::string::c_string() through said pointer also is UB. Your const_cast is a very bad idea because it would allow exactly this even if you got the lifetime right.
You could do this instead (includes a couple of unnecessary copies, but get it working first, then worry about the rest):
char *PulsDeviceMngr::convertQStr2char(QString str) {
return strdup(std::string(str.toUtf8().constData() ).c_str());
}
Then do not forget to free the buffer. But it would probably be better to just return the std::string by value and then use .c_str() outside of your conversion function. This way, you do not need to use the non-C++ strdup and do not need to manage memory by hand, which would be error prone anyway.

You don't need an extra method
txt = strdup(fileelt.toUtf8().constData());
will work fine.

Related

Issue with conversion QByteArray to char*

I faced an issue, which I can not explain when converting QByteArray to const char* not inline. Here is an example:
QString string1("ABCDEFGHI");
const char* stringData1 = string1.toUtf8().constData();
qDebug() << "String:" << string1 << "\nbytearray:" << string1.toUtf8()
<< "\ndata immediate:" << string1.toUtf8().constData() << "\ndata stored:" << stringData1;
QString string2("ABCDEFGHJ");
const char* stringData2 = string2.toUtf8().constData();
qDebug() << "String:" << string2 << "\nbytearray:" << string2.toUtf8()
<< "\ndata immediate:" << string2.toUtf8().constData() << "\ndata stored:" << stringData2;
I get the following output:
String: "ABCDEFGHI"
bytearray: "ABCDEFGHI"
data immediate: ABCDEFGHI
data stored:
String: "ABCDEFGHJ"
bytearray: "ABCDEFGHJ"
data immediate: ABCDEFGHJ
data stored: ABCDEFGHJ
The output of data stored is not guaranteed to be wrong in case 1, but correct in case 2. I can swap cases 1 and 2, and the result will be the same - wrong in case 1, but correct in case 2.
Inline conversion seems to work just fine.
Do you see any issues with conversion from QByteArray to const char* if a const char* variable is used to store the result?
toUtf8 returns an object whose lifetime ends at the end of the expression.
constData returns a pointer into this temporary object.
Thus, you're using dangling pointers and the behaviour is undefined.
You need to extend the lifetime of the converted string:
QString string1("ABCDEFGHI");
QByteArray utfString = string1.toUtf8();
const char* stringData1 = utfString.constData();
This call string1.toUtf8().constData() consists of two consequential ones: QString::toUtf8()which produces a temporary QByteArray, and QByteArray::constData() which returns a pointer to a temporary object, which eventually getting destroyed.
The way I used to get a QString variable, convert it to QByteArray and finally const char* is this:
QString var1 = ui->lineEdit->text().toUtf8();
QByteArray ba = var1.toLocal8Bit();
const char *var1final = ba.data();
The value of QString is collected by Ui, in lineEdit.

Passing string 'by value' change in local value reflect in original value

Why is the change of my local variable's value getting reflected into original variable? I am passing it by value in C++.
#include <string>
#include <iostream>
void test(std::string a)
{
char *buff = (char *)a.c_str();
buff[2] = 'x';
std::cout << "In function: " << a;
}
int main()
{
std::string s = "Hello World";
std::cout << "Before : "<< s << "\n" ;
test(s);
std::cout << "\n" << "After : " << s << std::endl;
return 0;
}
Output:
Before : Hello World
In function: Hexlo World
After : Hexlo World
As soon as you wrote
buff[2] = 'x';
and compiled your code all bets were off. Per [string.accessors]
const charT* c_str() const noexcept;
Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
Complexity: constant time.
Requires: The program shall not alter any of the values stored in the character array.
emphasis mine
Since you are not allowed to modify the characters that the pointer points to but you do, you have undefined behavior. The compiler at this point is allowed to do pretty much whatever it wants. Trying to figure out why it did what it did is meaningless as any other compiler might not do this.
The moral of the story is do not cast const away unless you are really sure that you know what you are doing and if you do you need to, then document the code to show you know what you are doing.
Your std::string implementation uses reference counting and makes a deep copy only if you modify the string via its operator[] (or some other method). Casting the const char* return value of c_str() to char* will lead to undefined behavior.
I believe since C++11 std::string must not do reference counting anymore, so switching to C++11 might be enough to make your code work (Edit: I did not actually check that before, and it seems my assumption was wrong).
To be on the safe side, consider looking for a string implementation that guarantees deep copying (or implement one yourself).
#include <cstring>
#include <string>
#include <iostream>
void test(std::string a)
{
// modification trough valid std::string API
a[2] = 'x';
const char *buff = a.c_str(); // only const char* is available from API
std::cout << "In function: " << a << " | Trough pointer: " << buff;
// extraction to writeable char[] buffer
char writeableBuff[100];
// unsafe, possible attack trough buffer overflow, don't use in real code
strcpy(writeableBuff, a.c_str());
writeableBuff[3] = 'y';
std::cout << "\n" << "In writeable buffer: " << writeableBuff;
}
int main()
{
std::string s = "Hello World";
std::cout << "Before : "<< s << "\n" ;
test(s);
std::cout << "\n" << "After : " << s << std::endl;
return 0;
}
Output:
Before : Hello World
In function: Hexlo World | Trough pointer: Hexlo World
In writeable buffer: Hexyo World
After : Hello World

C++ MFC missing const char* variable

So I have that simple code inside button click method:
std::stringstream ss;
unsigned counter = 0;
while(true)
{
ss.clear();
ss << DEFAULT_USER_CONFIG_NAME << " " << ++counter;
const char* name = ss.str().c_str();
MessageBox(name);
/* ... while break condition */
}
The problem is that messagebox is empty. But it works correctly when I pass text directly:
MessageBox(ss.str().c_str()); // that shows text just fine
What I found with debugger is that local variable "name" is not created(at least it is not showing in debugger). Any clue why it is working when passed directly and failing otherwise? Also when i casted "name" to CString it returned true on IsEmpty() check.
The expression ss.str() creates a temporary std::string object. Storing the result of c_str() thus points to memory of a temporary, which quickly turns into a dangling pointer. Once the full expression statement
const char* name = ss.str().c_str();
// ^ this is where the temporary ss.str() gets destroyed.
is evaluated, the temporary gets destroyed.
You already know, how to solve this, by placing the expression creating the temporary inside the full expression, that consumes it. This extends the lifetime of the temporary until the end of the full expression:
MessageBox(ss.str().c_str());
// ^ this is where the temporary ss.str() gets destroyed.
The following illustrates the sequence of events. Let's just define a few placeholder classes and functions:
void messagebox(const char*) {
cout << "messagebox()" << endl;
}
struct tmp {
tmp(const char* content) : content(content) { cout << "tmp c'tor" << endl; }
~tmp() { cout << "tmp d'tor" << endl; }
const char* c_str() { return content.c_str(); }
private:
string content;
};
struct ss {
tmp str() { return tmp("test"); }
};
With this in place, your first version
ss s;
const char* name = s.str().c_str();
messagebox(name);
produces the following output:
tmp c'tor
tmp d'tor
messagebox()
Whereas the second version
ss s;
messagebox(s.str().c_str());
changes the sequence in the output:
tmp c'tor
messagebox()
tmp d'tor
(Live sample code)

With a string longer than 10 letters, char* changes without any apparent reason. Why?

In step 2 I change only the value of name_C. Why does name_B also change?
Here is the code:
#include <cstdlib>
#include <dirent.h>
#include <iostream>
#include <fstream>
#include <direct.h>
using namespace std;
int main(int argc, char *argv[])
{
// step 1
char *name_A;
char *name_B;
char *name_C;
string str_L = "hello";
string str_M = "stringVar_A"; ;
name_A = (char *) str_M.c_str();
name_B = (char *) (str_L + "-car-" + str_M).c_str();
name_C = (char *) str_L.c_str();
cout << " name_A= " << name_A << endl;
cout << " name_B= " << name_B << endl;
cout << " name_C= " << name_C << endl << endl << endl;
// step 2
string str_N = "myStringMyString"; // (in my real code, i can't put this line in step 1)
string str_R = "ABCDEFGHI" + str_N; // (in my real code, i can't put this line in step 1)
name_C = (char *)str_R.c_str(); // change only name_C
cout << " name_A= " << name_A << endl;
cout << " name_B= " << name_B << endl; // changed, why?
cout << " name_C= " << name_C << endl; // changed, ok.
system("PAUSE");
return EXIT_SUCCESS;
};
Here the output:
(step 1:)
name_A= stringVar_A
name_B= hello-car-stringVar_A
name_C= hello
(step 2:)
name_A= stringVar_A
name_B= ABCDEFGHImyStringMyString
name_C= ABCDEFGHImyStringMyString
With:
string str_N = "myString"; // in step 2...
name_B does not change.
Why does name_B change if str_N is longer than 10 letters?
Can someone help me understand this behavior?
The pointer returned by a call to c_str is only valid for as long as the corresponding std::string stays in scope and is unmodified.
The behaviour in accessing it beyond that is undefined.
For example, (str_L + "-car-" + str_M).c_str(); is returning you the c_str of an anonymous temporary. It will be immediately invalid after the assignment. In your case, name_B is invalidated.
Also, don't cast away the const char* return of c_str(). It's const for a very good reason: you should not attempt to modify the string contents through that pointer.
You are causing undefined behaviour.
name_B = (char *) (str_L + "-car-" + str_M).c_str();
you create a temoprary string from the result of std::string::operator + , extract the C-character array out of it, but then no-one really cathes the temporary string.
when a temporary is not caught by const reference - it is destroyed right away. the string destructor de-allocates the inner character array and invalidates name_B.
so, this is undefined behaviour since you try to work with memory address that is no longer valid.
std::string::c_str() returns a pointer to an internal buffer of a std::string with the guarantee that:
it points to a NUL-terminated string;
the range [c_str(); c_str() + size()] is valid.
In your case, name_B points to an internal buffer of a temporary object name_B = (str_L + "-car-" + str_M).c_str(); which will lead to an Undefined Behaviour when you'll try to use it.
When you make some modifications on your stack (you define two new std::strings), you probably alter the stack place where your name_B points to (since the memory reserved by your temporary has been freed).
If you really have to get old style C-strings from your std::strings, make sure:
The pointer retrieved from std::string::c_str() is no longer used when the std::string is modified or destroyed,
hence you don't call std::string::c_str() from a temporary.

C++ returning stringstream.str()

I have a static method that should return the next available id. Several static members in other classes call this function, so each gets a different id assigned. However, when I am printing the assigned values I dont get "id0", "id1" but just a symbol like "*". I'm using this code:
int A::i = 0; //static member
std::string A::id()
{
std::stringstream sst;
sst<< "id" << A::i;
i++;
return sst.str(); //i've tried to return a const char* too, but doesnt work either
}
//assigning id's in several classes like this:
const char* B::id = A::id().c_str();
const char* C::id = A::id().c_str();
//printing them in the main function:
std::cout << B::id << " " << C::id << "\n";
I dont understand why the code above doesnt work. When I am executing the following code the expected result "id10" is printed:
static std::string gt()
{
std::stringstream ss;
ss << "id" << 10;
return ss.str();
}
Look at
const char* C::id = A::id().c_str();
You are creating a new id string, then you take a pointer to its data (as a c-string), and inmediately after that the temporary string to which contents you are pointing gets destroyed. Simple answer: either stick to std::string or to plain int ids.