bobobobo
bobobobo

Reputation: 67356

Returning reference to static local variable in C++

This question is just for my better understanding of static variables in C++.

I thought I could return a reference to a local variable in C++ if it was declared static since the variable should live-on after the function returns. Why doesn't this work?

#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 ) ;
}

Upvotes: 9

Views: 9355

Answers (8)

toto
toto

Reputation: 900

These "instant" strings are stored in a READ-ONLY "r" section of the PE on Windows. This is why you get an OS exception when you try to write to that location.

If you have Ollydbg or if you read the disassembly output, you can see that the strings are in the RDATA section (Read-only data section). If it was a regular string stored on the heap, there would be no problem

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

This will work because the string will be stored on the "heap", a read/write section of your executable image.

Upvotes: 1

Loki Astari
Loki Astari

Reputation: 264739

What you probably wanted was:

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 ;
}

Note: Here you are creating an array 'word' of characters and copying "why am I not legal?" into the array. You are allowed to make changes to the array.

Also because of the way arrays are handled by the language, they will de-generate into pointers at the drop of a hat, when you return an array (or pass it as a parameter) it will auto convert into a pointer.

Upvotes: 2

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 507413

The two functions are not itself illegal. First, you in both case return a copy of a pointer, which points to an object having static storage duration: The string literal will live, during the whole program duration.

But your main function is all about undefined behavior. You are not allowed to write into a string literal's memory :) What your main function does can be cut down to equivalent behavior

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

Both are undefined behavior and on some platforms crash (good!).

Edit: Note that string literals have a const type in C++ (not so in C): char const[N]. Your assignment to a pointer to a non-const character triggers a deprecated conversion (which a good implementation will warn about, anyway). Because the above writings to that const array won't trigger that conversion, the code will mis-compile. Really, your code is doing this

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

Read C++ strings: [] vs *

Upvotes: 22

CB Bailey
CB Bailey

Reputation: 793279

When you define and initialize a pointer to char like this:

char * word = "hello";

you are actually telling the compiler to put the fixed string "hello" into a fixed piece of storage somewhere and then create the word pointer variable to point at it.

Although you change change the word variable to point at something else and if it did point at some mutable storage you could change what it points to via * and [] operators, you are not allowed to change the fixed string "hello" through it.

C++ allows assigning a fixed string to a pointer to non-const char purely for backwards compatibility. It is much better to only assign these strings to pointers to const char. e.g.

const char * word = "hello";

This way you prevent causing illegal run time behaviour through compile time type checks.

Edit:

In your example there is essentially no externally visible difference between having the local variable declared static and not. This affects the life time of the pointer variable in each function. It does not affect the lifetime of the fixed strings that the pointer variables point at. As the functions return the value of the pointer variable (in C++ returns are always by value), it doesn't particularly matter whether the pointer variable in the function is destroyed at the end of the function or not. The strings themselves will always live beyond the scope of the function as string literals have static storage duration.

Upvotes: 3

Knowles Atchison
Knowles Atchison

Reputation: 61

Works for me...?

#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;
}

But as already noted in a comment in your question, we're returning pointers rather then references, which is its just a char&, you'll justget the first letter of the "string".

Upvotes: 0

poundifdef
poundifdef

Reputation: 19380

From wikipedia:

In the C programming language and its descendants, the term static variable has at least two specific and essentially unrelated meanings, each related to the semantics of C's static keyword:

  1. static local variables, which are scoped normally, but have static storage duration (as opposed to automatic local variables declared with the auto keyword)

  2. static global variables, which have the usual static storage duration, but are scoped to the file in which they are defined (as opposed to external variables declared with the extern keyword)

So. The static variables you are declaring are scoped normally - their scope is still within their respective functions, and are not available outside of those functions.

You can still return the pointers, but they don't really mean anything.

Edit:

Also from this page:

Static locals in global functions can be thought of as global variables, because their value remains in memory for the life of the program.1 The only difference is that they are only accessible (i.e., scoped) to one function.

Upvotes: 0

Joakim Elofsson
Joakim Elofsson

Reputation: 38314

Only the pointer is static and it points to a constant string. Doing leg[ 0 ] = '5' is not ok as it modifies the constant string.

static make little difference in this case, this is really the same:

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

Upvotes: 4

sean e
sean e

Reputation: 11935

Your static is a const string literal. You should not modify it. Some compilers might allow you to. If instead your static was a std::string, then you would be able to modify it from the caller.

Upvotes: 0

Related Questions