我知道,这是一个非常非常常见的问题。 我读过例如this,that,and this too。 我曾经认为返回局部变量的地址是一个非常糟糕的主意。我曾经认为你应该更好:
然后我尝试了这个:
#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;
}
我使用-pedantic -pedantic-errors进行编译 并得到预期的警告:函数返回局部变量的地址[-Wreturn-local-addr]
但仅适用于foo_2()! foo_1()工作正常。有没有人知道为什么以及这种未定义的行为?
答案 0 :(得分:4)
char * foo_1() {
char * p = "bar";
return p;
}
这里不是返回本地对象的地址,而是指向指向字符串文字的指针的指针值。字符串文字具有静态存储持续时间,可以返回指向字符串文字的指针。当foo_1
返回时,p
对象被销毁(自动存储持续时间),但不会被"bar"
(静态存储持续时间)。
答案 1 :(得分:3)
在foo_2()
中,您将返回本地变量p
的地址,这就是您收到警告的原因。
在foo_1()
中,您将返回文字字符串的地址,因为它具有静态存储持续时间,所以很好。
答案 2 :(得分:2)
在foo_2()
中,您将返回(非static
)局部变量的地址。当函数返回时,该地址变得不确定,因为指向的对象不再存在 - 因此警告。
在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()
功能表现良好。它返回的指针值是字符串文字的地址,它具有静态存储持续时间(即,它存在于程序的整个生命周期中)。
但是,由于修改静态数组具有未定义的行为,因此将地址作为const char*
而不是char*
返回是明智的,因此调用者不太可能尝试修改字符串字面量。 const
也可作为任何人类读者的文档,指出不得修改指向的值。
答案 3 :(得分:0)
char * p_1 = foo_1();
没关系。取消引用p_1
不是问题,只要您不修改p_1
指向的任何内容,因为foo_1
返回指向存储在只读部分中的字符串文字的指针该计划。
char ** p_2 = foo_2();
不行。取消引用p_2
是未定义行为的原因,因为p_2
指向已被删除的对象。