可以/为啥在返回类型中使用 char * 而不是 const char * 会导致崩溃?
Posted
技术标签:
【中文标题】可以/为啥在返回类型中使用 char * 而不是 const char * 会导致崩溃?【英文标题】:Can/Why using char * instead of const char * in return type cause crashes?可以/为什么在返回类型中使用 char * 而不是 const char * 会导致崩溃? 【发布时间】:2010-11-28 03:28:55 【问题描述】:我在某处读到,如果您希望 C/C++ 函数返回字符数组(而不是 std::string),则必须返回 const char* 而不是 char*。后者可能会导致程序崩溃。
谁能解释这是否属实?如果是真的,为什么从函数返回 char* 如此危险?谢谢。
const char * my_function()
....
void main(void)
char x[] = my_function();
【问题讨论】:
main() 应该总是返回 int! users.aber.ac.uk/auj/voidmain.shtml 【参考方案1】:你被告知的不是真实的。
返回 const char *
可以改进函数的语义(即不要混淆我给你的内容),但返回 char *
完全没问题。
但是,无论哪种情况,您必须确保返回在my_function
的堆上分配的char *
或const char *
(即使用malloc
或new
分配),否则每当my_function
返回时,[const] char *
的内存将被释放,您将访问无效指针。
最后,您必须记住在您完成后返回给您的free
或delete
[const] char *
,否则您将泄漏内存。 C/C++ 不是这么棒的语言吗?
所以,在 C 语言中,你会拥有
const char *my_function()
const char *my_str = (const char *)malloc(MY_STR_LEN + 1); // +1 for null terminator.
/* ... */
return my_str;
int main()
const char *my_str = my_function();
/* ... */
free(my_str);
/* ... */
return 0;
【讨论】:
这就是为什么我喜欢 C++ 的 std::string (即使它是字符串类定义的一个糟糕的 hack 工作)和智能指针。你只需要在 C 中经历那么多痛苦。 @DavidThornley 适当的文档将这种痛苦减少到几乎为零。【参考方案2】:通常,这不是问题,但有些事情需要考虑。这通常是关于 const 正确性的问题,这意味着跟踪可以更改的内容和不能更改的内容。
如果您要返回一个双引号字符串,它是const char *
,并且像对待其他任何东西一样对待它会招致麻烦。更改此类字符串是未定义的行为,但通常会导致程序崩溃或更改该字符串所引用的任何位置。
如果您在堆栈上返回一个字符数组(即,被调用函数的局部变量),它将消失,并且指针将不会特别指向任何内容,有时可能会导致错误的结果。
如果被调用函数返回的东西已经是const char *
,那么将其更改为char *
需要强制转换。此外,如果你真的要改变它,你需要确保它是可改变的。通常将其保留为const char *
会更好。
返回分配给malloc()
或new
的内存没有直接问题,但你确实有所有权问题:free()
/delete
应该使用什么函数,何时以及如何处理可能副本?这就是 C++ 的智能指针大放异彩的地方。
【讨论】:
【参考方案3】:只需更改返回码不会导致崩溃。但是,如果您返回的字符串是静态的(例如 return "AString"
),您应该返回 const char *
以确保编译器检测到对该内存的任何尝试修改,这将可能导致崩溃。您当然可以使用强制转换等来绕过编译器检查,但在这种情况下,您必须工作才能使崩溃发生。
【讨论】:
谢谢。你是说如果你返回一个文字字符串(例如返回“这是一个测试”;),返回类型必须是 const char*?如果返回类型改为 char* 会有什么危险? 如果字符串没有被修改,没有危险,但是如果调用者试图修改字符串,应用程序就会崩溃。如果返回类型是const char *
,那么编译器不会让你修改它。
谢谢。这大概就是他们所说的。 C 的另一个方面我不知道(为 std::string 欢呼三声很棒!)。【参考方案4】:
如果您有一个返回“字符串文字”的函数,那么它必须返回 const char*。这些不需要通过 malloc 在堆上分配,因为它们被编译成可执行文件本身的只读部分。
例子:
const char* errstr(int err)
switch(err)
case 1: return "error 1";
case 2: return "error 2";
case 3: return "error 3";
case 255: return "error 255 to make this sparse so people don't ask me why I didn't use an array of const char*";
default: return "unknown error";
【讨论】:
出于完整性考虑,还应注意这些是实习生的,其他变量可能指向相同的位置。不过,如果尊重 const,这应该不是问题。【参考方案5】:如果 char* 在堆栈上分配,则返回一个悬空指针。否则,只要它匹配函数的原型并且声明匹配返回值,就可以了。
【讨论】:
以上是关于可以/为啥在返回类型中使用 char * 而不是 const char * 会导致崩溃?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我可以使用有界通配符作为参数而不是方法中的返回类型? [复制]
为啥c#中bool要占4个字节 32位呢 为啥不用像byte 1个字节存储呢
为啥 char** 不能成为 C++ 中以下函数的返回类型?