Среда, 24.04.2024, 09:26
Приветствую Вас Гость | RSS

Лекции

Меню сайта
Форма входа
Категории раздела
ТАУ (Теория автоматического управления) [31]
лекции по ТАУ
Экология [151]
учебник
Бухгалтерский учет и налогообложение в строительстве [56]
Дементьев А.Ю. - Практическое пособие
Психология [104]
Пип
информатика [80]
с# Карли Ватсон
современные стулья [0]
новинки
Поиск

Главная » 2010 » Февраль » 11 » Область действия переменных
00:17
Область действия переменных
Область действия переменных
и другие программные конструкции
Перед тем как пойти дальше, следует обратить внимание на то, что важность
заявлений, сделанных в предшествующем разделе, далеко выходит за рамки опре-
деления области действия переменных в разных функциях. Утверждалось, что об-
ласть действия переменных распространяется на блок кода, в котором они описаны,
и на все блоки, непосредственно в него вложенные. Это также применимо и к дру-
гим типам блоков, например, к программным конструкциям, использующим ветв-
ление и циклы. Рассмотрим следующую программу:
i n t i ; • -': :;-•.. :v: ' .Л , :
for (i = 0; i < 10; i++)
{ : ' '
string text = *Line * + Convert.ToString(i);
Console.WriteLine{*{0}•, text);
}
Console.WriteLine(*Last text output in loop: {0}", text);
В данной программе строковая переменная text является локальной для цикла for.
ТаКОЙ КОД не пройдет КОМПИЛЯЦИЮ, ПОСКОЛЬКУ В Обращении К Console.WriteLine () ,
которое происходит вне этого цикла, делается попытка использовать переменную
text, область действия которой не распространяется за пределы цикла. Изменим
код следующим образом:
int i;
string text;
for (i = 0; i < 10; i++)
{
text = 'Line * + Convert.ToString(i);
Console.WriteLine("{О}*, text);
}
Console.WriteLine(*Last text output in loop: {0}", text);
Этот код также недопустим. Причина кроется в том, что переменные должны и опи-
сываться, и инициализироваться до того, как они будут использоваться, а перемен-
ная text инициализируется только в цикле for. Значение, присвоенное переменной
Функции 121
text, при выходе из цикла будет утрачено. Однако мы можем модифицировать код
еще раз:
int i;
string text = "";
for (i = 0; i < 10; i++)
{
text = 'Line • + Convert.ToString(i);
Console.WriteLine(jr{0}*/ text);
}
Console.WriteLine("Last text output in loop: {0}", text);
jG\0egCSharp\tr.
text output In loops Lioe 9
3 any key to continue
На этот раз переменная text инициа-
лизирована вне цикла, и мы имеем до-
ступ к ее значению. Результат выполнения
этой простой программы показан на ри-
сунке слева.
В данном случае значение, присвоен-
ное переменной text внутри цикла, ока-
зывается доступным и вне его.
Как вы, вероятно, заметили, эта тема
требует определенных усилий для пони-
мания. В первый момент представляется
не вполне очевидным, почему — в свете предыдущего примера — переменная
text не сохраняет в качестве своего значения пустую строку, присвоенную ей пе-
ред началом цикла, для кода, расположенного после его окончания.
Причина кроется в способе выделения памяти для переменной text, да и для
всех остальных переменных тоже. Простое объявление переменной некоторого
простого типа не влечет за собой выполнения каких-либо существенных действий.
Только тогда, когда переменным присваиваются значения, для этих значений вы-
деляется память, в которой они будут храниться. Когда такое выделение памяти
происходит внутри цикла, это значение определяется как локальное и область его
действия не выходит за пределы цикла. И хотя переменная не является локализо-
ванной внутри данного цикла, к ее значению это не относится. Напротив, присваи-
вание переменной значения вне цикла дает гарантию того, что это значение
локальное цдя всего основного кода и что область действия переменной распро-
страняется в том числе и на цикл. Другими словами, мы будем оставаться внутри
области действия переменной до тех пор, пока не покинем блок основного кода,
поэтому возможность доступа к переменной имеется и за пределами цикла.
На наше счастье, компилятор С# самостоятельно обнаруживает проблемы,
связанные с областью действия переменных, и генерирует сообщения об ошибках.
В качестве заключительного замечания необходимо упомянуть о "наилучшей
практике". Вообще говоря, лучше всего объявлять и инициализировать перемен-
ные перед теми блоками кода, в которых они используются. Исключением из этого
правила могут быть переменные циклов, объявление которых является составной
частью самого цикла. Например:
f o r ( i n t i = 0 ; i < 1 0 ; i + + )
• •' f | { Щ • •:•••• . • •• •• | i Щ ••. • ' :: • I \ Щ : o - Ш I : • ' Щ ' I . i | |
} '• '
В данном случае, переменная i является локализованной в блоке кода, пред-
ставляющем собой цикл, но это и хорошо, поскольку редко когда требуется доступ
к значению счетчика цикла из внешнего кода.
122 Глава 6
Параметры и возвращаемые значения
по сравнению с глобальными данными
Этот раздел посвящен более детальному рассмотрению обмена данными с функ-
циями через механизм глобальных переменных и через механизм параметров
и возвращаемых значений. Напомним, что речь идет о различиях между двумя про-
граммами. Первая из них имеет вид:
class Classl
{ чяйпнш ^ жшттшшшт - - -IMP
static void showDouble(ref int val)
{
;:
-:: •:.V'::;/,v-:-:-.--;::v::v-; '.:.--":,-':::- • ' v a l * = 2,-
Console.WriteLineCval doubled = {0}*, val);
}
static void Main(string[] args)
^ { .
int val = 5;
Console.WriteLineCval = {0}", val) ;
showDouble(ref val);
Console.WriteLineCval = {0}*, val);
Обратите внимание, что этот код несколько отличается
от того кода, где в функции Main о нами использовалась
переменная с именем туыитЬег. Это иллюстрация того факта,
что локальные переменные могут обладать идентичными
именами и не мешать друг другу. Это также означает,
что две программы, которые приводятся здесь, оказываются
очень похожими друг на друга, позволяя нам сосредоточить
внимание на принципиальных отличиях и не беспокоиться
об именах переменных.
Вторая программа имеет следующий вид:
class Classl
- • - - Ь -•--.•
static int val;
static void showDouble ()
{ ' ;
• val *= 2;
Console. WriteLineC val doubled - {0}" , val);
}
static void Main{string[] args)
{ # ^ ^ ^ ^ ^ 'ч -. . . ш^^^тшшттшшш:,.
val = 5;
Console.WriteLine(*val = {0}*, val);
•-.••;.•:. •"/ ...' s h o v / D o u b l e ( ) ; ;.:••, ;• ;', :-;'. ••.,.' ' '• . '...., • . ... . ... \
Console.WriteLine(< ' v a l = {0}*, v a l ) ;
Результаты выполнения обеих программ совершенно идентичны.
Следует заметить, что не существует жестких правил, определяющих предпоч-
тительность использования одного способа вместо другого: оба эти способа явля-
ются вполне допустимыми. Тем не менее существуют некоторые соображения,
которые желательно учитывать при выборе одного из них.
Функции J23
Для начала обратите внимание на то, что (это уже отмечалось выше) версия
функции showDoubleO, которая использует глобальное значение, сможет исполь-
зовать только глобальное значение переменной vai. Применение такой версии
функции принуждает нас использовать именно эту глобальную переменную, что
несколько ограничивает гибкость в применении данной функции и требует посто-
янно копировать значение глобальной переменной в другие переменные в том
' случае, если необходимо сохранить результат. Кроме того, глобальные данные
могут быть изменены где-нибудь в другом месте приложения, что приведет к по-
лучению непредсказуемых результатов (мы можем вспомнить о том, что значения
изменены, слишком поздно).
Однако такая потеря гибкости зачастую является преимуществом. Существуют
ситуации, когда применение некоторой функции планируется исключительно для
одной конкретной цели и использование глобально описанных данных уменьшает
вероятность того, что мы неправильно обратимся к функции, например, передав
неверные параметры.
Конечно, такая простота в действительности делает программу менее понят-
ной. Явное указание параметров позволяет увидеть, что именно подвергается из-
менениям, даже мельком взглянув на функцию. Если встречается вызов функции,
имеющий вид myFunction(vaii, out val2), то сразу становится ясно, что следует
обратить самое пристальное внимание на переменные vail и vai2 и что перемен-
ной vai2 по окончании выполнения функции будет присвоено новое значение.
И наоборот, если у этой функции не имеется никаких параметров, то мы не смо-
жем сделать предположения относительно того, над какими данными она выполня-
ет манипуляции.
Наконец, не следует забывать о том, что использование глобальных данных не
всегда оказывается возможным. Далее нам встретятся примеры программ, храня-
щихся в разных файлах и/или принадлежащих различным пространствам имен, ко-
торые взаимодействуют между собой посредством использования функций. В таких
случаях код зачастую оказывается до такой степени разделенным, что непонятно,
где именно следует хранить глобальные переменные.
Итак, оба способа обмена данными можно использовать с равным успехом.
В большинстве случаев мы будем настаивать на применении параметров вместо
глобальных данных, однако существуют отдельные ситуации, когда более подходя-
щим может оказаться использование именно глобальных данных; и уж, во всяком
случае, такой способ не является ошибкой.





























Категория: информатика | Просмотров: 1375 | Добавил: basic | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Календарь
«  Февраль 2010  »
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

krutoto.ucoz.ru
Бесплатный конструктор сайтов - uCoz