Основы программирования

Специально для Андрея Г.
август 2010

Как описать непрограммисту то, что называется программированием?

Я вспоминаю свои первые шаги в обучении этому ремеслу и мне кажется, что это было несложно. Думаю, что и для любого другого человека, уделившего немного внимания этой теме, это тоже должно быть легко.

Алгоритм

В основе каждой программы лежит алгоритм.

Нужно понимать, что язык в программировании имеет второстепенное значение. Языки меняются, меняется синтаксис, меняется структура, меняются поколения и платформы, которые эти языки понимают и исполняют, но алгоритм не меняется никогда.

Алгоритм является основой программирования. Алгоритм состоит из нескольких логических конструкций:

Существует очень простой язык описания алгоритма, доступный даже детям — блок-схема. Он выглядит как набор простых геометрических фигур с подписями внутри. Старт и конец изображается овалом, присвоение — прямоугольником, логическое ветвление — ромбиком. У овала имеется только один вход или выход, у прямоугольника — два (вход и выход), у ромбика — один вход и два альтернативных выхода. К примеру, рассмотрим такую простую задачу:

Даны два числа a и b, если их произведение больше нуля, завершаем программу, если меньше — умножаем a на -1 и возвращаемся к проверке.

Вот так выглядит его блок-схема алгоритма решения:

Элементы языка программирования

Чтобы описать алгоритм на языке, понятном компьютеру, существуют языки программирования. Структуру языка программирования составляют следующие элементы:

Переменная

Чтобы лучше понять смысл переменной, можно представить себе какую-нибудь емкость, например, коробку или бутылку, на которой написано ее обозначение. Например, в коробке с названием КРАСНАЯ_КОРОБОЧКА у нас хранится 10 жуков-пожарников, а в банке с названием МОЯ_ЛЮБИМАЯ_БАНОЧКА живет 2 бабочки-тутовницы.

На языке Basic это будет выглядеть так:

...
КРАСНАЯ_КОРОБОЧКА = 10
МОЯ_ЛЮБИМАЯ_БАНОЧКА = 2
...

Этими двумя операциями мы совершили присвоение значений переменным. Программе все равно, жуки там или бабочки, это нам придется помнить самим.

Операция над переменной (переменными)

Теперь, имея на руках данные в виде переменных, мы можем этими данными оперировать, то есть совершать над ними операции. Например, сложить их, а сумму сохранить в третью переменную:

...
ВСЕГО_НАСЕКОМЫХ = КРАСНАЯ_КОРОБОЧКА + МОЯ_ЛЮБИМАЯ_БАНОЧКА
...

Понятно, что кроме сложения, можно совершить любую мыслимую и немыслимую операцию над этими переменными: извлечь корень, возвести в миллионную степень, перемножить друг с другом и прочее.

Строго говоря, существуют операции строковые, арифметические, логические и операции сравнения. Арифметические — это сложение, вычитание, умножение, деление, возведение в степень, деление по модулю. Сравнение — это больше, больше или равно, меньше, меньше или равно, равно, не равно. Логические — это И, ИЛИ, НЕ.

Логические операции выполняются только с переменными булевского типа, то есть переменными, принимающими только два значения: Да или Нет. Результат логической операции — тоже булевское значение. Чтобы результат операции И был Да, нужно, чтобы оба операнда были Да, чтобы получить положительных результат операции ИЛИ, нужно, чтобы хотя бы один операнд был Да. Чтобы получить Да в результате операции НЕ, нужно, чтобы операнд был Нет. Все очень просто и соответствует обычной человеческой логике.

Результатом операции сравнения тоже является булевское значение, то есть Да или Нет.

Процедура/функция/метод

Процедура не является обязательным и основополагающим элементом языка программирования, в том смысле, что программу можно написать и без нее. Однако, ни одна программа не обходится без процедур, поскольку процедуры упрощают написание программ в невообразимое количество раз. Без них ни один программист не смыслит своей жизни и если бы вдруг какая-то вселенская сила отменила процедуры и функции, то от этой профессии отказались бы 99,99 процентов программистов.

Процедура или функция — это кусочек программы, который мы можем произвольно вызывать из любого места программы.

Например, функция набора телефонного номера. Предположим, что мы написали программу, которой в разной ситуации требуется кому-нибудь позвонить. Процедура набора телефонного номера состоит из нескольких шагов: снять трубку, набрать номер, послать сообщение, сохранить ответ, повесить трубку. Если бы не было функций, нам пришлось бы в разных местах программы описывать одну и ту же последовательность действий. Однако, поскольку у нас все же имеются функции, мы просто описываем эту функцию, даем ей имя, например, ПОЗВОНИТЬ и вызываем в нужных местах программы:

...
a = +7 921 866 5699
ПОЗВОНИТЬ(a)
...
b = +7 921 866 5700
ПОЗВОНИТЬ(b)
...
c = +7 921 866 5701
ПОЗВОНИТЬ(c)
...
FUNCTION ПОЗВОНИТЬ(НОМЕР)
    ...
END FUNCTION
...

Структурные конструкции

1. Цикл

Цикл — это повторение фрагмента программы заданное количество раз. Например, нам нужно обзвонить 10 миллионов абонентов в городском телефонном справочнике (или просто позвонить куда-нибудь 10 миллионов раз).

Пишем примерно такую программу на языке Quick Basic:

...
10 b = 0
20 НОМЕР = ПОЛУЧИТЬ_НОМЕР()
30 ПОЗВОНИТЬ(НОМЕР)
40 b = b+1
50 IF b<10000000 GOTO 20
...

Эта программа будет выполняться до тех пор, пока указатель цикла b не станет больше или равным миллиону. Мы используем в примере некую функцию ПОЛУЧИТЬ_НОМЕР(), которая, неважно сейчас как, дает нам следующий номер для звонка. Поскольку в строке 40 указатель b  увеличивается на 1, а начальное его значение было 0, то программа выполнит один миллион звонков. Остается только надеяться, что программа не будет звонить на один и тот же номер, и что по этому номеру не живет какой-нибудь человек!

2. Ветвление

Ветвление позволяет выполнять различные фрагменты программы в зависимости от некоторой проверки. Например, если жуков больше, чем бабочек, то нужно отпустить одного жука, иначе — отпустить одну бабочку: это и есть так называемая конструкция if-else (на языке C):

if (КРАСНАЯ_КОРОБОЧКА > МОЯ_ЛЮБИМОЯ_БАНОЧКА) {
    КРАСНАЯ_КОРОБОЧКА--;
} else {
    МОЯ_ЛЮБИМОЯ_БАНОЧКА--;
}

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

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

Ввод-вывод

Если бы не было возможности ввода-вывода, то программирование не имело бы прикладного смысла. Ввод позволяет программе получать данные извне, например, с помощью пользовательского ввода, а вывод позволяет пользователям получаеть результат.

Когда вы вводите свой логин и пароль на своем любимом сайте для блогов или почты, вы осуществляете ввод данных. Когда вы вводите текст для поиска на поисковом сайте — вы вводите данные. Когда играете в компьютерную игру, двигая мышкой, нажимая кнопки и крича что-нибудь в микрофон, реагируя на картинку и звук, выдаваемые компьютером — это и есть обмен ввода-вывода. Компьютер обрабатывает данные, которые вы в него вводите и осуществляет вывод в соответствии с программой.

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

В свете программирования, ввод данных выглядит как присвоение переменным значений, вводимых пользователем.

Например, в программе Бэйсик получение данных с клавиатуры выглядит так:

10 INPUT a

В результате, в переменную с именем a будет записана та произвольная комбинация клавиш, которые нажмет пользователь.

Чтобы вывести что-то на экран монитора, Бэйсику нужно сказать следующее:

20 PRINT a

Просто, не так ли?

Объектно-ориентированное программирование

В разделе о структуре, несмотря на обзорность статьи, необходимо коснуться объектно-ориентированного подхода в программировании — ООП. Объектно-ориентированный подход — сравнительно молодая концепция, однако именно она в данный момент имеет наибольшее влияние в мире программирования.

Ключевым понятием в ООП является Класс. Класс объектов — это описание свойств и методов класса. Свойства класса — это то, что у объектов этого класса есть.

Например, у объектов класса "стул" будет 4 ножки, сиденье и спинка. Ну, еще может быть цвет и материал. Метод класса — это то, что объект этого класса умеет делать. Например, объект класса "самолет" умеет летать, забирать и выпускать шасси, светить фарами и подавать различные радиосигналы. Объект класса будет обладать всеми свойствами и методами класса, но сам объект будет персонализирован. Например, один объект класса "стул" будет белым и деревянным, а другой — красным и пластиковым.

В процессе написания программы мы описываем класс только единожды, но можем использовать сколько угодно объектов этого класса, не задумываясь о том, каков этот объект — программа сама будет помнить все разнообразие объектов по мере их трансформации.

Огромная значимость ООП в мире программирования состоит в том, что технология написания программ как бы переходит из двумерного измерения в трехмерное. Программист мыслит теперь объектами и классами объектов, что намного более естественно для привычного человеческого образа мысли.

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

Заключение

Все вышеописанное — всего лишь детский набросок всеобщей картины. Здесь лишь слегка затронуты самые важные аспекты. Однако, мир идет вперед, мир программирования развивается быстрым темпом. Очень важно было бы поговорить о том, что движет сейчас этот мир быстрее всего — движение открытого кода, но об этом в следующий раз.