3

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

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(), as的警告warning: address of local variable ‘a’ returned。这是有道理的,但我不明白为什么编译器(gcc -Wall)可以使用f()andg()函数。

  • 那里没有局部变量吗?
  • 指针何时以及如何被释放f()或被g()释放?
4

7 回答 7

8

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

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

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

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

于 2012-08-29T18:10:59.273 回答
6

它是字符串文字。

n3337 2.14.5/8

普通字符串文字和 UTF-8 字符串文字也称为窄字符串文字。窄字符串文字的类型为“n const char 数组”,其中 n 是字符串的大小,定义如下,并且具有 静态存储持续时间

于 2012-08-29T18:09:26.923 回答
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不是局部变量的地址,它也可能会发出警告,在这种情况下,和的值将完全相同!现在尝试打印这些:str&str

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

他们将打印相同的值!

于 2012-08-29T18:12:20.463 回答
1

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

const char * f() {
  const char str[] = "this is a test";
  return str;
}
于 2012-08-29T18:10:55.153 回答
1

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

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

在 的定义中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,在编译它时,你应该看到关于返回局部变量地址的相同警告。

于 2012-08-29T18:09:58.993 回答
0

这些字符串物理上且永久地放置在您的数据存储器中,因此它们的地址是永久的。自动变量在堆栈上,所以它会在您从调用返回的那一刻消失。

于 2012-08-29T18:44:21.683 回答
0

字符串文字的存储分配是静态的,这就是您没有收到警告的原因。

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

const char* getFoo()
{

  std::string foo("hi");
  return foo.c_str();
}

因为字符串 foo 复制了文字字符串。

于 2012-08-29T18:09:55.647 回答