Этапы решения задач на компьютере
Академия маркетинга и социально-информационных технологий
Конспект лекций
по дисциплине
Программирование
Краснодар
2012
Лекция 1 Основы алгоритмизации
Языки программирования
Языки программирования делятся на 3 основных класса, как показано на рис. 1.1.
1. Языки низкого уровня исторически появились первыми. Команды этих языков выполняют простейшие операции по обработке информации: сложение, вычитание, умножение, деление и т.д. Программы для решения большинства даже самых простых задач состоят из нескольких десятков или сотен таких команд. Работать с такой программой человеку очень трудно. В то же время языки низкого уровня позволяют писать наиболее эффективные программы.
2. Языки высокого уровня близки к языку математики и разговорному (традиционно - английскому).
В этих языках:
1) формулы записываются на языке, близком к математическому (в одну строку, с явным указанием всех операций и т.д.);
2) используется ограниченное количество типовых конструкций (вычисление по формулам; принятие решения; повторение; цикл; процедуры);
3) для выполнения на ЭВМ программы преобразуются на машинный язык с помощью самой ЭВМ, при этом используются так называемые компиляторы и интерпретаторы с языков высокого уровня.
Итак, выполнение на ЭВМ программ, написанных на языках высокого уровня, состоит из следующих этапов (рис. 1.2):
1) ввод текста программы в ЭВМ (исходный модуль);
2) компиляция и получение текста на машинном языке (объектный модуль);
3) загрузка объектного модуля и стандартных процедур и функций в память ЭВМ и выполнение программы.
Этапы решения задач на компьютере
Решение задач на ЭВМ – сложный процесс, состоящий из следующих этапов.
1. Постановка задачи. Уяснение проблемы, определение целей решения и области применения результатов. На этом этапе при разработке больших программных систем составляется техническое задание.
2. Математическое описание. Выбор математических методов и моделей, запись формул, обеспечивающих решение задачи. Составление плана решения.
3. Программирование задачи. Оно состоит из трех частей:
1) графическое изображение метода решения (составление схемы алгоритма);
2) написание программы на языке программирования (кодирование);
3) ввод текста программы в ЭВМ.
4. Отладка программы. Выявление ошибок (кодирования и методов решения), проверка правильности результатов.
5. Обработка реальных данных и получение результатов. Выполнение готовой программы на ЭВМ, выдача результатов.
Из этих этапов первые три не требуют ЭВМ, наиболее сложные - первые два, а наиболее трудоемкий – четвертый. Все они сопровождаются соответствующей документацией, состав которой определяется стандартами.
Типы алгоритмов
Все алгоритмы традиционно можно разделить на три основных типа:
1. Линейный, который предполагает естественный порядок выполнения (следования) блоков ввода, процесса и вывода.
На рис. 1.4 приведена схема линейного алгоритма для решения следующей задачи.
Задача. Ввести длины a, b, c трех сторон треугольника. Вычислить его площадь, используя формулу Герона:
S=(p*(p-a)(p-b)(p-c))½,
где p – полупериметр треугольника.
2. Разветвляющийся, который задает выполнение вычислений по одному из возможных направлений в зависимости от исходных данных или промежуточных результатов.
На рис. 1.5 приведена схема разветвляющегося алгоритма для решения следующей задачи.
Задача. На плоскости с центром в начале координат проведена окружность радиусом R. Пользователь вводит координаты (X, Y) некоторой точки. Следует вывести на дисплей ответ: находится ли эта точка внутри (в том числе и на границе) круга, или вне его.
3. Циклический, который содержит многократно повторяющиеся участки (циклы). На рис. 1.6 приведена схема циклического алгоритма для решения следующей задачи.
Задача. Вычислить значение функции
Y=sin(X)
для аргумента, изменяющегося в некотором диапазоне
Xn ≤ X ≤ Xk.
Границы диапазона и шаг его прохождения вводить с клавиатуры. Выводить на экран соответствующие значения аргумента и функции.
Имена
Для символического обозначения величин, имен функций и т.п. используются имена или идентификаторы.
Идентификаторы в языке C++ – это последовательность знаков, начинающаяся с буквы. В идентификаторах можно использовать заглавные и строчные латинские буквы, цифры и знак подчеркивания. Длина идентификаторов произвольная. Примеры правильных идентификаторов:
abc A12 NameOfPerson BITES_PER_WORD
Отметим, что abc и Abc – два разных идентификатора, т.е. заглавные и строчные буквы различаются. Примеры неправильных идентификаторов:
12X a-bРяд слов в языке C++ имеет особое значение и не может использоваться в качестве идентификаторов. Такие зарезервированные слова называются ключевыми.
Список ключевых слов:
asm auto bad_cast bad_typeid bool break case catch char class const const_cast continue default delete do double dynamic_cast else enum extern float for friend goto if inline int long namespace new operator private protected public register reinterpret_cast return short signed sizeof static static_cast struct switch template then this throw try type_info typedef typeid union unsigned using virtualvoid volatile while xallocВ следующем примере
int max(int x, int y) { if (x > y) return x; else return y;}max, x и y – имена или идентификаторы. Слова int, if, return и else – ключевые слова, они не могут быть именами переменных или функций и используются для других целей.
Переменные
Программа оперирует информацией, представленной в виде различных объектов и величин. Переменная – это символическое обозначение величины в программе. Как ясно из названия, значение переменной (или величина, которую она обозначает) во время выполнения программы может изменяться.
С точки зрения архитектуры компьютера, переменная – это символическое обозначение ячейки оперативной памяти программы, в которой хранятся данные. Содержимое этой ячейки – это текущее значение переменной.
В языке C++ прежде чем использовать переменную, ее необходимо объявить. Объявить переменную с именем x можно так:
int x;В объявлении первым стоит название типа переменной int (целое число), а затем идентификатор x – имя переменной. У переменной x есть тип – в данном случае целое число. Тип переменной определяет, какие возможные значения эта переменная может принимать и какие операции можно выполнять над данной переменной. Тип переменной изменить нельзя, т.е. пока переменная x существует, она всегда будет целого типа.
Язык C++ – это строго типизированный язык. Любая величина, используемая в программе, принадлежит к какому-либо типу. При любом использовании переменных в программе проверяется, применимо ли выражение или операция к типу переменной. Довольно часто смысл выражения зависит от типа участвующих в нем переменных.
Например, если мы запишем x+y, где x – объявленная выше переменная, то переменная y должна быть одного из числовых типов.
Соответствие типов проверяется во время компиляции программы. Если компилятор обнаруживает несоответствие типа переменной и ее использования, он выдаст ошибку (или предупреждение). Однако во время выполнения программы типы не проверяются. Такой подход, с одной стороны, позволяет обнаружить и исправить большое количество ошибок на стадии компиляции, а, с другой стороны, не замедляет выполнения программы.
Переменной можно присвоить какое-либо значение с помощью операции присваивания. Присвоить – это значит установить текущее значение переменной. По-другому можно объяснить, что операция присваивания запоминает новое значение в ячейке памяти, которая обозначена переменной.
int x; // объявить целую переменную xint y; // объявить целую переменную yx = 0; // присвоить x значение 0y = x + 1; // присвоить y значение x + 1, // т.е. 1x = 1; // присвоить x значение 1y = x + 1; // присвоить y значение x + 1, // теперь уже 2Константы
В программе можно явно записать величину – число, символ и т.п. Например, мы можем записать выражение x + 4 – сложить текущее значение переменной x и число 4. В зависимости от того, при каких условиях мы будем выполнять программу, значение переменной x может быть различным. Однако целое число четыре всегда останется прежним. Это неизменяемая величина или константа.
Таким образом, явная запись значения в программе – это константа.
Далеко не всегда удобно записывать константы в тексте программы явно. Гораздо чаще используются символические константы. Например, если мы запишем
const int BITS_IN_WORD = 32;то затем имя BITS_IN_WORD можно будет использовать вместо целого числа 32.
Преимущества такого подхода очевидны. Во-первых, имя BITS_IN_WORD (битов в машинном слове) дает хорошую подсказку, для чего используется данное число. Без комментариев понятно, что выражение
b / BITS_IN_WORD(значение b разделить на число 32) вычисляет количество машинных слов, необходимых для хранения b битов информации. Во-вторых, если по каким-либо причинам нам надо изменить эту константу, потребуется изменить только одно место в программе – определение константы, оставив все случаи ее использования как есть. (Например, мы переносим программу на компьютер с другой длиной машинного слова.)
Выражения
Программа оперирует с данными. Числа можно складывать, вычитать, умножать, делить. Знаки можно сравнивать и т.д. То есть из разных величин можно составлять выражения, результат вычисления которых – новая величина. Приведем примеры выражений:
X * 12 + Y // значение X умножить на 12 и к // результату прибавить значение Yval < 3 // сравнить значение val с 3-9 // константное выражение -9Выражение, после которого стоит точка с запятой – это оператор-выражение. Его смысл состоит в том, что компьютер должен выполнить все действия, записанные в данном выражении, иначе говоря, вычислить выражение.
x + y – 12; // сложить значения x и y и затем // вычесть 12a = b + 1; // прибавить единицу к значению b и // запомнить результат в переменной aВыражения – это переменные, функции и константы, называемые операндами, объединенные знаками операций. Операции могут быть унарными – с одним операндом, например, минус; могут быть бинарные – с двумя операндами, например сложение или деление. В C++ есть даже одна операция с тремя операндами – условное выражение. Чуть позже мы приведем список всех операций языка C++ для встроенных типов данных. Подробно каждая операция будет разбираться при описании соответствующего типа данных. Кроме того, ряд операций будет рассмотрен в разделе, посвященном определению операторов для классов. Пока что мы ограничимся лишь общим описанием способов записи выражений.
В типизированном языке, которым является C++, у переменных и констант есть определенный тип. Есть он и у результата выражения. Например, операции сложения (+), умножения (*), вычитания (-) и деления (/), примененные к целым числам, выполняются по общепринятым математическим правилам и дают в результате целое значение. Те же операции можно применить к вещественным числам и получить вещественное значение.
Операции сравнения: больше (>), меньше (<), равно (==), не равно (!=) сравнивают значения чисел и выдают логическое значение: истина (true) или ложь (false).
Операция присваивания
Присваивание – это тоже операция, она является частью выражения. Значение правого операнда присваивается левому операнду.
x = 2; // переменной x присвоить значе-cond = x < 2; // ние 2, переменной cond // присвоить значение true, // если x меньше 2, в противном // случае присвоить значение 3 = 5; // false ошибка, число 3 // неспособно изменять свое // значениеПоследний пример иллюстрирует требование к левому операнду операции присваивания. Он должен быть способен хранить и изменять свое значение. Переменные, объявленные в программе, обладают подобным свойством. В следующем фрагменте программы
int x = 0;x = 3;x = 4;x = x + 1;вначале объявляется переменная x с начальным значением 0. После этого значение x изменяется на 3, 4 и затем 5. Опять-таки, обратим внимание на последнюю строчку. При вычислении операции присваивания сначала вычисляется левый операнд, а затем правый. Когда вычисляется выражение x + 1, значение переменной x равно 4. Поэтому значение выражения x + 1 равно 5. После вычисления операции присваивания (или, проще говоря, после присваивания) значение переменной x становится равным 5.
У операции присваивания тоже есть результат. Он равен значению левого операнда. Таким образом, операция присваивания может участвовать в более сложном выражении:
z = (x = y + 3);В приведенном примере переменным x и z присваивается значение y + 3.
Очень часто в программе приходится значение переменной увеличивать или уменьшать на единицу. Для того чтобы сделать эти действия наиболее эффективными и удобными для использования, применяются предусмотренные в C++ специальные знаки операций: ++ (увеличить на единицу) и -- (уменьшить на единицу). Существует две формы этих операций: префиксная и постфиксная. Рассмотрим их на примерах.
int x = 0;++x;Значение x увеличивается на единицу и становится равным 1.
--x;Значение x уменьшается на единицу и становится равным 0.
int y = ++x;Значение x опять увеличивается на единицу. Результат операции ++ – новое значение x, т.е. переменной y присваивается значение 1.
int z = x++;Здесь используется постфиксная запись операции увеличения на единицу. Значение переменной x до выполнения операции равно 1. Сама операция та же – значение x увеличивается на единицу и становится равным 2. Однако результат постфиксной операции – значение аргумента до увеличения. Таким образом, переменной z присваивается значение 1. Аналогично, результатом постфиксной операции уменьшения на единицу является начальное значение операнда, а префиксной – его конечное значение.
Подобными мотивами оптимизации и сокращения записи руководствовались создатели языка Си (а затем и C++), когда вводили новые знаки операций типа "выполнить операцию и присвоить". Довольно часто одна и та же переменная используется в левой и правой части операции присваивания, например:
x = x + 5;y = y * 3;z = z – (x + y);В C++ эти выражения можно записать короче:
x += 5;y *= 3;z -= x + y;Т.е. запись oper= означает, что левый операнд вначале используется как левый операнд операции oper, а затем как левый операнд операции присваивания результата операции oper. Кроме краткости выражения, такая запись облегчает оптимизацию программы компилятором.
4.3 Все операции языка C++
Наряду с общепринятыми арифметическими и логическими операциями, в языке C++ имеется набор операций для работы с битами – поразрядные И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ и НЕ, а также сдвиги.
Особняком стоит операция sizeof. Эта операция позволяет определить, сколько памяти занимает то или иное значение. Например:
sizeof(long); // сколько байтов занимает тип long sizeof b; // сколько байтов занимает переменная bОперация sizeof в качестве аргумента берет имя типа или выражение. Аргумент заключается в скобки (если аргумент – выражение, скобки не обязательны). Результат операции – целое число, равное количеству байтов, которое необходимо для хранения в памяти заданной величины.
Ниже приводятся все операции языка C++.
Арифметические операции
+ сложение- вычитание* умножение/ делениеОперации сложения, вычитания, умножения и деления целых и вещественных чисел. Результат операции – число, по типу соответствующее большему по разрядности операнду. Например, сложение чисел типа short и long в результате дает число типа long.
% остатокОперация нахождения остатка от деления одного целого числа на другое. Тип результата – целое число.
- минус+ плюсОперация "минус" – это унарная операция, при которой знак числа изменяется на противоположный. Она применима к любым числам со знаком. Операция "плюс" существует для симметрии. Она ничего не делает, т.е. примененная к целому числу, его же и выдает.
++ увеличить на единицу, префиксная и постфиксная формы-- уменьшить на единицу, префиксная и постфиксная формыЭти операции иногда называют "автоувеличением" и "автоуменьшением". Они увеличивают (или, соответственно, уменьшают) операнд на единицу. Разница между постфиксной (знак операции записывается после операнда, например x++) и префиксной (знак операции записывается перед операндом, например --y) операциями заключается в том, что в первом случае результатом является значение операнда до изменения на единицу, а во втором случае – после изменения на единицу.
Операции сравнения
== равно!= не равно< меньше> больше<= меньше или равно>= больше или равноОперации сравнения. Сравнивать можно операнды любого типа, но либо они должны быть оба одного и того же встроенного типа (сравнение на равенство и неравенство работает для двух величин любого типа), либо между ними должна быть определена соответствующая операция сравнения. Результат – логическое значение true или false.
Логические операции
&& логическое И|| логическое ИЛИ! логическое НЕЛогические операции конъюнкции, дизъюнкции и отрицания. В качестве операндов выступают логические значения, результат – тоже логическое значение true или false.
Битовые операции
& битовое И| битовое ИЛИ^ битовое ИСКЛЮЧАЮЩЕЕ ИЛИ~ битовое НЕПобитовые операции над целыми числами. Соответствующая операция выполняется над каждым битом операндов. Результатом является целое число.
<< сдвиг влево>> сдвиг вправоПобитовый сдвиг левого операнда на количество разрядов, соответствующее значению правого операнда. Результатом является целое число.
Условная операция
? : условное выражениеТрехарная операция; если значение первого операнда – истина, то результат – второй операнд; если ложь – результат – третий операнд. Первый операнд должен быть логическим значением, второй и третий операнды могут быть любого, но одного и того же, типа, а результат будет того же типа, что и третий операнд.
Последовательность
, последовательностьВыполнить выражение до запятой, затем выражение после запятой. Два произвольных выражения можно поставить рядом, разделив их запятой. Они будут выполняться последовательно, и результатом всего выражения будет результат последнего выражения.
Операции присваивания
= присваиваниеПрисвоить значение правого операнда левому. Результат операции присваивания – это значение правого операнда.
+=, -=, *=, /=, %=, |=, &=, ^=, <<=, >>= выполнить операцию и присвоитьВыполнить соответствующую операцию с левым операндом и правым операндом и присвоить результат левому операнду. Типы операндов должны быть такими, что, во-первых, для них должна быть определена соответствующая арифметическая операция, а во-вторых, результат может быть присвоен левому операнду.
Лекция 5 Операторы
Что такое оператор
Запись действий, которые должен выполнить компьютер, состоит из операторов. При выполнении программы операторы выполняются один за другим, если только оператор не является оператором управления, который может изменить последовательное выполнение программы.
Различают операторы объявления имен, операторы управления и операторы-выражения.
Операторы-выражения
Выражения мы рассматривали в предыдущей лекции. Выражение, после которого стоит точка с запятой, – это оператор-выражение. Его смысл состоит в том, что компьютер должен выполнить все действия, записанные в данном выражении, иначе говоря, вычислить выражение. Чаще всего в операторе-выражении стоит операция присваивания или вызов функции. Операторы выполняются последовательно, и все изменения значений переменных, сделанные в предыдущем операторе, используются в последующих.
a = 1;b = 3;m = max(a, b);Переменной a присваивается значение 1, переменной b – значение 3. Затем вызывается функция max с параметрами 1 и 3, и ее результат присваивается переменной m.
Как мы уже отмечали, присваивание – необязательная операция в операторе-выражении. Следующие операторы тоже вполне корректны:
x + y – 12; // сложить значения x и y и // затем вычесть 12func(d, 12, x) // вызвать функцию func с // заданными параметрамиОбъявления имен
Эти операторы объявляют имена, т.е. делают их известными программе. Все идентификаторы или имена, используемые в программе на языке C++, должны быть объявлены.
Оператор объявления состоит из названия типа и объявляемого имени:
int x; // объявить целую переменную xdouble f; // объявить переменную f типа // doubleconst float pi = 3.1415; // объявить константу pi типа float // со значением 3.1415Оператор объявления заканчивается точкой с запятой.
Операторы управления
Операторы управления определяют, в какой последовательности выполняется программа. Если бы их не было, операторы программы всегда выполнялись бы последовательно, в том порядке, в котором они записаны.
Условные операторы
Условные операторы позволяют выбрать один из вариантов выполнения действий в зависимости от каких-либо условий. Условие – это логическое выражение, т.е. выражение, результатом которого является логическое значение true (истина) или false (ложь).
Оператор if выбирает один из двух вариантов последовательности вычислений.
if (условие) оператор1else оператор2Если условие истинно, выполняется оператор1, если ложно, то выполняется оператор2.
if (x > y) a = x;else a = y;В данном примере переменной a присваивается значение максимума из двух величин x и y.
Конструкция else необязательна. Можно записать:
if (x < 0) x = -x;abs = x;В данном примере оператор x = -x; выполняется только в том случае, если значение переменной x было отрицательным. Присваивание переменной abs выполняется в любом случае. Таким образом, приведенный фрагмент программы изменит значение переменной x на его абсолютное значение и присвоит переменной abs новое значение x.
Если в случае истинности условия необходимо выполнить несколько операторов, их можно заключить в фигурные скобки:
if (x < 0) { x = -x; cout << "Изменить значение x на противоположное по знаку";}abs = x;Теперь если x отрицательно, то не только его значение изменится на противоположное, но и будет выведено соответствующее сообщение. Фактически, заключая несколько операторов в фигурные скобки, мы сделали из них один сложный оператор или блок. Прием заключения нескольких операторов в блок работает везде, где нужно поместить несколько операторов вместо одного.
Условный оператор можно расширить для проверки нескольких условий:
if (x < 0) cout << "Отрицательная величина";else if (x > 0) cout << "Положительная величина";else cout << "Ноль";Конструкций else if может быть несколько.
Хотя любые комбинации условий можно выразить с помощью оператора if, довольно часто запись становится неудобной и запутанной. Оператор выбора switch используется, когда для каждого из нескольких возможных значений выражения нужно выполнить определенные действия. Например, предположим, что в переменной code хранится целое число от 0 до 2, и нам нужно выполнить различные действия в зависимости от ее значения:
switch (code) {case 0: cout << "код ноль"; x = x + 1; break;case 1 : cout << "код один"; y = y + 1; break;case 2: cout << "код два"; z = z + 1; break;default: cout << "Необрабатываемое значение";}В зависимости от значения code управление передается на одну из меток case. Выполнение оператора заканчивается по достижении либо оператора break, либо конца оператора switch. Таким образом, если code равно 1, выводится "код один", а затем переменная y увеличивается на единицу. Если бы после этого не стоял оператор break, то управление "провалилось" бы дальше, была бы выведена фраза "код два", и переменная z тоже увеличилась бы на единицу.
Если значение переключателя не совпадает ни с одним из значений меток case, то выполняются операторы, записанные после метки default. Метка default может быть опущена, что эквивалентно записи:
default: ; // пустой оператор, не выполняющий // никаких действийОчевидно, что приведенный пример можно переписать с помощью оператора if:
if (code == 0) { cout << "код ноль"; x = x + 1;} else if (code == 1) { cout << "код один"; y = y + 1;} else if (code == 2) { cout << "код два"; z = z + 1;} else { cout << "Необрабатываемое значение";}Пожалуй, запись с помощью оператора переключения switch более наглядна. Особенно часто переключатель используется, когда значение выражения имеет тип набора. :
Операторы цикла
Предположим, нам нужно вычислить сумму всех целых чисел от 0 до 100. Для этого воспользуемся оператором цикла for:
int sum = 0;int i;for (i = 1; i <= 100; i = i + 1) // заголовок цикла sum = sum + i; // тело циклаОператор цикла состоит из заголовка цикла и тела цикла. Тело цикла – это оператор, который будет повторно выполняться (в данном случае – увеличение значения переменной sum на величину переменной i). Заголовок – это ключевое слово for, после которого в круглых скобках записаны три выражения, разделенные точкой с запятой. Первое выражение вычисляется один раз до начала выполнения цикла. Второе – это условие цикла. Тело цикла будет повторяться до тех пор, пока условие цикла истинно. Третье выражение вычисляется после каждого повторения тела цикла.
Оператор for реализует фундаментальный принцип вычислений в программировании – итерацию. Тело цикла повторяется для разных, в данном случае последовательных, значений переменной i. Повторение иногда называется итерацией. Мы как бы проходим по последовательности значений переменной i, выполняя с текущим значением одно и то же действие, тем самым постепенно вычисляя нужное значение. С каждой итерацией мы подходим к нему все ближе и ближе. С другим принципом вычислений в программировании – рекурсией – мы познакомимся в разделе, описывающем функции.
Любое из трех выражений в заголовке цикла может быть опущено (в том числе и все три). То же самое можно записать следующим образом:
int sum = 0;int i = 1;for (; i <= 100; ) { sum = sum + i; i = i + 1;}Заметим, что вместо одного оператора цикла мы записали несколько операторов, заключенных в фигурные скобки – блок. Другой вариант:
int sum = 0;int i = 1;for (; ;) { if (i > 100) break; sum = sum + i; i = i + 1;}В последнем примере мы опять встречаем оператор break. Оператор break завершает выполнение цикла. Еще одним вспомогательным оператором при выполнении циклов служит оператор продолжения continue. Оператор continue заставляет пропустить остаток тела цикла и перейти к следующей итерации (повторению). Например, если мы хотим найти сумму всех целых чисел от 0 до 100, которые не делятся на 7, можно записать это так:
int sum = 0;for (int i = 1; i <= 100; i = i+1) { if ( i % 7 == 0) continue; sum = sum + i;}Еще одно полезное свойство цикла for: в первом выражении заголовка цикла можно объявить переменную. Эта переменная будет действительна только в пределах цикла.
Другой формой оператора цикла является оператор while. Его форма следующая:
while (условие) операторУсловие – как и в условном операторе if – это выражение, которое принимает логическое значение "истина" или "ложь". Выполнение оператора повторяется до тех пор, пока значением условия является true (истина). Условие вычисляется заново перед каждой итерацией. Подсчитать, сколько десятичных цифр нужно для записи целого положительного числа N, можно с помощью следующего фрагмента:
int digits = 0;while (N > 0) { digits = digits + 1; N = N / 10;}Если число N меньше либо равно нулю, тело цикла не будет выполнено.
Третьей формой оператора цикла является цикл do while. Он имеет форму:
do { операторы } while ( условие);Отличие от предыдущей формы цикла while заключается в том, что условие проверяется после выполнения тела цикла. Предположим, требуется прочитать символы с терминала до тех пор, пока не будет введен символ "звездочка".
char ch;do { ch = getch(); // функция getch возвращает // символ, введёный с // клавиатуры} while (ch != '*');В операторах while и do также можно использовать операторы break и continue.
Как легко заметить, операторы цикла взаимозаменяемы. Оператор while соответствует операторатору for:
for ( ; условие ; ) операторПример чтения символов с терминала можно переписать в виде:
char ch;ch = getch(); while (ch != '*') { ch = getch();}Разные формы нужны для удобства и наглядности записи.
Оператор возврата
Оператор return завершает выполнение функции и возвращает управление в ту точку, откуда она была вызвана. Его форма:
return выражение;Где выражение – это результат функции. Если функция не возвращает никакого значения, то оператор возврата имеет форму
return;Оператор перехода
Последовательность выполнения операторов в программе можно изменить с помощью оператора перехода goto. Он имеет вид:
goto метка;Метка ставится в программе, записывая ее имя и затем двоеточие. Например, вычислить абсолютную величину значения переменной x можно следующим способом:
if ( x >= 0) goto positiv;x = -x; // переменить знак xpositiv: // объявление меткиabs = x; // присвоить переменной abs // положительное значениеПри выполнении goto вместо следующего оператора выполняется оператор, стоящий после метки positiv. Если значение x положительное, оператор x = - x выполняться не будет.
В настоящее время считается, что оператор goto очень легко запутывает программу.Без него, вообще говоря, можно обойтись, поэтому лучше его не использовать, ну разве что лишь в самом крайнем случае.
Пример:
int fact(int n){ int k; if (n == 1) { k = 1; } else { k = n * fact(n – 1); } return k;}Это функция вычисления факториала. Первый оператор в ней – это объявление переменной k, в которой будет храниться результат вычисления. Затем выполняется условный оператор if. Если n равно единице, то вычисления факториала закончены, и выполняется оператор-выражение, который присваивает переменной значение 1. В противном случае выполняется другой оператор-выражение.
Последний оператор – это оператор возврата из функции.
Лекция 6 Функции
Функции – это основные единицы построения программ при процедурном программировании на языке C++.
Вызов функций
Функция вызывается при вычислении выражений. При вызове ей передаются определенные аргументы, функция выполняет необходимые действия и возвращает результат.
Программа на языке C++ состоит, по крайней мере, из одной функции – функции main. С нее всегда начинается выполнение программы. Встретив имя функции в выражении, программа вызовет эту функцию, т.е. передаст управление на ее начало и начнет выполнять операторы. Достигнув конца функции или оператора return – выхода из функции, управление вернется в ту точку, откуда функция была вызвана, подставив вместо нее вычисленный результат.
Прежде всего, функцию необходимо объявить. Объявление функции, аналогично объявлению переменной, определяет имя функции и ее тип – типы и количество ее аргументов и тип возвращаемого значения.
// функция sqrt с одним аргументом – // вещественным числом двойной точности,// возвращает результат типа double double sqrt(double x);// функция sum от трех целых аргументов// возвращает целое число int sum(int a, int b, int c);Объявление функции называют иногда прототипом функции. После того, как функция объявлена, ее можно использовать в выражениях:
double x = sqrt(3) + 1;sum(k, l, m) / 15;Если функция не возвращает никакого результата, т.е. она объявлена как void, ее вызов не может быть использован как операнд более сложного выражения, а должен быть записан сам по себе:
func(a,b,c);Определение функции описывает, как она работает, т.е. какие действия надо выполнить, чтобы получить искомый результат. Для функции sum, объявленной выше, определение может выглядеть следующим образом:
int sum(int a, int b, int c){ int result; result = a + b + c; return result;}Первая строка – это заголовок функции, он совпадает с объявлением функции, за исключением того, что объявление заканчивается точкой с запятой. Далее в фигурных скобках заключено тело функции – действия, которые данная функция выполняет.
Аргументы a, b и c называются формальными параметрами. Это переменные, которые определены в теле функции (т.е. к ним можно обращаться только внутри фигурных скобок). При написании определения функции программа не знает их значения. При вызове функции вместо них подставляются фактические параметры – значения, с которыми функция вызывается. Выше, в примере вызова функции sum, фактическими параметрами ( или фактическими аргументами) являлись значения переменных k, l и m.
Формальные параметры принимают значения фактических аргументов, заданных при вызове, и функция выполняется.
Первое, что мы делаем в теле функции — объявляем внутреннюю переменную result типа целое. Переменные, объявленные в теле функции, также называют локальными. Это связано с тем, что переменная result существует только во время выполнения тела функции sum. После завершения выполнения функции она уничтожается – ее имя становится неизвестным, и память, занимаемая этой переменной, освобождается.
Вторая строка определения тела функции – вычисление результата. Сумма всех аргументов присваивается переменной result. Отметим, что до присваивания значение result было неопределенным (то есть значение переменной было неким произвольным числом, которое нельзя определить заранее).
Последняя строчка функции возвращает в качестве результата вычисленное значение. Оператор return завершает выполнение функции и возвращает выражение, записанное после ключевого слова return, в качестве выходного значения. В следующем фрагменте программы переменной s присваивается значение 10:
int k = 2;int l = 3;int m = 5;int s = sum(k, l, m);Имена функций
В языке C++ допустимо иметь несколько функций с одним и тем же именем, потому что функции различаются не только по именам, но и по типам аргументов. Если в дополнение к определенной выше функции sum мы определим еще одну функцию с тем же именем
doublesum(double a, double b, double c){ double result; result = a + b + c; return result;}это будет считаться новой функцией. Иногда говорят, что у этих функций разные подписи. В следующем фрагменте программы в первый раз будет вызвана первая функция, а во второй раз – вторая:
int x, y, z, ires;double p,q,s, dres;. . .// вызвать первое определение функции sumires = sum(x,y,z);// вызвать второе определение функции sumdres = sum(p,q,s);При первом вызове функции sum все фактические аргументы имеют тип int. Поэтому вызывается первая функция. Во втором вызове все аргументы имеют тип double, соответственно, вызывается вторая функция.
Важен не только тип аргументов, но и их количество. Можно определить функцию sum, суммирующую четыре аргумента:
intsum(int x1, int x2, int x3, int x4){ return x1 + x2 + x3 + x4;}Отметим, что при определении функций имеют значение тип и количество аргументов, но не тип возвращаемого значения. Попытка определения двух функций с одним и тем же именем, одними и теми же аргументами, но разными возвращаемыми значениями, приведет к ошибке компиляции:
int foo(int x);double foo(int x); // ошибка – двукратное определение имениРекурсия
Определения функций не могут быть вложенными, т.е. нельзя внутри тела одной функции определить тело другой. Разумеется, можно вызвать одну функцию из другой. В том числе функция может вызвать сама себя.
Рассмотрим функцию вычисления факториала целого числа. Ее можно реализовать двумя способами. Первый способ использует итерацию:
intfact(int n){ int result = 1; for (int i = 1; i <= n; i++) result = result * i; return result;}Второй способ:
intfact(int n){ if (n == 1) // факториал 1 равен 1 return 1; else // факториал числа n равен // факториалу n-1 // умноженному на n return n * fact(n -1);}Функция fact вызывае