“Переменность, непостоянство, изменчивость – главные свойства всего живого, позволяющие адаптироваться к окружающему миру.”
Учебник биологии
На этом занятии мы познакомимся с одним из удобнейших и мощнейших элементов языков программирования.
До этого мы взаимодействовали только с постоянными величинами, с константами. Значение константы записывается один раз – при создании программы. Изменить её значение в процессе работы программы невозможно – это можно сделать только при переписывании текста программы.
Но представьте себе, что вашей программе необходимо обрабатывать поступающие откуда-то снаружи изменяющиеся данные. Используя только константы такую задачу решить невозможно: поступающие данные просто негде хранить и непонятно, как обрабатывать. Кроме того, мы заранее не знаем, какие именно данные получит наша программа.
Предположим, мы хотим написать программу, в которую будет вводиться какое-то число, а программа должна будет вычислить квадрат этого числа и вывести результат на экран (в консоль).
Давайте рассмотрим алгоритм работы такой программы:
- Получить числовое значение (пока не важно, как это может быть выполнено в программе)
- Сохранить это значение в области памяти (иначе мы просто не сможем с ним работать)
- Выполнить возведение в квадрат полученного значения (достаточно просто умножить его само на себя)
- Сохранить полученное значение в области памяти.
- Вывести на экран сохраненное значение.
В данном алгоритме мы не знаем пока, как выполнить пункты 1, 2 и 4, потому что пока не умеем сохранять данные в памяти.
Что такое переменная
Будем считать, что пункт 1 кто-то уже выполнил за нас и у нас уже есть какое-то числовое значение. Теперь его нужно записать в область памяти для того, чтобы сохранить для дальнейшего использования. Для этого нам нужен некий программный объект, у которого можно не только считывать текущее значение (как мы это делаем с константами), но в который также можно записывать новое значение. Нам нужен объект, значение которого можно изменять. Такими объектами в языках программирования являются (по аналогии с алгеброй) переменные.
Всякая переменная – это просто область памяти, у которой есть адрес в памяти или имя (на самом деле, у каждой переменной есть и то и другое, но сейчас это не принципиально). Используя имя переменной (или её адрес) мы можем не только считывать находящееся по этому адресу значение, но и записывать туда новое (изменять значение переменной). Это невозможно для констант, потому что мы не знаем, где в памяти располагаются записанные нами в программе значения констант.
Переменную можно представить в виде коробки, в которой что-то находится (значение переменной), и на которой что-то написано (имя переменной), что позволяет отличить эту коробку от других похожих коробок.
Как правило, имена переменных в языках программирования могут содержать буквы, цифры и некоторые другие символы, при этом начинаться они должны только с букв или специальных символов (но не с цифр!).
Также очевидно, что имена различных переменных обязательно должны различаться между собой. Иначе ни мы ни компьютер не поймем, где какая переменная.
Объявление переменных
Так как данные бывают различных типов (по крайней мере, двух: текстовые и числовые), то и размер места для их хранения в памяти нужен разный. Числа, записываемые в памяти компьютера в двоичной системе счисления, как правило, занимают в памяти гораздо меньше места чем текстовые строки. Числовой код каждого символа строки требует отдельного места (например, столько же, сколько небольшое целое число), поэтому для строк приходится выделять достаточно большие участки памяти. Для того чтобы компьютер как-то “узнал”, сколько памяти ему нужно выделить под ту или иную переменную, используются команды создания (или объявления) переменных. Такая команда, как правило, включает в себя тип создаваемой переменной (фактически – требуемый размер памяти), её имя и начальное значение этой переменной (например, некую константу).
В тех языках, где объявление переменных обязательно, каждая переменная должна быть объявлена в программе до её использования. Иначе компьютер просто не поймёт, с чем он имеет дело. Кроме того, нельзя объявлять одну и ту же переменную (переменную с одним и тем же именем) дважды (за исключением особых случаев, которые относятся к специфике конкретных языков программирования).
Инициализация переменных. Присваивание
Для задания начального значения переменной в программировании часто используют команду, которая записывает в выделенную ячейку памяти новое значение переменной. Такая команда называется присваиванием.
В большинстве языков программирования присваивание выглядит точно так же как равенство в математике:
a = 12
только смысл этой записи в программировании совершенно другой. Если в математике такая запись всего лишь утверждает, что значение переменной а и число 12 равны (или должны быть равны) между собой, то в программировании это – команда, которая требует чтобы процессор записал в ячейку памяти с именем “а” числовое значение (значение указанной числовой константы) 12 вместо того, которое было записано в этой ячейке до выполнения этой команды. То есть, после выполнения этой команды переменная а (ячейка памяти с именем “а“) обязательно будет содержать числовое значение 12.
Можно считать, что присваивание имеет два параметра: имя переменной в левой части и то, что находится в правой части.
Задание начального значения при создании переменной называют инициализацией переменной. В ряде случаев возможно объявление переменной без её инициализации. Во многих современных языках программирования переменные при объявлении без инициализации автоматически получают некие “нейтральные” значения: например, 0 – для числовых и пустая строка (строка, не содержащая ни одного символа) – для текстовых. Однако, в ряде языков этого не происходит и тогда в переменной может оказаться тот “мусор”, который был в этом месте памяти до того как его выделили под нашу переменную.
В тех языках, где объявление переменной не требуется, если вам все-таки нужна определенность её типа, вы можете выполнить инициализацию переменной нужным вам значением. Это автоматически определит тип переменной.
Однако, в некоторых современных языках программирования переменные могут не только автоматически получать тип в соответствии с первым присваиваемым значением, но и менять его в процессе работы программы, подстраиваясь под специфику использования. С одной стороны это может быть очень удобно: программистам не надо беспокоиться о том, что какие-то данные “не поместятся” в переменную, но с другой стороны, нет никаких гарантий, что в какой-то момент в переменной окажутся именно те данные, которые вы ожидаете там найти: например, вместо числа в переменной может оказаться строка текста.
В тех языках, где объявление переменной обязательно (С, С++, C#, Java, Java Script) операция объявления переменной с инициализацией выглядит совершенно одинаково:
int a = 12;
Здесь:
int – оператор объявления типа переменной, в данном случае – это переменная целого типа (integer)
a – имя создаваемой переменной
= – команда присваивания
12 – значение, которым инициализируется новая переменная (то значение, которое она получит при создании)
; – признак завершения команды
Команда присваивания может записывать в переменные не только значения констант. Значение одной переменной можно записать в другую переменную:
a = b
При этом важно, что запись идет справа налево (так же как и с константами): то, что мы записываем (выражение, значение и т.п.) должно находиться справа от знака “равно”, а переменная, в которую мы хотим записать получившееся справа значение – слева.
Вообще в программировании везде где может стоять константа может стоять и переменная соответствующего типа.
В прошлый раз мы выяснили, что в результате выполнения операции получается новое значение, являющееся результатом выполнения этой операции. И это значение затем можно использовать вместо константы в выражениях.
В ряде Си-подобных языков присваивание – это операция, и оно, точно так же как и любая другая операция – возвращает значение, которое может быть использовано. Например в языке С возможна такая запись:
a = b = c = 12;
Здесь присваивание выполняется справа налево (по шагам), и в результате выполнения первого присваивания переменная с получит значение 12, а сама операция возвратит значение 12, которое будет использовано в следуюшей операции присваивания – так получит значение 12 переменная b, а затем и a.
Однако, существует ряд языков, где присваивание не является операцией, и, соответстсвенно, не может возвращать значения. Поэтому в таких языках подобная “каскадная” запись попросту невозможна и будет посчитана ошибочной в процессе компиляции программы.
Имена переменных могут участвовать о всех операциях (выражениях) в качестве элементов выражения (операндов) наравне с константами – в соответствии с типами этих переменных. При этом, мы помним, что любое выражение может являться частью другого выражения – вместо константы или переменной.
Там, где может стоять константа или переменная может стоять и любое подходящее выражение, использующее, в свою очередь, константы или переменные.
Примеры кода
Попробуем теперь записать наш алгоритм с учетом полученных знаний:
- Получить числовое значение (пока не важно, как это может быть выполнено в программе) – сейчас мы просто заменим результат этой пока неизвестной нам операции числовой константой 123
- Создадим переменную b для хранения нашей константы
- Сохраним значение константы в созданной нами переменной b
- Создадим еще одну переменную с, которую будем использовать для хранения результата вычислений
- Выполним операцию умножения переменной b на саму себя
- Сохраним получившееся значение в области памяти – в переменной с
- Выведем на экран сохраненное значение – значение переменной с
В данном алгоритме каждый шаг нам уже понятен и мы можем переписать его в виде программного кода:
RUbasic
1 2 3 |
<strong>b = 123 c = b * b Консоль.ПечатьСтроки(c)</strong> |
MS Small Basic
1 2 3 |
<strong>b = 123 c = b * b TextWindow.WriteLine(c)</strong> |
С
1 2 3 4 5 |
<strong>int b; b = 123; int c; c = b * b; printf("%i\n", c);</strong> |
С++
1 2 3 4 5 |
<strong>int b; b = 123; int c; c = b * b; std::cout << c << std::endl;</strong> |
C#
1 2 3 4 5 |
<strong>int b; b = 123; int c; c = b * b; Console.WriteLine(c);</strong> |
Java
1 2 3 4 5 |
<strong>int b; b = 123; int c; c = b * b; System.out.println(c);</strong> |
Java Script
1 2 3 4 5 |
<strong>let b; b = 123; let c; c = b * b; console.log(c);</strong> |
PHP
1 2 3 |
<strong>$b = 123; $c = $b * $b; echo $c;</strong> |
Python
1 2 3 |
<strong>b = 123 c = b * b print(c)</strong> |
Как мы уже говорили, языки программирования в этом примере сразу разделились на две группы: в одних объявление типа переменной обязательно (С, С++, C#, Java, Java Script), а в других (RUbasic, MS Small Basic, PHP, Python) – нет. Необходимость объявления переменных может показаться не очень удобной, однако этот механизм позволяет избегать многих ошибок и эффективнее управлять памятью.
Мы изучили мощнейший механизм в программировании, который позволяет выполнять практически неограниченные преобразования различных данных. При этом в присваивании можно использовать не только арифметические, но и любые конструкции, возвращающие значение.
Счетчики
А сейчас мы рассмотрим один из самых интересных моментов в выражениях с переменными. Смотрите:
n = n + 1
Что это? С точки зрения непрограммиста, человека привыкшего к математике это – полный бред. В математике такого просто не может быть: такое равнество никогда не будет верным.
А вот в программировании в этой записи нет ничего странного. Давайте разбираться, как же выполняется эта и любая другая, подобная ей команда.
Для начала, в этой строке присутствуют две операции: операция сложения и операция присваивания. При этом операция присваивания будет выполнена в самую последнюю очередь. Значит сначала будет выполнена операция сложения. Итак:
- Взять текущее значение переменной n
- Считать значение константы (1)
- Выполнить операцию сложения значения переменной n и 1. В результате операции сложения получилось некое число (большее текущего значения переменной n на 1)
- Теперь с помощью оператора присваивания записать получившееся число в переменную n
То есть, в результате этой операции мы просто увеличили текущее значение переменной n на единицу.
И никаких сложностей! Нужно просто понять, что любые операции и команды, даже записанные в одну строку, на самом деле выполняются последовательно, по шагам – как действия в арифметическом выражении.
Кстати, то же самое можно записать и более понятно (но менее удобно) с использованием дополнительной переменной m:
m = n + 1
n = m
Повторение подобных операций с переменными позволяет организовывать в программах различные счетчики: при каждом повторении такой операции значение переменной будет увеличиваться на единицу.
Если же вместо сложения мы используем вычитание, то значение переменной n будет каждый раз уменьшаться на единицу. А если использовать умножение или деление на какое-то число, то в результате повторения мы получим ряд значений, составляющих возрастающую или убывающую геометрическую прогрессию.
Немного об именах
Каждый программист волен давать переменным в своей программе любые имена. Если вы пишете для себя простую и короткую программу, достаточно использования в качестве имен переменных букв латинского алфавита. Но как только программа станет большой и сложной, окажется, что даже вам приходится тратить время на то, чтобы понять, что именно хранится в той или иной переменной. Однако, можно дать несколько советов, следование которым сделает вашу программу более понятной и вам и другим людям:
- Имена переменных следует образовывать от описаний объектов предметной области вашей программы таким образом, чтобы по имени переменной можно было понять, какая именно информация в ней хранится.
- Так как большинство языков программирования английские, и в именах переменных допускаются только английские буквы, то можно создавать имена переменных либо из английских слов, либо из русских слов, записанных латинскими буквами.
- Слова, составляющие имя переменной можно сокращать, но так, чтобы не страдали смысл и читаемость.
- В тех языках, где в именах переменных допускаются знаки подчеркивания “_” или дефис “-“, слова в имени переменной можно разделять этими символами. Это так называемые “Змеиная” (snake_case) и “Шашлычная” (kebab-case) запись.
- В тех языках, где в именах переменных допускаются большие и маленькие буквы, каждое слово можно начинать с большой буквы. Это так называемая “Верблюжья” (CamelCase) запись.
- При объявлении переменной лучше всего сразу инициализировать её начальным значением.
- Также, при объявлении переменной желательно описать в комментарии смысл этой переменной.
- В случаях, когда переменная используется в каком-то небольшом и очень локальном блоке допустимо придание ей имени минимальной длины (1-2 буквы).
- В некоторых случаях желательно включать в имя переменной одно-двух буквенный префикс, описывающий её тип или какие-то особенности использования. Такая запись называется “Венгерской”.
- Не увлекайтесь слишком короткими или слишкм длинными именами переменных. Иначе:
– в первом случае вы быстро потеряете понимание, что значит какая переменная, и кроме того, рискуете перепутать переменные,
– во втором – вы рискуете сделать программу нечитаемой из-за обилия текста.
Однако, кроме этих рекомендаций, из которых каждый волен выбрать для себя (если он не работает в команде) что-то наиболее удобное, существует также обязательное правило, нарушать которое нельзя:
Имена переменных не должны совпадать с именами команд, функций и другими словамя языка программирования (такие слова называют зарезервированными).
В случаях, когда одна и та же константа используется в программе многократно, вместо неё в программе также можно использовать переменную. При этом вам не придется просматривать весь текст программы при необходимости изменить значение этой константы: достаточно просто изменить его в одном месте (обычно в самом начале программы), а дальше просто обращаться к этой переменной по имени. Главное при этом – ничего не записывать в эту переменную в тексте, а только считывать её значение.
Обычно такие переменные-константы стараются называть так, чтобы их имена визуально отличались ото всех других имен переменных в программе – это поможет избежать ошибок. Например, во многих языках сложилась практика давать константам имена, состояшие только из больших букв.
Итак:
- Кроме констант в языках программирования существуют переменные – поименованные ячейки памяти, предназначенные для хранения данных из которых можно не только читать хранящиеся там данные, но также и записывать в них новые данные.
- Во многих языках переменные различаются по типам хранимой информации. Тип переменной, в частности, определяет размер памяти, требуемый для хранения этой переменной.
- Во многих языках перед использованием переменной требуется её объявить – кроме её имени указать также её тип.
- Переменные могут участвовать во всех операциях наравне с константами.
- Для записи значения в переменную используется специальная операция – операция присваивания.
- Переменные позволяют очень гибко и широко использовать их в программах.
- Программист может придумывать любые имена переменных, при этом он должен придерживаться правил языка программирования, кроме того, он может также следовать некоторым рекомендациям.
На следующем занятии мы узнаем, как можно создавать программы, в которых порядок выполнения команд не соответствует порядку их записи в программе и как графически отображать различные алгоритмы.
Поделиться: