C 又一个",;返回本地地址";-&引用;函数返回局部变量“的地址”;

C 又一个",;返回本地地址";-&引用;函数返回局部变量“的地址”;,c,C,我知道,这是一个非常非常普遍的问题。 我读过,例如。 我过去认为返回局部变量的地址是一个非常糟糕的主意。我过去认为你最好: 通过例如malloc分配内存 使局部变量为静态或 将指针作为参数传递 但后来我尝试了这个: #include <stdio.h> char * foo_1(); char ** foo_2(); int main() { char * p_1 = foo_1(); char ** p_2 = foo_2(); printf("

我知道,这是一个非常非常普遍的问题。 我读过,例如。 我过去认为返回局部变量的地址是一个非常糟糕的主意。我过去认为你最好:

  • 通过例如malloc分配内存
  • 使局部变量为静态或
  • 将指针作为参数传递
但后来我尝试了这个:

#include <stdio.h>
char *  foo_1();
char ** foo_2();

int main() {

    char * p_1 = foo_1();
    char ** p_2 = foo_2();

    printf("\n [%s] \n", p_1);
    printf("\n [%s] \n", *p_2);

return 0;
}

char * foo_1() {
    char * p = "bar";
    return p;
}

char ** foo_2() {
    char * p = "bar";
    return &p;
}
#包括
char*foo_1();
字符**foo_2();
int main(){
char*p_1=foo_1();
char**p_2=foo_2();
printf(“\n[%s]\n”,p\u 1);
printf(“\n[%s]\n”,*p_2);
返回0;
}
char*foo_1(){
char*p=“bar”;
返回p;
}
字符**foo_2(){
char*p=“bar”;
返回&p;
}
我编译时出现了-pedantic-pedantic错误 并得到预期的警告:函数返回局部变量[-Wreturn local addr]的地址

但只适用于foo_2()!foo_1()工作正常。有人知道为什么会有这种未定义的行为吗

char * foo_1() {
    char * p = "bar";
    return p;
}
这里返回的不是本地对象的地址,而是指向字符串文本的指针的指针值。字符串文字具有静态存储持续时间,可以返回指向字符串文字的指针。当
foo_1
返回时,
p
对象被销毁(自动存储持续时间),而不是
“bar”
(静态存储持续时间)。

foo_2()
中,您返回的是局部变量
p
的地址,这就是您收到警告的原因

foo_1()

char * p_1 = foo_1();
没关系。只要不修改
p_1
指向的任何内容,取消引用
p_1
就不是问题,因为
foo_1
返回指向存储在程序只读部分中的字符串文本的指针

char ** p_2 = foo_2();
这不好。取消引用
p_2
是导致未定义行为的原因,因为
p_2
指向已删除的对象。

foo_2()
中,返回(非
静态
)局部变量的地址。当函数返回时,该地址变得不确定,因为指向的对象不再存在——因此警告

foo_1()
中,您将返回局部变量的值。这样做一点问题都没有;这并不比:

int foo_3(void) {
    int local = 42;
    return local;
}
它返回
local
的值

foo_1()。例如:

int foo_1a(void) {
    char arr[] = "bar";
    char *p = arr; // or equivalently, &arr[0]
    return p;
}
在这里,您仍然返回一个局部变量的值(这很好),但该值恰好是另一个局部变量的地址,因此一旦函数返回,返回的指针值就变得无效

编译器对
foo_1a
发出警告的可能性小于对
foo_2
发出警告的可能性,因为编译器在执行return语句时不太可能确定
p
的值有问题。事实上,这种语言不需要对这种事情进行诊断。编译器可以很好地检测和警告一些但不是所有未定义行为的实例

一句话:您的
foo_1()
函数表现良好。它返回的指针值是字符串文本的地址,它具有静态存储持续时间(即,它存在于程序的整个生命周期)


但是,由于修改该静态数组具有未定义的行为,因此明智的做法是将地址作为
常量char*
返回,而不是作为
char*
返回,因此调用方不太可能尝试修改字符串文字。
const
还可以作为任何人类读者的文档,说明指向的值是不可修改的。

但我认为这不是标准行为。clang做到了,但IIRC至少有一些版本的gcc在每个函数调用上实例化本地字符串。@technosaurus这是标准行为。(c11,6.4.5p6)“[…]然后使用多字节字符序列初始化静态存储持续时间和长度刚好足以包含该序列的数组。”