I have found a lot of examples from stack overflow, but those examples are based on non-const std::string. What if the string is const(top level and non top level)?
std::string encrypt(std::string const &input)
{
//do something, ArrayGuard is a smart pointer to guard the raw char* delete by free
ArrayGuard<char> guard(encrypt_str(const_cast<char*>(input.c_str())));
return std::string(guard.get(), std::strlen(guard.get()));
}
case 1(non top level?) :
std::string input = "abcde";
std::string encrypt_password = encrypt(input);
case 2(top level?) :
std::string const input = "abcde";
std::string encrypt_password = encrypt(input);
I am sure that the encrypt_str would not alter the char* I pass into it(if it is possible, I would like to ask them to fix this non const correction api).
ps : I am not sure that I am fully understanding what is top level const/&/&&/volatile, that is why I put "?" behind the case
The rule you have to watch out for regarding const_cast is that if you use it to modify an object that was originally declared as const, then you get undefined behaviour.
As long as you're sure this doesn't happen, you're good.
The constness of the std::string doesn't make any difference. Even if the std::string is not const, the c_str function still returns a const char*. Nothing changes when you make the std::string const.
Related
I need a char* for my filename. It should be something like this: cards/h11.bmp
i have a function I cobbled together from various SO articles:
char* getFileName(int* pc1_no, char* suite)
{
int number;
char pCard1[80];
strcpy_s(pCard1, "cards/");
strcat_s(pCard1, suite);
number = *pc1_no;
cout << number << endl;
string str = to_string(number);
char const *pchar = str.c_str();
strcat_s(pCard1, pchar);
strcat_s(pCard1, ".bmp");
return pCard1;
}
Which of course, returns garbage. I don't quite get getting the pointer value. I pretty sure I have made a dumb mistake with the pointer. Thanks in advance.
The best way to do all this is get rid of all the pointers and use a string all of the way through:
std::string getFileName(int pc1_no,
const std::string & suite)
{
std::string pCard1 = "cards/" + suite + std::to_string(pc1_no) + ".bmp";
return pCard1;
}
or if building to older C++ standards where std::to_string is not available:
std::string getFileName(int pc1_no,
const std::string & suite)
{
std::stringstream pCard1;
pCard1<< "cards/" << suite << pc1_no << ".bmp";
return pCard1.str();
}
Rational
char pCard1[80];
is a local variable. It will die at the end of the function, so the function returns a pointer to invalid memory. Many bad things can happen as a result and few good. Watch out for the few good. They are liars waiting for the most opportune time to strike.
The simplest solution maintaining OP's structure is use a std::string to perform string manipulation inside the function.
std::string getFileName(int* pc1_no, char* suite)
{
std::string pCard1 = "cards/";
pCard1 += std::string(suite);
pCard1 += std::to_string(*pc1_no);
pCard1 += std::string(".bmp");
return pCard1;
}
The above is Horrible Code, both excessively verbose and inefficient, but we've already covered the right way in the intro. This is just a touch-point on the logical progression to that right way.
Faster and less complex is to take advantage of std::stringstream's ability to format c-style strings and numbers without any outside help. This approach is probably the best up until std::to_string became available in the C++11 standard.
std::string getFileName(int* pc1_no, char* suite)
{
std::stringstream pCard1;
pCard1<< "cards/" << suite << *pc1_no << ".bmp";
return pCard1.str();
}
There is the possibility of a performance penalty returning the string by value, but the compilers of the past few decades are good at detecting and taking advantage of opportunities to omit unnecessary copying and employing move semantics behind the scenes.
Returning string by value is also far less error-prone than dynamically allocating storage and returning the storage to a caller with the expectation that the caller release it. Any performance penalty that may remain is highly likely to be worth the price. Profile the code to be sure.
Improving the function call:
Passing pc1_no in as a pointer is not helping in any way. Unless you need to modify the value inside the function, just pass by value. If you do need to change the value, prefer a reference.
std::string getFileName(int pc1_no, char* suite)
If you try to pass a string literal: eg:
getFileName(&somenumber, "string literal");
string literals may be in non-writable memory and are always const char * in C++. Passing a const value into a space that could attempt to change the value is bad form. This was allowed for backwards compatibility with C under older C++ Standards, though it may generate an warning, but is illegal in after the C++ 11 Standard.
If your function does not need to modify the contents of the char array, and this doesn't, it's a good practice to tag the string as const and allow the compiler to prevent accidents regardless of whether your compiler allows const to non-const assignments:
std::string getFileName(int pc1_no, const char* suite)
You may have more versatility if you use a reference to a const std::string as it is implicitly convertible from both const and non-const char arrays and allows the rest of your program to take advantage of the many benefits of std::string without needless calls to c_str and data.
std::string getFileName(int pc1_no,
const std::string & suite)
That brings us back to where this answer came in.
Here is how this code would look like in C++:
#include <string>
std::string getFileName(int* n, const std::string& suite) {
return "cards/" + suite + std::to_string(*n) + ".bmp";
}
Even better would be to take the first parameter by value (int n) and dereference at the call site if necessary.
char* getFileName(int pc1_no, char* suite)
{
static char pCard1[80]; // Guarantee safe pointer return
strcpy_s(pCard1, "cards/");
strcat_s(pCard1, suite);
string str = to_string(pc1_no);
char const *pchar = str.c_str();
strcat_s(pCard1, pchar);
strcat_s(pCard1, ".bmp");
return pCard1; // Now you don't lose the result.
}
Or you can use recommended C++ style which is already answered.
I have a problem which i cannot fix on my own.
string filenameRaw;
filenameRaw= argv[1];
function(filenameRaw.c_str(),...);
function(const char* rawDataFile,const char* targetfieldFile,const char* resultFile,const char* filename)
...
this->IOPaths.rawData=rawDataFile;
...
works very fine so far. Now I try to put another string in the variable IOPaths.rawData...
function(const char* rawDataFile,const char* targetfieldFile,const char* resultFile,const char* filename)
...
string filenameRaw;
filenameRaw=reader.Get("paths", "rawData", "UNKNOWN")
...
const char* rawDataFile1=filenameRaw.c_str();
cout << "Compare: " << strcmp(rawDataFile,rawDataFile1) <<endl;
...
this->IOPaths.rawData=rawDataFile1;
this does not work any more. Later in my programm I get errors with the filename. The strcmp definitly gives a 0, so the strings must be equal. Does anyone has an idea what i am doing wrong?
The validity of the output of c_str() is limited to, at most, the lifetime of the object on which c_str() was called.1
I suspect that this->IOPaths.rawData is pointing to deallocated memory once filenameRaw is out of scope.
An adequate remedy would be to pass the std::string around rather than [const] char*. A good stl implementation would use copy on write semantics for the string class so perhaps you wouldn't be repeatedly copying string data.
1In certain instances (such as if the object is modified), it could be less.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Can I get a non-const C string back from a C++ string?
Do I need to convert it first? I saw in another post that .c_str() can be used if the function expected const char*. What about for just char*?
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
There is no way to get a char* from a string that is guaranteed to work on all platforms, for the simple fact that string is not required to use contiguous storage.
Your safest, most portable course of action is to copy the string somewhere that does use contigious storage (a vector perhaps), and use that instead.
vector<char> chars(my_string.begin(), my_string.end());
char* ptr = &chars[0];
If you want to be hacky and non-portable and decidedly unsafe, you can confirm that your string implementation does in fact use contigious storage, and then maybe use this:
&my_str[0]
But I would punch any developer that worked for me that did this.
EDIT:
I've been made aware that there are currently no known STL implementations that do not store the string data in a contiguous array, which would make &my_str[0] safe. It is also true (and I was asked to state this) that in the upcoming C++0x standard, it will be required for the storage to be contiguous.
It's been suggested that because if these facts that my post is factually incorrect.
Decide for yourself, but I say no. This is not in the current C++ standard, and so it is not required. I will still in practice do things the way I have suggested, and in any code review I will flag any code that assumes the underlying storage is contigious.
Consider this. Suppose there were a question about vtable pointers. Someone wants to examing a class and get the pointer to a virtual function by looking at the vtable. I would immediately tell them not to do this because there is no mention of how virtual methods are implemented in C++. Every implementation I know uses vtables, and I can't think of a better way to do it. It is likely that polymorphism will forever be implemented using vtables. Does that make it ok to examing the vtable directly?
IMO no, because this depends on undocumented implementation details. You have no control over this, and it could change at any time. Even if you expect it will never change, it is still bad engineering to rely on these implementation details.
Decide for yourself.
There are three scenarios:
If the function is outside of your control, and it either modifies the string, or you don't and can't know if it modifies the string:
Then, copy the string into a temporary buffer, and pass that to the function, like so:
void callFoo(std::string& str);
{
char* tmp = new char str(str.length() +1);
strncpy(tmp, str.c_str(), str.length());
foo(tmp);
// Include the following line if you want the modified value:
str = tmp;
delete [] tmp;
}
If the function is outside of your control, but you are certain it does not modify the string, and that not taking the argument as const is simply a mistake on the API's part.
Then, you can cast the const away and pass that to the function
void callFoo(const std::string& str)
{
foo(const_cast<char*> str.c_str());
}
You are in control of the function (and it would not be overly disruptive to change the signature).
In that case, change the function to accept either a string& (if it modifies the input buffer) or either const char* or const string& if it does not.
When a parameter is declared as char* there it is implicitly assumed that the function will have as a side effect the modification of the string that is pointed. Based in this and the fact that c_str() does not allow modifications to the enclosed string you cannot explicitly pass an std::string to such a method.
Something like this can be achived by following the following approach:
#include <cstdlib>
#include <string>
#include <iostream>
void modify_string(char* pz)
{
pz[0] = 'm';
}
class string_wrapper
{
std::string& _s;
char* _psz;
string_wrapper(const string_wrapper&);
string_wrapper& operator=(const string_wrapper&);
public:
string_wrapper(std::string& s) : _s(s), _psz(0) {}
virtual ~string_wrapper()
{
if(0 != _psz)
{
_s = _psz;
delete[] _psz;
}
}
operator char*()
{
_psz = new char[_s.length()+1];
strcpy(_psz,_s.c_str());
return _psz;
}
};
int main(int argc, char** argv)
{
using namespace std;
std::string s("This is a test");
cout << s << endl;
modify_string(string_wrapper(s));
cout << s << endl;
return 0;
}
If you are certain that the char* will not be modified, you can use const_cast to remove the const.
It's a dirty solution but I guess it works
std::string foo("example");
char* cpy = (char*)malloc(foo.size()+1);
memcpy(cpy, foo.c_str(), foo.size()+1);
Let's say that a function which returns a fixed ‘random text’ string is written like
char *Function1()
{
return “Some text”;
}
then the program could crash if it accidentally tried to alter the value doing
Function1()[1]=’a’;
What are the square brackets after the function call attempting to do that would make the program crash? If you're familiar with this, any explanation would be greatly appreciated!
The string you're returning in the function is usually stored in a read-only part of your process. Attempting to modify it will cause an access violation. (EDIT: Strictly speaking, it is undefined behavior, and in some systems it will cause an access violation. Thanks, John).
This is the case usually because the string itself is hardcoded along with the code of your application. When loading, pointers are stablished to point to those read-only sections of your process that hold literal strings. In fact, whenever you write some string in C, it is treated as a const char* (a pointer to const memory).
The signature of that function should really be constchar* Function();.
You are trying to modify a string literal. According to the Standard, this evokes undefined behavior. Another thing to keep in mind (related) is that string literals are always of type const char*. There is a special dispensation to convert a pointer to a string literal to char*, taking away the const qualifier, but the underlying string is still const. So by doing what you are doing, you are trying to modify a const. This also evokes undefined behavior, and is akin to trying to do this:
const char* val = "hello";
char* modifyable_val = const_cast<char*>(val);
modifyable_val[1] = 'n'; // this evokes UB
Instead of returning a const char* from your function, return a string by value. This will construct a new string based on the string literal, and the calling code can do whatever it wants:
#include <string>
std::string Function1()
{
return “Some text”;
}
...later:
std::string s = Function1();
s[1] = 'a';
Now, if you are trying to change the value that Function() reuturns, then you'll have to do something else. I'd use a class:
#include <string>
class MyGizmo
{
public:
std::string str_;
MyGizmo() : str_("Some text") {};
};
int main()
{
MyGizmo gizmo;
gizmo.str_[1] = 'n';
}
You can use static char string for return value, but you never use it. It's just like access violation error. The behavior of it is not defined in c++ Standard.
It's not the brackets, but the assignement. Your function returns not a simple char *, but const char *( i can be wrong here, but the memory is read-only here), so you try to change the unchangeable memory. And the brackets - they just give you access to the element of the array.
Note also that you can avoid the crash by placing the text in a regular array:
char Function1Str[] = "Some text";
char *Function1()
{
return Function1Str;
}
The question shows that you do not understand the string literals.
image this code
char* pch = "Here is some text";
char* pch2 = "some text";
char* pch3 = "Here is";
Now, how the compiler allocates memory to the strings is entirely a matter for the compiler. the memory might organised like this:
Here is<NULL>Here is some text<NULL>
with pch2 pointing to memory location inside the pch string.
The key here is understanding the memory. Using the Standard Template Library (stl) would be a good practice, but you may be quite a steep learning curve for you.
I have an error in my program: "could not convert from string to char*". How do I perform this conversion?
If you can settle for a const char*, you just need to call the c_str() method on it:
const char *mycharp = mystring.c_str();
If you really need a modifiable char*, you will need to make a copy of the string's buffer. A vector is an ideal way of handling this for you:
std::vector<char> v(mystring.length() + 1);
std::strcpy(&v[0], mystring.c_str());
char* pc = &v[0];
Invoke str.c_str() to get a const char*:
const char *pch = str.c_str();
Note that the resulting const char* is only valid until str is changed or destroyed.
However, if you really need a non-const, you probably shouldn't use std::string, as it wasn't designed to allow changing its underlying data behind its back. That said, you can get a pointer to its data by invoking &str[0] or &*str.begin().
The ugliness of this should be considered a feature. In C++98, std::string isn't even required to store its data in a contiguous chunk of memory, so this might explode into your face. I think has changed, but I cannot even remember whether this was for C++03 or the upcoming next version of the standard, C++1x.
If you need to do this, consider using a std::vector<char> instead. You can access its data the same way: &v[0] or &*v.begin().
//assume you have an std::string, str.
char* cstr = new char[str.length() +1];
strcpy(cstr, str.c_str());
//eventually, remember to delete cstr
delete[] cstr;
Use the c_str() method on a string object to get a const char* pointer. Warning: The returned pointer is no longer valid if the string object is modified or destroyed.
Since you wanted to go from a string to a char* (ie, not a const char*) you can do this BUT BEWARE: there be dragons here:
string foo = "foo";
char* foo_c = &foo[0];
If you try to modify the contents of the string, you're well and truly on your own.
If const char* is good for you then use this: myString.c_str()
If you really need char* and know for sure that char* WILL NOT CHANGE then you can use this: const_cast<char*>(myString.c_str())
If char* may change then you need to copy the string into something else and use that instead. That something else may be std::vector, or new char[], it depends on your needs.
std::string::c_str() returns a c-string with the same contents as the string object.
std::string str("Hello");
const char* cstr = str.c_str();