How to store a const char* to a char*?

15,238

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;
Share:
15,238
markzzz
Author by

markzzz

Updated on June 16, 2022

Comments

  • markzzz
    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 only char * as input) without using the strcpy (for practicality and readability of code, and learning too), how could I do? Keeping in const, 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
    default about 8 years
    Isn't removing const from a const char* undefined behavior?
  • default
    default about 8 years
    If I may ask, why are you suggesting something that is frowned upon, without giving other suggestions?
  • unwind
    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
    markzzz about 8 years
    What if I want to "copy" the const char* content to a char* (so, without specify fixed size)? I don't know the size of that char*, since later I'll concat other char.
  • Andrew
    Andrew about 8 years
    Why 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
    default about 8 years
    .c_str() is const. char *name = s.c_str(); isn't compilable.
  • markzzz
    markzzz about 8 years
    Oh wait. I see I can use char* name; and than strcpy(name, GetName()); as well. Basically, I got a non-length-definite string, which will serve my task. Is it correct doing so?
  • Andrew
    Andrew about 8 years
    @paizza No. Use something like std::string name = GetName(); then pass name.c_str() to any framework function that expects a const char*.
  • eerorika
    eerorika about 8 years
    @Default removing const is not UB. But you're correct that std::string::c_str won't work because it returns const char*.
  • Andrew
    Andrew about 8 years
    There'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
    Andrew about 8 years
    Attepting 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
    Bathsheba about 8 years
    You need to write name.c_str(). c_str is a function.
  • markzzz
    markzzz about 8 years
    string looks good, but I need char * later, not const char* :( .c_str() return const. I think I cannot pass a string to a char* right?
  • Bathsheba
    Bathsheba about 8 years
    Out of interest, why do you need a char* later?
  • markzzz
    markzzz about 8 years
    The 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
    markzzz about 8 years
    @Bathsheba: as I said, the function used by the Framework taks char* as input, I can't change them!
  • eerorika
    eerorika about 8 years
    @paizza in your question, you say some functions within a Frameworks I'm using use const char * as input
  • markzzz
    markzzz about 8 years
    @user2079303: I wrong, sorry! I updated the question. I need char*
  • Bathsheba
    Bathsheba about 8 years
    OK; consider using something on the lines of the class I give in the answer.