局部变量的地址

时间:2012-08-29 18:05:43

标签: c++

我很难理解这三者之间的区别:

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()返回的指针何时以及如何解除分配?

7 个答案:

答案 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是一个局部变量,在函数返回后不存在。您将指针返回给该变量,因此解除引用函数外部的指针是不正确的,并且是未定义的行为。

fg中,您将返回文字字符串。文字字符串具有静态存储:它们不是分配在堆栈上,并且它们将在函数的生命周期之外存在。

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)

这些字符串在物理上永久放置在您的数据记录中,因此它们的地址是永久性的。自动变量位于堆栈中,因此当您从通话中返回时它将消失。