返回指向字面(或常量)字符数组(字符串)的指针

33
我知道这是错误的。
char* getSomething() {
    char szLocal[5];
    /* Put something in the char array somehow */
    return szLocal;
}

因为函数返回后,szLocal 可能会在某个时候被销毁。
但这样可以吗?
char* getSomethingElse() {
    return "something else";
}

3
请查看C字符串字面量:它们去哪了? - Bertrand Marron
8
在第一个例子中,szLocal在函数返回的那一刻就被销毁了,而不是“之后的某个时间”,因此返回的指针已经失效。确实,它指向的数据将保持不变一段时间,但函数的堆栈帧已经被释放,该内存可以供任何需要创建一些本地变量或调用另一个函数的人使用。请注意,这里并没有改变原意,只是使得语言更加通俗易懂。 - Sergei Tachenov
3个回答

28

这其实是没问题的。字符串常量通常被分配在一个不可变的内存区域,在您的程序运行期间一直保持可用。

也可以参考C/C++何时分配/释放字符串字面值中的答案。


我同意romkyns的观点。但是,我们不知道你正在使用哪个系统?可能有一些系统不像那样工作。为了让自己安心,您可以尝试故意覆盖我们建议的字符串“不存活”的内存位置,即堆栈。通过声明和分配一些更多的本地变量或调用一些其他带有几个参数的函数来将内容放入堆栈。最好是调用另一个声明和分配一些本地变量的函数,并传递一些参数。 - Dave
哇塞,这个地方真是太棒了。10分钟内得到了10个有用的回复。感谢大家。(顺便说一下,我在使用vs2010时是在x64 windows上运行的。) - John Fitzpatrick
7
字符串字面量保证在应用程序的生命周期内存在。它们可能不在只读/不可变内存中,但它们保证在应用程序的整个生命周期内存在,因此返回指向字符串字面量的指针是可以的。 - nos

8

在分配方面没问题:字符串字面值隐含为static。但是返回一个非const指针给字面值是不行的。

如果你想返回一个可修改(非const)的字符串,将其声明为static char[]。或者更好的方法是返回一个副本:

return strdup("something else");

不要忘记在使用完后进行free操作。虽然strdup不符合ISO标准,但几乎在所有地方都可以使用(我相信除了MSVC)。


strdup在MSVC上不可用?你确定吗? - Mandrake
@Arabcoder:不好意思,我不确定,请纠正我如果我错了。我不使用MSVC。 - Fred Foo
1
const 的优点说得好。不过,一个(好的)编译器会捕获这个问题吗——试图将 const char 强制转换为非 const char? - Roman Starkov
2
@romkyns:GCC 4.5甚至不会对“-Wall”发出警告:正如Jens Gustedt在nominolo的答案下指出的那样,字面值并不是“const”。(G++会发出警告,但仍然编译模块,然后我们就离开了C世界。) - Fred Foo
1
我明白了。我想,如果我要严格遵守规则,那么将字面值作为非常量返回并不是一个绝对的错误。但是,让字面值成为非常量,这种做法非常类似于 C 语言,会让你自己给自己制造麻烦。 - Roman Starkov

5

字符串字面值的类型是 const char * (请参见下面的注释) static char[],但是不可变。 字符串字面值表示对静态分配内存的 指针。 因此:

  1. 返回这样的指针是完全可以的。

  2. 你的函数返回类型应与 const char* 兼容,即返回类型 char * 会给你至少一个警告 可能会在后面给你带来麻烦。

  3. 如果你的函数可能返回字面值或者 malloc 的字符串,你必须非常小心地处理内存管理。释放字符串字面值可能会导致 segfault。


2
实际上,类型是static const char [],即更接近于const char *const。您无法增加或减少文字。 - Fred Foo
3
很遗憾,由于历史原因,它的类型没有被标注为“const”。但是你没有权利更改它 :(( 因此,声明返回值为“const”是一个好主意,但语言并不强制执行。 - Jens Gustedt
@larsman,@Jens:谢谢,我认错了。在提交之前应该检查一下。 - nominolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接