本地变量的地址

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()时,出现了一个警告,提示warning: address of local variable ‘a’ returned。这有道理,但我不明白为什么编译器(gcc -Wall)对f()g()函数没有问题。

  • 那里难道不是有一个局部变量吗?
  • f()g()返回的指针何时以及如何被释放?

12
这些字符串常量并不是局部变量。 - Mysticial
你正在返回常量字符串,它们在可执行文件中静态分配,不会在运行时分配和释放。 - Joachim Isaksson
由于您没有为f()和g()分配内存,因此它们没有被释放,只是被覆盖。 - Ankur
它们也不会被释放。当您尝试释放字符串文字时(它们通常嵌入到可执行文件中),可能会发生糟糕的事情。 - ssube
7个回答

8

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

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

使用

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

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


6

这是字符串字面值。

n3337 2.14.5/8

普通字符串字面值和UTF-8字符串字面值也被称为窄字符串字面值。一个窄字符串字面值的类型为“n个const char的数组”,其中n是下面定义的字符串大小,并且具有静态存储期


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)

他们将会打印相同的值!

дЅ дёЌиѓЅиї”е›ћ&strпјЊе› дёєе®ѓзљ„з±»ећ‹const char(*)[11]дёЋиї”е›ћз±»ећ‹const char*дёЌе…је®№гЂ‚ - fredoverflow
@FredOverflow:什么?当我使用&str时,它是const char **,那么const char **就完全没有问题! - Nawaz
你在谈论哪个版本的函数 g? :) 我指的是最后一个版本,其中 str 是一个数组。 - fredoverflow
@FredOverflow:在最新版本中,我不返回&str - Nawaz
但是你说过,“在这种情况下,str&str的值将完全相同”。然而,如果我用return &str;替换return str;,g++会抱怨“Fehler: »const char (*)[11]« kann nicht nach »const char*« in Rückgabe umgewandelt werden”。 - fredoverflow
@FredOverflow:是相同的,但类型不同。这是有区别的,你不这么认为吗? - Nawaz

1
在函数 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 存在相同的问题,编译时应该会看到有关返回本地变量地址的警告。


1

字符串字面量不是本地变量。第三个函数的字符串等效形式是这样的

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

0

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

尝试这样做,你将会得到未定义的行为:

const char* getFoo()
{

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

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


0

这些字符串被物理地永久地放置在您的数据内存中,因此它们的地址是固定的。自动变量位于堆栈上,因此一旦从调用返回,它将消失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接