Лекция 1. Предисловие
Предисловие. Знакомство с языком С++
Книга, которую открыл читатель, является с одной стороны учебником по алгоритмизации и программированию на C++, а с другой — пособием по разработке визуальных приложений в среде Qt Creator. В книге описаны среда программирования Qt Creator и редактор Geany. При чтении книги не требуется предварительного знакомства с программированием.
В первой части книги (главы 1–9) на большом количестве примеров представлены методы построения программ на языке C++, особое внимание уделено построению циклических программ, программированию с использованием функций, массивов, матриц и указателей.
Вторая часть книги (глава 10) посвящена объектно-ориентированному программированию на C++.
В третьей части книги (главы 11–15) читатель научится создавать кроссплатформенные визуальные приложения с помощью Qt Creator и познакомится с библиотекой классов Qt.
В книге присутствуют задания для самостоятельного решения.
В приложениях описан текстовый редактор Geany, а также кроссплатформенная библиотека MathGL, предназначенная для построения различных двух- и трёхмерных графиков.
Главы 1–9 написаны Е. Р. Алексеевым и О. В. Чесноковой. Автором раздела по объектно-ориентированному программированию является Д. А. Костюк. Главы 11–15, посвящённые программированию с использованием инструментария Qt, написаны Г. Г. Злобиным и А. C. Чмыхало.
Авторы благодарят компанию ALT Linux (www.altlinux.ru) и лично Алексея Смирнова и Владимира Чёрного за возможность издать очередную книгу по свободному программному обеспечению.
Знакомство с языком С++
В этой главе читатель напишет свои первые программы на языке С(С++), познакомится с основными этапами перевода программы с языка C++ в машинный код. Второй параграф главы посвящён знакомству со средой Qt Creator.
1.1 Первая программа на C++
Знакомство с языком С++ начнём с написания программ, предназначенных для решения нескольких несложных задач.
Задача 1.1. Заданы две стороны прямоугольника a, b. Найти его площадь и периметр.
Как известно, периметр прямоугольника , а его площадь
. Ниже приведён текст программы.
1 #include <iostream> 2 using namespace std; 3 int main( ) 4 { 5 float a, b, s, p; 6 cout<<"a="; 7 cin>>a; 8 cout<<"b="; 9 cin>>b; 10 p=2*(a+b ); 11 s=a*b; 12 cout << "Периметр прямоугольника равен " << p <<endl; 13 cout << "Площадь прямоугольника равна " << s <<endl; 14 return 0; 15 }
Давайте построчно рассмотрим текст программы и познакомимся со структурой программы на С++ и с некоторыми операторами языка.
Строка 1. Указывает компилятору (а точнее, препроцессору), что надо использовать функции из стандартной библиотеки iostream. Библиотека iostream нужна для организации ввода с помощью инструкции cin и вывода — с помощью cout. В программе на языке C++ должны быть подключены все используемые библиотеки.
Строка 2. Эта строка обозначает, что при вводе и выводе с помощью cin и cout будут использоваться стандартные устройства (клавиатура и экран), если эту строку не указывать, то каждый раз при вводе вместо cin надо будет писать std::cin, а вместо cout –- std::cout.
Строка 3. Заголовок главной функции (главная функция имеет имя main). В простых программах присутствует только функция main().
Строка 4. Любая функция начинается с символа {.
Строка 5. Описание вещественных (float) переменных a (длина одной стороны прямоугольника), b (длина второй стороны прямоугольника), s (площадь прямоугольника), p (периметр прямоугольника). Имя переменной1)состоит из латинских букв, цифр и символа подчёркивания. Имя не может начинаться с цифры. В языке С++ большие и малые буквы различимы. Например, имена PR_1, pr_1, Pr_1 и pR_1 — разные.
Строка 6. Вывод строки символов a= с помощью cout. Программа выведет подсказку пользователю, что необходимо вводить переменную a
Строка 7. Ввод вещественного числа a с помощью cin. В это момент программа останавливается и ждёт, пока пользователь введёт значение переменой a с клавиатуры.
Строка 8. Вывод строки символов b= с помощью cout.
Строка 9. Ввод вещественного числа b с помощью cin.
Строка 10. Оператор присваивания для вычисления периметра прямоугольника (переменная p) по формуле . В операторе присваивания могут использоваться круглые скобки и знаки операций: + (сложение), - (вычитание), * (умножение), / (деление).
Строка 11. Оператор присваивания для вычисления площади прямоугольника.
Строка 12. Вывод строки "Периметр прямоугольника равен " и значения p на экран. Константа endl хранит строку "\n", которая предназначена для перевода курсора в новую строку дисплея2).Таким образом строка
cout <<"Периметр прямоугольника равен "<< p <<endl;
выводит на экран текст "Периметр прямоугольника равен "3), значение переменной p, и переводит курсор в новую строку.
Строка 13. Вывод строки "Площадь прямоугольника равна ", значения площади прямоугольника s, после чего курсор переводится в новую строку дисплея.
Строка 14. Оператор return, который возвращает значение в операционную систему. Об этом подробный разговор предстоит в п. 4.9.Сейчас следует запомнить: если программа начинается со строки int main(), последним оператором должен быть4)return 0.
Строка 15. Любая функция (в том числе и main) заканчивается символом }.
Мы рассмотрели простейшую программу на языке С++, состоящую из операторов ввода данных, операторов присваивания (в которых происходит расчёт по формулам) и операторов вывода.
Программа на языке С++ представляет собой одну или несколько функций. В любой программе обязательно должна быть одна функция main(). С этой функции начинается выполнение программы. Правилом хорошего тона в программировании является разбиение задачи на подзадачи, и в главной функции чаще всего должны быть операторы вызова других функций. Общую структуру программы на языке C++ можно записать следующим образом.
Директивы препроцессора Объявление глобальных переменных Тип_результата f1 (Список_переменных) { Операторы } Тип_результата f2 (Список_переменных) { Операторы } ... Тип_результата fn (Список_переменных) { Операторы } Тип_ результата main (Список_переменных) { Операторы }
На первом этапе знакомства с языком мы будем писать программы, состоящие только из функции main, без использования глобальных переменных. Структура самой простой программы на C(C++) имеет вид.
Директивы препроцессора Тип_ результата main (Список_переменных) { Операторы }
Введённая в компьютер программа на языке С++ должна быть переведена в двоичный машинный код (формируется исполняемый файл). Для этого существуют специальные программы, называемые трансляторами. Все трансляторы делятся на два класса:
- интерпретаторы — трансляторы, которые переводят каждый оператор программы в машинный код, и по мере перевода операторы выполняются процессором;
- компиляторы переводят всю программу целиком, и если перевод всей программы прошёл без ошибок, то полученный двоичный код можно запускать на выполнение.
Процесс перевода программы в машинный код называется трансляцией. Если в качестве транслятора выступает компилятор, то используют термин компиляция программы. При переводе программы с языка С++ в машинный код используются именно компиляторы, и поэтому применительно к языку С++ термины "компилятор" и "транслятор" эквивалентны.
Рассмотрим основные этапы обработки компилятором программы на языке С++ и формирования машинного кода.
- Сначала с программой работает препроцессор5), он обрабатывает директивы, в нашем случае это директивы включения заголовочных файлов (файлов с расширением .h) — текстовых файлов, в которых содержится описание используемых библиотек. В результате формируется полный текст программы, который поступает на вход компилятора.
- Компилятор разбирает текст программ на составляющие элементы, проверяет синтаксические ошибки и в случае их отсутствия формирует объектный код (файл с расширением .o или .obj). Получаемый на этом этапе двоичный код не включает в себя двоичные коды библиотечных функций и функций пользователя.
- Компоновщик подключает к объектному коду программы объектные модули библиотек и других файлов (если программа состоит из нескольких фай-лов) и генерирует исполняемый код программы (двоичный файл), который уже можно запускать на выполнение. Этот этап называется компоновкой или сборкой программы.
После написания программы её необходимо ввести в компьютер. В той книге будет рассматриваться работа на языке C++ в среде Qt Creator6). Поэтому перед вводом программы в компьютер надо познакомиться со средой программирова-ния.
1.2 Среда программирования Qt Creator
Среда программирования Qt Creator (IDE QT Creator) находится в репози-тории большинства современных дистрибутивов Linux (OC Linux Debian, OC Linux Ubuntu, OC ROSA Linux, ALT Linux и др.). Установка осуществляется штатными средствами вашей операционной системы (менеджер пакетов Synaptic и др.) из репозитория, достаточно установить пакет qtcreator, необходимые па-кеты и библиотеки будут доставлены автоматически. Последнюю версию IDE Qt Creator можно скачать на сайте QtProject (http://qt-project.org/downloads). Установочный файл имеет расширение .run. Для установки приложения, необходимо запустить его на выполнение. Установка проходит в графическом режиме. После запуска программы пользователь увидит на экране окно, подобное представленному на рис. 1.11).

увеличить изображение
Рис. 1.1. Окно Qt Creator
При работе в Qt Creator вы находитесь в одном из режимов:
- Welcome (Начало) — отображает экран приветствия, позволяя быстро загружать недавние сессии или отдельные проекты. Этот режим можно увидеть при запуске Qt Creator без указания ключей командной строки.
- Edit (Редактор) — позволяет редактировать файлы проекта и исходных кодов. Боковая панель слева предоставляет различные виды для перемещения между файлами.
- Debug (Отладка) — предоставляет различные способы для просмотра состояния программы при отладке.
- Projects (Проекты) — используется для настройки сборки, запуска и редактирования кода.
- Analyze (Анализ) — в Qt интегрированы современные средства анализа кода разрабатываемого приложения.
- Help (Справка) — используется для вывода документации библиотеки Qt и Qt Creator.
- Output (Вывод) — используется для вывода подробных сведений о проекте.
Рассмотрим простейшие приёмы работы в среде Qt Creator на примере создания консольного приложения для решения задачи 1.1. Для этого можно поступить одним из способов:
- В меню File (Файл) выбрать команду New File or Project (Новый файл или проект) (комбинация клавиш Ctrl+N).
- Находясь в режиме Welcome (Начало) главного окна QtCreator (рис. 1.1) щёлкаем по ссылке Develop (Разработка) и выбираем команду Create Project (Создать проект).
После это откроется окно, подобное представленному на рис. 1.2. Для создания простейшего консольного приложения выбираем Non-Qt Project (Проект без использования Qt) — Plain C++ Project (Простой проект на языке С++).
Далее выбираем имя проекта и каталог для его размещения (см. рис. 1.3)2). Следующие два этапа создания нашего первого приложения оставляем без изменения3). После чего окно IDE Qt Creator будет подобно представленному на рис. 1.4. Заменим текст "Hello, Word" стандартного приложения, на текст программы решения задачи 1.1.

увеличить изображение
Рис. 1.2. Окно выбора типа приложения в Qt Creator
Для сохранения текста программы можно воспользоваться командой Сохранить или Сохранить всё из меню Файл. Откомпилировать и запустить программу можно одним из следующих способов:
- Пункт меню Сборка-Запустить.
- Нажать на клавиатуре комбинацию клавиш Ctrk+R.
- Щёлкнуть по кнопке Запустить (
).
Окно с результатами работы программы представлено на рис. 1.5.

увеличить изображение
Рис. 1.3. Выбор имени и каталога нового проекта

увеличить изображение
Рис. 1.4. Главное окно создания консольного приложения
Авторы сталкивались с тем, что в некоторых дистрибутивах Ubuntu Linux и Linux Mint после установки Qt Creator не запускались консольные приложения. Если читатель столкнулся с подобной проблемой, скорее всего надо корректно настроить терминал, который отвечает за запуск приложений в консоли. Для этого вызываем команду Tools — Options — Environment (см. рис. 1.6). Параметр Terminal (Терминал) должен быть таким же, как показано на рис. 1.6. Проверьте установлен ли в Вашей системе пакет xterm, и при необходимости доставьте его. После этого не должно быть проблем с запуском консольных приложений.
Аналогичным образом можно создавать и запускать любое консольное приложение.

Рис. 1.5. Результаты работы программы решения задачи 1.1

увеличить изображение
Рис. 1.6. Окно настроек среды Qt Creator
Дальнейшее знакомство со средой Qt Creator продолжим, решая следующую задачу.
Задача 1.2. Заданы длины трёх сторон треугольника и
(см. рис. 1.7). Вычислить площадь и периметр треугольника.
Для решения задачи можно воспользоваться формулой Герона , где
— периметр.
Решение задачи можно разбить на следующие этапы:
- Определение значений
и
(ввод величин
с клавиатуры в память компьютера).
- Расчёт значений
и
по приведённым выше формулам.
- Вывод
и
на экран дисплея.
Ниже приведён текст программы. Сразу заметим, что в тексте могут встречаться строки, начинающие с двух наклонных (//). Это комментарии. Комментарии не являются обязательными элементами программы и ничего не сообщают компьютеру, они поясняют человеку, читающему текст программы, назначение отдель ных элементов программы. В книге комментарии будут широко использоваться для пояснения отдельных участков программы.

Рис. 1.7. Треугольник
#include <iostream> #include <math.h> using namespace std; int main( ) { float a, b, c, s, p; cout<<"Введите длины сторон треугольника"<<endl; //Ввод значений длин треугольника a, b, c . cin>>a>>b>>c; //Вычисление периметра треугольника . p=a+b+c; //Вычисление площади треугольника . s=sqrt ( p /2*( p/2-a )*( p/2-b )*( p/2-c ) ); //Вывод на экран дисплея значений площади и периметра треугольника. cout<<"Периметр треугольника равен "<<p<<", его площадь равна "<<s<<endl; return 0; }
Кроме используемой в предыдущей программе библиотеки iostream, в строке 2 подключим библиотеку math.h, которая служит для использования математических функций языка С(С++). В данной программе используется функция извлечения квадратного корня — . Остальные операторы (ввода, вывода, вычисления значений переменных) аналогичны используемым в предыдущей программе.
Таким образом, выше были рассмотрены самые простые программы (линейной структуры), которые предназначены для ввода исходных данных, расчёта по формулам и вывода результатов.
Лекция 2. Общие сведения о языке С++
2.1 Алфавит языка
Программа на языке С++ может содержать следующие символы:
- прописные, строчные латинские буквы
и знак подчёркивания;
- арабские цифры от 0 до 9;
- специальные знаки:
- символы пробела, табуляции и перехода на новую строку.
Из символов алфавита формируют ключевые слова и идентификаторы. Ключевые слова — это зарезервированные слова, которые имеют специальное значение для компилятора и используются только в том смысле, в котором они определены (операторы языка, типы данных и т.п.). Идентификатор — это имя программного объекта, представляющее собой совокупность букв, цифр и символа подчёркивания. Первый символ идентификатора — буква или знак подчёркивания, но не цифра. Идентификатор не может содержать пробел. Прописные и строчные буквы в именах различаются, например, ABC, abc, Abc — три различных имени. Каждое имя (идентификатор) должно быть уникальным в пределах функции и не совпадать с ключевыми словами.
В тексте программы можно использовать комментарии. Если текст начинается с двух символов "косая черта" // и заканчивается символом перехода на новую строку или заключён между символами /* и */, то компилятор его игнорирует.
/* Комментарий может выглядеть так! */ //А если вы используете такой способ, //то каждая строка должна начинаться //с двух символов "косая черта".
Комментарии удобно использовать как для пояснений к программе, так и для временного исключения фрагментов программы при отладке.
2.2 Данные
Для решения задачи в любой программе выполняется обработка каких-либо данных. Данные хранятся в памяти компьютера и могут быть самых различных типов: целыми и вещественными числами, символами, строками, массивами. Типы данных определяют способ хранения чисел или символов в памяти компьютера. Они задают размер ячейки, в которую будет записано то или иное значение, определяя тем самым его максимальную величину или точность задания. Участок памяти (ячейка), в котором хранится значение определённого типа, называется переменной. У переменной есть имя (идентификатор) и значение. Имя служит для обращения к области памяти, в которой хранится значение. Во время выполнения программы значение переменной можно изменить. Перед использованием любая переменная должна быть описана. Оператор описания переменных в языке С++ имеет вид:
тип имя_переменной;
или
тип список_переменных;
Типы данных языка С++ можно разделить на основные и составные.
К основным типам данных языка относят:
- char — символьный;
- int— целый;
- float— с плавающей точкой;
- double — двойной точности;
- bool — логический.
Для формирования других типов данных используют основные типы и так называемые спецификаторы. Типы данных, созданные на базе стандартных типов с использованием спецификаторов, называют составными типами данных. В С++ определены четыре спецификатора типов данных:
- short — короткий;
- long — длинный;
- signed — знаковый;
- unsigned — беззнаковый.
Далее будут рассмотрены назначение и описание каждого типа.
2.2.1 Символьный тип
Данные типа char в памяти компьютера занимают один байт1).Это связано с тем, что обычно под величину символьного типа отводят столько памяти, сколько необходимо для хранения любого из 256 символов клавиатуры. Символьный тип может быть со знаком или без знака (табл. 2.1).
Тип | Диапазон | Размер |
---|---|---|
char | –128... 127 | 1 байт |
unsigned char | 0... 255 | 1 байт |
signed char | –128... 127 | 1 байт |
Пример описания символьных переменных:
char c, str; //Описаны две символьные переменные.
При работе с символьными данными нужно помнить, что если в выражении встречается одиночный символ, он должен быть заключён в одинарные кавычки.
Например, 'a', 'b', '+', '3'.
Последовательность символов, то есть строка, при использовании в выражениях заключается в двойные кавычки: "Hello!".
2.2.2 Целочисленный тип
Переменная типа int в памяти компьютера может занимать два, четыре или восемь байтов. Это зависит от разрядности процессора.
Диапазоны значений целого типа представлены в таблице 2.2. По умолчанию все целые типы считаются знаковыми, т.е. спецификатор signed можно не указывать.
Тип | Диапазон | Размер |
---|---|---|
int | –2147483647...2147483647 | 4 байта |
unsigned int | 0...4294967295 | 4 байта |
signed int | –2147483647...2147483647 | 4 байта |
short int | –32767...32767 | 2 байта |
long int | –2147483647...2147483647 | 4 байта |
unsigned short int | 0...65535 | 2 байта |
signed short int | –32767...32767 | 2 байта |
long long int | –(263–1)...(263–1) | 8 байт |
signed long int | –2147483647...2147483647 | 4 байта |
unsigned long int | 0...4294967295 | 4 байта |
unsigned long long int | 0...264–1 | 8 байт |
Пример описания целочисленных данных:
int a, b, c; unsigned long int A, B, C;
2.2.3 Вещественный тип
Внутреннее представление вещественного числа в памяти компьютера отличается от представления целого числа. Число с плавающей точкой представлено в экспоненциальной форме , где
— мантисса (целое или дробное число с десятичной точкой),
— порядок (целое число). Для того чтобы перевести число в экспоненциальной форме к обычному представлению с фиксированной точкой, необходимо мантиссу умножить на десять в степени порядок. Например,

Обычно величины типа float занимают 4 байта, из которых один двоичный разряд отводится под знак, 8 разрядов под порядок и 23 под мантиссу. Поскольку старшая цифра мантиссы всегда равна 1, она не хранится.
Величины типа double занимают 8 байт, в них под порядок и мантиссу отводится 11 и 52 разряда соответственно. Длина мантиссы определяет точность числа, а длина порядка его диапазон. Спецификатор типа long перед именем типа double указывает, что под величину отводится 10 байт.
Диапазоны значений вещественного типа представлены в табл. 2.3.
Тип | Диапазон | Размер |
---|---|---|
float | 3.4Е-38...3.4E+38 | 4 байта |
double | 1.7Е-308...1.7E+308 | 8 байт |
long double | 3.4Е-4932...3.4E+4932 | 10 байт |
Пример описания вещественных переменных:
double x1, x2, x3; float X, Y, Z;
2.2.4 Логический тип
Переменная типа bool может принимать только два значения true (истина) или false (ложь). Любое значение не равное нулю интерпретируется как true, а при преобразовании к целому типу принимает значение равное 1. Значение false представлено в памяти как 0.
Пример описания данных логического типа:
bool F, T;
2.2.5 Тип void
Множество значений этого типа пусто. Он используется для определения функций, которые не возвращают значения, для указания пустого списка аргументов функции, как базовый тип для указателей и в операции приведения типов.
2.3 Константы
Константы это величины, которые не изменяют своего значения в процессе выполнения программы. Оператор описания константы имеет вид:
сonst тип имя_константы = значение;
Константы в языке С++ могут быть целыми, вещественными, символьными или строковыми. Обычно компилятор определяет тип константы по внешнему виду, но существует возможность и явного указания типа, например,
const double pi=3.141592653589793;
Кроме того, константа может быть определена с помощью директивы1) #define. Эта директива служит для замены часто использующихся констант, ключевых слов, операторов или выражений некоторыми идентификаторами. Идентификаторы, заменяющие текстовые или числовые константы, называют именованными константами. Основная форма синтаксиса директивы следующая:
#define идентификатор текст
Например,
#define PI 3.141592653589793 int main( ) ...
2.4 Структурированные типы данных
Структурированный тип данных характеризуется множественностью образующих его элементов. В C++ это массивы, строки, структуры и файлы.
Массив — совокупность данных одного и того же типа2).Число элементов массива фиксируется при описании типа и в процессе выполнения программы не изменяется.
В общем виде массив можно описать так:
тип имя [размерность_1][размерность_2]...[размерность_N];
Например,
float x 10]; //Описан массив из 10 вещественных чисел. int a[3][4]; //Описан двумерный целочисленный массив, матрица из 3-х строк и 4-х столбцов. double b[2][3][2]; //Описан трехмерный массив.
Для доступа к элементу массива достаточно указать его порядковый номер, а если массив многомерный (например, таблица), то несколько номеров:
имя_массива[номер_1][номер_2]...[номер_N]
Например:
x[5], a[2][3], b[1][2][2] .
Элементы массива в С++ нумеруются с нуля. Первый элемент, всегда имеет номер ноль, а номер последнего элемента на единицу меньше заданной при его описании размерности:
char C[5]; //Описан массив из 5 символов, нумерация от 0 до 4.
Строка — последовательность символов3).В С++ строки описывают как массив элементов типа char. Например:
char s[25]; //Описана строка из 25 символов.
Структура4) это тип данных, который позволяет объединить разнородные данные и обрабатывать их как единое целое.
Например
struct fraction //Объявлена структура правильная дробь. { //Определяем поля структуры: int num; //поле числитель, int den; //поле знаменатель. } ... fraction d, D [ 2 0 ]; //Определена переменная d, массив D[20], типа fraction. ... d. num; //Обращение к полю num переменной d. D[4]. den; //Обращение к полю den четвёртого элемента массива D.
2.5 Указатели
Указатели широко применяются в С++. Можно сказать, что именно наличие указателей сделало этот язык удобным для программирования. С другой стороны это одна из наиболее сложных для освоения возможностей С++. Идея работы с указателями состоит в том, что пользователь работает с адресом ячейки памяти.
Как правило, при обработке оператора объявления переменной
тип имя_переменной;
компилятор автоматически выделяет память под переменную имя_переменной в соответствии с указанным типом:
char C; //Выделена память под символьную переменную C
Доступ к объявленной переменной осуществляется по её имени. При этом все обращения к переменной заменяются на адрес ячейки памяти, в которой хранится её значение. При завершении программы или функции, в которой была описана переменная, память автоматически освобождается.
Доступ к значению переменной можно получить иным способом — определить собственные переменные для хранения адресов памяти. Такие переменные называют указателями. С помощью указателей можно обрабатывать массивы, строки и структуры, создавать новые переменные в процессе выполнения программы, передавать адреса фактических параметров функциям и адреса функций в качестве параметров.
Итак, указатель это переменная, значением которой является адрес памяти, по которому хранится объект определённого типа (другая переменная). Например, если С это переменная типа char, а Р — указатель на С, значит в Р находится адрес по которому в памяти компьютера хранится значение переменной С.
Как и любая переменная, указатель должен быть объявлен. При объявлении указателей всегда указывается тип объекта, который будет храниться по данному адресу:
тип *имя_переменной;
Например:
int *p; //По адресу, записанному в переменной p, будет храниться переменная типа int
Звёздочка в описании указателя, относится непосредственно к имени, поэтому чтобы объявить несколько указателей, её ставят перед именем каждого из них:
float *x, y, *z; //Описаны указатели на вещественные числа x и z (сами вещественные //значения — *x, *z), а так же вещественная переменная y, её адрес — &y.
2.6 Операции и выражения
Выражение задаёт порядок выполнения действий над данными и состоит из операндов (констант, переменных, обращений к функциям), круглых скобок и знаков операций. Операции делятся на унарные (например, -с) и бинарные (например, а+b). В таблице 2.4 представлены основные операции языка С++.
Операция | Описание |
---|---|
Унарные операции | |
++ | увеличение значения на единицу |
-- | уменьшение значения на единицу |
~ | поразрядное отрицание |
! | логическое отрицание |
- | арифметическое отрицание (унарный минус) |
+ | унарный плюс |
& | получение адреса |
* | обращение по адресу |
(type) | преобразование типа |
Бинарные операции | |
+ | сложение |
- | вычитание |
* | умножение |
/ | деление |
% | остаток от деления |
<< | сдвиг влево |
>> | сдвиг вправо |
< | меньше |
> | больше |
<= | меньше или равно |
>= | больше или равно |
== | равно |
!= | не равно |
& | поразрядная конъюнкция (И) |
^ | поразрядное исключающее ИЛИ |
| | поразрядная дизъюнкция (ИЛИ) |
&& | логическое И |
|| | логическое ИЛИ |
= | присваивание |
*= | умножение с присваиванием |
/= | деление с присваиванием |
+= | сложение с присваиванием |
-= | вычитание с присваиванием |
%= | остаток от деления с присваиванием |
<<= | сдвиг влево с присваиванием |
>>= | сдвиг вправо с присваиванием |
&= | поразрядная конъюнкция с присваиванием |
|= | поразрядная дизъюнкция с присваиванием |
^= | поразрядное исключающее ИЛИ с присваиванием |
Другие операции | |
? | условная операция |
, | последовательное вычисление |
sizeof | определение размера |
(тип) | преобразование типа |
Перейдём к подробному рассмотрению основных операций языка.
2.6.1 Операции присваивания
Обычная операция присваивания имеет вид:
имя_переменной=значение;
где значение это выражение, переменная, константа или функция. Выполняется операция так. Сначала вычисляется значение выражения указанного в правой части оператора, а затем его результат записывается в область памяти, имя которой указано слева.
Например,
b=3; //Переменной b присваивается значение, равное трём. a=b; //Переменной а присваивается значение b. c=a+2*b; //Переменной c присваивается значение выражения. c=c +1; //Значение переменой с увеличивается на единицу. a=a *3; //Значение переменой а увеличивается в три раза.
Задача 2.1. Пусть в переменной а хранится значение, равное 3, а в переменную b записали число 5. Поменять местами значения переменных а и b.
Для решения задачи понадобится дополнительная переменная c(см. рис. 2.1). В ней временно сохраняется значение переменной а. Затем, значение переменной bзаписывается в переменную a, а значение переменной c в переменную b.
c=a; //Шаг 1. с=3 a=b; //Шаг 2. a=5 b=c; //Шаг 3. b=3

Рис. 2.1. Использование буферной переменной
Если в операторе присваивания левая и правая часть это переменные разных типов, то происходит преобразование: значение переменной в правой части преобразуется к типу переменной в левой части. Следует учитывать, что при этом можно потерять информацию или получить другое значение.
В С++ существует возможность присваивания нескольким переменным одного и того же значения. Такая операция называется множественным присваиванием и в общем виде может быть записана так:
имя_1 = имя_2 = ... = имя_N = значение;
Запись a=b=c=3.14159/6; означает, что переменным a, b и c было присвоено одно и то же значение 3.14159/6.
Операции + =, -=, *=, / = называют составным присваиванием. В таких операциях при вычислении выражения стоящего справа используется значение переменной из левой части, например так:
x+=p; //Увеличение x на p, то же что и x=x+p. x-=p; //Уменьшения x на p, то же что и x=x-p. x*=p; //Умножение x на p, то же что и x=x*p. x/=p; //Деление x на p, то же что и x=x/p.
2.6.2 Арифметические операции
Операции +, -, *, / относят к арифметическим операциям. Их назначение понятно и не требует дополнительных пояснений. При программировании арифметических выражений следует придерживаться простых правил. Соблюдать очерёдность выполнения арифметических операций. Сначала выполняются операции умножения и деления (1-й уровень), а затем сложения и вычитания (2-й уровень). Операции одного уровня выполняются последовательно друг за другом. Для изменения очерёдности выполнения операций используют скобки. Таблица 2.5 содержит примеры записи алгебраических выражений.
Математическая запись | Запись на языке С++ |
---|---|
![]() | 2*a+b*(c+d) |
![]() | 3*(a+b)/(c+d) |
![]() | (3*a-2*b)/(c*d) или (3*a-2*b)/c/d |
![]() | (b-a)*(b-a)/(c+1/(d-2))-(a*a+1)/(b*b+c*d) |
Операции инкремента ++ и декремента -- так же причисляют к арифметическим, так как они выполняют увеличение и уменьшение на единицу значения переменной. Эти операции имеют две формы записи: префиксную (операция записывается перед операндом) и постфиксную (операция записывается после операнда). Так, например оператор p=p+1; можно представить в префиксной форме ++p; и в постфиксной p++;.Эти формы отличаются при использовании их в выражении. Если знак декремента (инкремента) предшествует операнду, то сначала выполняется увеличение (уменьшение) значения операнда, а затем операнд участвует в выражении. Например,
x=12; y=++x; //В переменных x и y будет храниться значение 13.
Если знак декремента (инкремента) следует после операнда, то сначала операнд участвует в выражении, а затем выполняется увеличение (уменьшение) значения операнда:
x=12; y=x++; //Результат — число 12 в переменной y, а в x — 13.
Остановимся на операциях целочисленной арифметики.
Операция целочисленного деления / возвращает целую часть частного (дробная часть отбрасывается) в том случае, если она применяется к целочисленным операндам, в противном случае выполняется обычное деление: 11/4 = 2 или 11.0/4 = 2.75.
Операция остаток от деления % применяется только к целочисленным операндам: 11%4 = 3.
К операциям битовой арифметики относятся следующие операции: &, |, ^, ~, <<, >>. В операциях битовой арифметики действия происходят над двоичным представлением целых чисел.
Арифметическое И (&). Оба операнда переводятся в двоичную систему, затем над ними происходит логическое поразрядное умножение операндов по следующим правилам:
1&1=1, 1&0=0, 0&1=0, 0&0=0.
Например, если А=14 и В=24, то их двоичное представление — А=0000000000001110 и В=0000000000011000. В результате логического умножения A and B получим 0000000000001000 или 8 в десятичной системе счисления (рис. 2.2). Таким образом, A&B=14&24=8.

Рис. 2.2. Пример логического умножения

Рис. 2.3. Пример логического сложения
Арифметическое ИЛИ (|). Здесь также оба операнда переводятся в двоичную систему, после чего над ними происходит логическое поразрядное сложение операндов по следующим правилам:
1|1=1, 1|0=1, 0|1=1, 0|0=0.
Например, результат логического сложения чисел А=14 и В=24 будет равен A |B=30 (рис. 2.3).
Арифметическое исключающее ИЛИ (^). Оба операнда переводятся в двоичную систему, после чего над ними происходит логическая поразрядная операция ^ по следующим правилам:
1^1=0, 1^0=1, 0^1=1, 0^0=0.
Арифметическое отрицание (~). Эта операция выполняется над одним операндом. Применение операции ~ вызывает побитную инверсию двоичного представления числа (рис. 2.4).

Рис. 2.4. Пример арифметического отрицания
Сдвиг влево (M<<L). Число M, представленное в двоичной системе, сдвигается влево на Lпозиций. Рассмотрим операцию 15 << 3. Число 15 в двоичной системе имеет вид 1111. При сдвиге его на 3 позиции влево получим 1111000. В десятичной системе это двоичное число равно 120. Итак, 15 << 3 =120(рис. 2.5). Заметим, что сдвиг на один разряд влево соответствует умножению на два, на два разряда — умножению на четыре, на три — умножению на восемь. Таким образом, операция M << Lэквивалентна умножению числа M на 2 в степени L.

Рис. 2.5. Пример операции "Сдвиг влево"

Рис. 2.6. Пример операции "Сдвиг вправо"
Сдвиг вправо (M>>L). Число M, представленное в двоичной системе, сдвигается вправо на L позиций, что эквивалентно целочисленному делению числа M на 2 в степени L. Например, 15 >> 1=7 (рис. 2.6), 15 >> 3= 2.
2.6.3 Логические операции
В С++ определены следующие логические операции || (или), && (и), ! (не). Логические операции выполняются над логическими значениями true (истина) и false (ложь). В языке С ложь — 0, истина — любое значение 60. В таблице 2.6 приведены результаты логических операций.
2.6.4 Операции отношения
Операции отношения возвращают в качестве результата логическое значение. Таких операций шесть: >, >=, <, <=, ==, !=. Результат операции отношения — логическое значение true (истина) или false (ложь).
2.6.5 Условная операция
Для организации разветвлений в простейшем случае можно использовать условную операцию ? :. Эта операция имеет три операнда и в общем виде может быть представлена так:
условие ? выражение1 : выражение2;
Работает операция следующим образом. Если условие истинно (не равно 0), то результатом будет выражение1, в противном случае выражение2. Например, операция y=x<0 ? -x : x; записывает в переменную y модуль числа х.
2.6.6 Операция преобразования типа
Для приведения выражения к другому типу данных в С++ существует операция преобразования типа:
(тип) выражение;
Например, в результате действий x=5; y=x/2; z=(float) x/2; переменная y примет значение равное 2 (результат целочисленного деления), а переменная z = 2.5.
2.6.7 Операция определения размера
Вычислить размер объекта или типа в байтах можно с помощью операции определения размера, которая имеет две формы записи:
sizeof (тип); или sizeof выражение;
Например, предположим, что была описана целочисленная переменная int k=3;.Исходя из того, что тип int занимает в памяти 4 байта, в переменную m=sizeof k; будет записано число 4.
В результате работы команд double z=123.456; p=sizeof (k+z); значение переменной p стало равно 8, т. к. вещественный тип double более длинный (8 байтов) по сравнению с типом int(4 байта) и значение результата было преобразовано к более длинному типу. В записи операции sizeof (k+z) были использованы скобки. Это связано с тем, что операция определения типа имеет более высокий приоритет, чем операция сложения. При заданном значении z=123.456; та же команда, но без скобок p=sizeof k+z; вычислит p=4+123.456=127.456.
Команда s = sizeof "Hello"; определит, что под заданную строку в памяти было выделено s=6 байтов, т. к. объект состоит из 5 символов и один байт на символ окончания строки.
2.6.8 Операции с указателями
При работе с указателями часто используют операции получения адреса & и разадресации * (табл. 2.7).
Описание | Адрес | Значение, хранящееся по адресу |
---|---|---|
тип *p | p | *p |
тип p | &p | p |
Операция получения адреса & возвращает адрес своего операнда. Например:
float a; //Объявлена вещественная переменная а float *adr_a; //Объявлен указатель на тип float adr_a=&a; //Оператор записывает в переменную adr_a адрес переменной a
Операция разадресации * возвращает значение переменной, хранящееся по заданному адресу, т.е. выполняет действие, обратное операции &:
float a; //Объявлена вещественная переменная а. float *adr_a; //Объявлен указатель на тип float. a=*adr_a; //Оператор записывает в переменную a вещественное значение, //хранящееся по адресу adr_a.
К указателям применяют операцию присваивания. Это значит, что значение одного указателя можно присвоить другому. Если указатели одного типа, то для этого применяют обычную операцию присваивания:
//Описана вещественная переменная и два указателя. float PI =3.14159,*p1, *p2; //В указатели p1 и p2 записывается адрес переменной PI. p1=p2=&PI;
Если указатели ссылаются на различные типы, то при присваивании значения одного указателя другому, необходимо использовать преобразование типов. Без преобразования можно присваивать любому указателю указатель void*.
Рассмотрим пример работы с указателями различных типов:
float PI = 3.14159; //Объявлена вещественная переменная. float *p1; //Объявлен указатель на float. double *p2; //Объявлен указатель на double. p1=&PI; //Переменной p1 присваивается значение адреса PI. p2=(double *) p1; //Указателю на double присваивается значение, //которое ссылается на тип float.
В указателях p1 и p2 хранится один и тот же адрес (p1=0012FF7C), но значения, на которые они ссылаются разные (*p1=3.14159, *p2=2.642140e-308). Это связано с тем, указатель типа *float адресует 4 байта, а указатель *double — 8 байт. После присваивания p2=(double *)p1; при обращении к *p2 происходит следующее: к переменной, хранящейся по адресу p1, дописывается ещё следующих 4 байта из памяти. В результате значение *p2 не совпадает со значением *p1.
Таким образом, при преобразовании указателей разного типа приведение типов разрешает только синтаксическую проблему присваивания. Следует помнить, что операция * над указателями различного типа, ссылающимися на один и тот же адрес, возвращает различные значения.
Над адресами С++ определены следующие арифметические операции:
- сложение и вычитание указателей с константой;
- вычитание одного указателя из другого;
- инкремент;
- декремент.
Сложение и вычитание указателей с константой n означает, что указатель перемещается по ячейкам памяти на столько байт, сколько занимает n переменных того типа, на который он указывает. Например, пусть указатель имеет символьный тип, и его значение равно 100. Результат сложения этого указателя с единицей — 101, так как для хранения переменной типа char требуется один байт. Если же значение указателя равно 100, но он имеет целочисленный тип, то результат его сложения с единицей будет составлять 104, так как для переменной типа int отводится четыре байта.
Эти операции применимы только к указателям одного типа и имеют смысл в основном при работе со структурными типами данных, например массивами.
Фактически получается, что значение указателя изменяется на величину sizeof(тип).Если указатель на определённый тип увеличивается или уменьшается на константу, то его значение изменяется на величину этой константы, умноженную на размер объекта данного типа. Например:
//Объявление массива из 10 элементов. double mas [10] = { 1.29,3.23,7.98,5.54,8.32,2.48,7.1 }; double *p1; //Объявление указателя на double p1=&mas [ 0 ]; //Присвоение указателю адреса нулевого элемента массива. p1=p1+3; //Увеличение значения адреса на 3*8=24 (размер типа double), в результате указатель //сместится на три ячейки, размером double каждая.
Вычитание двух указателей определяет, сколько переменных данного типа размещается между указанными ячейками. Разность двух указателей это разность их значений, делённая на размер типа в байтах. Так разность указателей на третий и нулевой элементы массива равна трём, а на третий и девятый — шести. Суммирование двух указателей не допускается.
Операции инкремента и декремента, соответственно, увеличивают или уменьшают значение адреса:
double *p1; float *p2; int *i; p1++; //Увеличение значения адреса на 8. p2++; //Увеличение значения адреса на 4. i ++; //Увеличение значения адреса на 4.
К указателям так же применимы операции отношения ==, !=, <, >, <=, >=. Иными словами, указатели можно сравнивать. Например, если указывает на пятый элемент массива, а
на первый, то отношение
истинно. Кроме того, любой указатель всегда можно сравнить на равенство с константой нулевого указателя (NULL)1). Однако все эти утверждения верны, если речь идёт об указателях, ссылающихся на один массив. В противном случае результат арифметических операций и операций отношения будет не определён.
2.7 Стандартные функции
В C++ определены стандартные функции над арифметическими операндами1).В табл. 2.8 приведены некоторые из них.
Обозначение | Действие |
---|---|
abs(x) | Модуль целого числа ![]() |
fabs(x) | Модуль вещественного числа ![]() |
sin(x) | Синус числа ![]() |
cos(x) | Косинус числа ![]() |
tan(x) | Тангенс числа ![]() |
atan(x) | Арктангенс числа ![]() |
acos(x) | Арккосинус числа ![]() |
asin(x) | Арксинус числа ![]() |
exp(x) | Экспонента, ![]() |
log(x) | Натуральный логарифм, ![]() |
log10(x) | Десятичный логарифм, ![]() |
sqrt(x) | Корень квадратный, ![]() |
pow(x,y) | Возведение числа ![]() ![]() |
ceil(x) | Округление числа ![]() |
floor(x) | Округление числа ![]() |
Примеры записи математических выражений с использованием встроенных функций представлены в табл. 2.9.
Математическая запись | Запись на языке С++ |
---|---|
![]() | pow((a+b) *(a+b),1./3) или pow(pow(a+b,2),1./3) |
![]() | pow(cos(x), 4) |
![]() | exp(2*x) |
![]() | exp(5*sin(x/2)) |
![]() | pow(sin(sqrt(x)),2) |
![]() | log(fabs(x -2)) |
![]() | log(a)/log(b) |
![]() | log10(x*x+1)/log10(4) |
![]() | z=x*x+y*y; sin(z)+cos(z/(2*y))+sqrt(z); |
Определённую проблему представляет применение функции pow(x,y).При программировании выражений, содержащих возведение в степень, надо внимательно проанализировать значения, которые могут принимать и
, так как в некоторых случаях возведение
в степень
невыполнимо.
Так, ошибка возникает, если — отрицательное число, а
— дробь. Предположим, что
— правильная дробь вида
. Если знаменатель
чётный, это означает вычисление корня чётной степени из отрицательного числа, а значит, операция не может быть выполнена. В противном случае, если знаменатель m нечётный, можно воспользоваться выражением z = –pow(fabs(x),y). Например, вычисление кубического корня из вещественного числа можно представить командой:
z=(x<0)? -pow(fabs(x),(double)1/3): pow(x,(double)1/3);
2.8 Структура программы
Программа на языке С++ состоит из функций, описаний и директив препроцессора.
Одна из функций должна обязательно носить имя main. Элементарное описание функции имеет вид:
тип_результата имя_функции (параметры) { оператор1; оператор2; ... операторN; }
Здесь, тип_результата — это тип того значения, которое функция должна вычислить (если функция не должна возвращать значение, указывается тип void), имя_функции — имя, с которым можно обращаться к этой функции, параметры — список аргументов функции (может отсутствовать), оператор1, оператор2,..., операторN — операторы, представляющие тело функции, они обязательно заключаются в фигурные скобки и каждый оператор заканчивается точкой с запятой. Как правило, программа на С++ состоит из одной или нескольких, не вложенных друг в друга, функций.
Основному тексту программы предшествуют директивы препроцессора, предназначенные для подключения библиотек, которые в общем виде выглядят так:
#include <имя_библиотеки>
Каждая такая строка даёт компилятору команду присоединить программный код, который хранится в отдельном файле с расширением .h. Такие файлы называют файлами заголовков. С их помощью можно выполнять ввод-вывод данных, работать с математическими функциями, преобразовывать данные, распределять память и многое другое. Например, описание стандартных математических функций находится в заголовочном файле math.h.
Общую структуру программы на языке С++ можно записать следующим образом:
директивы препроцессора описание глобальных переменных тип_результата имя1(параметры1) { описание переменных функции имя1; операторы1; } тип_результата имя2(параметры2) { описание переменных функции имя2; операторы2; } ............................... . тип_результата имяN(параметрыN) { описание переменных функции имяN; операторыN; } тип_результата main(параметры) { описание переменных главной функции; операторы главной функции; }
По месту объявления переменные в языке Си можно разделить на три класса: локальные, глобальные и формальные параметры функции.
Локальные переменные объявляются внутри функции и доступны только в ней. Например:
int f1 ( ) { //В функции f1 описана другая переменная s, int s; s =6; //ей присвоено значение 6 . } int f2 ( ) { //В функции f2 определена ещё одна переменная s, long int s; s =25; //ей присвоено значение 25. } int main ( ) { //В функции main определена вещественная переменная s, float s; s =4.5; //и ей присвоено значение 4.5. }
Глобальные переменные описываются до всех функций и доступны из любого места программы. Например:
float s; //Определена глобальная переменная s . int f1 ( ) { //В функции f1 переменной s присваивается значение 6 . s =6; } int f2 ( ) { //В функции f2 переменной s присваивается значение 2.1. s =2.1; } int main ( ) { //В главной функции переменной s присваивается значение 4.5 . s =4.5; }
Формальные параметры функций описываются в списке параметров функции. Работа с функциями подробно описана в главе 4.
2.9 Ввод и вывод данных
Ввод-вывод данных в языке С++ осуществляется либо с помощью функций ввода-вывода в стиле С, либо с использованием библиотеки классов С++. Преимущество объектов С++ в том, что они легче в использовании, особенно если ввод-вывод достаточно простой. Функции ввода-вывода, унаследованные от С — громоздкие, но более гибко управляют форматированным выводом данных.
Функция
printf(строка форматов, список выводимых переменных);
выполняет форматированный вывод переменных, указанных в списке, в соответствии со строкой форматов.
Функция
scanf(строка форматов, список адресов вводимых переменных);
выполняет ввод переменных, адреса которых указанны в списке, в соответствии со строкой форматов.
Строка форматов содержит символы, которые будут выводиться на экран или запрашиваться с клавиатуры, и так называемые спецификации. Спецификации это строки, которые начинаются символом % и выполняют управление форматированием:
% флаг ширина.точность модификатор тип
Параметры флаг, ширина, точность и модификатор в спецификациях могут отсутствовать. Значения параметров спецификаций приведены в табл. 2.10.
Параметр | Назначение |
---|---|
Флаги | |
- | Выравнивание числа влево. Правая сторона дополняется пробелами. По умолчанию выравнивание вправо. |
+ | Перед числом выводится знак "+" или "-" |
Пробел | Перед положительным числом выводится пробел, перед отрицательным "–" |
# | Выводится код системы счисления: 0 — перед восьмеричным числом, 0х (0Х) перед шестнадцатеричным числом. |
Ширина | |
n | Ширина поля вывода. Если n позиций недостаточно, то поле вывода расширяется до минимально необходимого. Незаполненные позиции заполняются пробелами. |
On | То же, что и n, но незаполненные позиции заполняются нулями. |
Точность | |
ничего | Точность по умолчанию |
n | Для типов e, E, f выводить n знаков после десятичной точки |
Модификатор | |
h | Для d, i, o, u, x, X тип short int. |
l | Для d, i, o, u, x, X тип long int. |
Тип | |
c | Символьный тип char. |
d | Десятичное int со знаком. |
i | Десятичное int со знаком. |
o | Восьмеричное int unsigned. |
u | Десятичное int unsigned. |
x,X | Шестнадцатеричное int unsigned, при х используются символы a-f, при Х — A - F. |
f | Значение со знаком вида [-]dddd.dddd. |
e | Значение со знаком вида [-]d.dddde[+|-]ddd. |
E | Значение со знаком вида [-]d.ddddE[+|-]ddd. |
g | Значение со знаком типа e или fв зависимости от значения и точности. |
G | Значение со знаком типа e или F в зависимости от значения и точности. |
s | Строка символов. |
Кроме того, строка форматов может содержать некоторые специальные символы, которые приведены в табл. 2.11.
Символ | Назначение |
---|---|
\b | Сдвиг текущей позиции влево. |
\n | Перевод строки. |
\r | Перевод в начало строки, не переходя на новую строку |
\t | Горизонтальная табуляция. |
\' | Символ одинарной кавычки. |
\" | Символ двойной кавычки. |
\? | Символ ? |
Первой строкой программы, в которой будут применяться функции вводавывода языка С, должна быть директива #include <stdio.h>. Заголовочный файл stdio.h содержит описание функций ввода-вывода.
Рассмотрим работу функций на примере следующей задачи.
Задача 2.2. Зная a, b, c — длины сторон треугольника, вычислить площадь S и периметр P этого треугольника.
Входные данные: a, b, c. Выходные данные: S, P.
Для вычисления площади применим формулу Герона: , где
— полупериметр.
Далее приведены две программы для решения данной задачи и результаты их работы (рис. 2.7,рис. 2.8).
//ЗАДАЧА 2.2 Вариант первый #include <iostream> #include <stdio.h> #include <math.h> using namespace std; int main ( ) { float a, b, c, S, r; //Описание переменных. printf ( " a = " ); //Вывод на экран символов a=. //В функции scanf для вычисления адреса переменной применяется операция &. scanf ( " % f ",&a ); //Запись в переменную а значения введённого с клавиатуры . printf ( " b = " ); //Вывод на экран символов b=. scanf ( " % f ",&b ); //Запись в переменную b значения введённого с клавиатуры. printf ( " c = " ); //Вывод на экран символов c= scanf ( " % f ",&c ); //Запись в переменную c значения введённого с клавиатуры. r=(a+b+c ) / 2; //Вычисление полупериметра. S=sqrt ( r * ( r -a ) *( r -b )*( r -c ) ); //Вычисление площади треугольника. printf ( " S =%5.2 f \ t ", S ); //Вывод символов S=, значения S и символа табуляции \t. //Спецификация %5.2f означает, что будет выведено вещественное //число из пяти знаков, два из которых после точки. printf ( " p =%5.2 f \ n ",2 *r ); //Вывод символов p=, значения выражения 2*r //и символа окончания строки. //Оператор printf("S=%5.2f \t p=%5.2f \n",S,2*r) выдаст тот же результат. return 0; }

Рис. 2.7. Результаты работы программы к задаче 2.2 (вариант 1)
//ЗАДАЧА 2.2. Вариант второй #include <iostream> #include <stdio.h> #include <math.h> using namespace std; int main ( ) { float a, b, c, S, r; printf ( " Vvedite a, b, c \ n " ); //Вывод на экран строки символов. scanf ( " % f % f % f ",&a,&b,& c ); //Ввод значений. r=(a+b+c ) / 2; S=sqrt ( r * ( r-a ) * ( r-b ) * ( r -c ) ); printf ( " S =%5.2 f \ t p =%5.2 f \ n ",S, 2 * r ); //Вывод результатов. return 0; }

Рис. 2.8. Результаты работы программы к задаче 2.2 (вариант 2)
2.9.1 Объектно-ориентированные средства ввода-вывода.
Описание объектов для управления вводом-выводом содержится в заголовочном файле iostream. При подключении этого файла с помощью директивы #include <iostream> в программе автоматически создаются объекты-потоки1)cin для ввода с клавиатуры и cout для вывода на экран, а также операции помещения в поток << и чтения из потока >>.
Итак, с помощью объекта cin и операции >> можно ввести значение любой переменной. Например, если переменная i описана как целочисленная, то команда cin>> i; означает, что в переменную i будет записано некое целое число, введённое с клавиатуры. Если нужно ввести несколько переменных, следует написать cin>>x>>y>>z; .
Объект cout и операция << позволяют вывести на экран значение любой переменной или текст. Текст необходимо заключать в двойные кавычки, кроме того, допустимо применение специальных символов \t и \n (табл. 2.11). Запись cout<<i; означает вывод на экран значения переменной i. А команда cout<<x<<"\t"<<y;выведет на экран значения переменных xи y, разделённые символом табуляции.
Задача 2.3. Дано трехзначное число. Записать его цифры в обратном порядке и вывести на экран новое число.
Разберём решение данной задачи на конкретном примере. Здесь будут использоваться операции целочисленной арифметики.
Пусть P=456. Вычисление остатка от деления числа P на 10 даст его последнюю цифру (количество единиц в числе P): 456 % 10 =6.
Операция деления нацело числа P на 10 позволит уменьшить количество разрядов и число станет двузначным:
456 / 10 = 45.
Остаток от деления полученного числа на 10 будет следующей цифрой числа P (количество десятков в числе P):
45 % 10 = 5.
Последнюю цифру числа P (количество сотен) можно найти так:
456 / 100 = 4.
Так как в задаче требовалось записать цифры числа P в обратном порядке, значит в новом числе будет 6 сотен, 5 десятков и 4 единицы:
S = 6*100 + 5*10 + 4 = 654.
Далее приведён текст программы, реализующей данную задачу для любого трехзначного числа.
#include <iostream> using namespace std; int main ( int argc, char *argv [ ] ) { unsigned int P, S; //Определение целочисленных переменных без знака . cout<<" P = "; //Вывод на экран символов P=. cin >>P; //Ввод заданного числа P. S=P%10*100+P/10%10*10+P/ 100; //Вычисление нового числа S . cout<<" S = "<<S<<endl; //Вывод на экран символов S= и значения переменной S . return 0; }
Задача 2.4. Пусть целочисленная переменная i и вещественная переменная d вводятся с клавиатуры. Определить размер памяти, отведённой для хранения этих переменных и их суммы, в байтах. Вычислить, сколько памяти будет выделено для хранения строки С Новым Годом!.Вывести на экран размеры различных типов данных языка С++ в байтах.
Далее приведён текст программы.
#include <iostream> using namespace std; int main ( ) { int i; //Определение целочисленной переменной . double d; //Определение вещественной переменной . cout<<" i = "; cin >>i; //Ввод переменной i . cout<<" d = "; cin >>d; //Ввод переменной d . //Размер памяти, отведённой под переменную i . cout<<" Размер i : "<< sizeof i <<" \ n "; //Размер памяти, отведённой под переменную d . cout<<" Размер d : "<< sizeof d<<" \ n "; //Размер памяти, отведённой под значение выражения i+d . cout<<" Размер i + d : "<< sizeof ( i+d )<<" \ n "; cout<<" Размер строки <С Новым Годом!>: "; //Размер памяти, отведённой под строку. cout<<sizeof " С Новым годом! "<<" \ n "; //Вычисление размеров различных типов данных: cout<<" Размер char : "<< sizeof ( char )<<" \ n "; cou<<" Размер int : "<< sizeof ( int )<<" \ n "; cout<<" Размер short int : "<< sizeof ( short int )<<" \ n "; cout<<" Размер long int : "<< sizeof ( long int )<<" \ n "; cout<<" Размер long long int : "; cout<<sizeof ( long long int )<<" \ n "; cout<<" Размер float : "<< sizeof ( float )<<" \ n "; cout<<" Размер double : "<< sizeof ( double )<<" \ n "; cout<<" Размер long double : "<<sizeof ( long double )<<" \ n "; return 0; }
Результаты работы программы2)
i= 23 d= 45.76 Размер i: 4 Размер d: 8 Размер i+d: 8 Размер <С Новым годом!>:26 Размер char: 1 Размер int: 4 Размер short int: 2 Размер long int: 4 Размер long long int:8 Размер float: 4 Размер double: 8 Размер long double: 12
2.10 Задачи для самостоятельного решения
2.10.1 Ввод-вывод данных. Операция присваивания.
Разработать программу на языке С++. Все входные и выходные данные в задачах — вещественные числа. Для ввода и вывода данных использовать функции scanf и printf.
- Даны катеты прямоугольного треугольника
и
. Найти гипотенузу
и углы треугольника
.
- Известна гипотенуза c и прилежащий угол _ прямоугольного треугольника. Найти площадь треугольника
и угол
.
- Известна диагональ квадрата
. Вычислить площадь
и периметр
квадрата.
- Дан диаметр окружности
. Найти длину окружности
и площадь круга
.
- Даны три числа —
. Найти среднее арифметическое и среднее геометрическое заданных чисел.
- Даны катеты прямоугольного треугольника
и
. Найти гипотенузу
и периметр
.
- Дана длина окружности
. Найти радиус окружности
и площадь круга
.
- Даны два ненулевых числа
и
. Найти сумму
, разность
, произведение
и частное
квадратов заданных чисел.
- Поменять местами содержимое переменных
и
и вывести новые значения
и
.
- Точки
и
заданы координатами на плоскости:
. Найти длину отрезка
.
- Заданы два катета прямоугольного треугольника
и
. Вычислить площадь
и периметр
.
- Даны переменные
. Изменить их значения, переместив содержимое
в
,
— в
,
— в
, и вывести новые значения переменных
.
- Известна диагональ ромба
. Вычислить площадь
и периметр
.
- Найти значение функции
и её производной при заданном значении
.
- Даны два ненулевых числа
и
. Найти сумму
, разность
, произведение
и частное
модулей заданных чисел.
- Известны координаты вершин квадрата
и
. Найти площадь
и периметр
.
- Даны длины сторон прямоугольника
и
. Найти площадь
и периметр
.
- Известно значение периметра
равностороннего треугольника. Вычислить площадь
.
- Задан периметр квадрата
. Вычислить сторону квадрата
, диагональ
и площадь
.
- Дана сторона квадрата
. Вычислить периметр квадрата
, его площадь
и длину диагонали
.
- Три точки заданы координатами на плоскости:
и
. Найти длины отрезков
и
.
- Даны переменные
. Изменить их значения, переместив содержимое
в
,
— в
,
— в
, и вывести новые значения переменных
.
- Даны числа —
. Найти их среднее арифметическое и среднее геометрическое значения.
- Найти значение функции
и её производной при заданном значении
.
- Точки
и
заданы координатами в пространстве:
. Найти длину отрезка
.
2.10.2 Операции целочисленной арифметики.
Разработать программу на языке С++. Все входные данные в задачах — целые числа. Для ввода и вывода данных использовать объектно-ориентированные средства ввода-вывода.
- Расстояние
задано в сантиметрах. Найти количество полных метров в нём и остаток в сантиметрах.
- Масса
задана в килограммах. Найти количество полных тонн в ней и остаток в килограммах.
- Размер файла
дан в байтах. Найти количество полных килобайтов, которые занимает данный файл и остаток в байтах.
- Дано двузначное число. Вывести на экран количество десятков и единиц в нём.
- Дано двузначное число. Найти сумму его цифр.
- Дано двузначное число. Найти произведение его цифр.
- Дано двузначное число. Вывести число, полученное при перестановке цифр исходного числа.
- Дано трехзначное число. Определить, сколько в нём единиц, десятков и сотен.
- Дано трехзначное число. Найти сумму его цифр.
- Дано трехзначное число. Найти произведение его цифр.
- Дано трехзначное число. Вывести число, полученное при перестановке цифр сотен и десятков исходного числа.
- Дано трехзначное число. Вывести число, полученное при перестановке цифр сотен и единиц исходного числа.
- Дано трехзначное число. Вывести число, полученное при перестановке цифр десятков и единиц исходного числа.
- С начала суток прошло
секунд. Найти количество полных минут, прошедших с начала суток и остаток в секундах.
- С начала суток прошло
секунд. Найти количество полных часов, прошедших с начала суток и остаток в секундах.
- Дано двузначное число. Найти сумму квадратов его цифр.
- Дано двузначное число. Найти квадрат разности его цифр.
- Расстояние
задано в метрах. Найти количество полных километров в нём и остаток в метрах.
- Масса
задана в граммах. Найти количество полных килограммов в ней и остаток в граммах.
- Размер файла
дан в килобайтах. Найти количество полных мегабайтов, которые занимает данный файл и остаток в килобайтах.
- Расстояние
задано в дециметрах. Найти количество полных метров в нём и остаток в сантиметрах.
- С начала года прошло
дней. Найти количество полных недель, прошедших с начала года и остаток в днях.
- С начала года прошло
часов. Найти количество полных дней, прошедших с начала года и остаток в часах.
- Дано трехзначное число. Найти сумму квадратов его цифр.
- Дано трехзначное число. Найти квадрат суммы его цифр.
2.10.3 Встроенные математические функции
Разработать программу на языке С++. Все входные и выходные данные в задачах — вещественные числа. Для ввода и вывода данных использовать функции scanf и printf
Вычислить значение выражения при заданном значении x. Варианты заданий представлены в табл. 2.12.
№ | Выражение ![]() |
---|---|
1 | ![]() |
2 | ![]() |
3 | ![]() |
4 | ![]() |
5 | ![]() |
6 | ![]() |
7 | ![]() |
8 | ![]() |
9 | ![]() |
10 | ![]() |
11 | ![]() |
12 | ![]() |
13 | ![]() |
14 | ![]() |
15 | ![]() |
16 | ![]() |
17 | ![]() |
18 | ![]() |
19 | ![]() |
20 | ![]() |
21 | ![]() |
22 | ![]() |
23 | ![]() |
24 | ![]() |
25 | ![]() |
Лекция 3. Операторы управления
3.1 Основные конструкции алгоритма
При разработке простейших программ несложно перейти от словесного описания к написанию программы. Однако большинство реально разрабатываемых программ довольно сложные и созданию программы предшествует разработка алгоритма1).Алгоритм — это чёткое описание последовательности действий, которые необходимо выполнить, для того чтобы при соответствующих исходных данных получить требуемый результат. Одним из способов представления алгоритма является блок-схема. При составлении блок-схемы все этапы решения задачи изображаются с помощью различных геометрических фигур. Эти фигуры называют блоками и, как правило, сопровождают надписями. Последовательность выполнения этапов указывают при помощи стрелок, соединяющих эти блоки. Типичные этапы решения задачи изображаются следующими геометрическими фигурами:
- блок начала-конца (рис. 3.1). Надпись внутри блока: "начало" ("конец");
- блок ввода-вывода данных (рис. 3.2). Надпись внутри блока: ввод (вывод или печать) и список вводимых (выводимых) переменных;
- блок решения или арифметический (рис. 3.3). Внутри блока записывается действие, вычислительная операция или группа операций;
- условный блок (рис. 3.4). Логическое условие записывается внутри блока. В результате проверки условия осуществляется выбор одного из возможных путей (ветвей) вычислительного процесса.

Рис. 3.1. Блок начала-конца алгоритма

Рис. 3.2. Блок ввода-вывода данных

Рис. 3.3. Арифметичёский блок

Рис. 3.4. Условный блок

Рис. 3.5. Линейный процесс

Рис. 3.6. Разветвляющийся процесс

Рис. 3.7. Циклический процесс
Рассмотренные блоки позволяют описать три основные конструкции алгоритма: линейный процесс, разветвляющийся процесс и циклический процесс.
Линейный процесс это конструкция, представляющая собой последовательное выполнение двух или более операторов (рис. 3.5). Разветвляющийся процесс задаёт выполнение одного или другого оператора в зависимости от выполнения условия (рис. 3.6). Циклический процесс задаёт многократное выполнение оператора или группы операторов (рис. 3.7).
Нетрудно заметить, что каждая из основных конструкций алгоритма имеет один вход и один выход. Это позволяет вкладывать конструкции друг в друга произвольным образом и составлять алгоритмы для решения задач любой сложности.
Одним из важных понятий при написании программ на С(С++) является понятие составного оператора.
3.2 Составной оператор
Составной оператор — это группа операторов, отделённых друг от друга точкой с запятой, начинающихся с открывающей фигурной скобки { и заканчивающихся закрывающейся фигурной скобкой }:
{ оператор_1; ... оператор_n; }
Транслятор воспринимает составной оператор как одно целое.
Рассмотрим операторы языка С++, реализующие основные конструкции алгоритма.
3.3 Условные операторы
Одна из основных конструкций алгоритма — разветвляющийся процесс. Он реализован в языке С++ двумя условными операторами: if и switch Рассмотрим каждый из них.
3.3.1 Условный оператор
При решении большинства задач порядок вычислений зависит от определённых условий, например, от исходных данных или от промежуточных результатов, полученных на предыдущих шагах программы. Для организации вычислений в зависимости от какого-либо условия в С++ предусмотрен условный оператор if, который в общем виде записывается следующим образом:
if (условие) оператор_1; else оператор_2;
где условие — это логическое (или целое) выражение, переменная или константа, оператор_1 и оператор_2 — любой оператор языка С(С++) .
Работает условный оператор следующим образом. Сначала вычисляется значение выражения, указанного в скобках. Если оно не равно нулю, т.е. имеет значение истина (true), выполняется оператор_1. В противном случае, когда выражение равно нулю, т.е. имеет значение ложь (false), выполняется оператор_2. Алгоритм, который реализован в условном операторе if, представлен на рис. 3.8.
Например, чтобы сравнить значения переменных a и b нужно написать следующий программный код:
cin>>a; cin>>b; if ( a==b) cout<<" a равно b "; else cout<<" a не равно b ";
Внимание! Не путайте знак проверки равенства == и оператор присваивания =. Например, в записи if (a=0) b=1; синтаксической ошибки нет. Операция присваивания a=0 формирует результат и его значение проверяется в качестве условия. В данном примере присваивание b=1 не будет выполнено никогда, так как переменная a всегда будет принимать значение равное нулю, то есть ложь. Верная запись: if (a==0) b=1;.

Рис. 3.8. Алгоритм условного оператора if ... else

Рис. 3.9. Алгоритм условного оператора if
Внимание! Если в задаче требуется, чтобы в зависимости от значения условия выполнялся не один оператор, а несколько, их необходимо заключать в фигурные скобки, как составной оператор. В этом случае компилятор воспримет группу операторов как один:
if ( условие ) { оператор_1; оператор_2; ... } else { оператор_3; оператор_4; ... }
Альтернативная ветвь else в условном операторе может отсутствовать, если в ней нет необходимости:
if ( условие ) оператор; или if ( условие ) { оператор_1; оператор_2; ... }
В таком "усечённом" виде условный оператор работает так: оператор (группа операторов) либо выполняется, либо пропускается, в зависимости от значения выражения, представляющего условие. Алгоритм этого условного процесса представлен на рис. 3.9.
Пример применения условного оператора без альтернативной ветви else может быть таким:
cin>>a; cin>>b; c =0; //Значение переменной c изменяется только при условии, что a не равно b if ( a!=b) c=a+b; cout<<" c = "<<c;
Условные операторы могут быть вложены друг в друга. При вложениях условных операторов всегда действует правило: альтернатива else считается принадлежащей ближайшему if. Например, в записи
if (условие_1) if (условие_2) оператор_А; else оператор_Б;
оператор_Б относится к условию_2, а в конструкции
if (условие_1) { if (условие_2) оператор_А; } else оператор_Б;
он принадлежит оператору if с условием_1.
Рассмотрим несколько задач с применением условных процессов.
Задача 3.1. Дано вещественное число . Для функции, график которой приведён на рис. 3.10, вычислить
.

Рис. 3.10. Графическое представление задачи 3.1
Аналитически функцию, представленную на рис. 3.10, можно записать так:

Составим словесный алгоритм решения этой задачи:
- Начало алгоритма.
- Ввод числа
(аргумент функции).
- Если значение
меньше либо равно -2, то переход к п. 4, иначе переход к п. 5.
- Вычисление значения функции:
, переход к п. 8.
- Если значение
больше либо равно 1, то переход к п. 6, иначе переход к п. 7.
- Вычисление значения функции:
, переход к п. 8.
- Вычисление значения функции:
.
- Вывод значений аргумента
и функции
.
- Конец алгоритма.
Блок-схема, соответствующая описанному алгоритму, представлена на рис. 3.11.

Рис. 3.11. Блок-схема алгоритма решения задачи 3.1
Текст программы на языке C++ будет иметь вид:
#include <iostream> using namespace std; int main ( ) { float X,Y; cout<<" X = "; cin >>X; if (X<=_2) Y=4; else i f (X>=1) Y=1; else Y=X*X; cout <<" Y = " <<Y<< endl; return 0; }
Задача 3.2. Даны вещественные числа и
. Определить, принадлежит ли точка с координатами (
) заштрихованной области (рис. 3.12).

Рис. 3.12. Графическое представление задачи 3.2

Рис. 3.13. Алгоритм решения задачи 3.2
Как показано на рис. 3.12, область ограничена линиями и
. Значит точка с координатами (
) будет принадлежать этой области, если будут выполняться следующие условия:
и
. Иначе точка лежит за пределами области.
Блок-схема, описывающая алгоритм решения данной задачи, представлена на рис. 3.13.
Текст программы к задаче 3.2:
#include <iostream> using namespace std; int main ( ) { float X,Y; cout<<" X = "; cin >>X; cout<<" Y = "; cin >>Y; if (X>=-1 && X<=3 && Y>=-2 && Y<=4) cout <<"Точка принадлежит области"<< endl; else cout<<"Точка не принадлежит области"<<endl; return 0; }
Задача 3.3. Даны вещественные числа и
. Определить, принадлежит ли точка с координатами (
) заштрихованной области (рис. 3.14).
Составим уравнения линий, ограничивающих заданные области. В общем виде уравнение прямой, проходящей через точки с координатами () и (
), имеет вид:


Рис. 3.14. Графическое представление задачи 3.3
Треугольник в первой координатной области ограничен линиями, проходящими через точки:
- (0, 1) - (4, 3);
- (4, 3) - (5, 1);
- (5, 1) - (0, 1).
Следовательно, уравнение первой линии:

уравнение второй линии:

и уравнение третьей линии: .
Линии, которые формируют треугольник во второй координатной области, проходят через точки:
- (0, 1) - (-4, 3);
- (-4, 3) - (-5, 1);
- (-5, 1) - (0, 1);
Следовательно, уравнение первой линии:

уравнение второй линии:

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

Далее приведён текст программы для решения задачи 3.3.
#include <iostream> using namespace std; int main ( ) { float X,Y; cout<<" X = "; cin >>X; cout<<" Y = "; cin >>Y; if ( (Y<=1+( float ) 1/2 *X && Y<=-2*X+11 && Y>=1) | | (Y<=1-( float ) 1/2 *X && Y<=2*X+11 && Y>=1)) cout <<"Точка принадлежит области"<< endl; else cout<<"Точка не принадлежит области"<< endl; return 0; }
Задача 3.4. Написать программу решения квадратного уравнения .
Исходные данные: вещественные числа и
— коэффициенты квадратного уравнения.
Результаты работы программы: вещественные числа и
— корни квадратного уравнения либо сообщение о том, что корней нет.
Вспомогательные переменные: вещественная переменная , в которой будет храниться дискриминант квадратного уравнения.
Составим словесный алгоритм решения этой задачи.
- Начало алгоритма.
- Ввод числовых значений переменных
и
.
- Вычисление значения дискриминанта
по формуле
.
- Если
, то переход к п.5, иначе переход к п.6.
- Вывод сообщения "Действительных корней нет" и переход к п.8.
- Вычисление корней
и
.
- Вывод значений
и
на экран.
- Конец алгоритма.
Блок-схема, соответствующая этому описанию, представлена на рис. 3.15.
Текст программы, которая реализует решение квадратного уравнения:
#include <iostream> #include <math.h> using namespace std; int main ( ) { float a, b, c, d, x1, x2; //Ввод значений коэффициентов квадратного уравнения. cout<<" a = "; cin >>a; cout<<" b = "; cin >>b; cout<<" c = "; cin >>c; d=b*b-4*a*c; //Вычисление дискриминанта. if (d<0) //Если дискриминант отрицательный, то вывод сообщения, о том что действительных корней нет, cout<<"Нет действительных корней"; else { //иначе вычисление действительных корней x1=( -b+sqrt (d) ) /2/a; x2=( -b-sqrt (d) ) /(2 * a); //и вывод их значений. cout<<" X1 = "<<x1<<" \t X2 = "<<x2<<" \n "; } return 0; }

Рис. 3.15. Алгоритм решения квадратного уравнения
Задача 3.5. Составить программу нахождения действительных и комплексных корней квадратного уравнения .
Исходные данные: вещественные числа a, b и c — коэффициенты квадратного уравнения.
Результаты работы программы: вещественные числа и
— действительные корни квадратного уравнения либо
и
— действительная и мнимая части комплексных корней квадратного уравнения.
Вспомогательные переменные: вещественная переменная , в которой будет храниться дискриминант квадратного уравнения.
Можно выделить следующие этапы решения задачи:
- Ввод коэффициентов квадратного уравнения
и
.
- Вычисление дискриминанта
по формуле
.
- Проверка знака дискриминанта. Если
, то вычисление действительных корней:
и
и вывод их на экран. При отрицательном дискриминанте выводится сообщение о том, что действительных корней нет, и вычисляются комплексные корни1)
.
У обоих комплексных корней действительные части одинаковые, а мнимые отличаются знаком. Поэтому можно в переменной хранить действительную часть числа
, в переменной
— модуль мнимой части
, а в качестве корней вывести
и
.
На рис. 3.16 изображена блок-схема решения задачи. Блок 1 предназначен для ввода коэффициентов квадратного уравнения. В блоке 2 осуществляется вычисление дискриминанта. Блок 3 осуществляет проверку знака дискриминанта, если дискриминант отрицателен, то корни комплексные, их расчёт происходит в блоке 4 (действительная часть корня записывается в переменную , модуль мнимой — в переменную
), а вывод — в блоке 5 (первый корень
, второй —
). Если дискриминант положителен, то вычисляются действительные корни уравнения (блок 6) и выводятся на экран (блок 7).
Текст программы, реализующей поставленную задачу:
#include <iostream> #include <math.h> using namespace std; int main ( ) { float a, b, c, d, x1, x2; cout<<" a = "; cin>>a; cout<<" b = "; cin>>b; cout<<" c = "; cin>>c; d=b*b-4*a*c; if (d<0) { //Если дискриминант отрицательный, то вывод соответствующего сообщения. cout<<"Нет вещественных корней \n "; x1=-b/(2 * a ); //Вычисление действительной части комплексных корней. x2=sqrt ( fabs (d) ) /(2 * a ); //Вычисление модуля мнимой части комплексных корней //Сообщение о комплексных корнях уравнения вида ax2 + bx + c = 0. cout<<"Комплексные корни уравнения \n "; cout<<a<<" x ^2+ "<<b<<" x + "<<c<<" =0 \n "; //Вывод значений комплексных корней в виде x1 + ix2, x1 - ix2 if ( x2>=0) { cout<<x1<<" + "<<x2<<" i \t "; cout<<x1<<" -"<<x2<<" i \n "; } else { cout<<x1<<" -"<<abs ( x2 )<<" i \t "; cout<<x1<<" + "<<abs ( x2 )<<" i \n "; } } else { //Если дискриминант положительный, вычисление действительных корней и вывод их на экран. x1=( -b+sqrt (d) ) /2/a; x2=( -b- sqrt (d) ) /(2 * a ); cout<<"Вещественные корни уравнения \n "; cout<<a<<" x ^2+ "<<b<<" x + "<<c<<" =0 \n "; cout<< X1 = "<<x1<<" \t X2 = "<<x2<<" \n "; } return 0; }

Рис. 3.16. Алгоритм решения задачи 3.5
Результаты работы программы к задаче 3.5 показаны ниже.
a=-5 b=-3 c=-4 Нет вещественных корней Комплексные корни уравнения -5x^2+-3x+-4=0 -0.3-0.842615i -0.3+0.842615i ============================== a=2 b=-3 c=1 Вещественные корни уравнения 2x^2+-3x+1=0 X1=1 X2=0.5
Задача 3.6. Составить программу для решения кубического уравнения .
Кубическое уравнение имеет вид
![]() | (3.1) |
После деления на a уравнение 3.1 принимает канонический вид:
![]() | (3.2) |
где .
В уравнении 3.2 сделаем замену и получим приведённое уравнение:
![]() | (3.3) |
где .
Число действительных корней приведённого уравнения (3.3) зависит от знака дискриминанта (табл. 3.1) .
Дискриминант | Количество действительных корней | Количество комплексных корней |
---|---|---|
![]() | 1 | 2 |
![]() | 3 | - |
Корни приведённого уравнения могут быть рассчитаны по формулам Кардано:
![]() | (3.4) |
где .
При отрицательном дискриминанте уравнение (3.1) имеет три действительных корня, но они будут вычисляться через вспомогательные комплексные величины. Чтобы избавиться от этого, можно воспользоваться формулами:
![]() | (3.5) |
где .
Таким образом, при положительном дискриминанте кубического уравнения (3.3) расчёт корней будем вести по формулам (3.4), а при отрицательном — по формулам (3.5). После расчёта корней приведённого уравнения (3.3) по формулам (3.4) или (3.5), необходимо по формулам

перейти к корням заданного кубического уравнения (3.1).
Блок-схема решения кубического уравнения представлена на рис. 3.18.
Описание блок-схемы. В блоке 1 вводятся коэффициенты кубического уравнения, в блоках 2–3 рассчитываются коэффициенты канонического и приведённого уравнений. Блок 4 предназначен для вычисления дискриминанта. В блоке 5 проверяется знак дискриминанта кубического уравнения. Если он отрицателен, то корни вычисляются по формулам 3.5 (блоки 6–7). При положительном значении дискриминанта расчёт идёт по формулам 3.4 (блок 9, 10). Блоки 8 и 11 предназначены для вывода результатов на экран.
Текст программы с комментариями приведён ниже1).
#include <iostream> #include <math.h> using namespace std; #define pi 3.14159 //Определение константы int main ( ) { float a, b, c, d,D, r, s, t, p, q, ro, fi, x1, x2, x3, u, v, h, g; //Ввод коэффициентов кубического уравнения. cout<<" a = "; cin >>a; cout<<" b = "; cin >>b; cout<<" c = "; cin >>c; cout<<" d = "; cin >>d; //Расчёт коэффициентов канонического уравнения по формуле 3.2 r=b/a; s=c /a; t=d/a; //Вычисление коэффициентов приведённого уравнения по формуле 3.3 p=(3*s -r * r ) / 3; q=2* r* r * r /27 - r * s/3+t; //Вычисление дискриминанта кубического уравнения D=(p /3) * ( p /3) * ( p /3) +(q /2) * ( q /2); if (D<0) { //Формулы 3.5 ro=sqrt ( ( float )( -p* p* p/27) ); fi=-q /(2 * ro ); fi=pi/2 - atan ( fi / sqrt (1 - fi * f i ) ); x1=2*pow( ro, ( float ) 1/3) * cos ( f i /3)- r /3; x2=2*pow( ro, ( float ) 1/3) * cos ( f i /3+2* pi /3)- r /3; x3=2*pow( ro, ( float ) 1/3) * cos ( f i /3+4* pi /3)- r /3; cout<<" \n x1 = "<<x1<<" \t x2 = "<<x2; cout<<" \t x3 = "<<x3<<" \n "; } else { //Формулы 3.4 if ( -q/2+sqrt (D) >0) u=pow(( - q/2+sqrt (D) ),( float ) 1/3); else if ( -q/2+sqrt (D) <0) u=-pow( fabs( -q/2+sqrt (D) ),( float ) 1/3); else u=0; if (-q/2 - sqrt (D) >0) v=pow(( -q/2 - sqrt (D) ),( float ) 1/3); else if ( -q/2 - sqrt (D) <0) v=-pow( fabs( -q/2 - sqrt (D) ),( float ) 1/3); else v=0; x1=u+v-r /3; //Вычисление действительного корня кубического уравнения. h= -(u+v)/2 - r /3; //Вычисление действительной g=(u-v) /2 -sqrt (( float ) 3); //и мнимой части комплексных корней cout<<" \ n x1 = "<<x1; if (x2>=0) { cout<<x1<<" + "<<x2<<" i \t "; cout<<x1<<" -"<<x2<<" i \n "; } else { cout<<x1<<" -"<<fabs ( x2 )<<" i \t "; cout<<x1<<" + "<<fabs ( x2 )<<" i \n "; } } if (g>=0) { cout<<" \t x2 = "<<h<<" + "<<g<<" i "; cout<<" \t x3 = "<<h<<" -"<<g<<" i \n "; } else { cout<<" \t x2 = "<<h<<" -"<<fabs (g)<<" i "; cout<<" \t x2 = "<<h<<" + "<<fabs (g)<<" i "; } return 0; }

Рис. 3.17. Алгоритм решения кубического уравнения
Задача 3.7. Заданы коэффициенты и
биквадратного уравнения
. Найти все его действительные корни.
Входные данные: .
Выходные данные: .
Для решения биквадратного уравнения необходимо заменой привести его к квадратному уравнению
и решить это уравнение.
Опишем алгоритм решения этой задачи (рис. 3.18):
- Ввод коэффициентов биквадратного уравнения
и
(блок 1).
- Вычисление дискриминанта уравнения
(блок 2).
- Если d < 0 (блок 3), вывод сообщения, что корней нет (блок 4), а иначе определяются корни соответствующего квадратного уравнения y1 и y2(блок 5).
- Если y1 < 0 и y2 < 0 (блок 6), то вывод сообщения, что корней нет (блок 7).
- Если y1 >= 0 и y2 >= 0 (блок 8), то вычисляются четыре корня по формулам
(блок 9) и выводятся значения корней (блок 10).
- Если условия 4) и 5) не выполняются, то необходимо проверить знак y1. Если y1 >= 0 (блок 11), то вычисляются два корня по формуле
(блок 12), иначе (если y2 >= 0) вычисляются два корня по формуле
(блок 13). Вывод вычисленных значений корней (блок 14).

увеличить изображение
Рис. 3.18. Алгоритм решения биквадратного уравнения
Текст программы решения биквадратного уравнения приведён ниже.
Внимание! Если в условном операторе проверяется двойное условие, необходимо применять логические операции ||, &&, !.Например, условие "если y1 и y2 положительны" правильно записать так: if (y1>=0 && y2>=0).
#include <iostream> #include <math.h> using namespace std; int main ( ) { //Описание переменных: //a, b, c - коэффициенты биквадратного уравнения, //d - дискриминант, // x1, x2, x3, x4 - корни биквадратного уравнения, //y1, y2 - корни квадратного уравнения ay^2+by+c =0, float a, b, c, d, x1, x2, x3, x4, y1, y2; //Ввод коэффициентов уравнения. cout<<" a = "; cin >>a; cout<<" b = "; cin >>b; cout<<" c = "; cin >>c; d=b* b-4*a*c; //Вычисление дискриминанта. if ( d<0) //Если дискриминант отрицательный, вывод сообщения "Корней нет". cout<<" Нет действительных корней \ n "; else //Если дискриминант положительный, { //Вычисление корней соответствующего квадратного уравнения . y1=( -b+sqrt ( d ) ) /2/ a; y2=( -b- sqrt ( d ) ) /(2 * a ); //Если оба корня квадратного уравнения отрицательные, if ( y1<0 && y2<0) //вывод сообщения "Корней нет" cout<<" Нет действительных корней \ n "; //Если оба корня квадратного уравнения положительные, else if ( y1>=0 && y2>=0) { //Вычисление четырёх корней биквадратного уравнения x1=sqrt ( y1 ); x2=-x1; x3=sqrt ( y2 ); x4=- sqrt ( y2 ); //Вывод корней уравнения на экран . cout<<" \t X1 = "<<x1<<" \t X2 = "<<x2; cout<<" \t X3 = "<<x3<<" \t X4 = "<<x4<<" \n "; } //Если не выполнились условия // 1.y1<0 и y2<0 // 2.y1>=0 и y2>=0, //то проверяем условие y1>=0. else if ( y1>=0) //Если оно истинно { //вычисляем два корня биквадратного уравнения. x1=sqrt ( y1 ); x2=-x1; cout<<" X1 = "<<x1<<" \t X2 = "<<x2<<" \n "; } else { //Если условие y1>=0 ложно, то вычисляем два корня биквадратного уравнения x1=sqrt ( y2 ); x2=-x1; cout<<" X1 = "<<x1<<" \t X2 = "<<x2<<" \n "; } } return 0; }
Читателю предлагается самостоятельно модифицировать программу таким образом, чтобы она находила все корни (как действительные, так и комплексные) биквадратного уравнения.
3.3.2 Оператор варианта
Оператор варианта switch необходим в тех случаях, когда в зависимости от значений какой-либо переменной надо выполнить те или иные операторы:
switch (выражение) { case значение_1: Операторы_1; break; case значение_2: Операторы_2; break; case значение_3: Операторы_3; break; ... case значение_n: Операторы_n; break; default : Операторы; break; }
Оператор работает следующим образом. Вычисляется значение выражения (оно должно быть целочисленным). Если выражение принимает значение_1, то выполняются операторы_1. Если выражение принимает значение_2, то выполняется операторы_2 и так далее. Если выражение не принимает ни одно из значений, то выполняются операторы, расположенные после ключевого слова default.
Альтернативная ветвь default может отсутствовать, тогда оператор имеет вид:
switch (выражение) { case значение_1: Операторы_1; break; case значение_2: Операторы_2; break; case значение_3: Операторы_3; break; ... case значение_n: Операторы_n; break; }
Оператор break необходим для того, чтобы осуществить выход из оператора switch. Если оператор break не указан, то будут выполняться следующие операторы из списка, несмотря на то, что значение, которым они помечены, не совпадает со значением выражения.
Рассмотрим применение оператора варианта.
Задача 3.8. Вывести на печать название дня недели, соответствующее заданному числу , при условии, что в месяце 31 день и 1-е число — понедельник.
Для решения задачи воспользуемся операцией %, позволяющей вычислить остаток от деления двух чисел, и условием, что 1-е число — понедельник. Если в результате остаток от деления (обозначим его ) заданного числа
на семь будет равен единице, то это понедельник, двойке — вторник, тройке — среда и так далее. Следовательно, при построении алгоритма необходимо использовать семь условных операторов, как показано рис. 3.19. Решение задачи станет значительно проще, если при написании программы воспользоваться оператором варианта switch:
#include <iostream> using namespace std; int main ( ) { unsigned int D,R; //Описаны целые положительные числа. cout<<" D = "; cin>>D; //Ввод числа от 1 до 31. R=D%7; switch (R) { case 1 : cout<<" Понедельник \n "; break; case 2 : cout<<" Вторник \n "; break; case 3 : cout<<" Среда \n "; break; case 4 : cout<<" Четверг \n "; break; case 5 : cout<<" Пятница \n "; break; case 6 : cout<<" Суббота \n "; break; case 0 : cout<<" Воскресенье \n "; break; } return 0; }
В предложенной записи оператора варианта отсутствует ветвь default. Это объясняется тем, что переменная может принимать только одно из указанных значений, т.е. 1, 2, 3, 4, 5, 6 или 0. Однако программа будет работать неправильно, если пользователь введёт значение
, превышающее 31. Чтобы избежать подобной ошибки лучше сделать дополнительную проверку входных данных:
#include <iostream> using namespace std; int main ( ) { unsigned int D,R; cout<<" \ n D = "; cin >>D; if (D<32) //Проверка введённого значения. { R=D%7; switch (R) { case 1 : cout<<" Понедельник \n "; break; case 2 : cout<<" Вторник \n "; break; case 3 : cout<<" Среда \n "; break; case 4 : cout<<" Четверг \n "; break; case 5 : cout<<" Пятница \n "; break; case 6 : cout<<" Суббота \n "; break; case 0 : cout<<" Воскресенье \n "; break; } } //Сообщение об ошибке в случае некорректного ввода. else cout<<" ОШИБКА! \n "; return 0; }

увеличить изображение
Рис. 3.19. Алгоритм решения задачи 3.8
Задача 3.9. По заданному номеру месяца вывести на экран его название.
Для решения данной задачи необходимо проверить выполнение двенадцати условий. Если равно единице, то это январь, если двойке, то февраль, тройке — март и так далее. Понятно, что область возможных значений переменной
находится в диапазоне от 1 до 12 и если пользователь введёт число не входящее в этот интервал, то появится сообщение об ошибке.
#include <iostream> using namespace std; int main ( ) { unsigned int m; //Описано целое положительное число. cout<<" m = "; cin >>m; switch (m) { //В зависимости от значения m выводится название месяца. case 1 : cout<<" Январь \n "; break; case 2 : cout<<" Февраль \n "; break; case 3 : cout<<" Март \n "; break; case 4 : cout<<" Апрель \n "; break; case 5 : cout<<" Май \n "; break; case 6 : cout<<" Июнь \n "; break; case 7 : cout<<" Июль \n "; break; case 8 : cout<<" Август \n "; break; case 9 : cout<<" Сентябрь \n "; break; case 1 0 : cout<<" Октябрь \n "; break; case 1 1 : cout<<" Ноябрь \n "; break; case 1 2 : cout<<" Декабрь \n "; break; //Если значение переменной m выходит за пределы области //допустимых значений, то выдаётся сообщение. default : cout<<" ОШИБКА! \n "; break; } return 0; }
3.4 Операторы цикла
Циклический процесс или просто цикл это повторение одних и тех же действий. Последовательность действий, которые повторяются в цикле, называют телом цикла. Один проход цикла называют шагом или итерацией. Переменные, которые изменяются внутри цикла и влияют на его окончание, называются параметрами цикла.
При написании циклических алгоритмов следует помнить следующее. Во- первых, чтобы цикл имел шанс когда-нибудь закончиться, содержимое его тела должно обязательно влиять на условие цикла. Во-вторых, условие должно состоять из корректных выражений и значений, определённых ещё до первого выполнения тела цикла.
В С++ для удобства пользователя предусмотрены три оператора, реализующих циклический процесс: while, do...while и for.
3.4.1 Оператор цикла с предусловием
На рис. 3.20 изображена блок-схема алгоритма цикла с предусловием. Оператор, реализующий этот алгоритм в С++, имеет вид:
while (условие) оператор;
здесь условие — логическое или целочисленное выражение, оператор — любой оператор языка С(С++) .

Рис. 3.20. Алгоритм циклической структуры с предусловием
Работает цикл с предусловием следующим образом. Вычисляется условие. Если оно истинно (не равно нулю), то выполняется оператор, и условие проверяется вновь. В противном случае цикл заканчивается, и управление передаётся оператору, следующему за телом цикла. Условие вычисляется перед каждой итерацией цикла. Если при первой проверке выражение равно нулю, цикл не выполнится ни разу. Тип выражения должен быть арифметическим или приводимым к нему.
Если тело цикла состоит более чем из одного оператора, необходимо использовать составной оператор:
while (условие) { оператор 1; оператор 2; ... оператор n; }
Рассмотрим пример. Пусть необходимо вывести на экран таблицу значений функции на отрезке [0; π] с шагом 0.1. Применив цикл с предусловием, получим:
#include <stdio.h> #include <math.h> #define PI 3.14159 using namespace std; int main ( ) { float x, y; //Описание переменных x=0; //Присваивание параметру цикла стартового значения //Цикл с предусловием while (x<=PI ) //Пока параметр цикла не превышает конечное значение { //выполнять тело цикла y=exp ( sin ( x ) ) * cos ( x ); //Вычислить значение y //Вывод на экран пары x и y . printf ( " \t x =%5.2 f \t y =%5.4 f \n ",x, y ); x+=0.1; //Изменение параметра цикла // (переход к следующему значению x ) } //Конец цикла return 0; }
В результате работы данного фрагмента программы на экран последовательно будут выводиться сообщения со значениями переменных и
:
x= 1.00 y=1.2534 x= 2.10 y=-1.1969 x= 1.10 y=1.1059 x= 2.20 y=-1.3209 x= 1.20 y=0.9203 x= 2.30 y=-1.4045 x= 1.30 y=0.7011 x= 2.40 y=-1.4489 x= 1.40 y=0.4553 x= 2.50 y=-1.4576 x= 1.50 y=0.1918 x= 2.60 y=-1.4348 x= 1.60 y=-0.0793 x= 2.70 y=-1.3862 x= 1.70 y=-0.3473 x= 2.80 y=-1.3172 x= 1.80 y=-0.6017 x= 2.90 y=-1.2334 x= 1.90 y=-0.8328 x= 3.00 y=-1.1400 x= 2.00 y=-1.0331 x= 3.10 y=-1.0416Пример 1.1. (html, txt)
3.4.2 Оператор цикла с постусловием
В цикле с предусловием предварительной проверкой определяется, выполнять тело цикла или нет, до первой итерации. Если это не соответствует логике алгоритма, то можно использовать цикл с постусловием. На рис. 3.21 видно, что в этом цикле проверяется, делать или нет очередную итерацию, лишь после завершения предыдущей. Это имеет принципиальное значение лишь на первом шаге, а далее циклы ведут себя идентично.

Рис. 3.21. Алгоритм циклической структуры с постусловием
В С++ цикл с постусловием реализован конструкцией
do оператор while (условие);
здесь условие — логическое или целочисленное выражение, оператор — любой оператор языка С(С++). Если тело цикла состоит более чем из одного оператора:
do { оператор_1; оператор_2; ... оператор_n; } while (условие);
Работает цикл следующим образом. В начале выполняется оператор, представляющий собой тело цикла. Затем вычисляется условие. Если оно истинно (не равно нулю), оператор тела цикла выполняется ещё раз. В противном случае цикл завершается, и управление передаётся оператору, следующему за циклом.
Таким образом, не трудно заметить, что цикл с постусловием всегда будет выполнен хотя бы один раз, в отличие от цикла с предусловием, который может не выполниться ни разу.
Если применить цикл с постусловием для создания программы, которая выводит таблицу значений функции на отрезке [0; π] с шагом 0.1, получим:
#include <iostream> #include <stdio.h> #include <math.h> #define PI 3.14159 using namespace std; int main ( ) { float x, y; //Описание переменных x=0; //Присваивание параметру цикла стартового значения do //Цикл с постусловием { //Выполнять тело цикла y=exp ( sin ( x ) ) * cos ( x ); printf ( " \t x =%5.2 f \t y =%5.4 f \n ",x, y ); x+=0.1; //Изменение параметра цикла } while (x<=PI ); //пока параметр цикла не превышает конечное значение return 0; }
Результаты работы этой программы будут такими.
3.4.3 Оператор цикла for с параметром
Кроме того, в С++ предусмотрен цикл for с параметром:
for (начальные_присваивания;условие;последействие) оператор;
где начальные_присваивания — оператор или группа операторов, разделённых запятой1), применяются для присвоения начальных значений величинам, используемым в цикле, в том числе параметру цикла, и выполняются один раз в начале цикла; условие — целое или логическое выражение, которое определяет условие входа в цикл, если условие истинно (не равно нулю), то цикл выполняется; последействие — оператор или группа операторов, разделённых запятой, которые выполняются после каждой итерации и служат для изменения параметра цикла; оператор — любой оператор языка, представляющий собой тело цикла. Последействие или оператор должны влиять на условие, иначе цикл никогда не закончится. Начальные_присваивания, выражение или последействие в записи оператора for могут отсутствовать, но при этом "точки с запятой" должны оставаться на своих местах. Опишем алгоритм работы цикла for:
- Выполняются начальные_присваивания.
- Вычисляется условие, если оно не равно 0 (true), то выполняется переход к п.3. В противном случае выполнение цикла завершается.
- Выполняется оператор.
- Выполняется оператор последействие и осуществляется переход к п.2, опять вычисляется значение выражения и т.д.
Понятно, что этот алгоритм представляет собой цикл с предусловием (рис. 3.22).

Рис. 3.22. Алгоритм работы цикла с параметром
В дальнейшем, чтобы избежать создания слишком громоздких алгоритмов, в блок-схемах цикл for будем изображать, так как показано на рис. 3.23.
В случае если тело цикла состоит более чем из одного оператора, необходимо использовать составной оператор:
for (начальные_присваивания; условие; последействие) { оператор_1; ... оператор_n; }
Применение цикла for рассмотрим на примере печати таблицы значений функции на отрезке [0;π] с шагом 0.1:
#include <stdio.h> #include <math.h> #define PI 3.14159 using namespace std; int main ( ) { float x, y; //Параметру цикла присваивается начальное значение, если оно не превышает конечное значение, //то выполняются операторы тела цикла и значение параметра изменяется, в противном случае //цикл заканчивается. for ( x=0;x<=PI; x+=0.1) { y=exp ( sin ( x ) ) * cos ( x ); printf ( " \t x =%5.2 f \t y =%5.4 f \n ", x, y ); } return 0; }

Рис. 3.23. Блок-схема цикла с параметром
Программный код выдаст результат.
3.4.4 Операторы передачи управления
Операторы передачи управления принудительно изменяют порядок выполнения команд. В С++ таких операторов четыре: goto, break, continue и return.
Оператор goto метка, где метка обычный идентификатор, применяют для безусловного перехода, он передаёт управление оператору с меткой: метка: оператор;2).
Оператор break осуществляет немедленный выход из циклов while, do... while и for, а так же из оператора выбора switch. Управление передаётся оператору, находящемуся непосредственно за циклом или оператором выбора.
Оператор continue начинает новую итерацию цикла, даже если предыдущая не была завершена.
Оператор return выражение завершает выполнение функции и передаёт управление в точку её вызова. Если функция возвращает значение типа void, то выражение в записи оператора отсутствует. В противном случае выражение должно иметь скалярный тип.
3.5 Решение задач с использованием циклов
Рассмотрим использование циклических операторов на конкретных примерах.
Задача 3.10. Написать программу решения квадратного уравнения . Предусмотреть проверку ввода данных.
Решение квадратного уравнения было подробно рассмотрено в задаче 3.4. Однако алгоритм, изображённый на рис. 3.15, не будет работать, если пользователь введёт нулевое значение в переменную a (при попытке вычислить корни уравнения произойдёт деление на ноль). Чтобы избежать подобной ошибки нужно в программе предусмотреть проверку входных данных, например, так как показано на рис. 3.24. Вводится значение переменной a, если оно равно нулю, то ввод повторяется, иначе следует алгоритм вычисления корней квадратного уравнения. Здесь применяется цикл с постусловием, так как значение переменной необходимо ввести, а затем проверить его на равенство нулю.

Рис. 3.24. Блок-схема проверки ввода данных
Программа решения задачи:
#include <iostream> #include <math.h> using namespace std; int main ( ) { float a, b, c, d, x1, x2; //Проверка ввода значения коэффициента a . do //Выполнять тело цикла пока а равно нулю { cout<<" a = "; cin >>a; } while ( a==0); cout<<" b = "; cin >>b; cout<<" c = "; cin >>c; d=b* b-4*a*c; if (d<0) cout<<" Нет вещественных корней"; else { x1=( -b+sqrt (d) ) /2/a; x2=( -b- sqrt (d) ) /(2 *a ); cout<<" X1 = "<<x1<<" \t X2 = "<<x2<<" \n "; } return 0; }
Задача 3.11. Найти наибольший общий делитель (НОД) натуральных чисел и
.
Входные данные: и
.
Выходные данные: — НОД.
Для решения поставленной задачи воспользуемся алгоритмом Евклида: будем уменьшать каждый раз большее из чисел на величину меньшего до тех пор, пока оба значения не станут равными, так, как показано в табл. 3.2.
Шаг | A | B |
---|---|---|
Исходные данные | 25 | 15 |
Шаг 1 | 10 | 15 |
Шаг 2 | 10 | 5 |
Шаг 3, НОД | 5 | 5 |
В блок–схеме, представленной на рис. 3.25, для решения поставленной задачи используется цикл с предусловием, то есть тело цикла повторяется до тех пор, пока не равно
. Следовательно, при создании программы воспользуемся циклом while:
#include <iostream> using namespace std; int main ( ) { unsigned int a, b; cout<<" A = "; cin>>a; cout<<" B = "; cin>>b; //Если числа не равны, выполнять тело цикла while ( a!=b) //Если число A больше, чем B, то уменьшить его значение на B, if ( a>b) a=a-b; //иначе уменьшить значение числа B на A else b=b-a; cout<<" НОД= "<<a<<" \n "; return 0; }
Результат работы программы не изменится, если для её решения воспользоваться циклом с постусловием do...while:
#include <iostream> using namespace std; int main ( ) { unsigned int a, b; cout<<" A = "; cin >>a; cout<<" B = "; cin >>b; do if ( a>b ) a=a-b; else b=b-a; while ( a !=b ); cout<<" НОД= "<<a<<" \n "; return 0; }

Рис. 3.25. Поиск наибольшего общего делителя двух чисел.
Задача 3.12. Вычислить факториал числа .
Входные данные: — целое число, факториал которого необходимо вычислить.
Выходные данные: factorial — целое число, значение факториала числа , произведение чисел от 1 до
.
Промежуточные переменные: — параметр цикла, целочисленная переменная, последовательно принимающая значения 2, 3, 4 и так далее до
.
Блок-схема приведена на рис. 3.26.
Итак, вводится число . Переменной factorial, предназначенной для хранения значения произведения последовательности чисел, присваивается начальное значение, равное единице. Затем организуется цикл, параметром которого выступает переменная
. Если значение параметра цикла не превышает
, то выполняется оператор тела цикла, в котором из участка памяти с именем factorial считывается предыдущее значение произведения, умножается на текущее значение параметра цикла, а результат снова помещается в участок памяти с именем factorial. Когда параметр
превысит
, цикл заканчивается, и на экран выводится значение переменой factorial, которая была вычислена в теле цикла.

Рис. 3.26. Алгоритм вычисления факториала.
Обратите внимание, как в программе записан оператор цикла. Здесь операторы ввода и операторы присваивания стартовых значений записаны как начальные присваивания цикла for, а оператор накапливания произведения и оператор модификации параметра цикла представляют собой последействие:
#include <iostream> using namespace std; int main ( ) { unsigned long long int factorial; 1 unsigned int N, i; for ( cout<<" N = ", cin >>N, factorial =1, i =2; i<=N; factorial*=i, i ++); cout<<" факториал= "<<factorial <<" \ n "; return 0; }
Задача 3.13. Вычислить сумму натуральных чётных чисел, не превышающих .
Входные данные: — целое число.
Выходные данные: — сумма чётных чисел.
Промежуточные переменные: — параметр цикла, принимает значения 2, 4, 6, 8 и так далее, также имеет целочисленное значение.
При сложении нескольких чисел необходимо накапливать результат в определённом участке памяти (), каждый раз считывая из этого участка (
) предыдущее значение суммы (
) и прибавляя к нему слагаемое
. Для выполнения первого оператора накапливания суммы из участка памяти необходимо взять такое число, которое не влияло бы на результат сложения. Перед началом цикла переменной, предназначенной для накапливания сумы, необходимо присвоить значение нуль. Блок-схема решения этой задачи представлена на рис. 3.27.
Решим задачу двумя способами: с применением циклов while и for:
//Решение задачи с помощью цикла while #include <iostream> using namespace std; int main ( ) { unsigned int N, i, S; cout<<" N = "; cin >>N; S=0; i =2; while ( i<=N) { S=S+i; i=i +2; } cout<<" S = "<<S<<" \n "; return 0; } //__________________________________ //Решение задачи с помощью цикла for #include <iostream> using namespace std; int main ( ) { unsigned int N, i, S; for ( cout<<" N = ", cin >>N, S=0, i =2; i<=N; S+=i, i +=2); cout<<" S = "<<S<<" \n "; return 0; }

Рис. 3.27. Алгоритм вычисления суммы чётных натуральных чисел.
Задача 3.14. Дано натуральное число . Определить
— количество делителей этого числа, меньших самого числа (Например, для
делители 1, 2, 3,
4, 6. Количество
).
Входные данные: — целое число.
Выходные данные: целое число — количество делителей
.
Промежуточные переменные: — параметр цикла, возможные делители числа
.
В блок-схеме, изображённой на рис. 3.28, реализован следующий алгоритм: в переменную , предназначенную для подсчёта количества делителей заданного числа, помещается значение, которое не влияло бы на результат, т.е. нуль. Далее организовывается цикл, в котором изменяющийся параметр
выполняет роль возможных делителей числа
. Если заданное число
делится нацело на параметр цикла
, это означает, что
является делителем
, и значение переменной
следует увеличить на единицу. Цикл необходимо повторить
раз.

Рис. 3.28. Алгоритм определения делителей натурального числа.
Текст программы на С++:
#include <iostream> using namespace std; int main ( ) { unsigned int N, i,K; cout<<" N = "; cin >>N; for (K=0, i =1; i<=N/ 2; i ++) if (N%i ==0) K++; cout<<" K = "<<K<<" \n "; return 0; }
Задача 3.15. Дано натуральное число . Определить, является ли оно простым. Натуральное число
называется простым, если оно делится без остатка только на единицу и на само себя. Число 13 — простое, так как делится только на 1 и 13, а число 12 таковым не является, так как делится на 1, 2, 3, 4, 6 и 12.
Входные данные: — целое число.
Выходные данные: сообщение.
Промежуточные переменные: — параметр цикла, возможные делители числа
.
Необходимо проверить, есть ли делители числа в диапазоне от 2 до
(рис. 3.29). Если делителей нет,
— простое число, иначе оно таковым не является. Обратите внимание на то, что в алгоритме предусмотрено два выхода из цикла. Первый — естественный, при исчерпании всех значений параметра, а второй — досрочный. Нет смысла продолжать цикл, если будет найден хотя бы один делитель из указанной области изменения параметра.

Рис. 3.29. Алгоритм определения простого числа.
При составлении программы на языке С++ досрочный выход из цикла удобно выполнять при помощи оператора break:
#include <iostream> using namespace s t d; int main ( ) { unsigned int N, i; bool Pr; cout<<" N = "; cin >>N; Pr=true; //Предположим, что число простое for ( i =2; i <=N/ 2; i ++) if (N%i ==0) //Если найдётся хотя бы один делитель, то { Pr=false; //число простым не является и break; //досрочный выход из цикла } if ( Pr ) //Проверка значения логического параметра и вывод на печать //соответствующего сообщения cout<<N<<" - простое число\n "; else cout<<N<<" - не является простым\n "; return 0; }
Задача 3.16. Дано натуральное число . Определить количество цифр в числе.
Входные данные: — целое число.
Выходные данные: — количество цифр в числе.
Промежуточные данные: — переменная для временного хранения значения
1).
Для того, чтобы подсчитать количество цифр в числе, необходимо определить, сколько раз заданное число можно разделить на десять нацело. Например, пусть , тогда количество цифр
. Результаты вычислений сведены в табл. 3.3.
kol | N |
---|---|
1 | 12345 |
2 | 12345 / 10 = 1234 |
3 | 1234 / 10 = 123 |
4 | 123 / 10 = 12 |
5 | 12 / 10 = 1 |
1 / 10 = 0 |
Алгоритм определения количества цифр в числе представлен на рис. 3.30.
#include <iostream> using namespace std; int main ( ) { unsigned long int N, M; unsigned int kol; cout<<" N = "; cin >>N; for (M=N, kol =1; M/10 >0; kol ++,M/=10); cout<<" kol = "<<kol <<endl; return 0; }

Рис. 3.30. Алгоритм определения количества цифр в числе.
Задача 3.17. Дано натуральное число . Определить, содержит ли это число нули и в каких разрядах они расположены (например, число 11011110111 содержит ноль в третьем и восьмом разрядах, а число 120405 — в первом и третьем).
Входные данные: — целое число.
Выходные данные: — позиция цифры в числе.
Промежуточные данные: — параметр цикла,
— переменная для временного хранения значения
.
В связи с тем, что разряды в числе выделяются начиная с последнего, для определения номера разряда в числе, необходимо знать количество цифр в числе2).Таким образом, на первом этапе решения задачи необходимо определить — количество цифр в числе. Затем нужно выделять из числа цифры, если очередная цифра равна нулю, вывести на экран номер разряда, который занимает эта цифра. Процесс определения текущей цифры числа
представлен в табл. 3.4.
i | Число М | Цифра | Номер позиции |
---|---|---|---|
1 | 120405 | 120405 % 10 = 5 | 0 |
2 | 12040/10 = 1204 | 12040 % 10 = 0 | 1 |
3 | 1204/10 = 120 | 1204 % 10 = 4 | 2 |
4 | 120/10 = 12 | 120 % 10 = 0 | 3 |
5 | 12/10 = 1 | 12 % 10 = 2 | 4 |
6 | 1/10 = 0 | 1 % 10 = 1 | 5 |
Программный код к задаче 3.17.
#include <iostream> using namespace s t d; int main ( ) { unsigned long int N,M; int kol, i; cout<<" N = "; cin >>N; for ( kol =1,M=N;M/10 >0; k o l ++,M/=10); for (M=N, i =0; i <kol;M/=10, i ++) if (M%10==0) cout<<"Позиция = "<<i <<endl; return 0; }
Задача 3.18. Дано натуральное число . Получить новое число, записав цифры числа
в обратном порядке. Например, 17852 — 25871.
Входные данные: — целое число.
Выходные данные: — целое число, полученное из цифр числа
, записанных в обратном порядке.
Промежуточные данные: — параметр цикла,
— переменная для временного хранения значения
— количество разрядов в заданном числе,
— старший разряд заданного числа.
Рассмотрим пример. Пусть , тогда
.
Значит, для решения поставленной задачи, нужно знать количество разрядов в заданном числе и его старший разряд
. Новое число
формируют как сумму произведений последней цифры заданного числа на старший разряд
. Цикл выполняют
раз, при каждой итерации уменьшая само число и старший разряд в десять раз.
#include <iostream> using namespace std; int main ( ) { unsigned long int N,M, R, S; int kol, i; cout<<" N = "; cin >>N; for (R=1, kol =1,M=N;M/10 >0; kol ++,R* =10,M/=10); for ( S=0,M=N, i =1; i<=kol; S+=M%10*R,M/=10,R/=10, i ++); cout<<" S = "<<S<<endl; return 0; }
Задача 3.19. Проверить, является ли заданное число палиндромом3). Например, числа 404, 1221 — палиндромы.
Входные данные: — целое число.
Выходные данные: сообщение.
Промежуточные данные: — параметр цикла,
— переменная для временного хранения значения
— количество разрядов в заданном числе,
— старший разряд заданного числа,
— целое число, полученное из цифр числа
, записанных в обратном порядке.
Можно предложить следующий алгоритм решения задачи. Записать цифры заданного числа в обратном порядке (задача 3.18), получится новое число
. Сравнить полученное число
с исходным
. Если числа равны, то заданное число является палиндромом.
Текст программы на языке С++:
#include <iostream> using namespace std; int main ( ) { unsigned long int N,M,R, S; int kol, i; cout<<" N = "; cin>>N; for (R=1, kol =1,M=N;M/10 >0; kol++,R* =10,M/=10); for (S=0,M=N, i =1; i<=kol; S+=M%10*R,M/=10,R/=10, i++); if (N==S) cout<<"Число - палинром"<<endl; else cout<<"Число не является палиндромом"<<endl; return 0; }
Задача 3.20. Поступает последовательность из вещественных чисел. Определить наибольший элемент последовательности.
Входные данные: — целое число;
— вещественное число, определяет текущий элемент последовательности.
Выходные данные: — вещественное число, элемент последовательности с наибольшим значением.
Промежуточные переменные: — параметр цикла, номер вводимого элемента последовательности.
Алгоритм поиска наибольшего элемента в последовательности следующий (рис. 3.31). Вводится — количество элементов последовательности и
— первый элемент последовательности. В памяти компьютера отводится ячейка, например с именем
, в которой будет храниться наибольший элемент последовательности — максимум. Далее предполагаем, что первый элемент последовательности наибольший и записываем его в
. Затем вводим второй элемент последовательности и сравниваем его с предполагаемым максимумом. Если окажется, что второй элемент больше, его записывают в ячейку
. В противном случае никаких действий не предпринимаем. Потом переходим к вводу следующего элемента последовательности (
), и алгоритм повторяется с начала. В результате в ячейке
сохранится элемент последовательности с наибольшим значением1).

Рис. 3.31. Алгоритм поиска наибольшего числа в последовательности.
Текст программы на С++:
#include <iostream> using namespace std; int main ( ) { unsigned int i,N; float X,Max; cout<<" N = "; cin>>N; cout<<" X = "; cin>>X; //Ввод первого элемента последовательности //Параметр цикла принимает стартовое значение i =2, т.к. первый элемент //уже введён предположим, что он максимальный, т.е. Max=X. for ( i =2, Max=X; i<=N; i++) { cout<<" X = "; cin>>X; //Ввод следующих элементов последовательности. //Если найдётся элемент, превышающий максимум, записать его в ячейку Max, //теперь он предполагаемый максимум. if (X>Max) Max=X; } //Вывод наибольшего элемента последовательности. cout<<" Max = "<<Max<<" \n "; return 0; }
Задача 3.21. Вводится последовательность целых чисел, 0 — конец последовательности. Найти наименьшее число среди положительных, если таких значений несколько2), определить, сколько их.
Блок-схема решения задачи приведена на рис. 3.32.

Рис. 3.32. Алгоритм поиска минимального положительного числа в последовательности.
Далее приведён текст подпрограммы с подробными комментариями3).
#include <iostream> using namespace std; int main ( ) { float N, Min; int K; //Предположим, что в последовательности нет положительных чисел, K=0. //Вводим число и если оно не равно нулю for ( cout<<" N = ", cin>>N,K=0;N!=0; cout<<" N = ", cin>>N) //проверяем является ли оно положительным. if (N>0) //если K=0, поступил 1-й положительный элемент, предположим, что он минимальный. if (K==0) {K=1;Min=N; } //если элемент не первый, сравниваем его с предполагаемым минимумом, //если элемент меньше, записываем его в Min и сбрасываем счётчик else if (N<Min) {Min=N;K=1;} //если элемент равен минимуму, увеличиваем значение счётчика. else if (N==Min) K++; //Конец цикла //Если значение счётчика не равно нулю, печатаем значение //минимального элемента и количество таких элементов. if (K!=0) cout<<" Min = "<<Min<<" \n "<<" K = "<<K<<" \n "; //в противном случае выдаём сообщаем. else cout<<"В последовательности нет положительных элементов \n "; return 0; }
Задача 3.22. Определить, сколько раз последовательность из произвольных чисел меняет знак.
Чтобы решить задачу, нужно попарно перемножать элементы последовательности. Если результат произведения пары чисел — отрицательное число, значит, эти числа имеют разные знаки.
Пусть в переменной хранится текущий элемент последовательности, в
— предыдущий. Введём первое число
(до цикла) и второе
(в цикле). Если их произведение отрицательно, то увеличиваем количество смен знака на 1 (k++). После чего сохраняем значение
в переменную
и повторяем цикл (рис. 3.33).

Рис. 3.33. Алгоритм решения задачи 3.22.
Предлагаем читателю самостоятельно разобраться с текстом программы на С++:
#include <iostream> using namespace std; int main ( ) { float A,B; int i,K,N; cout<<" N = "; cin>>N; for (K=0, cout<<" A = ", cin>>A, i =2; i<=N; i++) { cout<<" B = "; cin>>B; if (A_B<0) K++; A=B; } cout<<" K = "<<K<<" \n "; return 0; }
Задача 3.23. Поступает последовательность из вещественных чисел. Определить количество простых чисел в последовательности.
Блок-схема алгоритма изображена на рис. 3.34. Обратите внимание, что для решения задачи было организовано два цикла. Первый цикл обеспечивает ввод элементов последовательности. Второй цикл находится внутри первого и определяет, является ли поступившее число простым (задача 3.15).

Рис. 3.34. Алгоритм поиска простых чисел в последовательности.
#include <iostream> using namespace std; int main ( ) { unsigned long int X; unsigned int N; int i, k, j; bool Pr; for ( k=0, cout<<" N = ", cin >>N, i =1; i<=N; i ++) { for ( cout<<" X = ", cin >>X, Pr=true, j =2; j<=X/ 2; j ++) if (X%j ==0) { Pr=false; break; } if ( Pr ) k++; } if ( k==0) cout<<"Простых чисел нет \n "; else cout<<"Количество простых чисел k = "<<k<<" \n "; return 0; }
Задача 3.24. Дано наборов ненулевых целых чисел. Каждый набор содержит не менее двух элементов, признаком его завершения является число 0. Найти количество наборов, элементы которых возрастают.
Блок-схема алгоритма решения задачи показана на рис. 3.35. Нетрудно заметить, что алгоритм реализован с помощью двух циклических процессов. Внутренний цикл проверяет является ли последовательность возрастающей, а внешний повторяет алгоритм для новой последовательности.

Рис. 3.35. Алгоритм решения задачи 3.24.
Программный код решения задачи 3.24:
#include <iostream> using namespace std; int main ( ) { unsigned int K, i, kol, A, B; bool pr; for ( cout<< K = ", cin >>K, kol =0, i =1; i<=K; i ++) { for ( pr=true, cout<<" A = ", cin >>A;A! = 0; A=B) { cout<<" B = "; cin >>B; if (B!=0 && A>=B) pr=false; } if ( pr ) kol++; } cout << " kol = " << kol <<endl; return 0; }
3.6 Задачи для самостоятельного решения
3.6.1 Разветвляющийся процесс. Вычисление значения функции.
Разработать программу на языке С++. Дано вещественное число a. Для функции , график которой приведён ниже, вычислить
. Варианты заданий представлены на рисунках ниже.

Рис. 3.36. Задание 1

Рис. 3.37. Задание 2

Рис. 3.38. Задание 3

Рис. 3.39. Задание4

Рис. 3.40. Задание 5

Рис. 3.41. Задание 6

Рис. 3.42. Задание 7

Рис. 3.43. Задание 8

Рис. 3.44. Задание 9

Рис. 3.45. Задание 10

Рис. 3.46. Задание 11

Рис. 3.47. Задание 12

Рис. 3.48. Задание 13

Рис. 3.49. Задание 14

Рис. 3.50. Задание 15

Рис. 3.51. Задание 16

Рис. 3.52. Задание 17

Рис. 3.53. Задание 18

Рис. 3.54. Задание 19

Рис. 3.55. Задание 20

Рис. 3.56. Задание 21

Рис. 3.57. Задание 22

Рис. 3.58. Задание 23

Рис. 3.59. Задание 24

Рис. 3.60. Задание 25
3.6.2 Разветвляющийся процесс. Попадание точки в область на плоскости
Разработать программу на языке С++. Даны вещественные числа и
. Определить, принадлежит ли точка с координатами (
) заштрихованной области. Варианты заданий представлены на рисунках ниже.

Рис. 3.61. Задание 1

Рис. 3.62. Задание 2

Рис. 3.63. Задание 3

Рис. 3.64. Задание 4

Рис. 3.65. Задание 5

Рис. 3.66. Задание 6

Рис. 3.67. Задание 7

Рис. 3.68. Задание 8

Рис. 3.69. Задание 9

Рис. 3.70. Задание 10

Рис. 3.71. Задание 11

Рис. 3.72. Задание 12

Рис. 3.73. Задание 13

Рис. 3.74. Задание 14

Рис. 3.75. Задание 15

Рис. 3.76. Задание 16

Рис. 3.77. Задание 17

Рис. 3.78. Задание 18

Рис. 3.79. Задание 19

Рис. 3.80. Задание 20

Рис. 3.81. Задание 21

Рис. 3.82. Задание 22

Рис. 3.83. Задание 23

Рис. 3.84. Задание 24

Рис. 3.85. Задание 25
3.6.3 Разветвляющийся процесс. Пересечение линий и решение уравнений.
Разработать программу на языке С++ для следующих заданий:
- Задан круг с центром в точке
, радиусом
и точка
. Определить, находится ли точка внутри круга.
- Задана окружность с центром в точке
и радиусом
. Определить, пересекается ли заданная окружность с осью абсцисс, если пересекается — найти точки пересечения.
- Задана окружность с центром в точке
и радиусом
. Определить, пересекается ли заданная окружность с осью ординат, если пересекается — найти точки пересечения.
- Задана окружность с центром в точке
и радиусом
и прямая
. Определить, пересекаются ли прямая и окружность. Если пересекаются, найти точки пересечения.
- Заданы окружности. Первая с центром в точке
и радиусом
, вторая с центром в точке
и радиусом
. Определить, пересекаются окружности, касаются или не пересекаются.
- Заданы три точки
. Определить, какая из точек наиболее удалена от начала координат.
- Заданы три точки
). Определить, какая из точек
или
наименее удалена от точки
.
- Определить, пересекаются ли линии
и
. Если пересекаются, найти точку пересечения.
- Определить, пересекает ли линия
ось абсцисс. Если пересекает, найти точку пересечения.
- Определить, пересекаются ли линии
и
. Если пересекаются, найти точки пересечения.
- Определить, пересекаются ли линии
и
. Если пересекаются, найти точки пересечения.
- Определить, пересекаются ли линии
и
. Если пересекаются, найти точки пересечения.
- Определить, пересекаются ли линии
и