2009-06-06 13 views
9

Cette question est juste pour ma meilleure compréhension des variables statiques en C++.Renvoyer la référence à la variable locale statique en C++

Je pensais pouvoir renvoyer une référence à une variable locale en C++ si elle était déclarée statique car la variable devrait être active après le retour de la fonction. Pourquoi ça ne marche pas?

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

Juste pour que vous sachiez que ce sont des pointeurs, pas des références. – Zifre

Répondre

19

Les deux fonctions ne sont pas elles-mêmes illégales. Tout d'abord, dans les deux cas, vous renvoyez une copie d'un pointeur, qui pointe vers un objet ayant une durée de stockage statique: La chaîne littérale vivra pendant toute la durée du programme.

Mais votre fonction main est tout au sujet du comportement indéfini. Vous n'êtes pas autorisé à écrire dans une chaîne mémoire de littéral :) Ce que votre fonction principale ne peut être réduit à un comportement équivalent

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

Les deux sont un comportement non défini et sur certaines plates-formes accident (bien!).

Édition: Notez que les littéraux de chaîne ont un type const en C++ (pas en C): char const[N]. Votre affectation à un pointeur vers un caractère non-const déclenche une conversion obsolète (dont une bonne mise en œuvre avertira, de toute façon).Parce que les écritures ci-dessus à ce tableau const ne déclencher cette conversion, le code va mal compiler. Vraiment, votre code est en train de faire ce

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

Lire C++ strings: [] vs *

3

Lorsque vous définissez et initialiser un pointeur vers un char comme ceci:

char * word = "hello"; 

vous dites en fait le compilateur de mettre la chaîne fixe « bonjour » dans un morceau fixe de stockage quelque part, puis créez la variable de pointeur word pour pointer dessus. Bien que vous changiez de changer la variable word pour pointer vers quelque chose d'autre et si elle pointait vers un stockage mutable vous pourriez changer ce qu'elle pointe vers les opérateurs * et [], vous n'êtes pas autorisé à changer la chaîne fixe "bonjour " à travers. C++ permet d'assigner une chaîne fixe à un pointeur vers char non-const pour des raisons de compatibilité descendante. Il est préférable d'affecter uniquement ces chaînes aux pointeurs const char. par exemple. De cette façon, vous évitez de provoquer un comportement d'exécution illégal en compilant des vérifications de type de temps.

Edit:

Dans votre exemple, il n'y a pratiquement pas de différence visible entre l'extérieur ayant la variable locale statique et non déclarée. Cela affecte la durée de vie de la variable pointeur dans chaque fonction. Cela n'affecte pas la durée de vie des chaînes fixes sur lesquelles les variables de pointeur pointent. Comme les fonctions renvoient la valeur de la variable pointeur (dans les retours C++ sont toujours par valeur), il importe peu que la variable pointeur de la fonction soit détruite à la fin de la fonction ou non. Les chaînes elles-mêmes vont toujours au-delà de la portée de la fonction car les chaînes de caractères ont une durée de stockage statique.

0

Votre statique est un littéral de chaîne const. Vous ne devriez pas le modifier. Certains compilateurs peuvent vous le permettre. Si à la place votre statique était une chaîne std ::, vous seriez capable de la modifier depuis l'appelant.

3

Seul le pointeur est statique et il pointe vers une chaîne constante. Doing leg [0] = '5' n'est pas correct car il modifie la chaîne de caractères constante.

statique font peu de différence dans ce cas, ce qui est vraiment le même:

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

Oui, c'est une bonne chose que vous montriez ceci, parce que la plupart des gens ne réalisent pas que vous pouvez le faire. – toto

0

De wikipedia:

Dans le langage de programmation C et sa variable statique descendants , le terme a au moins deux significations spécifiques et non apparentées, chacune liée à la sémantique de C statique mot-clé:

  1. statiques variables locales, qui sont scope normalement, mais ont une durée de stockage statique (par opposition aux variables locales automatiques déclarées avec le mot-clé automatique)

  2. variables globales statiques, qui ont l'habitude statique durée de stockage, mais sont portée définie dans le fichier dans lequel ils sont définis (par opposition à des variables externes déclarées avec le mot-clé extern)

Donc. Les variables statiques que vous déclarez ont une portée normale - leur portée est toujours dans leurs fonctions respectives et n'est pas disponible en dehors de ces fonctions.

Vous pouvez toujours renvoyer les pointeurs, mais ils ne veulent rien dire.

Edit:

aussi de this page:

habitants statiques dans les fonctions globales peuvent être considérées des variables globales comme, parce que leur valeur reste en mémoire pour la durée du programme. 1 La seule différence est qu'ils sont seulement accessibles (c'est-à-dire limités) à une fonction .

0

Fonctionne pour moi ...?

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

Mais comme nous l'avons noté dans un commentaire dans votre question, nous sommes des pointeurs de retour plutôt que des références, ce qui est juste un omble chevalier &, vous justget la première lettre de la « chaîne ».

2

Qu'est-ce que vous avez probablement voulu était:

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: Vous créez un tableau « mot » des personnages et la copie « Pourquoi suis-je pas légal? » dans le tableau. Vous êtes autorisé à apporter des modifications au tableau.

En raison de la façon dont les tableaux sont gérés par le langage, ils seront générés en pointeurs à la baisse d'un chapeau, lorsque vous retournez un tableau (ou le passez en paramètre) il se convertira automatiquement en un pointeur .

1

Ces chaînes "instantanées" sont stockées dans une section "r" du PE sous Windows. C'est pourquoi vous obtenez une exception de système d'exploitation lorsque vous essayez d'écrire dans cet emplacement.

Si vous avez Ollydbg ou si vous lisez la sortie de désassemblage, vous pouvez voir que les chaînes sont dans la section RDATA (section de données en lecture seule). Si elle était une chaîne régulière stockée sur le tas, il n'y aurait pas de problème

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

Cela fonctionne parce que la chaîne sera stockée sur le « tas », une section de lecture/écriture de l'image exécutable.

Questions connexes