可以/为啥在返回类型中使用 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 *(即使用mallocnew 分配),否则每当my_function 返回时,[const] char * 的内存将被释放,您将访问无效指针。

最后,您必须记住在您完成后返回给您的freedelete [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++ 中更喜欢 char* 而不是字符串?

为啥c#中bool要占4个字节 32位呢 为啥不用像byte 1个字节存储呢

为啥 char** 不能成为 C++ 中以下函数的返回类型?

为啥我的 Dart 构造函数返回的是动态对象而不是类型对象?

为啥 putchar、toupper、tolow 等采用 int 而不是 char?