在C ++中返回对静态局部变量的引用

时间:2009-06-06 15:39:19

标签: c++

这个问题只是为了让我更好地理解C ++中的静态变量。

我认为如果它被声明为静态,我可以在C ++中返回对局部变量的引用,因为变量应该在函数返回后生效。为什么这不起作用?

#include <stdio.h>
char* illegal()
{
  char * word = "hello" ;
  return word ;
}

char* alsoNotLegal()
{
  static char * word = "why am I not legal?" ;
  return word ;
}


int main()
{
  // I know this is illegal
  //char * ill = illegal();
  //ill[ 0 ] = '5' ;
  //puts( ill ) ;

  // but why is this? I thought the static variable should "live on" forever -
  char * leg = alsoNotLegal() ;
  leg[ 0 ] = '5' ;
  puts( leg ) ;
}

8 个答案:

答案 0 :(得分:20)

这两个功能本身并不违法。首先,在这两种情况下,您都会返回指针的副本,该指针指向具有静态存储持续时间的对象:字符串文字将在整个程序持续时间内生效。

但是你的main函数是关于未定义的行为。你不能写入字符串文字的内存:)你的主要功能可以减少到相同的行为

"hello"[0] = '5';
"why am I not legal?"[0] = '5';

两者都是未定义的行为,并且在某些平台上崩溃(好!)。

编辑:请注意,字符串文字在C ++中具有const类型(在C中不是这样):char const[N]。对指向非const字符的指针的赋值会触发不推荐的转换(无论如何,一个好的实现都会警告)。因为上面对const数组的写法不会触发转换,所以代码会错误编译。真的,你的代码正在这样做

((char*)"hello")[0] = '5';
((char*)"why am I not legal?")[0] = '5';

阅读C++ strings: [] vs *

答案 1 :(得分:4)

只有指针是静态的,它指向一个常量字符串。做leg [0] ='5'不行,因为它修改了常量字符串。

静态在这种情况下没有什么区别,这实际上是一样的:

char* alsoNotLegal()
{
     return "why am I not legal?";
}

答案 2 :(得分:3)

当您定义并初始化指向char的指针时:

char * word = "hello";

你实际上是在告诉编译器将固定字符串“hello”放到某个固定的存储区中,然后创建word指针变量来指向它。

虽然您更改了word变量以指向其他内容,如果它确实指向某个可变存储,您可以通过*和[]运算符更改其指向的内容,则不允许更改已修复的字符串“你好”通过它。

C ++允许将固定字符串分配给指向非const char的指针,纯粹是为了向后兼容。最好只将这些字符串分配给指向const char的指针。 e.g。

const char * word = "hello";

这样可以防止通过编译时类型检查导致非法的运行时行为。

编辑:

在您的示例中,将局部变量声明为静态与否之间基本上没有外部可见的区别。这会影响每个函数中指针变量的生命周期。它不会影响指针变量指向的固定字符串的生命周期。当函数返回指针变量的时(在C ++中返回总是按值),函数末尾是否销毁函数中的指针变量并不特别重要。字符串本身将永远超出函数的范围,因为字符串文字具有静态存储持续时间。

答案 3 :(得分:2)

你可能想要的是:

char* alsoNotLegal()
{
    static char[] word = "why am I not legal?" ;
 // static char*        x = "X"; <- Not good.
 // static const char*  y = "Y"; <- Good. As the compiler will warn you about
 //                                       Illegal attempts to modify it.

    return word ;
}

注意:在这里你要创建一个字符数组'单词'并复制“为什么我不合法?”进入阵列。您可以对阵列进行更改。

另外,由于语言处理数组的方式,它们会在一个帽子处生成指针,当你返回一个数组(或将它作为参数传递)时,它会自动转换为指针。

答案 4 :(得分:1)

这些“即时”字符串存储在Windows上PE的READ-ONLY“r”部分中。这就是当您尝试写入该位置时出现操作系统异常的原因。

如果您有Ollydbg或者您阅读了反汇编输出,则可以看到字符串位于RDATA部分(只读数据部分)。 如果它是存储在堆上的常规字符串,则没有问题

char* alsoNotLegal()
{
  static char word[] = "why am I not legal?" ;
  return word ;
}

这将起作用,因为字符串将存储在“堆”中,即可执行映像的读/写部分。

答案 5 :(得分:0)

你的static是一个const字符串文字。你不应该修改它。有些编译器可能允许你这样做。如果你的静态是一个std :: string,那么你就可以从调用者那里修改它。

答案 6 :(得分:0)

来自wikipedia

  

在C编程语言及其中   后代,术语静态变量   至少有两个特定和   基本上不相关的含义   与C的静态语义有关   关键字:

     
      
  1. 静态局部变量,它们通常作用域,但具有静态   储存期限(相对于   声明自动局部变量   使用auto关键字)

  2.   
  3. 静态全局变量,具有通常的静态存储持续时间,但是   范围限定在它们所在的文件中   定义(与外部相对)   用extern声明的变量   关键字)

  4.   

因此。您声明的静态变量通常是作用域 - 它们的范围仍然在它们各自的函数内,并且在这些函数之外不可用。

你仍然可以返回指针,但它们并不意味着什么。

编辑:

同样来自this page

  

全局函数中的静态局部可以   被认为是全局变量,   因为他们的价值仍然在记忆中   为了节目的生命。1   唯一的区别是它们只是   可访问(即,作用域)到一个   功能

答案 7 :(得分:0)

适合我......?

#include<iostream>
using namespace std;

char* legal() {
    char* word = "helllo";
    return word;
}

char* alsoLegal() {
    static char* word = "hello!";
    return word;
}

int main(){

    cout << legal() << endl;
    cout << alsoLegal() << endl;
    return 0;
}

但正如你在问题中的评论中已经指出的那样,我们返回指针而不是引用,这只是一个字符&amp;,你只需要输入“字符串”的第一个字母。