如何将 const char* 存储到 char*?

Posted

技术标签:

【中文标题】如何将 const char* 存储到 char*?【英文标题】:How to store a const char* to a char*? 【发布时间】:2016-08-15 19:44:06 【问题描述】:

我有 this code 按预期工作:

#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*'。这种转换的最佳习惯是什么?

【问题讨论】:

你想做什么?如果您不想更改字符串,则第一个成语为您服务,并且不会使用额外的内存;如果要更改字符串,则需要将其内容复制到其他位置(因此您需要 strcpy 或类似的)。 【参考方案1】:

在 C++ 中,“删除const”的典型方法是使用const_cast&lt;&gt;

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

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

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

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

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

【讨论】:

不会从 const char* 未定义的行为中删除 const 吗? 如果我可以问,你为什么提出一些不受欢迎的事情,而不给出其他建议? @Default 因为那是发帖人想知道怎么做的,我不能确定在有问题的情况下它会不会很糟糕。 .c_str() 是常量。 char *name = s.c_str(); 不可编译。 @Default 移除 const 不是 UB。但你是对的,std::string::c_str 不起作用,因为它返回 const char*【参考方案2】:

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*,在这种情况下,只会获取指针的浅拷贝(并且析构函数不会删除内存)。

【讨论】:

如果我想将const char* 内容“复制”到char* 怎么办(所以,没有指定固定大小)?我不知道那个 char* 的大小,因为稍后我会连接其他 char。 哦等等。我知道我也可以使用char* name; 而不是strcpy(name, GetName());。基本上,我得到了一个长度不定的字符串,它将为我的任务服务。这样做对吗? @paizza 没有。使用类似std::string name = GetName(); 的东西,然后将name.c_str() 传递给任何需要const char* 的框架函数。 还有strdup 用于创建字符串的副本。不过,您稍后需要释放内存,因此在 C++ 中使用std::string 要容易得多。 你需要写name.c_str()c_str 是一个函数【参考方案3】:

这种转换的最佳习惯是在整个代码中使用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;

【讨论】:

【参考方案4】:

你可以显式地转换它。 (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() 一样)。

【讨论】:

你为什么建议使用有潜在危险的演员阵容?从 C++ 字符串文字中获取非常量 C 字符串的唯一正确方法是复制它。任何修改非常量转换版本的尝试都是 UB。请不要建议一种会(几乎可以肯定)导致难以诊断程序行为的方法。

以上是关于如何将 const char* 存储到 char*?的主要内容,如果未能解决你的问题,请参考以下文章

在Qt中如何将QString转换为const char*

我收到从 char 到 const char 错误的无效转换。如何修复这个程序?

如何将char赋给const char *

C++标准库 如何连接两个const char *类型字符串,并返回const char * 类型结果?

const char * 和 char *

在 iphone 上为 sqlite 将 json 转换为 const char