我很难理解这三者之间的区别:
const char * f() {
return "this is a test";
}
const char * g() {
const char * str = "test again";
return str;
}
const double * h() {
const double a = 2.718;
return &a;
}
我收到h()
的警告,warning: address of local variable ‘a’ returned
。这是有道理的,但我不明白为什么编译器(gcc -Wall
)可以使用f()
和g()
函数。
f()
或g()
返回的指针何时以及如何解除分配?答案 0 :(得分:8)
字符串文字不存储在本地堆栈帧中。它们位于可执行文件的固定位置。对比:
const char * g() {
const char * p = "test again";
return p;
}
与
const char * g() {
const char a[] = "test again";
return a;
}
在前者中,返回值指向可执行文件中的固定位置。在后者中,返回值指向堆栈中的(现在无效的位置)。
答案 1 :(得分:6)
这是字符串文字。
n3337 2.14.5 / 8
普通字符串文字和UTF-8字符串文字也称为窄字符串文字。一个箭头 string literal的类型为“const of n const char”,其中n是下面定义的字符串的大小,并且具有 静态存储时间
答案 2 :(得分:3)
const char * g() {
const char * str = "test again";
return str;
}
这不返回局部变量的地址。该变量为str
,因此,其地址应为&str
,与str
本身不同:
std::cout << (void*) str << std::endl;
std::cout << (void*) &str << std::endl; //address of str (local variable)
他们会打印不同的值!
所以一个更恰当的例子是:
const char ** g() {
const char * str = "test again";
return &str; //difference!
}
现在它返回局部变量的地址。一个好的编译器可能会为此发出警告。
另一个例子是:
const char * g() {
const char str[] = "test again"; //difference!
return str; //same as before
}
现在,即使您将似乎的str
作为本地变量的地址返回,它也可能会发出警告,如本例所示,{{1 }和str
完全相同!立即尝试打印:
&str
他们会打印相同的值!
答案 3 :(得分:1)
在函数h
中,a
是一个局部变量,在函数返回后不存在。您将指针返回给该变量,因此解除引用函数外部的指针是不正确的,并且是未定义的行为。
在f
和g
中,您将返回文字字符串。文字字符串具有静态存储:它们不是分配在堆栈上,并且它们将在函数的生命周期之外存在。
在g
:
const char *g()
{
const char *str = "test again";
return str;
}
str
是一个局部变量,但它是指向非 -local - 静态分配 - 内存的指针。这是你要返回的地址,而不是对局部变量的引用。
考虑g
的另一个定义:
const char *g()
{
const char str[] = "test again";
// incorrect: can't use str after the return:
return str;
}
现在g
与您的函数h
存在同样的问题,在编译它时,您应该看到有关返回局部变量地址的相同警告。
答案 4 :(得分:1)
字符串文字不是局部变量。相当于第三个函数的字符串是
const char * f() {
const char str[] = "this is a test";
return str;
}
答案 5 :(得分:0)
字符串文字的存储分配是静态的,这就是您没有收到警告的原因。
试试这个,你会得到未定义的行为:
const char* getFoo()
{
std::string foo("hi");
return foo.c_str();
}
因为字符串foo创建了文字字符串的副本。
答案 6 :(得分:0)
这些字符串在物理上永久放置在您的数据记录中,因此它们的地址是永久性的。自动变量位于堆栈中,因此当您从通话中返回时它将消失。