Программирование: концепции
Базовые понятия, не привязанные к конкретному языку
Последовательность однозначных команд для исполнителя (человека, робота, программы), которая за конечное число шагов приводит к результату. Свойства: дискретность, понятность исполнителю, результативность.
✗ «Алгоритм = программа». Нет: программа — это запись алгоритма на конкретном языке.
Цикл, из которого выполнение никогда не выходит: условие остановки не наступает или его забыли написать. Программа при этом не ломается — она занята бесконечным повторением, и со стороны кажется, что устройство зависло. Бывает и намеренным: главный цикл игры или прошивки крутится, пока устройство включено.
✗ «Зациклившаяся программа сломалась и сейчас выдаст ошибку». Нет: она исправно выполняет команды — просто одни и те же; со стороны это выглядит как зависание.
Стандартная запись алгоритма фигурами: овал — начало и конец, прямоугольник — действие, ромб — вопрос с выходами «да» и «нет», стрелки — порядок выполнения. Схема не зависит от языка программирования: по одной блок-схеме можно написать программу блоками или текстом.
✗ «Блок-схема — украшение для отчёта, её рисуют после кода». Нет: схему рисуют до программы, чтобы поймать ошибку в логике, пока её дёшево исправить.
Обмен данными между программой и внешним миром. Ввод — данные поступают в программу: с клавиатуры, от датчика, из файла. Вывод — программа отдаёт результат: на экран, на светодиод, в файл. Почти любая программа устроена по схеме «ввод → обработка → вывод».
✗ «Ввод — это клавиатура, а вывод — экран». Нет: ввод — любые данные, попадающие в программу (датчик, файл, сеть), вывод — любой результат наружу (свет, звук, движение).
Помещение конструкции в тело другой. Во вложенном цикле на каждый проход внешнего внутренний выполняется от начала до конца: «повторить 3» снаружи и «повторить 4» внутри дают 3 × 4 = 12 повторов. Уровень вложенности видно по отступам или рамкам блоков; чем глубже, тем труднее читать код.
✗ «Внешний и внутренний циклы шагают по очереди: шаг одного — шаг другого». Нет: на каждый шаг внешнего цикла внутренний прокручивается целиком, от первого повтора до последнего.
Человек, устройство или программа, выполняющая алгоритм. У каждого исполнителя — свой набор команд и своя среда: что умеет один, не умеет другой, поэтому алгоритм записывают под конкретного исполнителя, командами из его набора.
✗ «Исполнитель — это обязательно робот или компьютер». Нет: исполнителем может быть и человек, играющий по правилам; главное свойство — выполнять команды точно, ничего не додумывая.
Наименьшее действие из набора, который исполнитель понимает без уточнений. Программа — последовательность команд, выполняемых по одной и по порядку. Команду не из набора исполнитель не выполняет и не «понимает примерно» — он сообщает об ошибке или останавливается.
✗ «Исполнителю можно сказать как угодно — он догадается». Нет: у исполнителя есть набор команд, которые он знает; незнакомую команду он не выполнит, а не «поймёт примерно».
Текст в коде, который исполнитель не читает: в скетчах Arduino — всё после // до конца строки. Пишут для людей, в том числе для себя через месяц: объясняют замысел («зачем»), а не пересказывают команду («что»). Комментарием также временно отключают строку кода — удобно при отладке.
✗ «Комментарии нужны компьютеру, чтобы лучше понять программу». Нет: исполнитель пропускает их целиком; комментарии пишут для людей — в том числе для себя через месяц.
Именованное значение, которое нельзя перезаписать: в скетче Arduino — const int LED_PIN = 13;. При проверке скетча Arduino IDE не даст присвоить константе новое значение — защита от случайной порчи. Константы убирают из кода «магические числа»: имя объясняет смысл, а менять значение при настройке нужно в одном месте, а не по всему коду.
✗ «Раз значение не меняется, проще писать число прямо в коде». Нет: безымянное «магическое число» расползается по коду и объясняется только догадкой; константа даёт ему имя и одну точку изменения.
Набор элементов одного типа под общим именем; длина задаётся при создании и не меняется. К элементу обращаются по индексу, счёт с нуля: первый — a[0], у массива из 5 элементов последний — a[4]. Этим массив отличается от списка Scratch, который растёт и уменьшается на ходу; в скетчах Arduino (C++) используются именно массивы.
✗ «Массив и список — два названия одного и того же». Нет: классический массив — фиксированная длина и один тип элементов, список меняет длину на ходу; список Scratch — не массив C++.
Часть программы, где действует имя переменной. Локальная объявлена внутри функции: видна только в ней и исчезает при выходе; глобальная видна во всей программе. Одинаковые имена в разных функциях — разные, независимые переменные. В Scratch то же: переменная «для всех спрайтов» или «только для этого».
✗ «Одно имя — одна переменная на всю программу». Нет: локальные переменные с одинаковыми именами в разных функциях — независимые ячейки.
Знак, который сравнивает два значения и выдаёт логический ответ — истину или ложь: «больше», «меньше», «равно», а в текстовой записи ещё >= (не меньше), <= (не больше) и != (не равно). Сравнение не меняет сами значения; его ответ программа подставляет в условия и циклы.
✗ «Сравнение изменяет переменные». Нет: оператор сравнения только вычисляет ответ — истину или ложь; сами значения остаются какими были.
Программа, управляющая устройством и другими программами: распределяет между ними память и время процессора, ведёт файлы и папки, подключает клавиатуру, мышь и экран. Программы просят всё это у ОС, а не у «железа» напрямую, поэтому программа для Windows не запустится на Android без переделки.
✗ «Операционная система — это и есть компьютер». Нет: ОС — программа; Windows на компьютере можно заменить на Linux, а «железо» останется тем же.
Систематический поиск причины ошибки: воспроизвести её, предположить, где ломается, проверить догадку — например, выводя значения переменных на экран или в монитор порта Arduino, — исправить и убедиться, что ошибка исчезла. Ошибки бывают синтаксические (программа не запускается) и логические (делает не то).
✗ «Запустилось без ошибок — значит, работает правильно». Нет: самые коварные ошибки — логические: программа выполняется, но делает не то, что задумано.
Одновременная работа нескольких частей программы: каждая ветка выполняет свои команды, не дожидаясь остальных. Устройство может делать несколько дел по-настоящему сразу, а может очень быстро чередовать их — со стороны это неотличимо.
✗ «Компьютер с одним процессорным ядром делает несколько дел по-настоящему одновременно». Нет: одно ядро быстро чередует задачи; настоящая одновременность — только на нескольких ядрах.
Величина, которую функция получает при вызове: в blink(5) параметр times принимает значение 5 — и функция мигает пять раз. Внутри функции параметр ведёт себя как переменная, но создаётся заново при каждом вызове и исчезает после него. Параметры делают один код пригодным для разных данных.
✗ «Параметр — настройка, которую функция запоминает навсегда». Нет: при каждом вызове параметр получает значение заново и исчезает, когда вызов завершён.
Область памяти с именем, значение которой программа читает и перезаписывает. Знак «=» в коде — присваивание («вычисли справа — положи в ячейку слева»), поэтому x = x + 1 — обычная команда, а не уравнение. У переменной есть тип: число, строка, логическое значение.
✗ «x = x + 1 — бессмыслица, в математике так не бывает». Нет: «=» в коде — присваивание, а не равенство: справа вычисляем, слева сохраняем.
Алгоритм, записанный на понятном исполнителю языке: для компьютера — на языке программирования. Один алгоритм можно записать разными программами — блоками или текстом. Что не записано в программе, исполнитель не выполнит.
✗ «Компьютер поймёт, что ты имел в виду». Нет: программа выполняет только записанные команды — буквально и по порядку; чего в программе нет, того компьютер не сделает.
Текст программы, записанный по правилам языка программирования — синтаксису. Исполнитель читает код буквально: одна опечатка — и программа не запустится или сделает не то. Пишут код для машины, а читают люди, поэтому важны понятные имена и аккуратная запись.
✗ «Код — тайный шифр для избранных». Нет: код — открытый текст, записанный по правилам языка; прочитать его может каждый, кто эти правила выучил.
Приём, когда функция вызывает саму себя, но для меньшей задачи. Обязательны две части: базовый случай — ответ известен сразу, без нового вызова — и рекурсивный шаг, сводящий задачу к меньшей. Без базового случая вызовы никогда не закончатся.
✗ «Рекурсивный вызов — это прыжок к началу функции». Нет: каждый вызов — новая копия функции со своими переменными; прежние вызовы ждут её завершения.
Формальные правила языка программирования: как пишутся команды, где стоят скобки, кавычки и точки с запятой. Синтаксическую ошибку исполнитель замечает ещё до запуска и указывает строку — программа даже не стартует. Этим она отличается от логической, когда программа работает, но делает не то.
✗ «Синтаксическая ошибка значит, что задумка неверна». Нет: синтаксис — только форма записи: верная идея может не запуститься из-за потерянной скобки, а безупречно записанная программа — делать не то.
Тип данных, хранящий пары «ключ — значение»: значение находят по ключу, а не по номеру, как в списке. Ключи не повторяются: запись по новому ключу добавляет пару, по существующему — заменяет старое значение новым.
✗ «Словарь — тот же список, только с подписями». Нет: в списке элемент ищут по номеру, в словаре — по ключу; порядковых номеров у пар нет.
Число из заданного диапазона, которое программе выдаёт генератор случайных чисел: в Scratch — блок «выдать случайное от 1 до 10», в Arduino — функция random(). Каждый вызов выдаёт очередное число — может выпасть и то же самое; без случайности игра при каждом запуске шла бы одинаково.
✗ «Компьютер выбирает по-настоящему наугад». Нет: обычный генератор — псевдослучайный: числа вычисляются по формуле из стартового значения и при том же старте повторяются.
Происшествие, на которое программа отвечает: нажатие клавиши, щелчок, сообщение, сигнал таймера. На событие назначают обработчик — скрипт или функцию, запускаемую в момент события. В Scratch это блоки-шапки «когда…»: каждый скрипт ждёт своего события, и разные скрипты работают независимо.
✗ «Обработчик события работает всё время». Нет: он ждёт; код запускается только в момент события — между двумя нажатиями кнопки обработчик не выполняется.
Упорядоченный набор значений под одним именем; к элементу обращаются по номеру — индексу. Списки обрабатывают циклом: «для каждого элемента сделай…». Длина может меняться: элементы добавляют и удаляют, при удалении номера следующих элементов сдвигаются.
✗ «Для ста чисел нужно сто переменных». Нет: список хранит их все под одним именем, а к каждому значению обращаются по его номеру.
Тип данных для текста: последовательность символов в кавычках — буквы, цифры, пробелы, знаки. У строки есть длина, каждый символ стоит на своём номере, и их можно перебирать, как элементы списка. «10» — это не число десять, а два символа: чтобы посчитать, строку сначала преобразуют в число.
✗ «Строка «5» и число 5 — одно и то же». Нет: 5 — число, «5» — символ текста; текст складывается склейкой («5» и «5» дают «55»), а числа — сложением (10).
Вид значения, определяющий допустимые операции и место в памяти. В скетчах Arduino (C++): int — целые, float — дробные, bool — истина или ложь, String — текст; тип указывают при объявлении переменной, и он не меняется. Положишь 2.7 в int — дробная часть отбросится, останется 2.
✗ «Тип — формальность: компьютер сам разберётся». Нет: от типа зависит результат — деление 7 / 2 в целых числах даёт 3, в дробных — 3.5.
Команда ветвления (если/иначе, if/else): исполнитель проверяет логическое выражение и выполняет только одну из ветвей. Проверка срабатывает в тот момент, когда программа доходит до неё, — поэтому в игре или «умном доме» её выполняют снова и снова, а не один раз при старте.
✗ «if следит за условием постоянно». Нет: проверка выполняется один раз — в момент, когда программа доходит до этой строки; чтобы следить постоянно, проверку повторяют в цикле.
Подпрограмма с именем, которую вызывают из любого места кода. Может принимать параметры (что именно обработать) и возвращать результат. Само определение ничего не выполняет — шаги срабатывают только при вызове. Главная польза: код без повторов, исправил в одном месте — починилось везде.
✗ «Функция выполняется там, где написана». Нет: определение только описывает шаги; выполняются они в момент вызова — или ни разу, если вызова нет.
Конструкция повторения: тело цикла выполняется заданное число раз («повторить N», for) или пока условие истинно (while). После каждого прохода исполнитель возвращается к проверке. Если условие никогда не станет ложным, цикл бесконечен: для игры это норма, для расчёта — ошибка.
✗ «Бесконечный цикл — всегда ошибка». Нет: главный цикл игры или прошивки Arduino бесконечен намеренно; ошибка — бесконечность незапланированная.