如何将常量字符*存储到字符*

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

本文关键字:字符 存储 常量      更新时间:2023-10-16

我有这段代码可以按预期工作:

#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;
}

如果我想将结果存储到char *(因为我使用的框架中的某些函数仅使用char *作为输入)而不使用strcpy(为了代码的实用性和可读性,以及学习),我该怎么办?保持const,这很有效:

const char* name;
name = GetName();

但我还有const.

尝试只使用char*

char* name;
name = GetName();

我得到invalid conversion from 'const char*' to 'char*'.这种转换的最佳习惯是什么?

这种转换的最佳习惯是在整个代码中使用std::string。由于您使用的框架将const char*作为其输入,因此您始终可以向其传递c_str()调用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;
}

第二好的方法是在代码中使用const char*

const char* name = GetName();

由于您使用的框架需要const char*因此您在这里也很好。

如果需要非常量指针,则无法复制字符串。您可以创建一个为您执行此操作的函数,但您仍然负责释放从中获得的副本:

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";返回指向只读字符串文本的指针。

如果您使用的函数将char*作为输入,并且您有一个const char*(例如只读字符串文本),那么您应该向此类函数提供从该const char*开始的字符串的深层副本。

否则,如果函数尝试修改只读字符串,则在运行时存在未定义行为的风险。

你目前拥有的已经足够了;假设你不能与std::string一起工作。(如果你可以使用std::string并且你的所有框架函数都接受const char*输入,那么我建议你重构你的代码以使用std::string,并将该字符串类上的c_str()方法的输出传递给你的框架函数。

最后,如果你的某些框架函数需要char*那么你总是可以为自己构建一个小的适配器类:

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;
};

然后对于函数void foo(char* c),您可以调用foo(Adapter("Hello"/*or any const char* */));foo可以随心所欲地使用嵌入在匿名临时中的char*!您甚至可以增强此类以将构造函数带到一个char*在这种情况下,仅获取指针的浅表副本(析构函数不会删除内存)。

在C++中,"删除const"的典型方法是使用const_cast<>

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

当然,这是不受欢迎的,丑陋的和潜在的危险,因为GetName()确实有可能返回一个指向不应该更改的内容的指针,然后你去允许自己更改它。在这种情况下,这是很难找到错误的好方法。

解决方法是使用 std::string 作为临时保留区域;这意味着复制字符串,但这在性能方面可能是可以接受的:

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

当然,只有在s超出范围时不保留name的情况下,这才有效。如果是这种情况,那么你将拥有某种形式的持久字符串存储层。

你可以显式转换它。 (char*) getName() .但你可能不应该。因为const位的意思是"承诺不改变它"。因此,如果我有一个函数void foo(const char* string)我正在搜索:"给我一个指向字符串的指针。我不会改变它。如果你声明一个变量const char* string = "hello";你说,这个字符串不应该被改变。而且因为你做出了这个承诺,编译器知道,并且可以让你的代码更有效率。这就是为什么:

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

编译器知道您不会更改ab因此会使它们指向同一地址,因此它只需要存储一个"hello"字符串。如果你现在去改变ab也会改变,这不是你想要的。

长话短说,如果你绝对确定你调用的函数不会改变字符串,你可以显式地强制转换它。(或者更好的是,如果函数是你的,请将函数更改为(const char*))。
如果您不确定,则必须复制一份(就像您已经在对strcpy()所做的那样)。