Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 858
markzzz Avatar asked Apr 22 '16 08:04

markzzz


People also ask

Can I assign const char to char?

char* const says that the pointer can point to a char and value of char pointed by this pointer can be changed. But we cannot change the value of pointer as it is now constant and it cannot point to another char.

Can you assign a const char * to a string?

You absolutely can assign const char* to std::string , it will get copied though. The other way around requires a call to std::string::c_str() .

What is const char * str?

The const char *Str tells the compiler that the DATA the pointer points too is const . This means, Str can be changed within Func, but *Str cannot. As a copy of the pointer is passed to Func, any changes made to Str are not seen by main....

What is the difference between const char * and char * const?

The difference is that const char * is a pointer to a const char , while char * const is a constant pointer to a char . The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).


2 Answers

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;
like image 198
Sergey Kalinichenko Avatar answered Nov 10 '22 12:11

Sergey Kalinichenko


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

like image 36
Bathsheba Avatar answered Nov 10 '22 13:11

Bathsheba