我总是对从函数返回字符串文字或字符串感到困惑。我被告知可能存在内存泄漏,因为您不知道何时会删除内存?
例如,在下面的代码中,如何实现foo()
以使代码输出为“Hello World”?
void foo ( ) // you can add parameters here.
{
}
int main ()
{
char *c;
foo ( );
printf ("%s",c);
return 0;
}
另外,如果foo()
的返回类型不是无效,但您可以返回char*
,那该怎么办?
答案 0 :(得分:10)
我假设我们无法修改main。为了使您的程序在没有泄漏的情况下工作,您需要具备静态存储的东西:
void foo(char*& pC) // reference
{
static char theString[] = "thingadongdong";
pC = theString;
}
但实际上,这不是非常传统的C ++代码。您将使用std::string
和std::cout
,因此您不担心内存:
std::string foo(void)
{
return "better thingadongdong";
}
int main(void)
{
// memory management is done
std::cout << foo() << std::endl;
}
如果您想知道某些事情是否需要手动解除分配,那就错了。
答案 1 :(得分:5)
由于旧的char *使用已被弃用,你不能简单地使用字符串吗?
const char* func1 () {return "string literal";}
string func2 () {return "another string literal";}
这两种方法都很好,没有编译器警告。
然而
char* func3 () {return "yet another string literal";}
根本不会编译。也不会
char* func4 () {return &"a ref to a string literal?";}
Stroustrup在“The C ++ Programming Language”(第三版)中说:
“静态分配字符串文字,以便从函数返回一个字符串是安全的。
const char* error_message (int i)`
{
//...
return "range error";
}
调用error_messages()后,存储范围错误的内存不会消失。“
因此程序中的每个字符串文字都分配在自己的小内存中,该内存持续一段时间(即静态分配)。 将const放在char *前面让编译器知道你不打算(也不能)改变那个字符串文字的小内存,这可能是危险的,所以尽管从字符串文字转换为char *,它们仍然允许这个赋值滑动已被弃用。
返回字符串必须将字符串文字复制到string类型的对象中,即调用者负责的内存。
无论哪种方式都没有内存泄漏:每个字符串文字都有自己的内存,在程序终止时清理;返回const char *返回一个指向文字内存的指针(知道你不能改变它);并返回一个字符串,将一个副本复制到调用者代码中存在的字符串对象中,该字符串对象由调用者清理。
虽然看起来有点丑陋的符号,但我猜他们离开了const char *来保留廉价替代品(不涉及副本)。
答案 2 :(得分:4)
我总是对从函数返回字符串文字或字符串感到困惑。
不可变的文字字符串
据我了解,如果返回类型声明为const,则可以直接返回字符串文字,以声明该字符串不打算更改。这意味着您无需担心字符串/内存泄漏的生命周期。
可变,非文字字符串
但是,如果您需要一个可以就地更改的字符串,则需要考虑字符串的生命周期以及存储它的内存分配的大小。 这成为一个问题,因为您不能再为每次调用函数轻松地返回包含字符串的相同内存,因为之前的使用可能已经改变了该内存的内容,和/或可能仍在使用中。因此,必须分配新的内存来保存返回的字符串。
这是发生泄漏的可能性,以及需要在何处进行分配和解除分配的选择。您可以让函数本身在文档中分配内存和状态,并在其中规定调用者必须在不再需要时释放内存(防止泄漏)。这意味着该函数可以简单地返回一个char *。
另一种选择是将一些内存传递给调用者分配的函数,并让函数将字符串放在该内存中。在这种情况下,调用者既分配又负责释放该内存。
最后,我提到在使用可变字符串时需要管理内存和字符串的大小。对于最初由函数设置的字符串,以及在释放内存之前在函数之后进行的任何更改,分配都必须足够大。如果不能正确执行此操作可能会导致缓冲区溢出,方法是将字符串写入long以适合最初分配的内存;这对您的计划的健康和安全极为危险。它可能导致很难发现的错误和安全漏洞(因为错误的来源 - 溢出 - 可以远离程序失败时看到的症状)。
答案 3 :(得分:2)
这样的事情:
void foo(char ** pChar)
{
// Make sure the string is shorter
// than the buffer
*pChar = new char[256];
strcpy(*pChar,"Hello World!");
}
然后这样称呼:
foo(&c);
如评论中所述,请注意您存储的字符串小于缓冲区,否则您将获得...堆栈溢出! (双关语)