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


我有一个返回字符串的函数。但是,当我调用它并对其执行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;
}

8891
2017-12-23 20:17


起源

c_str()返回指向底层char数组的指针。问题是你是在临时调用它。所以之后 ; 对象被删除,并且presto:你得到了垃圾。 - Borgleader
关于“如何”它不起作用的一些信息会有所帮助..编译器错误?垃圾数据?这个片段中有很多潜在的错误。 - Yeraze
@Yeraze OP清楚地声明它存储了一个垃圾值,所以它肯定不是编译错误。 - Borgleader


答案:


SomeFunction().c_str() 给你一个临时指针(自动变量) str 在体内 SomeFunction)。与参考文献不同,在这种情况下,临时工的生命周期并没有延长,你最终得到了 charArray 是一个悬空指针,解释了你在以后尝试使用时看到的垃圾值 charArray

另一方面,当你这样做

string str_copy = SomeFunction();

str_copy 是一个返回值的副本 SomeFunction()。调用 c_str() 现在,它为您提供了指向有效数据的指针。


17
2017-12-23 20:21





函数返回的值对象是临时的。结果 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的平台,它已经存在了。


2
2017-12-23 20:59





  1. string str“在方法中 SomeFunction() 是一个局部变量 SomeFunction(),只存在于范围内 SomeFunction();

  2. 由于返回类型的方法 SomeFunction() 是字符串,而不是字符串的引用,在“return str;SomeFunction() 将返回值的副本 str,在调用之后,它将作为临时值存储在某个内存位置 SomeFunction(),临时价值将立即销毁;

  3. string str = SomeFunction();“将存储返回的临时值 SomeFunction() 串起来 str,实际上是该值的副本并存储到 str,分配一个新的内存块,并使用它的生命周期 str 大于返回的临时值 SomeFunction(), 之后 ”;“呼唤 SomeFunction() 完成后,返回的临时值立即被销毁,内存由系统回收,但该值的副本仍存储在 str。这就是为什么 ”const char* strConverted = str.c_str();“实际上可以获得正确的价值 c_str() 返回了一个初始元素的指针 str (第一个元素的内存地址 str 指向字符串值),而不是返回的临时值 SomeFunction();

  4. const char* charArray= SomeFunction().c_str();“ 是不同的, ”SomeFunction().c_str()“将返回一个返回临时值的初始元素的指针(返回的临时字符串值的第一个元素内存地址),但是在调用之后 SomeFunction(),销毁返回的临时值,并由系统重用该内存地址, charArray 可以获取该内存地址的值,但不是您期望的值;


0
2018-05-23 14:15





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


-3
2017-12-23 20:21



无论哪种方式, SomeFunction().c_str() 会给你一个无效的地址。如果你试着 strcpy 它会导致未定义的行为。 - David Young
不。今天做了。工作得很好。 - Bruce
你能提供一个小而完整的工作实例来证明这种行为吗? - David Young
这在很大程度上是不同的。问题是 c_str() 在函数调用的结果上调用。这使内部无效 char 指针那个 c_str() 给你,因为 string 对象,它是您的调用函数的本地,已超出范围。它也没有被复制,如果你有类似的东西 string a = SomeFunction(); ... a.c_str();。链接到因为的代码中不会发生这种情况 c_str() 不直接调用函数调用的结果。 - David Young
我觉得你没那么清楚。一个例子 真 走了很长的路。事实上,我还不完全确定你的意思是什么 char* str = new char[...length goes here...]; strcpy(str, SomeFunction().c_str());。 - David Young