И.Г. Головин, И.А. Волкова - Языки и методы программирования (1160773), страница 15
Текст из файла (страница 15)
Приведем примерструктуры на языке C++:struct Complex{double Re, Im;}; // объявление структуры с двумя полямиComplex ImagOne = {0.0, -1.0};// объявление переменной типа структурыI I с одновременной инициализациейComplex cl, с2; // две переменных типа структурыcl.Re = 1.0; с2.Im = 0.0; // Обращение к полямс2 = cl; // структуры можно присваиватьПонятие класса в объектно-ориентированных языках заведомошире и универсальней понятия записи, поэтому в современных языках структуры либо упразднены (как в Java), либо являются частнымслучаем класса (как в C++). В C# есть понятие структуры, но мырассмотрим его вместе с понятием классов С#.Другие составные типы данныхРяд языков программирования содержит другие составные типыданных, отличные от массивов и записей.
Например, язык Паскальвключает в себя понятия файла и множества.Что касается типов (и операторов), абстрагирующих ввод-вывод,то большинство языков программирования не содержат в базисе со67ответствующие конструкции. Весь ввод-вывод отнесен к стандартнымили специализированным библиотекам. Причина этого — разнообразие и эволюция устройств ввода-вывода. Фиксация каких-либоконцепций ввода-вьйГода в конструкциях языка неизбежно приведетк неадекватности этих конструкций в более поздних реализациях.Например, файлы языка Паскаль отлично подходили к самым популярным устройствам хранения данных в 1960-х гг. (это ленточныеустройства).
Однако концепция файлов языка Паскаль совершенноне соответствовала интерактивному вводу-выводу, который сталстандартом, начиная с 1980-х гг. Поэтому ряд диалектов Паскаля (например, ТурбоПаскаль) игнорировал эти конструкции, вводя вместоних свои понятия.Сменить библиотеку значительно проще, чем реализацию.То же самое относится к введению в базис языка различного родаконтейнеров, т. е. структур данных, предназначенных для храненияи выборки данных.
Современные языки индустриального программирования содержат единственный контейнер — массив. Болееспециализированные контейнеры предоставляются стандартнымибиблиотеками.Это связано с тем, что не существует универсального и абсолютнолучшего для любых применений способа реализации контейнеров(это относится и к алгоритмам). Поэтому в стандартную библиотекувключают реализации контейнеров, подходящие для большинстваприложений. Если же стандартная реализация не подходит, то можноиспользовать вместо стандартной специализированную библиотекус тем же стандартизованным интерфейсом.5.3.
Управление последовательностьюдействий: операторный базис языковпрограммированияОператор — конструкция языка программирования, основнойцелью которой является изменение состояния выполняемой программы. Оператор — это абстракция понятия машинной команды,поэтому понятие оператора характерно для языков с императивнойпарадигмой. Изменение состояния выполняемой программы называется побочным эффектом. Таким образом, цель оператора — побочный эффект.По видам побочного эффекта различают следующие категорииоператоров:• оператор присваивания;• операторы управления последовательностью вычислений;• операторы ввода-вывода.68Отметим, что операторный базис современных языков наиболеестабилен по сравнению с другими базисными конструкциями.
Операторы одного языка похожи на операторы другого. Далее мы будемрассматривать операторы только из языков C++, Java и С#.Как отмечалось ранее, эти языки не содержат непосредственно понятия «оператор присваивания», его роль может выполнять операторвыражение, т.е. выражение, за которым следует точка с запятой:выражение; // обратите внимание на!Поскольку выражение — это суперпозиция операций, то такоепонятие имеет смысл только при наличии операций с побочнымэффектом.
Как мы уже знаем, рассматриваемые языки обладаютбогатым набором операций с побочным эффектом, главная из которых — операция присваивания.Несмотря на свою гибкость (а может быть благодаря ей), операторвыражение может иметь очень странный вид:5;Другой пример (С и C++):void ргос(); // это объявление процедурыргос; // это не вызов ргос, но и не ошибкаргос();// а вот это - вызов ргосТак как имя подпрограммы в С и С+н— это указатель (так же,как имя массива тоже указатель), то вторая строка данного примерасодержит корректное выражение (состоящее только из указателя) безпобочного эффекта.Операторы ввода-вывода также отсутствуют в рассматриваемыхязыках, их роль выполняют классы и функции из стандартных библиотек.Так что самый широкий класс операторов — это операторы передачи управления.
Вспомним, что нормальный порядок выполнениякоманд — последовательный. Поэтому и операторы императивнойпрограммы выполняются последовательно, пока не встретится какойлибо оператор управления.Блоки. Блок — это последовательность операторов и объявлений,заключенная в фигурные скобки {}. Строго говоря, блок не меняетпоследовательность выполнения, но он позволяет сгруппировать последовательность операторов в один оператор — блок.
Блок можетпоявляться везде, где может стоять одиночный оператор. Некоторыеконструкции требуют наличия блока: тело функции, try-блок, переключатель.Блок является областью действия переменных, объявления которых он содержит. После выхода управления из блока эти переменныеперестают существовать (напомним, что такое поведение мы называем квазистатическим).69Оператор перехода. Оператор перехода имеет видgoto метка;Оператор, помеченный меткой, будет выполняться следующимпосле оператора перехода.
Метка — это идентификатор. Операторперехода локален, т. е. он может располагаться только в том же блоке,где и метка — в теле функции. Кроме того, переходы внутрь блоковзапрещены.Сейчас общепризнано, что употребление оператора перехода ведетк появлению непонятных и потенциально ошибочных программ.Программы должны строиться только из структурных управляющихконструкций — блоков, ветвлений, циклов (возможность этого доказана математически).
Методология построения таких программназывается структурным программированием [15]. Употреблениеоператора перехода нельзя признать удачным почти ни в каком случае. Операторы return, break, continue специально введены дляминимизации употребления переходов.Оператор перехода есть в языках C++ и С#. Язык Java не имеетоператора goto вообще, хотя слово goto зарезервированное. Интересно, что первый язык программирования Фортран имел пятьвариантов оператора перехода!Операторы ветвления. Операторы ветвления бывают простыеи многовариантные. Простой оператор ветвления имеет видif (условие)оператор1elseоператор2Если логическое условие истинно, то выполняется оператор1,а в противном случае — оператор2.Если оператор2 пуст, то можно использовать укороченнуюформу:if (условие)оператор1Например:if (а < Ь)min = а;elsemin = b;Наличие укороченной формы может приводить к неоднозначности:if (а < b) if (а < с) х = 0; else х = 1;// плохой стиль — нужно использовать отступы!70Это можно интерпретировать, какif (а < Ь){if (а < с) х = 0; else х = 1;}' лОV-либо какif (а < Ь){if ( а < с )elseх = 1;х=0;}Обе интерпретации равноправны, но по соглашению, которогопридерживаются все языки (а не только рассматриваемые), выбирается первая.
Говорят, что e l s e приклеивается к ближнему i f .В любом случае нужно использовать отступы для облегчениячтения.Многовариантное ветвление в общем виде представляет собойсуперпозицию операторов if, поэтому особого оператора для этогоне предусмотрено, но обратите внимание на расположение операторов:if (условие1)олератор1else if (условие2)олератор2else if (условие!)onepaT opielseоператорПоследняя e l s e -часть может отсутствовать.Существует частный случай многовариантного ветвления, для которого введен специальный оператор — оператор переключателя:switch (выражение) блокВыражение должно быть целого или перечислимого типа.
Блок может содержать метки специального вида c a s e N:. Также может присутствовать в одном экземпляре метка d e f a u l t :. Эффект операторапереключателя состоит в том, что вычисляется значение выражения.Пусть его значение есть i. Если в блоке переключателя есть меткаc a se i :, то происходит переход на эту метку. Если этой метки нет,но есть метка d e f a u l t :, то происходит переход на метку d e f a u l t :.В противном случае ничего не происходит, и все операторы внутриблока игнорируются.
Для выхода из середины блока переключателяиспользуется оператор b r e a k ; . Например:switch (color)71case RED:colorStringbrea,k;case GREEN:colorStringbreak;case YELLOW:colorStringbreak;default:colorStringbreak;= "красный";= "зеленый";= "желтый";= "неверный цвет";}Мы рассмотрели семантику переключателя в С, C++ и Java.Основной недостаток переключателя в языке С — это использование перехода.
Что будет, если мы забудем расставить операторыbreak; ? Ничего хорошего: при любом значении переменной colorпроизойдет переход на какую-либо метку, а дальше операторы в блокебудут выполняться последовательно таким образом, что переменнаяcolorString всегда получит значение "неверный цвет", посколькусоответствующий оператор последний в блоке.В языке C# требуется, чтобы каждая последовательность операторов после метки case или default завершалась оператором break;или return;. Следовательно, компилятор не позволит сделать описанную ранее ошибку.Операторы цикла. Есть три вида операторов цикла:• цикл с предусловием (цикл-while);• цикл с постусловием (цикл-do);• цикл-fo r.Циклы while и do.
Эти циклы имеют видwhile (условие) S// цикл-whiledo S while (условие); // цикл-doОператор S называется телом цикла. Тело выполняется, пока логическое условие истинно.Циклы отличаются тем, что в первом случае условие повторенияпроверяется перед первым выполнением тела, а во втором — послепервого его выполнения.Например (линейный поиск элемента X в массиве А):1 = 0;while (i < A.length && X != A[i])i++;Попробуйте ответить на вопросы: на каком языке написан фрагмент (C++, C# или Java) и что будет, если условие записать в виде72X != A[i] && i < A.lengthЦикл-for. Этот очень мощный оператор, который может моделировать семантику других видов цикла, имеет видfor (el; е2; еЗ) SВыражения el, е2 и еЗ могут быть опущены.
Выражение el можетсодержать объявления переменных. Область действия этих переменных — оператор цикла (т.е. выражения el, е2, еЗ и тело цикла S).Выражение е2 должно быть логическим.Сначала вычисляется выражение el, дальше вычисляется е2и пока е2 истинно выполняется тело цикла S, причем после выполнения S обязательно вычисляется еЗ. Например, предыдущий примерцикла while можно переписать с помощью цикла for:int i;for (i = 0; i < A.length && X != A[i]; i++);Тело цикла — пустой оператор.Если выражение е2 отсутствует, то цикл выполняется без проверки условия.