简体   繁体   中英

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

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?

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;

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).

In C++, the typical way to "drop const " is by using const_cast<> :

char *name = const_cast<char*>(GetName());

This is, of course, frowned upon, ugly and potentially dangerous, since it's really possible that GetName() returns a pointer to something that shouldn't be changed , and then you go and give yourself permission to change it. It's a good way to get very hard to find bugs, in that case.

A workaround is to use a std::string as a temporary holding area; it will mean copying the string but that might be acceptable performance-wise:

std::string s(GetName());
char *name = s.c_str();

This will of course only work if name isn't kept around when s goes out of scope. If that is the case, then you're going to have some form of persistent string storage layer.

You could explicitly cast it. (char*) getName() . But you probably shouldn't. Because the const bit means something like "promise not to change it". So if i have a function void foo(const char* string) I am saiying: "give me a pointer to a string. I won't change it." And if you declare a variable const char* string = "hello"; You are saying, this string should not be changed. And because you make this promise, the compiler knows, and can make your code more efficient. This is why:

const char* a = "hello";
const char* b = "hello";
(a==b); //is probably true

your compiler knows you won't change a or b so it makes them point to the same address, so it only has to store one "hello" string. If you now go about changing a , b gets also changed, and this is not what you wanted.

So long story short, if you are absolutely sure that the function your calling does not change the string, you can explicitly cast it. (or better, change the function to (const char*) if it's yours).
If your not sure, you will have to make a copy. (Like you are already doing with strcpy() ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM