为啥在返回字符串的函数上调用 c_str() 不起作用?

Posted

技术标签:

【中文标题】为啥在返回字符串的函数上调用 c_str() 不起作用?【英文标题】:Why does calling c_str() on a function that returns a string not work?为什么在返回字符串的函数上调用 c_str() 不起作用? 【发布时间】:2014-12-23 20:17:02 【问题描述】:

我有一个返回字符串的函数。但是,当我调用它并对其执行 c_str() 以将其转换为 const char* 时,它仅在我先将其存储到另一个字符串时才有效。如果我直接从函数中调用 c_str(),它会将垃圾值存储在 const char* 中。

为什么会这样?感觉我在这里遗漏了一些非常基本的东西......

string str = SomeFunction();
const char* strConverted = str.c_str(); // strConverted stores the value of the string properly
const char* charArray= SomeFunction().c_str(); // charArray stores garbage value

static string SomeFunction()

    string str;
    // does some string stuff
    return str;

【问题讨论】:

c_str() 返回指向底层 char 数组的指针。问题是你临时调用它。所以在; 之后,对象被删除,然后:你会得到垃圾。 一些关于“如何”它不起作用的信息会有所帮助.. 编译器错误?垃圾数据?在这个 sn-p 中有很多潜在的错误。 @Yeraze OP 明确表示它存储了一个垃圾值,所以它绝对不是编译器错误。 【参考方案1】:

SomeFunction().c_str() 为您提供一个指向临时变量的指针(SomeFunction 正文中的自动变量 str)。与引用不同,在这种情况下,临时对象的生命周期不会延长,并且您最终会得到 charArray 是一个悬空指针,解释您稍后在尝试使用 charArray 时看到的垃圾值。

另一方面,当你这样做时

string str_copy = SomeFunction();

str_copySomeFunction() 的返回值的副本。现在调用c_str() 会给你一个指向有效数据的指针。

【讨论】:

Nowdays str_copy 实际上只是移动了所有权,但这一点仍然有效。【参考方案2】:

函数返回的值对象是临时的。 c_str() 的结果仅在临时的生命周期内有效。在大多数情况下,临时的生命周期是到完整表达式的末尾,通常是分号。

const char *p = SomeFunction();
printf("%s\n", p); // p points to invalid memory here.

解决方法是确保在完整表达式结束之前使用c_str() 的结果。

#include <cstring>

char *strdup(const char *src_str) noexcept 
    char *new_str = new char[std::strlen(src_str) + 1];
    std::strcpy(new_str, src_str);
    return new_str;


const char *p = strdup(SomeFunction.c_str());

注意strdup是一个POSIX函数,所以如果你是一个支持POSIX的平台,它已经存在了。

【讨论】:

【参考方案3】:

    方法SomeFunction()中的“string str”是SomeFunction()中的局部变量,只存在于SomeFunction()的范围内;

    由于SomeFunction()方法的返回类型是字符串,不是字符串的引用,所以在“return str;”之后,SomeFunction()会返回一个str值的副本,即作为临时值存储在内存的某个地方,调用SomeFunction()后,临时值会立即销毁;

    string str = SomeFunction();”将返回的临时值SomeFunction()存储到字符串str,实际上是该值的一个副本并存储到str,分配了一个新的内存块,并且str的生命周期大于SomeFunction()返回的临时值,“;”调用结束后SomeFunction()的返回值立即销毁,内存被系统回收,但是此值的副本仍存储在str 中。这就是为什么“const char* strConverted = str.c_str();”可以得到正确的值,其实c_str()返回了str的初始元素的指针(str指向的字符串值的首元素内存地址),而不是返回的临时值SomeFunction();

    const char* charArray= SomeFunction().c_str();”不同,“SomeFunction().c_str()”会返回一个指向返回临时值的初始元素的指针(返回临时字符串值的首元素内存地址),但是在调用之后SomeFunction(),返回的临时值被销毁,那个内存地址被系统重用,charArray可以得到那个内存地址的值,但不是你期望的值;

【讨论】:

【参考方案4】:

使用 strcpy 将字符串复制到本地定义的数组中,您的代码就可以正常工作了。

【讨论】:

不管怎样,SomeFunction().c_str() 会给你一个无效的地址。如果您尝试strcpy 它,那将导致未定义的行为。 不。今天做了。效果很好。 您能否提供一个小而完整的工作示例来演示此行为? 这在很大程度上是不同的。问题是 c_str() 在函数调用的结果上被调用。这会使c_str() 提供给您的内部char 指针无效,因为您调用的函数的本地对象string 已超出范围。如果你有类似string a = SomeFunction(); ... a.c_str(); 的东西,它也没有被复制。这不会在链接到的代码中发生,因为 c_str() 不会直接在函数调用的结果上调用。 我觉得你没有说得很清楚。一个例子真的会有很长的路要走。事实上,我仍然不能完全确定你的意思是不是像 char* str = new char[...length goes here...]; strcpy(str, SomeFunction().c_str()); 这样的东西。

以上是关于为啥在返回字符串的函数上调用 c_str() 不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

c++中的c_str()

为啥在父类的构造函数中调用重载函数时,在 ES6 类上设置属性不起作用

C++中的c_str()函数用法

为啥用c_str()转换路径类型后opendir()打不开路径?

如何从string类型的变量 返回一个char* 类型

C++ c_str() 函数应用