How to store a const char* to a char*?
Solution 1
return "Test text";
returns a pointer to a read-only string literal.
If you're using a function that takes a char*
as an input, and you have a const char*
(such as a read-only string literal), then you ought to supply a deep copy of the string starting at that const char*
to such functions.
Else you risk undefined behaviour at runtime if a function attempts to modify a read-only string.
What you currently have is adequate; assuming you can't work with std::string
. (If you can work with std::string
and all your framework functions take a const char*
input, then I'd suggest your refactoring your code to use a std::string
, and pass the output of the c_str()
method on that string class to your framework functions.)
Finally, if some of your framework functions require a char*
then you could always build yourself a small adapter class:
class Adapter
{
public:
Adapter(const& Adapter) = delete; /*don't try to copy me please*/
Adapter& operator=(const Adapter& ) = delete; /*don't try to copy me please*/
Adapter(const char* s) : m_s(::strdup(s))
{
}
~Adapter() /*free memory on destruction*/
{
::free(m_s); /*use free to release strdup memory*/
}
operator char*() /*implicit cast to char* */
{
return m_s;
}
private:
char* m_s;
};
Then for a function void foo(char* c)
, you can call foo(Adapter("Hello"/*or any const char* */));
and foo
can do as it pleases with the char*
that's embedded in the anonymous temporary! You could even enhance this class to take a constructor to a char*
where in that case only a shallow copy of the pointer is taken (and the destructor doesn't delete the memory).
Solution 2
The best habit for this kind of conversion is to use std::string
throughout your code. Since the framework that you are using takes const char*
as its input, you can always pass it the results of c_str()
call on your std::string
:
std::string GetName() {
return "Test text";
}
int main() {
std::string name = GetName();
int res = external_framework_function(name.c_str());
cout << "result: " << res << " for " << name << endl;
}
A distant second best is using const char*
in your code:
const char* name = GetName();
Since the framework that you are using takes const char*
you are good here as well.
If you need a non-const pointer, there is no way around copying the string. You can make a function that does it for you, but you would remain responsible for freeing the copies that you get from it:
char* copy(const char* orig) {
char *res = new char[strlen(orig)+1];
strcpy(res, orig);
return res;
}
...
char *name = copy(GetName());
...
delete[] name;
markzzz
Updated on June 16, 2022Comments
-
markzzz almost 2 years
I have this code that works as expected:
#define MAX_PARAM_NAME_LEN 32 const char* GetName() { return "Test text"; } int main() { char name[MAX_PARAM_NAME_LEN]; strcpy(name, GetName()); cout << "result: " << name << endl; }
If I'd like to store the result to a
char *
(because some functions within a Frameworks I'm using use onlychar *
as input) without using thestrcpy
(for practicality and readability of code, and learning too), how could I do? Keeping inconst
, this works well:const char* name; name = GetName();
but I still have
const
.Trying to just use
char*
:char* name; name = GetName();
I get
invalid conversion from 'const char*' to 'char*'
. What's the best habit for this kind of conversion? -
default about 8 yearsIsn't removing const from a
const char*
undefined behavior? -
default about 8 yearsIf I may ask, why are you suggesting something that is frowned upon, without giving other suggestions?
-
unwind about 8 years@Default Because that was what the poster wanted to know how to do, and I can't know for certain that it will be bad in the situation in question.
-
markzzz about 8 yearsWhat if I want to "copy" the
const char*
content to achar*
(so, without specify fixed size)? I don't know the size of that char*, since later I'll concat other char. -
Andrew about 8 yearsWhy are you suggesting potentially dangerous casts? The only correct way to obtain a non-const C string from a C++ string literal is to copy it. Any attempt to modify the non-const casted version is UB. Please don't suggest a method that will (almost certainly) result in hard-to-diagnose program behaviour down the line.
-
default about 8 years
.c_str()
is const.char *name = s.c_str();
isn't compilable. -
markzzz about 8 yearsOh wait. I see I can use
char* name;
and thanstrcpy(name, GetName());
as well. Basically, I got a non-length-definite string, which will serve my task. Is it correct doing so? -
Andrew about 8 years@paizza No. Use something like
std::string name = GetName();
then passname.c_str()
to any framework function that expects aconst char*
. -
eerorika about 8 years@Default removing const is not UB. But you're correct that
std::string::c_str
won't work because it returnsconst char*
. -
Andrew about 8 yearsThere's also strdup to create a copy of a string. You'll need to free the memory later, though, so it's far easier to use
std::string
in C++. -
Andrew about 8 yearsAttepting to modify characters in a C++ string literal is UB. They're typically stored in a read-only section of memory. Casting away the const won't cause the problem, but a subsequent attempt to write to that memory region will. Don't suggest such things; the only way to correctly make a mutable string from a C++ string literal is to copy it.
-
Bathsheba about 8 yearsYou need to write
name.c_str()
.c_str
is a function. -
markzzz about 8 years
string
looks good, but I needchar *
later, notconst char*
:( .c_str()
return const. I think I cannot pass astring
to achar*
right? -
Bathsheba about 8 yearsOut of interest, why do you need a
char*
later? -
markzzz about 8 yearsThe only way is to define a fixed size (guessing it is enough) and use strcpy. That's risky, I can get access memory violation if the char* grown more than the size I've set :(
-
markzzz about 8 years@Bathsheba: as I said, the function used by the Framework taks
char*
as input, I can't change them! -
eerorika about 8 years@paizza in your question, you say some functions within a Frameworks I'm using use
const char *
as input -
markzzz about 8 years@user2079303: I wrong, sorry! I updated the question. I need char*
-
Bathsheba about 8 yearsOK; consider using something on the lines of the class I give in the answer.