5

这些对 get_string 和 get_string2 的调用都返回了在函数返回时超出范围的对象。返回的对象不应该是函数返回后超出范围的内存地址吗?这是使用 Visual Studio 2008。这应该总是有效吗?为什么?

#include <iostream>

enum myID { SMALL, MEDIUM, LARGE };

const char* get_string(myID id) {
   switch(id){
      case SMALL: return "small";
      case MEDIUM: return "medium";
      case LARGE: return "large";
      default: return "unknown";
   }
}

const char* get_string2(myID id) {
   char* s = 0;
   switch(id){
      case SMALL:  s = "small"; return s;
      case MEDIUM: s = "medium"; return s;
      case LARGE:  s = "large"; return s;
      default: return "unknown";
   }
}

int main() {
   std::cout << get_string(SMALL) << std::endl;
   std::cout << get_string2(SMALL) << std::endl;
   return 0;
}
4

2 回答 2

12

字符串文字是唯一的左值文字并且具有静态存储持续时间。所以返回一个指向字符串字面量第一个元素的指针是非常安全的。相比

const char* f1()
{
      return "Hello"; // OK
} 

const char* f2()
{
      const char s[6] = "Hello";
      return s; // Undefined Behavior
} 


const char* f3()
{
      const char* s = "Hello";
      return s; //OK
} 

从评论来看,这个答案需要一些细节。好的,看,一个字符串文字存储在内存中,直到程序完成。在案例 1 中,您返回一个指向它的指针。指向的对象指针是活动的,所以没关系。在情况 3 中,您将文字的地址放入局部变量 s 并通过副本返回后者。地址的副本仍然指向有效的内存,所以没问题。然而,在第二种情况下,我们将字符串文字复制到本地数组 s 中,该数组在函数退出时被销毁。返回局部变量的地址是未定义的行为。

此外,如果您认为未定义的行为实际上是未定义的,那么您也不应该感到惊讶,因为未定义的行为可能意味着

  • 不工作
  • 有时有效
  • 总是有效
  • 做有趣的莫名其妙的事情
  • 任何事物

因此,如果某些东西有效,并不意味着它没问题。在这种情况下,它是,但不是在一般情况下。

于 2013-05-16T15:33:26.517 回答
4

此内存不会超出范围。这些是字符串文字,它们在程序运行时一直存在。

于 2013-05-16T15:33:38.900 回答