Лексические основы языка программирования высокого уровня. Понятия синтаксис и семантика языка. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Лексические основы языка программирования высокого уровня. Понятия синтаксис и семантика языка.



Лексические основы языка программирования высокого уровня. Понятия синтаксис и семантика языка.

 

 

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

 

• Алфавит языка, или его символы — это основные неделимые знаки, с помощью которых пишутся все тексты на языке.

• Лексема, или элементарная конструкция, — минимальная единица языка, имеющая самостоятельный смысл.

• Выражение задает правило вычисления некоторого значения.

• Оператор задает законченное описание некоторого действия.

 

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

действия над данными. Неисполняемые операторы служат для описания данных, поэтому их часто называют операторами описания или просто описаниями.

 

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

 

Выражения и операторы.

 

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

Примеры выражений: (а + 0.12)/6, (t * sin(x)-L05e4)/((2 * к + 2) * (2 * к + 3))

Операции выполняются в соответствии с приоритетами. Для изменения порядка выполнения операций используются круглые скобки. Если в одном выражении записано несколько операций одинакового приоритета, унарные операции, условная операция и операции присваивания выполняются справа налево, остальные — слева направо. Например, а = b = с означает а = (Ь = с), а а + b + с означает (а + Ь) + с.

Порядок вычисления подвыражений внутри выражений не определен: например, нельзя считать, что в выражении (sin(x + 2) + cos(y + 1)) обращение к синусу будет выполнено раньше, чем к косинусу, и что х + 2 будет вычислено раньше, чем У+1.

Результат вычисления выражения характеризуется значением и типом. Например, если а и b — переменные целого типа и описаны так: int а = 2. b = 5:

 

то выражение а + b имеет значение 7 и тип int, а выражение а = b имеет значение, равное помещенному в переменную а (в данному случае 5) и тип, совпадающий с типом этой переменной. Таким образом, в C++ допустимы выражения вида а = b = с: сначала вычисляется выражение b = с, а затем его результат становится правым операндом для операции присваивания переменной а.

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

Преобразования бывают двух типов:

• изменяющие внутреннее представление величин (с потерей точности или без потери точности); • изменяющие только интерпретацию внутреннего представления.

К первому типу относится, например, преобразование целого числа в вещественное (без потери точности) и наоборот (возможно, с потерей точности), ко второму — преобразование знакового целого в беззнаковое.

В любом случае величины типов char, signed char, unsigned char, short int и unsigned short int преобразуются в тип int, если он может представить все значения, или в unsigned int в противном случае. После этого операнды преобразуются к типу наиболее длинного из них, и он используется

как тип результата.

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

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

оператор требуется, а по смыслу — нет). Примеры:

i++: // выполняется операция инкремента

а* = b + с; // выполняется умножение с присваиванием

Операторы ветвления

Условный оператор if Условный оператор if используется для разветвления процесса вычислений на два направления. Структурная схема оператора приведена на рис. 1.5. Формат оператора:

if (выражение) оператор_1; [else оператор_2;]

Сначала вычисляется выражение, которое может иметь арифметический тип или тип указателя. Если оно не равно нулю (имеет значение true), выполняется первый оператор, иначе — второй. После этого управление передается на оператор, следующий за условным.

Одна из ветвей может отсутствовать, логичнее опускать вторую ветвь вместе с ключевым словом еТ se. Если в какой-либо ветви требуется выполнить несколько операторов, их необходимо заключить в блок, иначе компилятор не сможет понять, где заканчивается ветвление. Блок может содержать любые операторы, в том числе описания и другие условные операторы (но не может состоять из одних описаний). Необходимо учитывать, что переменная, описанная в блоке, вне

блока не существует.

 

В примере 1 отсутствует ветвь else. Подобная конструкция называется «пропуск оператора», поскольку присваивание либо выполняется, либо пропускается в зависимости от выполнения условия.

Если требуется проверить несколько условий, их объединяют знаками логических операций. Например, выражение в примере 2 будет истинно в том случае, если выполнится одновременно условие а<Ь и одно из условий в скобках. Если опустить внутренние скобки, будет выполнено сначала логическое И, а потом — ИЛИ.

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

часть else к ближайшему if.

 

Тип переменных выбирается исходя из их назначения. Координаты выстрела нельзя представить целыми величинами, так как это приведет к потере точности результата, а счетчик очков не имеет смысла описывать как вещественный.

 

Если какая-либо переменная используется только внутри условного оператора, рекомендуется объявить ее внутри скобок, например:

i f (int i = fun(t)) a -= 1; else a += 1:

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

 

Оператор switch

Оператор switch (переключатель) предназначен для разветвления процесса вычислений

па несколько направлений. Структурная схема оператора приведена на

рис. 1.7. Формат оператора:

switch (выражение){

case константное_выражение_1: [список_операторов_1]

case константное_выражение_2: [список_операторов_2]

case константное_выражение_п: [список_операторов_п]

[default: операторы ]

 

Выполнение оператора начинается с вычисления выражения (оно должно быть

целочисленным), а затем управление передается первому оператору из списка,

помеченгюго константным выражением, значение которого совпало с вычисленным.

После этого, если выход из переключателя явно не указан, последовательно

выполняются все остальные ветви.

Выход из переключателя обычно выполняется с помощью операторов break или

return. Оператор break выполняет выход из самого внутреннего из объемлющих

его операторов switch, for, while и do. Оператор return выполняет выход из функции,

в теле которой он записан.

Все константные выражения должны иметь разные значения, но быть одного и

того же целочисленного типа. Несколько меток могут следовать подряд. Если

совпадения не произошло, выполняются операторы, расположенные после слова

default (а при его отсутствии управление передается следующему за switch оператору).

 

 

Понятие переменной.

 

 

Переменная — это именованная область памяти, в которой хранятся данные определенного

типа. У переменной есть имя и значение. Имя служит для обращения

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

значение переменной можно изменять. Перед использованием любая

переменная должна быть описана.

Пример описания целой переменной с именем а и вещественной переменной х:

1nt а; float х;

Общий вид оператора описания переменных:

[класс памяти] [const] тип имя [инициализатор];

Рассмотрим правила задания составных частей этого оператора.

• Необязательный класс памяти может принимать одно из значений auto, extern,

static и register. О них рассказывается чуть ниже.

• Модификатор const показывает, что значение переменной изменять нельзя.

Такую переменную называют именованной константой, или просто константой.

• При описании можно присвоить переменной начальное значение, это называется

инициализацией. Инициализатор можно записывать в двух формах — со

знаком равенства:

" значение

или в круглых скобках:

(значение)

Константа должна быть инициализирована при объявлении. В одном операторе

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

Примеры:

short int а = 1; // целая переменная а

const char С = ' С; // символьная константа С

char s. sf = 'f; // инициализация относится только к sf

char t (54);

float с = 0.22. x(3). sum;

Если тип инициализирующего значения не совпадает с типом переменной, выполняются

преобразования типа по определенным правилам (см. с. 38 и приложение

3).

Описание переменной, кроме типа и класса памяти, явно или по умолчанию задает

ее область действия. Класс памяти и область действия зависят не только от

собственно описания, но и от места его размещения в тексте программы.

Область действия идентификатора — это часть программы, в которой его можно

использовать для доступа к связанной с ним области памяти. В зависимости

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

Если переменная определена внутри блока (напомню, что блок ограничен фигурными

скобками), она называется локальной, область ее действия — от точки описания

до конца блока, включая все вложенные блоки. Если переменная определена

вне любого блока, она называется глобальной и областью ее действия считается

файл, в котором она определена, от точки описания до его конца.

Класс памяти определяет время жизни и область видимости программного объекта

(в частности, переменной). Если класс памяти не указан явным образом, он

определяется компилятором исходя из контекста объявления.

Время жизни может быть постоянным (в течение выполнения программы) и временным

(в течение выполнения блока).

Областью видимости идентификатора называется часть текста программы, из

которой допустим обычный доступ к связанной с идентификатором областью памяти.

Чаще всего область видимости совпадает с областью действия. Исключением

является ситуация, когда во вложенном блоке описана переменная с таким__

 

же именем. В этом случае внешняя переменная во вложенном блоке невидима,

хотя он и входит в ее область действия. Тем не менее к этой переменной, если она

глобальная, можно обратиться, используя операцию доступа к области видимости

::.

Для задания класса памяти используются следующие спецификаторы:

auto — автоматическая переменная. Память под нее выделяется в стеке и при необходимости

инициализируется каждый раз при выполнении оператора, содержащего

ее определение. Освобождение памяти происходит при выходе из блока,

в котором описана переменная. Время ее жизни — с момента описания до конца

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

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

большого смысла не имеет.

extern — означает, что переменная определяется в другом месте программы

(в другом файле или дальше по тексту). Используется для создания переменных,

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

употреблении внешних переменных рассказывается в разделе «Внешние объявления

», с. 98.

static — статическая переменная. Время жизни — постоянное. Инициализируется

один раз при первом выполнении оператора, содержащего определение переменной.

В зависимости от расположения оператора описания статические переменные

могут быть глобальными и локальными. Глобальные статические

переменные видны только в том модуле, в котором они описаны.

register — аналогично auto, но память выделяется по возможности в регистрах

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

как auto.

int а: //1 глобальная переменная а

int main(){

Целый тип (int)

Размер типа int не определяется стандартом, а зависит от компьютера и компилятора.

Для 16-разрядного процессора под величины этого типа отводится 2 байта,

для 32-разрядного — 4 байта.

Спецификатор short перед именем типа указывает компилятору, что под число

требуется отвести 2 байта независимо от разрядности процессора. Спецификатор

long означает, что целая величина будет занимать 4 байта. Таким образом, на

16-разрядном компьютере эквиваленты int и short int, а на 32-разрядном — int

и long int.

Внутреннее представление величины целого типа — целое число в двоичном

коде. При использовании спецификатора signed старший бит числа интерпретируется

как знаковый (О — положительное число, 1 — отрицательное). Спецификатор

unsigned позволяет представлять только положительные числа, поскольку

старший разряд рассматривается как часть кода числа. Таким образом, диапазон

значений типа 1nt зависит от спецификаторов. Диапазоны значений величин целого

типа с различными спецификаторами для IBM PC-совместимых компьютеров

приведены в табл. 1.4.

По умолчанию все целочисленные типы считаются знаковыми, то есть спецификатор

signed можно опускать.

Константам, встречающимся в программе, приписывается тот или иной тип в соответствии

с их видом. Если этот тип по каким-либо причинам не устраивает

программиста, он может явно указать требуемый тип с помощью суффиксов L, 1

(long) и и, U (unsigned). Например, константа 32L будет иметь тип long и занимать

4 байта. Можно использовать суффиксы L и U одновременно, например,

Ox22UL или 05LU.

 

Символьный тип (char)

Под величину символьного типа отводится количество байт, достаточное для

размещения любого символа из набора символов для данного компьютера, что и

обусловило название типа. Как правило, это 1 байт. Тип char, как и другие целые

типы, может быть со знаком или без знака. В величинах со знаком можно хранить

значения в диапазоне от -128 до 127. При использовании спецификатора

unsigned значения могут находиться в пределах от О до 255. Этого достаточно для

хранения любого символа из 256-символьного набора ASCH. Величины типа

char применяются также для хранения целых чисел, не превышающих границы

указанных диапазонов.

Расширенный символьный тип (wchar_t)

Тип wchar_t предназначен для работы с набором символов, для кодировки которых

недостаточно 1 байта, например, Unicode. Размер этого типа зависит от реализации;

как правило, он соответствует типу short. Строковые константы типа

wchar_t записываются с префиксом L, например, L"Gates".

Логический тип (bool)

Величины логического типа могут принимать только значения true и false, являющиеся

зарезервированными словами. Внутренняя форма представления значения

false — О (нуль). Любое другое значение интерпретируется как true. При

преобразовании к целому типу true имеет значение 1.

 

Тип void

Кроме перечисленных, к основным типам языка относится тип void, но множество

значений этого типа пусто. Он используется для определения функций, которые

не возвращают значения, для указания пустого списка аргументов функции

(о функциях рассказывается на с. 73), как базовый тип для указателей (с. 51) и в

операции приведения типов (cf 56).

 

 

Указатели

Когда компилятор обрабатывает оператор определения переменной, например,

int i=10:, он выделяет память в соответствии с типом (int) и инициализирует ее

указанным значением (10). Все обращения в программе к переменной по ее имени

(i) заменяются компилятором на адрес области памяти, в которой хранится

значение переменной. Программист может определить собственные переменные

для хранения адресов областей памяти. Такие переменные называются указателями.

Итак, указатели предназначены для хранения адресов областей памяти. В C++

различают три вида указателей — указатели на объект, на функцию и на void, отличающиеся

свойствами и набором допустимых операций. Указатель не является

самостоятельным типом, он всегда связан с каким-либо другим конкретным

типом.

 

Указатель на функцию содержит адрес в сегменте кода, по которому располагается

исполняемый код функции, то есть адрес, по которому передается управление

при вызове функции. Указатели на функции используются для косвенного вызова

функции (не через ее имя, а через обращение к переменной, хранящей ее адрес),

а также для передачи имени функции в другую функцию в качестве параметра.

Указатель функции имеет тип «указатель функции, возвращающей

значение заданного типа и имеющей аргументы заданного типа»:

тип (*имя) (список_типов_аргументов);

Например, объявление:

1nt (*fun) (double, double);

задает указатель с именем fun на функцию, возвращающую значение типа int и

имеющую два аргумента типа double.

Указатель на объект содержит адрес области памяти, в которой хранятся данные

определенного типа (основного или составного). Простейшее объявление указателя

на объект (в дальнейшем называемого просто указателем) имеет вид:

тип *имя:

где тип может быть любым, кроме ссылки (о ссылках рассказывается на с. 57) и

битового поля (см. с. 69), причем тип может быть к этому моменту только объявлен,

но еще не определен (следовательно, в структуре, например, может присутствовать

указатель на структуру того же типа).

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

несколько указателей, требуется ставить ее перед именем каждого из них. Например,

в операторе

1nt *д. Ь. *с;

описываются два указателя на целое с именами а и с, а также целая переменная Ь.

Размер указателя зависит от модели памяти. Можно определить указатель на

указатель и т. д.

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

которого требуется хранить, не определен (например, если в одной и той же

переменной в разные моменты времени требуется хранить адреса объектов различных

типов).

Указателю на void можно присвоить значение указателя любого типа, а также

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

с областью памяти, на которую он ссылается, требуется преобразовать его к

конкретному типу явным образом (см. с. 231).

Указатель может быть константой или переменной, а также указывать на константу

или переменную. Рассмотрим примеры:

 

Указатель может быть константой или переменной, а также указывать на константу

или переменную. Рассмотрим примеры:

int 1; // целая переменная

const int ci = 1; // целая константа

int * p i; // указатель на целую переменную

const int * pci; // указатель на целую константу

int * const ср = &i; // указатель-константа на целую переменную

const int * const срс = &ci; // указатель-константа на целую константу

Как видно из примеров, модификатор const, находящийся между именем указателя

и звездочкой, относится к самому указателю и запрещает его изменение,

а const слева от звездочки задает постоянство значения, на которое он указывает.

Для инициализации указателей использована операция получения адреса &.

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

действия, видимости и времени жизни.

 

Массивы.

 

При использовании простых переменных каждой области памяти для хранения

данных соответствует свое имя. Если с группой величин одинакового типа требуется

выполнять однообразные действия, им дают одно имя, а различают по порядковому

номеру. Это позволяет компактно записывать множество операций с

помощью циклов. Конечная именованная последовательность однотипных величин

называется массивом. Описание массива в программе отличается от описания

простой переменной наличием после имени квадратных скобок, в которых

задается количество элементов массива (размерность):

f!oat а [10]; // описание массива из 10 вещественных чисел

 

Элементы массива нумеруются с нуля. При описании массива используются те

же модификаторы (класс памяти, const и инициализатор), что и для простых переменных.

Инициализирующие значения для массивов записываются в фигурных

скобках. Значения элементам присваиваются по порядку. Если элементов в

массиве больше, чем инициализаторов, элементы, для которых значения не указаны,

обнуляются:

int b[5] = {3. 2. 1}; / / b[0]=3. b[l]=2. b[2]=l. b[3]=0. b[4]=0

Размерность массива вместе с типом его элементов определяет объем памяти, необходимый

для размещения массива, которое выполняется на этапе компиляции,

поэтому размерность может быть задана только целой положительной константой

или константным выражением. Если при описании массива не указана размерность,

должен присутствовать инициализатор, в этом случае компилятор выделит

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

увидим, что размерность может быть опущена также в списке формальных параметров

(см. раздел «Параметры функции», с. 77).

Для доступа к элементу массива после его имени указывается номер элемента

(индекс) в квадратных скобках. В следующем примере подсчитывается сумма

элементов массива.

#include <1estream.h>

int ma1n(){

const int n = 10;

int i. sum;

int marksCn] = {3. 4. 5. 4. 4};

for (1 = 0. sum = 0; 1<n; 1++) sum += marks[1];

cout «"Сумма элементов; " «sum;

return 0;

}

Размерность массивов предпочтительнее задавать с помощью именованных констант,

как это сделано в примере, поскольку при таком подходе для ее изменения

достаточно скорректировать значение константы всего лишь в одном месте

программы. Обратите внимание, что последний элемент массива имеет номер, на

единицу меньший заданной при его описании размерности.

 

Многомерные массивы задаются указанием каждого измерения в квадратных

скобках, например, оператор

int matr [6][8]:

задает описание двумерного массива из 6 строк и 8 столбцов. В памяти такой

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

массивы размещаются так, что при переходе к следующему элементу быстрее

всего изменяется последний индекс. Для доступа к элементу многомерного массива

указываются все его индексы, например, matr[i][j], или более экзотическим

способом: *(matr[i]+j) или *(*(matr+i)+j). Это возможно, поскольку matr[i]

является адресом начала i-й строки массива.

При инициализации многомерного массива он представляется либо как массив из

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

случае левую размерность при описании можно не указывать), либо задается общий

список элементов в том порядке, в котором элементы располагаются в памяти:

int mass2 [][2] = { {1. 1}. {0. 2}. {1. 0} }:

int mass2 [3][2] = {1. 1. 0. 2. 1. 0}:

 

Типы данных, определяемые пользователем на примере структур.

 

В реальных задачах информация, которую требуется обрабатывать, может иметь

достаточно сложную структуру. Для ее адекватного представления используются

типы данных, построенные на основе простых типов данных, массивов и указателей.

Язык C++ позволяет программисту определять свои типы данных и правила

работы с ними. Исторически для таких типов сложилось наименование,

вынесенгюе в название главы, хотя правильнее было бы назвать их типами, определяемыми

программистом.

 

Структуры (struct)

в отличие от массива, все элементы которого однотипны, структура может содержать

элементы разных типов. В языке C++ структура является видом класса

и обладает всеми его свойствами, но во многих случаях достаточно использовать

структуры так, как они определены в языке С:

struct [ имя_типа ] {

тип_1 элемент_1:

тип_2 элемент_2;

тип^п элемент^п;

} [ список^описателей ];

Элементы структуры называются полями структуры и могут иметь любой тип,

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

имя типа, должен быть указан список описателей переменных, указателей

или массивов. В этом случае описание структуры служит определением элементов

этого списка:

/ / Определение массива структур и указателя на структуру:

struct {

char f1o[30]:

int date, code:

double salary:

}staff[100]. *ps:

Если список отсутствует, описание структуры определяет новый тип, имя которого

можно использовать в дальнейшем наряду со стандартными типами, например:

struct Worker{ // описание нового типа Worker

char f1o[30]:

int date, code:

 

double salary;

}; // описание заканчивается точкой с запятой

/ / определение массива типа Worker и указателя на тип Worker:

Worker staff[100]. *ps;

Имя структуры можно использовать сразу после его объявления (определение

можно дать позднее) в тех случаях, когда компилятору не требуется знать размер

структуры, например:

struct List;. // объявление структуры List

struct Link{

List *p; // указатель на структуру List

Link *prev. *succ; // указатели на структуру Link

}:

struct List { / * определение структуры List * / };

Это позволяет создавать связные списки структур.

Для инициализации структуры значения ее элементов перечисляют в фигурных

скобках в порядке их описания:

struct{

char fio[30];

int date, code;

double salary;

}worker = {"Страусенке". 31. 215. 3400.55};

При инициализации массивов структур следует заключать в фигурные скобки

каждый элемент массива (учитывая, что многомерный массив — это массив массивов):

struct complex!

float real. im;

} compl [2][3] = {

{{1. 1}. {1. 1}. {1. 1}}. // строка 1. TO есть массив compl[0]

{{2. 2}. {2. 2}. {2. 2}} // строка 2. то есть массив compl[1]

,. }:

Для переменных одного и того же структурного типа определена операция присваивания,

при этом происходит поэлементное копирование. Структуру можно

передавать в функцию и возвращать в качестве значения функции. Другие операции

со структурами могут быть определены пользователем (см. «Перегрузка

операций», с. 189). Размер структуры не обязательно равен сумме размеров ее

элементов, поскольку они могут быть выровнены по границам слова.

Доступ к полям структуры выполняется с помощью операций выбора. (точка)

при обращении к полю через имя структуры и -> при обращении через указатель,

например:

Worker worker, staff[100]. *ps;

worker.fio = "Страусенке";

staff[8].code = 215;

ps->salary = 0.12;

 

Если элементом структуры является другая структура, то доступ к ее элементам

выполняется через две операции выбора:

struct А {int а; double х;};

struct В {А а: double х;} х[2]:

х[0].а.а = 1;

х[1].х = 0.1;

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

у них разная область видимости. Более того, можно объявлять в одной

области видимости структуру и другой объект (например, переменную или массив)

с одинаковыми именами, если при определении структурной переменной

использовать слово struct, но не советую это делать — запутать компилятор труднее,

чем себя.

 

Управляющие структуры языка программирования. Основные управляющие структуры: цепочки, ветвления, циклы и реализующие их конструкции языка С++.

 

Операторы цикла

Операторы цикла используются для организации многократно повторяющихся

вычислений. Любой цикл состоит из тела цикла, то есть тех операторов, которые

выполняются несколько раз, начальных установок, модификации параметра

цикла и проверки условия продолжения выполнения цикла (рис. 1.8).

Один проход цикла называется итерацией. Проверка условия выполняется на

каждой итерации либо до тела цикла (тогда говорят о цикле с предусловием),

либо после тела цикла (цикл с постусловием). Разница между ними состоит в

том, что тело цикла с постусловием всегда выполняется хотя бы один раз, после

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

цикла с предусловием делается до тела цикла, поэтому возможно, что

он не выполнится ни разу.

Переменные, изменяющиеся в теле цикла и используемые при проверке условия

продолжения, называются параметрами цикла. Целочисленные параметры цикла,

изменяющиеся с постоянным шагом на каждой итерации, называются счетчиками

цикла.

Начальные установки могут явно не присутствовать в программе, их смысл состоит

в том, чтобы до входа в цикл задать значения переменным, которые в нем

используются.

Цикл завершается, если условие его продолжения не выполняется. Возможно

принудительное завершение как текущей итерации, так и цикла в целом. Для

этого служат операторы break, continue, return и goto (см. раздел «Операторы передачи

управления», с. 49). Передавать управление извне внутрь цикла не рекомендуется.

Для удобства, а не по необходимости, в C++ есть три разных оператора цикла —

while, do while и for.

 

 

Цикл с предусловием (while)

Цикл с предусловием реализует структурную схему, приведенную на рис. 1.8,«,

и имеет вид:

while (выражение) оператор

Выражение определяет условие повторения тела цикла, представленного простым

или составным оператором. Выполнение оператора начинается с вычисления

выражения. Если оно истинно (не равно false), выполняется оператор цикла.

Если при первой проверке выражение равно false, цикл не выполнится ни

разу. Тип выражения должен быть арифметическим или приводимым к нему.

Выражение вычисляется перед каждой итерацией цикла.

Пример (программа печатает таблицу значений функции г/=х2+1 во введенном

диапазоне):

Распространенный прием программирования — организация бесконечного цикла

с заголовком while (true) либо while (1) и принудительным выходом из тела

цикла по выполнению какого-либо условия.

В круглых скобках после ключевого слова while можно вводить описание переменной^.

Областью ее действия является цикл:

while (int х = 0){... / * область действия х */ }

 

Цикл с постусловием (do while)

Цикл с постусловием реализует структурную схему, приведенную на рис. 1.8, б,

и имеет вид:

do оператор while выражение:

Сначала выполняется простой или составной оператор, составляющий тело цикла,

а затем вычисляется выражение. Если оно истинно (не равно f а! se), тело цикла

выполняется еще раз. Цикл завершается, когда выражение станет равным

false или в теле цикла будет выполнен какой-либо оператор передачи управления.

Тип выражения должен быть арифметическим или приводимым к нему.

Цикл с параметром (for)

Цикл с параметром имеет следующий формат:

for (инициализация: выражение: модификации) оператор:

Инициализация используется для объявления и присвоения начальных значений

величинам, используемым в цикле. В этой части можно записать несколько операторов,

разделенных запятой (операцией «последовательное выполнение»), например,

так:

Областью действия переменных, объявленных в части инициализации цикла, является

цикл!. Инициализация выполняется один раз в начале исполнения цикла.

Выражение определяет условие выполнения цикла: если его результат, приведенный

к типу bool, равен true, цикл выполняется. Цикл с параметром реализован

как цикл с предусловием.

Модификации выполняются после каждой итерации цикла и служат обычно для

изменения параметров цикла. В части модификаций можно записать несколько

операторов через запятую. Простой или составной оператор представляет собой

тело цикла. Любая из частей оператора for может быть опущена (но точки с запятой

надо оставить на своих местах!).

 

Конструкции перехода.

 

в C++ есть четыре оператора, изменяющих естественный порядок выполнения

вычислений:

• оператор безусловного перехода goto;

• оператор выхода из цикла break;

• оператор перехода к следующей итерации цикла continue;

• оператор возврата из функции return.

Оператор goto

Оператор безусловного перехода goto имеет формат:

goto метка:

В теле той же функции должна присутствовать ровно одна конструкция вида:

метка: оператор:

Оператор goto передает управление на помеченный оператор. Метка — это обычный

идентификатор, областью видимости которого является функция, в теле которой

он задан.

Использование оператора безусловного перехода оправдано в двух случаях:

• принудительный выход вниз по тексту программы из нескольких вложенных

циклов или переключателей;

• переход из нескольких мест функции в одно (например, если перед выходом

из функции всегда необходимо выполнять какие-либо действия).

В остальных случаях для записи любого алгоритма существуют более подходящие

средства, а использование goto приводит только к усложнению структуры

программы и затруднению отладки^. Применение goto нарушает принципы

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

состоит программа, должны иметь только один вход и один выход.

В любом случае не следует передавать управление внутрь операторов if, switch и

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

на операторы, расположенные после нее, поскольку в этом случае инициализация

не будет выполнена:

инициализация



Поделиться:


Последнее изменение этой страницы: 2017-02-07; просмотров: 459; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 107.21.176.63 (0.325 с.)