2009-06-06 4 views
9

Этот вопрос предназначен только для моего лучшего понимания статических переменных в 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) ; 
} 
+4

Просто так вы знаете, что это указатели, а не ссылки. – Zifre

ответ

19

Эти две функции сами по себе не являются незаконными. Во-первых, вы в обоих случаях возвращаете копию указателя, который указывает на объект со статической продолжительностью хранения: строковый литерал будет жить в течение всей продолжительности программы.

Но ваша функция main - все о неопределенном поведении. Вы не может писать в память строки литерала :) Какие основная функция не может быть сокращена до эквивалентного поведения

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

Оба неопределенное поведение и на некоторых платформах аварии (хорошо!).

Редактировать: Обратите внимание, что строковые литералы имеют тип const в C++ (не так в C): char const[N]. Ваше назначение указателю на неконстантный символ вызывает устаревшее преобразование (которое в любом случае будет предупреждать о хорошей реализации).Поскольку приведенные выше записи к этому массиву const не будут, это преобразование, код будет неправильно компилироваться. Действительно, ваш код делает этот

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

Read C++ strings: [] vs *

3

При определении и инициализировать указатель на символ, как это:

char * word = "hello"; 

вы на самом деле говорит компилятору поставить фиксированную строку «Привет» в основной части хранения где-то, а затем создать переменную указателя word указать на нее.

Хотя вы меняете изменение переменной word, чтобы указать на что-то еще, и если бы оно указывало на какое-то изменяемое хранилище, вы могли бы изменить то, на что оно указывает, с помощью операторов * и [], вам не разрешено изменять фиксированную строку «привет» " через это.

C++ позволяет назначать фиксированную строку указателю на неконстантный char исключительно для обратной совместимости. Гораздо лучше назначить эти строки указателям на const char. например

const char * word = "hello"; 

Таким образом, вы предотвращаете нелегальное поведение во время выполнения при проверке типа времени компиляции.

Edit:

В вашем примере нет, по существу, не внешне видимой разницы между наличием локальной переменной объявляются статическими и нет. Это влияет на время жизни переменной указателя в каждой функции. Это не влияет на время жизни фиксированных строк, на которые указывают указатели. Поскольку функции возвращают значение переменной-указателя (в C++ возвращается всегда по значению), не имеет особого значения, будет ли переменная-указатель в функции уничтожена в конце функции или нет. Строки сами по себе всегда будут выходить за рамки функции, поскольку строковые литералы имеют статическую продолжительность хранения.

0

Ваш статический текст является строковым литералом. Вы не должны изменять его. Некоторые компиляторы могут позволить вам. Если вместо этого ваша статика была std :: string, вы могли бы изменить ее от вызывающего.

3

Только указатель является статическим и он указывает на постоянную строку. Выполнение ножки [0] = '5' не подходит, поскольку оно изменяет константную строку.

статическое небольшое значение в данном случае, это действительно то же самое:

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

Да, хорошо, что вы это показываете, потому что большинство людей не понимает, что вы можете это сделать. – toto

0

От wikipedia:

В языке программирования С и его потомки, срок статической переменной имеет по меньшей мере два конкретных и по существу несвязанные значения, каждый , связанный с семантикой статического элемента C ключевое слово:

  1. статические локальные переменные, которые находятся в области видимости нормально, но имеют статический срок хранения (в отличие от автоматических локальных переменных, объявленных с автоматическим ключевое слово)

  2. статические глобальные переменные, которые имеют обычные статические срок хранения, но находятся в области видимости в файл, в котором они определены (в отличии от внешних переменных, объявленных с экстерном ключевым словом)

So. Статические переменные, которые вы объявляете, обычно имеют область видимости - их область действия все еще находится в пределах их соответствующих функций и недоступна вне этих функций.

Вы все равно можете вернуть указатели, но они ничего не означают.

Edit:

Кроме того, из this page:

Статические местные жители в глобальные функции могут рассматривать как глобальные переменные, , потому что их значение остается в памяти для жизни программы. 1 Единственное отличие состоит в том, что они являются только доступными (то есть, областями) до одного функция.

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

Но, как уже отмечалось в комментарии в вашем вопросе, мы возвращаем указатели, а затем ссылки, что его просто символ &, вы justget первую букву «строка».

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

Примечание: Здесь вы создаете массив «слово» символов и копирования «почему я не законно?» в массив. Вы можете вносить изменения в массив.

Также из-за того, как массивы обрабатываются языком, они будут дегенерировать в указатели при падении шляпы, когда вы возвращаете массив (или передаете его как параметр), он автоматически преобразует в указатель ,

1

Эти «мгновенные» строки хранятся в разделе «r» READ-ONLY PE в Windows. Вот почему вы получаете исключение ОС при попытке записи в это место.

Если у вас есть Ollydbg или если вы читаете вывод разборки, вы можете видеть, что строки находятся в разделе RDATA (раздел данных только для чтения). Если это была обычная строка хранится в куче, то не было бы никаких проблем

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

Это будет работать, потому что строка будет храниться на участке чтения/записи вашего исполняемого образа «кучи»,.

Смежные вопросы