如何将 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<>
:
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
您的编译器知道您不会更改a
或b
,因此它使它们指向相同的地址,因此它只需要存储一个"hello"
字符串。如果您现在要更改 a
,b
也会更改,这不是您想要的。
长话短说,如果您绝对确定调用的函数不会更改字符串,则可以显式转换它。 (或者更好的是,如果是您的,请将函数更改为 (const char*)
)。
如果您不确定,则必须制作副本。 (就像您已经在使用 strcpy()
一样)。
【讨论】:
你为什么建议使用有潜在危险的演员阵容?从 C++ 字符串文字中获取非常量 C 字符串的唯一正确方法是复制它。任何修改非常量转换版本的尝试都是 UB。请不要建议一种会(几乎可以肯定)导致难以诊断程序行为的方法。以上是关于如何将 const char* 存储到 char*?的主要内容,如果未能解决你的问题,请参考以下文章
我收到从 char 到 const char 错误的无效转换。如何修复这个程序?