局部变量的地址

address of local variable

本文关键字:地址 局部变量      更新时间:2023-10-16

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

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()返回的指针何时以及如何被释放

字符串文字不存储在本地堆栈帧中。它们位于可执行文件中的固定位置。对比度:

const char * g() {
  const char * p = "test again";
  return p;
}

带有

const char * g() {
  const char a[] = "test again";
  return a;
}

在前者中,返回值指向可执行文件中的固定位置。在后者中,返回值指向堆栈(现在是堆栈中的无效位置)。

它是字符串文字。

n3337 2.14.5/8

普通字符串文字和UTF-8字符串文字也称为窄字符串文字。狭窄string literal的类型为"array of n const char",其中n是下面定义的字符串大小,并且静态存储持续时间

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似乎不是本地变量的地址,但它可能会发出警告,因为在这种情况下,str&str的值将完全相同!现在尝试打印这些:

std::cout << (void*) str  << std::endl; 
std::cout << (void*) &str << std::endl; //address of str (local variable)

他们会打印相同的值!

字符串文字不是局部变量。第三个函数的字符串等价物是这个

const char * f() {
  const char str[] = "this is a test";
  return str;
}

在函数h中,a是一个局部变量,在函数返回后将不存在。您正在向该变量返回指针,因此在函数外取消引用指针是不正确的,并且是未定义的行为。

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

g的定义中:

const char *g()
{
   const char *str = "test again";
   return str;
}

str局部变量,但它是指向-局部-静态分配-内存的指针。返回的是地址,而不是对局部变量的引用。

考虑g的另一个定义:

const char *g()
{
    const char str[] = "test again";
    // incorrect: can't use str after the return:
    return str;
}

现在g和函数h有同样的问题,在编译它时,应该会看到关于返回局部变量地址的同样警告。

字符串文字的存储分配是静态的,这就是为什么不会收到警告的原因。

试试这个,你会得到未定义的行为:

const char* getFoo()
{
  std::string foo("hi");
  return foo.c_str();
}

因为字符串foo是文本字符串的副本。

这些字符串被物理地和永久地放置在数据存储器中,因此它们的地址是永久的。自动变量在堆栈上,因此当您从调用返回时,它将消失。