Вычислительный процесс часто выполняется не по линейному алгоритму, он может разветвляться по нескольким направлениям в зависимости от каких-то условий, возвращаться назад или переходить на несколько операторов вперёд. Условия разветвления программы или безусловный переход задаются с помощью оперторов ветвления и перехода.
Оператор безусловного перехода.
Общий вид оператора GOTO (идти к)
GOTO [n]
n – метка, к которой осуществляется безусловный переход,
Этот оператор передает управление первому оператору в строке с меткой n.
Условные операторы.
Условный оператор позволяет изменить порядок выполнения операторов в программе в зависимости от какого-либо условия.
Условный оператор имеет три структуры:
IF L THEN n
L – логическое выражение;
n – метка оператора, к которому осуществляется переход, если огиическое выражение имеет значение "истинно". Если логическое выражение имеет значение "ложно", то выполняется оператор, расположенный в следующей строке.
IF L THEN S
S – последовательность, состоящая из одного или нескольких операторов, записанных через символ ":".
IF L THEN S1 ELZE S2
S1и S2 – последовательности, состоящие из одного или нескольких операторов, записанных через символ ":".
Порядок выполнения структурного условного оператора :
§ определяется значение логического выражения;
§ если оно имеет значение "истинно", то выполняется последовательность операторов, записанных за THEN до ключевого слова ELSE;
§ если логическое выражение имеет значение "ложно" , то выполняются операторы, записанные за ELSE до конца строки.
После выполнения любой последовательности осуществляется переход к следующей строке (если в этих последовательностях нет других управляющих операторов).
Метка может содержать любые латинские символы (кроме служебных – $,! И т.п.), но начинаться обязательно должна с буквы, например, М12, m, alpha14, beta32, metka2, t, A и др. В строке, которой передаётся управление после метки обязательно ставится знак ":", например:
Операторы циклов.
Операторы цикла используются для организации многократно повторяющихся вычислений. Любой цикл состоит из тела цикла, то есть тех операторов, которые выполняются несколько раз, начальных установок, модификации параметра цикла и проверки условия продолжения выполнения цикла.
Для удобства, а не по необходимости, в C++ есть три разных оператора цикла — while, do while и for.
1) Цикл с предусловием имеет вид: while (выражение) оператор.
Рис.1 Структурная схема цикла с предусловием
Выражение определяет условие повторения тела цикла, представленного простым или составным оператором. Выполнение оператора начинается с вычисления выражения. Если оно истинно (не равно false), выполняется оператор цикла. Если при первой проверке выражение равно false, цикл не выполнится ни разу.
Пример (программа находит все делители целого положительного числа):
2) Цикл с постусловием имеет вид: do оператор while (выражение).
Рис.2 Структурная схема цикла с постусловием
Сначала выполняется простой или составной оператор, составляющий тело цикла, а затем вычисляется выражение. Если оно истинно (не равно fаlse), тело цикла выполняется еще раз. Цикл завершается, когда выражение станет равным false или в теле цикла будет выполнен какой-либо оператор передачи управления.
Пример (программа осуществляет проверку ввода):
3) Цикл с параметром.
Цикл с параметром имеет следующий формат: for (инициализация: выражение: модификации) оператор. Инициализация используется для объявления и присвоения начальных значений величинам, используемым в цикле. В этой части можно записать несколько операторов, разделенных запятой (операцией «последовательное выполнение»).
Пример (оператор, вычисляющий сумму чисел от 1 до 100):
Областью действия переменных, объявленных в части инициализации цикла, является цикл. Инициализация выполняется один раз в начале исполнения цикла. Выражение определяет условие выполнения цикла. Модификации выполняются после каждой итерации цикла и служат обычно для изменения параметров цикла.
Операторы условных и безусловных переходов.
1) Условный оператор if
Данный оператор используется для разветвления процесса вычислений на два направления. Структурная схема оператора приведена на рис. 3. Формат оператора: if (выражение) оператор_1; [else оператор_2;].
Оператор if позволяет определить действие при истинном условии, т.е. если логическое_выражение имеет значение true, выполняется составной_оператор_1, а если логическое_выражение имеет значение false, то управление передается следующему оператору после оператора if.
Рис.3 Структурная схема оператора if
2) Условный оператор двойного выбора if…else
Оператор if…else применяется для того чтобы в зависимости от конкретных значений исходных данных обеспечить выполнение двух разных составных операторов. Структурная схема оператора приведена на рис. 4. Формат оператора: if (логическое_выражение) <составной_оператор_1;>else <составной_оператор_2; >.
Рис.4 Структурная схема оператора if…else
Оператор if else позволяет определить программисту действие, когда условие истинно и альтернативное действие, когда условие ложно, т.е. если логическое_выражение имеет значение true, то выполняется составной_оператор_1, а если логическое_выражение имеет значение false, то выполняется составной_оператор_2. Так как логическое_выражение не может одновременно иметь значения true и false, то составной_оператор_1 и составной_оператор_2 не могут выполняться оба. После выполнения составной_оператор_1 или составной_оператор_2 управление передается следующему оператору после оператора if.
3) Оператор безусловного перехода
Оператор goto имеет формат: goto метка. В теле той же функции должна присутствовать ровно одна конструкция вида: метка: оператор.
Оператор goto передает управление на помеченный оператор. Метка — это обычный идентификатор, областью видимости которого является функция, в теле которой он задан.
Использование оператора безусловного перехода оправдано в двух случаях, если принудительный выход вниз по тексту программы из нескольких вложенных циклов или переключателей или переход из нескольких мест функции в одно (например, если перед выходом из функции всегда необходимо выполнять какие-либо действия).
В остальных случаях для записи любого алгоритма существуют более подходящие средства, а использование goto приводит только к усложнению структуры программы и затруднению отладки. Применение goto нарушает принципы структурного и модульного программирования, по которым все блоки, из которых состоит программа, должны иметь только один вход и один выход. В любом случае не следует передавать управление внутрь операторов if, switch и циклов. Нельзя переходить внутрь блоков, содержащих инициализацию переменных, на операторы, расположенные после нее, поскольку в этом случае инициализация не будет выполнена.
Оператор выбора.
Структура множественного выбора (switch) применяется для того чтобы в зависимости от конкретных значений исходных данных обеспечить выполнение множества разных составных операторов. Структурная схема оператора приведена на рис. 3. Формат оператора:
Рис.3 Структурная схема оператора выбора
Оператор switch позволяет определить программисту действие из списка возможных вариантов, т.е. если значение выражения совпадает со значением константное_выражение_1, то выполняется составной оператор_1, если со значением константное_выражение_2, то выполняется составной оператор_2 и т.д. Если совпадения не произошло, выполняется составной_оператор_по_умолчанию, расположенный после слова default. Выполнение не может переходить на следующий раздел switch.
Пример (программа реализует простейший калькулятор на 4 действия):
Оператор switch может содержать любое количество разделов switch, а каждый раздел может иметь одну или несколько меток case. Однако две метки case не могут содержать одно и то же постоянное значение. Выполнение списка операторов в выбранном разделе switch начинается с первого оператора и продолжается по списку, обычно до достижения оператора перехода, такого как break, goto case, return или throw (оператор break выполняет выход из самого внутреннего из объемлющих его операторов switch; оператор goto выполняет переход на указанную после него метку, обычно это метка case одной из нижележащих ветвей оператора switch ; оператор return выполняет выход из функции, в теле которой он записан). В этой точке управление передаётся за пределы оператора switch или к другой метке case. Не допускается, чтобы выполнение, начавшись в одном разделе, продолжалось в следующем.
| | следующая лекция ==> | |
дәріс. Әлсіз магнитті кендерді бөлгіштер | | | Шаг 2. Определим условия, способствующие мотивации работой |
Дата добавления: 2016-12-31 ; просмотров: 1769 | Нарушение авторских прав
Для организации условных и безусловных переходов в программе на языке Си используются операторы: if – else, switch и goto. Первый из них записывается следующим образом:
if (проверка_условия) оператор_1; else оператор_2;
Если условие в скобках принимает истинное значение, выполняется оператор_1, если ложное – оператор_2. Если вместо одного необходимо выполнить несколько операторов, то они заключаются в фигурные скобки. В операторе if слово else может отсутствовать.
В операторе if – else непосредственно после ключевых слов if и else должны следовать другие операторы. Если хотя бы один из них является оператором if, его называют вложенным. Согласно принятому в языке Си соглашению слово else всегда относится к ближайшему предшествующему ему if.
Оператор switch позволяет выбрать одну из нескольких альтернатив. Он записывается в следующем формальном виде:
Здесь вычисляется значение целого выражения в скобках (его иногда называют селектором) и оно сравнивается со всеми константами (константными выражениями). Все константы должны быть различными. При совпадении выполнится соответствующий вариант операторов (один или несколько операторов). Вариант с ключевым словом default реализуется, если ни один другой не подошел (слово default может и отсутствовать). Если default отсутствует, а все результаты сравнения отрицательны, то ни один вариант не выполняется.
Для прекращения последующих проверок после успешного выбора некоторого варианта используется оператор break, обеспечивающий немедленный выход из переключателя switch.
Допускаются вложенные конструкции switch.
Рассмотрим правила выполнения безусловного перехода, который можно представить в следующей форме:
Метка – это любой идентификатор, после которого поставлено двоеточие. Оператор goto указывает на то, что выполнение программы необходимо продолжить начиная с оператора, перед которым записана метка. Метку можно поставить перед любым оператором в той функции, где находится соответствующий ей оператор goto. Ее не надо объявлять.
![]() |
РАЗДЕЛ 3. СТРУКТУРИРОВАННЫЕ ТИПЫ ДАННЫХ
Массивы
В программе на языке Си можно использовать структурированные типы данных. К ним будем относить массивы, структуры и файлы.
Массив состоит из многих элементов одного и того же типа. Ко всему массиву целиком можно обращаться по имени. Кроме того, можно выбирать любой элемент массива. Для этого необходимо задать индекс, который указывает на его относительную позицию. Число элементов массива назначается при его определении и в дальнейшем не изменяется. Если массив объявлен, то к любому его элементу можно обратиться следующим образом: указать имя массива и индекс элемента в квадратных скобках. Массивы определяются так же, как и переменные:
int a[100]; char b[20]; float d[50];
В первой строке объявлен массив а из 100 элементов целого типа: а[0], а[1], . а[99] (индексация всегда начинается с нуля). Во второй строке элементы массива b имеют тип char, а в третьей – float.
Двумерный массив представляется как одномерный, элементами которого так же являются массивы. Например, определение char а[10][20]; задает такой массив. По аналогии можно установить и большее число измерений. Элементы двумерного массива хранятся по строкам, т.е. если проходить по ним в порядке их расположения в памяти, то быстрее всего изменяется самый правый индекс. Например, обращение к девятому элементу пятой строки запишется так: а[5][9].
Пусть задан массив:
Тогда элементы массива а будут размещаться в памяти следующим образом: a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2].
Имя массива – это константа, которая содержит адрес его первого элемента (в данном примере а содержит адрес элемента а[0][0]). Предположим, что a = 1000. Тогда адрес элемента а[0][1] будет равен 1002 (элемент типа int занимает в памяти 2 байта), адрес следующего элемента а[0][2] – 1004 и т.д. Что же произойдет, если выбрать элемент, для которого не выделена память? К сожалению, компилятор не отслеживает данной ситуации. В результате возникнет ошибка и программа будет работать неправильно.
В языке Си существует сильная взаимосвязь между указателями и массивами. Любое действие, которое достигается индексированием массива, можно выполнить и с помощью указателей, причем последний вариант будет работать быстрее.
задает массив из пяти элементов а[0], a[1], a[2], a[3], a[4]. Если объект *у определен как
то оператор у = &a[0]; присваивает переменной у адрес элемента а[0]. Если переменная у указывает на очередной элемент массива а, то y+1 указывает на следующий элемент, причем здесь выполняется соответствующее масштабирование для приращения адреса с учетом длины объекта (для типа int – 2 байта, long – 4 байта, (double – 8 байт и т.д.).
Так как само имя массива есть адрес его нулевого элемента, то оператор у = &a[0]; можно записать и в другом виде: у = а. Тогда элемент а[1] можно представить как *(а+1). С другой стороны, если у – указатель на массив a, то следующие две записи: a[i] и *(у+i) – эквивалентны.
Между именем массива и соответствующим указателем есть одно важное различие. Указатель – это переменная и у = а; или y++; – допустимые операции. Имя же массива – константа, поэтому конструкции вида a = y; a++; использовать нельзя, так как значение константы постоянно и не может быть изменено.
Переменные с адресами могут образовывать некоторую иерархическую структуру (могут быть многоуровневыми) типа указатель на указатель (т.е. значение указателя является адресом другого указателя), указатель на указатель на указатель и т.д. Если указатели адресуют элементы одного массива, то их можно сравнивать (отношения вида , = =, != и другие работают правильно). В то же время нельзя сравнивать ли6о использовать в арифметических операциях указатели на разные массивы (соответствующие выражения не приводят к ошибкам при компиляции, но в большинстве случаев не имеют смысла). Любой адрес можно проверить на равенство или неравенство со значением NULL. Указатели на элементы одного массива можно также вычитать. Тогда результатом будет число элементов массива, расположенных между уменьшаемым и вычитаемым объектами.
Язык Си позволяет инициализировать массив при его определении. Для этого используется следующая форма:
В последнем случае: b[0][0] = 1, b[0][1] = 2, b[0][2] = 3, b[1][0] = 4, b[1][1] = 5, b[1][2] = 6.
В языке допускаются массивы указателей, которые определяются, например, следующим образом: char *m[5];. Здесь m[5] – массив, содержащий адреса элементов типа char.
![]() |
Строки символов
Язык Си не поддерживает отдельный строковый тип данных, но он позволяет определить строки двумя различными способами. В первом используется массив символов, а во втором – указатель на первый символ массива.
Определение char а[10]; указывает компилятору на необходимость резервирования места для максимум 10 символов. Константа а содержит адрес ячейки памяти, в которой помещено значение первого из десяти объектов типа char. Процедуры, связанные с занесением конкретной строки в массив а, копируют ее по одному символу в область памяти, на которую указывает константа а, до тех пор, пока не будет скопирован нулевой символ, оканчивающий строку. Когда выполняется функция типа printf("%s", а), ей передается значение а, т.е. адрес первого символа, на который указывает а. Если первый символ – нулевой, то работа функции printf() заканчивается, а если нет, то она выводит его на экран, прибавляет к адресу единицу и снова начинает проверку на нулевой символ. Такая обработка позволяет снять ограничения на длину строки (конечно, в пределах объявленной размерности): строка может иметь любую длину, но в пределах доступной памяти.
Инициализировать строку при таком способе определения можно следующим образом:
(при определении массива с одновременной инициализацией пределы изменения индекса можно не указывать).
Второй способ определения строки – это использование указателя на символ. Определение char *b; задает переменную b, которая может содержать адрес некоторого объекта. Однако в данном случае компилятор не резервирует место для хранения символов и не инициализирует переменную b конкретным значением. Когда компилятор встречает оператор вида b ="IBM PC";, он производит следующие действия. Во-первых, как и в предыдущем случае, он создает в каком-либо месте объектного модуля строку "IBM PC", за которой следует нулевой символ (‘