
МЕТОДИЧЕСКОЕ ПОСОБИЕ ПО ПРОГРАММИРОВАНИЮ
Язык Си ++
Хабаровск 2004
Министерство образования Российской Федерации
Государственное образовательное учреждение
высшего профессионального образования
"Хабаровский государственный технический университет"
ИНФОРМАТИКА
Методическое пособие
по выполнению лабораторных работ № 1 – 8
для студентов I курса специальности 210100
"Управление и информатика в технических системах"
дневной формы обучения
Хабаровск
Издательство ХГТУ
2004
” ВВОДНО-ОЗНАКОМИТЕЛЬНАЯ” ЛАБОРАТОРНАЯ РАБОТА
Язык Си давно завоевал особую популярность у программистов вследствие уникального сочетания возможностей языков высокого и низкого уровней. Язык Си разработан в. 1972 г. Д. Ритчи во время работы над операционной системой Unix. Изначально предполагалось, что этот язык будет использоваться профессиональными программистами. Язык Си является достаточно трудным для начального ознакомления с программированием, но в тоже время достаточно гибким, позволяющим с помощью небольшого числа конструкций решать трудные задачи. Главное преимущество языка Си заключается в библиотеках, поддерживаемых компилятором, и библиотеках, создаваемых программистами.
Знаменательной вехой, в эволюции языка Си стало появление системы Турбо Си, получившей признание как одно из самых удачных инструментальных средств для персональных компьютеров. Язык Си называют скромным, быстрым, удобным. Иногда его называют вероломным [15], потому как программы на Си беззащитны для класса ошибок, от которых другие языки защищают. На такие ошибки в пособии обращается особое внимание. Язык Си - относительно мобильный язык. Программы, написанные на этом языке для одной операционной системы, с небольшими доработками могут использоваться в другой операционной системе.
Язык C++ был разработан Бьерном Страуструпом на основе языка программирования Си и с немногими изменениями сохраняет Си как подмножество. Сначала язык C++ назывался "язык Си с классами" и, в общем-то Си становится C++ с введением объектно-ориентированного программирования.
Д
2
Фон Неймана описал, как должен быть устроен компьютер для того, чтобы он был универсальным и эффективным устройством для обработки информации [2]. Прежде всего, компьютер должен иметь следующие устройства (рис.1):
процессор, осуществляющий арифметические и логические операции, а также организующий процесс выполнения программ;
запоминающее устройство, или память для хранения программ и данных;
внешние (периферийные) устройства для ввода/вывода информации.
Рис.1
Память должна состоять из некоторого количества пронумерованных ячеек, в каждой из которых могут находиться или обрабатываемые данные, или инструкции Программ. Всё ячейки памяти должны быть одинаково доступны для других устройств компьютера.
На рис. 1 одинарные линии показывают управляющие связи, двойные - информационные.
В
3
Как Правило, после выполнения одной команды процессор начинает обрабатывать команду из ячейки памяти, которая находится непосредственно за только что выполненной командой. Однако этот порядок может быть изменен с помощью Команд управления (перехода). Эти команды указывают процессору, что ему следует продолжить выполнение программы, начиная с команды, содержащейся в некоторой другой ячейке памяти. Такой "скачок", или переход, осуществляется в программе не" всегда, а только при соблюдении некоторых условий. Например, если некоторые числа равны, если в результате предыдущей арифметической операции получился нуль, Это позволяет использовать одни и те же последовательности команд в программе много раз (организовывать циклы), выполнять различные последовательности команд в зависимости от соблюдения определенных условий и т.д., одним словом, создавать сложные программы.
Таким образом, процессор выполняет инструкции программы автоматически, без вмешательства человека. Он может обмениваться информацией с памятью и внешними устройствами компьютера. Поскольку внешние устройства, как правило, работают значительно медленнее, чем остальные части компьютера, процессор может приостанавливать выполнение программы до завершения операции ввода-вывода с внешним устройством. Все результаты выполненной программы должны быть ею выведены на внешние устройства компьютера, после чего компьютер переходит к ожиданию каких-либо сигналов внешних устройств.
Многие современные быстродействующие компьютеры осуществляют параллельную обработку данных на нескольких процессорах одновременно, обрабатывают прерывания от внешних устройств, тем не менее, в основных чертах соответствуют принципам фон Неймана.
Современный компьютер - это не просто вычислительное устройство, а целая вычислительная система - совокупность аппаратных и программных средств, обеспечивающих выполнение возложенных на систему функций.
Совокупность программных средств можно разделить на три категории [2]:
Прикладные программы, непосредственно обеспечивающие выполнение необходимых пользователям работ: редактирование текстов, рисование картинок, обработка информационных массивов, и т. д.;
системные программы, выполняющие различные вспомогательные функции, например, создание копии используемой информации, выдача справочной информации о компьютере, проверка работоспособности устройств компьютера, обеспечивающие диалог с пользователем и т. д.;
и
4
Рассмотрим некоторые системные программы. Одной из важнейших системных программ является операционная система. Операционная система - это программа, которая загружается при включении компьютера. Она осуществляет диалог с пользователем, управление, компьютером, его ресурсами (оперативной памятью, местом на дисках и т. д.), запускает другие (прикладные) программы на выполнение. Операционная система обеспечивает пользователю и прикладным программам удобный способ общения (интерфейс) с устройствами компьютера. Для компьютеров типа IBM PC чаще всего используется операционная система MS DOS, Unix, OS/2, Windows.
Важным классом системных программ являются программы-драйверы. Они расширяют возможности DOS по управлению устройствами ввода-вывода компьютера (клавиатурой, жестким диском, мышью и т.д.). С помощью драйверов можно подключать к компьютеру новые устройства или нестандартно использовать имеющиеся устройства.
C++ относится к инструментальным системам и включает в себя как язык программирования, так и среду, предназначенную для написания, отладки и запуска программ.
Этапы решения задачи на ЭВМ
Так как ЭВМ является "слепым" исполнителем программ, то успешное решение задачи полностью определяется квалификацией программиста.
В общем случае решение задачи на ЭВМ можно разбить на следующие этапы:
постановка задачи;
разработка алгоритма;
составление программы;
трансляция программы;
отладка и выполнение программы;
анализ результатов.
Слово "алгоритм" произошло от имени узбекского математика Аль Хорезми, который в IX в. разработал правила четырех арифметических действий над числами в десятичной системе счисления. Примерами алгоритмов могут служить врачебные и кулинарные рецепты, способы решения квадратных и дифференциальных уравнений.
В программировании используется такое определение алгоритма: "алгоритм - это точное предписание, определяющее вычислительный процесс, ведущий от варьируемых начальных данных к искомому результату".
Алгоритм должен обладать следующими основными свойствами:
детерминированность (определенность) - при заданных исходных данных обеспечивается однозначность искомого результата;
м
5
результативность - реализуемый вычислительный процесс выполняется за конечное число этапов с выдачей осмысленного результата;
дискретность - разбиение на отдельные этапы, выполнение которых не вызывает сомнений.
Под программой понимают описание, воспринимаемое ЭВМ и достаточное для решения на ней определенной задачи. Для создания программы используются искусственные языки, называемые языками программирования. ЭВМ, как правило, непосредственно воспринимает и выполняет программы, написанные только на одном из языков программирования - машинном языке для данной ЭВМ. С помощью специальных программ можно получить опосредованное "понимание" других языков. Одна из таких программ - транслятор. Транслятор - это программа, осуществляющая перевод текстов с одного языка на другой, т. е. с входного языка (Паскаль, Си, Пл-1 и т. д.) на машинный язык реальной ЭВМ. Программа, попадающая на вход транслятора, называется исходной, а результат трансляции - объектной программой.
Графический способ описания алгоритмов
Одним из самых трудоемких этапов решения задачи на ЭВМ является разработка алгоритма. Человечество разработало эффективный алгоритм завязывания шнурков на ботинках. Многие дети с пятилетнего возраста могут это делать. Но дать чисто словесное описание этого алгоритма без картинок и демонстрации - очень трудно.
При разработке алгоритмов чаще всего используют следующие способы их описания: словесный, графический, с помощью языков программирования.
Рассмотрим два способа: графический и с помощью языков программирования.
Графический способ записи алгоритмов - наиболее наглядный и распространенный. Он основан на использовании геометрических: фигур (блоков), каждая из которых отображает конкретный этап процесса обработки данных, соединяемых между собой прямыми линиями, называемыми линиями потока. Обозначение и назначение элементов графических схем алгоритмов приведено в табл. 1. В поле каждого блочного символа указывают выполняемую функцию. При необходимости справа можно поместить комментарии, относящиеся к данному блоку или направлению потока. Каждый блочный символ (кроме начального и конечного) помечается порядковым номером. Для отличия ситуаций пересечения и слияния потоков последняя изображается точкой. Линии потока, имеющие направление вверх или направо, дополняются стрелками.
6
Таблица 1
7
По своей структуре различают следующие типы алгоритмов; линейные, разветвляющиеся и циклические. В линейных схемах алгоритмов все предписания выполняются одно за другим. Например, алгоритм вычисления длины окружности по известной площади круга (рис.2). В разветвляющихся схемах алгоритмов для конкретных исходных данных выполняются не все заданные предписания. Однако какие именно предписания будут выполняться, конкретно определяется в процессе выполнения алгоритма в результате проверки некоторых условий. Разветвляющийся алгоритм всегда избыточен. Примером разветвляющегося алгоритма является алгоритм, приведенный на рис.3 и определяющий, пройдет ли график функции у=3х+4 чepeз точку с координатами x1,y1.
Циклическим алгоритмом называется такой алгоритм, в котором можно выделить многократно повторяющуюся последовательность предписаний, называемую циклом. Для таких алгоритмов характерно наличие параметра цикла, которое перед входом в цикл имеет начальное значение, а затем изменяется внутри цикла. Имеется также предписание о проверке условия окончания цикла. Применение циклов сокращает текст алгоритма и, в конечном итоге, длину программы. Примером циклического алгоритма может служить алгоритм, приведенный на рис.4 и определяющий факториал натурального числа n. В этом алгоритме введена дополнительная переменная i, которая является параметром цикла и изменяется от начального значения 1 до конечного значения n с шагом 1. На каждом шаге итерации искомая величина f умножается на переменную цикла. В реальных задачах, как правило, сочетаются все три типа алгоритмов. Способ описания алгоритма с помощью алгоритмического языка подробно рассматривается в следующем разделе.
8
Задачи для составления схем алгоритмов
1. Дано натуральное число n. Вычислить произведение
2. Дано натуральное число n и действительное число а. Вычислить произведение а(а+1)(а+2)*...*(а+n-1).
3. Дано натуральное число n и действительные числа х и h. Вычислить
4. Дано натуральное число n. Вычислить сумму n первых слагаемых
5.
Дано натуральное число n.
Вычислить
сумму n
первых слагаемых
6. Дано натуральное число n. Вычислить сумму n первых слагаемых
7. Дано натуральное число n. Вычислить сумму n первых слагаемых
8. Дано натуральное число n. Вычислить сумму n первых слагаемых
9. Дано натуральное число n. Вычислить сумму n первых слагаемых
10. Дано натуральное число n. Вычислить произведение n первых сомножителей
11. Дано натуральное число n. Вычислить сумму n первых слагаемых
12. Дано натуральное число n. и действительное число х. Вычислить сумму n первых слагаемых
1
9
14. Дано натуральное число n. Вычислить сумму n первых слагаемых
15. Дано натуральное число n и действительное число х. Вычислить сумму n первых слагаемых
16. Дано натуральное число n. Вычислить произведение n первых сомножителей
17. Дано натуральное число n и действительное число х. Вычислить сумму n первых слагаемых
18. Дано натуральное число n. Вычислить произведение n первых сомножителей
19. Дано натуральное число n и действительное число х. Вычислить сумму n первых слагаемых
20. Дано натуральное число n. Вычислить сумму n первых слагаемых
21. Дано натуральное число n и действительные числа х и h. Вычислить
22. Дано натуральное число n. Вычислить произведение
23. Дано натуральное число n. Вычислить произведение n первых сомножителей
10
ЛАБОРАТОРНАЯ РАБОТА № 1
ЛИНЕЙНЫЕ ПРОГРАММЫ
Цель работы:
ознакомится с сеансом работы в среде C++; освоить структуру программы; изучить оператор присваивания; научиться записывать выражения на C++; научиться пользоваться функциям» scanf и printf.
Порядок выполнения работы:
В соответствии с поставленной задачей разработать" графическую схему алгоритма, составить программу и отладить ее в среде C++, подготовить отчет, ответить на контрольные вопросы и защитить лабораторную работу перед преподавателем.
Общие сведения
Чтобы иметь представление о том, как программируют на языке С++, приведем пример программы pr1, определяющей сумму двух чисел:
/* Пример pr1 */
#include <stdio.h>
#include <conio.h>
//Главная функция
void main()
{
int a,b,result ;
printf(”\nВведите a и b:”);
scanf(”%d%d”,&a,&b);
result =a+b;
printf(”result =%d”,result);
getch();
}
Это – линейная программа. К линейным программам чаще всего приводят задачи, в которых необходимо выполнить обработку данных по формулам. В любой линейной программе имеются блоки ввода исходных данных, вычислительный блок, который выполняет присваивание переменной значения некоторого выражения, и блок вывода результатов решения задачи.
Структура программы на языке С++ в общем случае представляет собой некоторую совокупность функций, из которых одна является главной и присутствует в каждой программе. Эта функция носит стандартное Имя main и с неё начинается выполнение программы. Язык C++ является языком свободного формата, что позволяет размещать в строке как один, так и несколько операторов.
Р
11
Первая строка программы - комментарий. Комментарий начинается с символов/*, а завершается - */. Комментарий компилятором игнорируется и служит для улучшения читаемости программы. Две следующие строчки программы - директивы препроцессора, которые помещают на своё место соответственно файлы Stdio.h и conio.h, содержащие заголовки функций ввода и вывода. Это необходимо потому, что в языке C++ нет встроенных функций для ввода и вывода. Из файла Stdio.h в нашей программе используются функции printf и scanf. Функция scanf служит для ввода исходных данных с клавиатуры, а printf- для вывода результатов на экран монитора. Из файла coniо. h используется функция getch, которая читает с клавиатуры символ. В данном случае она служит для ожидания нажатия любой клавиши, чтобы можно было успеть рассмотреть результаты работы программы. Синтаксис директивы препроцессора следующий:
#include < имя_файла >
#include "имя_файла"
В первом случае поиск файла происходит только в пределах специфицированных каталогов включаемых файлов (include directories). При использовании второй формы сначала просматривается текущий каталог, а затем каталоги включаемых файлов [3]. С помощью директивы include можно включить в текст программы любой другой исходный файл.
Четвертая строка также является комментарием. Этот комментарий однострочный: всё, что расположено в текущей строке после двух косых линий считается комментарием. Синтаксис комментария первой строки используется как для многострочных, так и однострочных пояснительных текстов.
В пятой строке начинается главная функция, и именно в этой строке расположен заголовок главной функции. Перед именем main стоит слово void, которое означает, что функция не возвращает никакого значения. Пустые круглые скобки после слова main означают, что функция без параметров. После заголовка функции следует тело функции, заключенное в фигурные скобки. Тело функции может содержать описания переменных и операторы.
В
12
Восьмая строка программы содержит вызов функции printf, которая выводит на экран с новой строки сообщение: Введите а и b:. Вывод с новой строки обеспечивается за счет использования параметра \n. Девятая строка программы содержит вызов функции scanf, которая читает с клавиатуры значения в переменные а и Ь, в соответствии с форматом %d для целых чисел. Более подробно об этих функциях читайте в разделе 3.1.4.
Десятая строка программы содержит оператор присваивания, вычисляющий сумму целых чисел а и b и размещающий результат в переменной rezult. В следующей строке содержится вызов функции printf, которая выводит на экран значение переменной rezult. В предпоследней строке содержится вызов функции getch, которая ждет нажатия любой клавиши, чтобы дать возможность пользователю просмотреть результат: В последней строке программы находится фигурная скобка, завершающая тело функции main.
Для выполнения программы необходимо [3]:
подготовить её текст в файле с расширением .срр (для этого необходимо загрузить C++, выбрав команду bc\bin\bc);
передать этот файл на компиляцию (ALT-F9);
устранить синтаксические ошибки, выявленные компилятором;
безошибочно откомпилировать (получится объектный файл с расширением .obj);
дополнить объектный файл нужными библиотечными функциями (компоновка CTRL-F9)n получит исполняемый Модуль программы в файле с расширением .ехе.
Схема подготовки исполняемой программы приведена на рис.5, где перед шагом компиляции показан шаг препроцессорной обработки текста программы. В приведенном выше примере обрабатывается директива include. Следует сказать, что препроцессор не только добавляет к тексту программы функции для ввода и вывода, но и обрабатывает текст программы.
Рассмотрим подробнее описания переменных и операторы, необходимые для написания линейной программы.
13
Рис. 5
14
Описание переменных
В языке C++ возможна обработка данных «различных типов. Тип любого объекта определяет множество допустимых значений и множество допустимых операций над этими значениями. Любой идентификатор, используемый в исполняемых операторах, должен быть предварительно описан в любом месте программы, но обязательно до начала применения.
Рис. 6
В этом строгом требовании языка C++ проявляется тенденция развития языков программирования в сторону повышения надежности создаваемых программ, При описании переменных их можно инициализировать. На рис.6 приведена структура типов данных C++. В данном разделе рассматриваются только целые и вещественнее типы данных.
Диапазон возможных значений целых типов зависит от их внутреннего представления, которое может занимать один, два или четыре байта. В табл.2 приводятся названия целых типов, длина их внутреннего представления в байтах и диапазон возможных значений. Целые типы относятся к так называемым порядковым типам. Для порядковых типов характерно то, что такие типы имеют конечное число возможных значений и эти значения можно каким-либо образом упорядочить и каждому значению поставить в соответствие целое число.
15
Таблица 2
Описание переменных целого типа может выглядеть так:
int а, b=0;
long с;
unsigned int d;
В данном случае переменная b инициализирована при описании.
Основные операции над целыми числами:
“+” – сложение; “*” – умножение; “/ ” - деление;
“-” – вычитание; “%” – получение остатка от целовычисленного деления. Следует обратить внимание на операцию деления. В языке С++ специальной операции целочисленного деления нет, поэтому тип операции определяется типами операндов. Если оба операнда целые, то операция деления выполняется как операция целочисленного деления. Если хотя бы один из операндов с плавающей точкой, то операция деления выполняется не как целочисленная. Приоритеты выполнения операций такие же, как в математике.
Например, 5/2 дает результат 2, 6/2 – 3, 5%2 – 1.
Под данными вещественного типа понимаются числа, записанные с десятичной точкой. Значение числа вещественного типа представляется в ЭВМ лишь с некоторой конечной точностью, которая зависит от внутреннего формата вещественного числа. В табл.3 приведены названия вещественных типов, их длина в байтах, а также диапазон возможных значений. Существует две формы представления вещественных чисел: с фиксированной и с плавающей точками. Примеры записи вещественных чисел с фиксированной точкой приведены в первом столбце, а с плавающей – во втором:
1.36 1.36е0
0.0013 1.3е-3
16
Переменные вещественного типа можно описать так:
float a,b;
double c,d;
long double l,m,n;
Таблица 3
В табл.4 приведены наиболее часто используемые функции, для разработки данных вещественного типа. Следует знать, что этими функциями можно пользоваться только после подключения файла math.h с помощью директивы препроцессора include.
Следует заметить, что для вычисления модуля целого числа используется функция abs(x).
Таблица 4
Оператор присваивания
Оператор присваивания является самым важным оператором в любом языке программирования. Этот оператор служит для изменения областей памяти. Оператор присваивания заменяет значение переменной, идентификатор которой стоит в левой части оператора, значением выражения, стоящего в правой части, и имеет следующую форму:
<
17
Необходимо учесть, что переменная и выражение должны быть согласованы по типам. Например, если переменные описаны следующим образом:
int x,y;
float a, b;
то можно записать операторы присваивания
х = 2;
х=х+5;
у = х;
а = b = 3.1;
b = 5.33*х + у/2;
Что происходит со старым значением переменной, когда ей присваивается новое значение? Оно просто стирается. Поскольку переменная может хранить только одно число, то выполнение оператора присваивания приводит к потере предыдущего значения переменной. Переменная всегда содержит результат последнего оператора присваивания.
Как уже говорилось, тип переменной позволяет не только устанавливать длину ее внутреннего представления, но и контролировать те действия, которые осуществляются над ней в программе. Ниже приведены схемы, преобразования типов, гарантирующие сохранение точности и неизменность численного значения [3]:
signed char => short => int => long
float => double => long double
unsigned char => unsigned short => unsigned int => unsigned long
Значит, для описанных выше переменных оператор х = а будет неверным, так как невозможно точно преобразовать вещественный тип к целому, а оператор а = х будет верным. При этом следует заметить, что сообщение об ошибке выдаваться не будет, так как язык С++ относится менее жестко, чем скажем Паскаль, к соответствию типов.
Кроме стандартных преобразований типов, существуют явные преобразования типов. Синтаксис использования явного преобразования типов имеет две различные формы:
(имя_типа) операнд,
имя_типа (операнд).
Во второй форме не может использоваться составное наименование типа (например, unsigned short). Как и при автоматическом преобразовании типов, ответственность за сохранение значения и точности результата лежит на разработчике программы.
Следующий пример рг2 демонстрирует, какие последствия можно иметь от преобразования типов:
//Пример рг2
#include <stdio.h>
#include <conio.h>
v
18
{
long a=123456789;
float b;
int rezult1,rezult2;
rezult1=1.6+1.7;
rezult2=(int)1.6+(int) 1.7;
printf("\n rezult1=%d",rezult1); // Печатаем rezult1=3
printf("\n rezult2=%d",rezult2); // Печатает rezult2=2
b=(float)a;
printf("\n a=%ld",a); // Печатает а=123456789
printf("\n b=%е",b); // Печатает b=1.2345689е + 08
a=(long)b;
printf("\n а=%ld",а); // Печатает a=1.23456892
b=2.222222е+2;
rezult1=(int)b;
printf("\n b=%f",b); // Печатает b=222.222198
printf("\n rezult1=%d",rezult1); // Печатает rezult1=222
b=(float) rezult1;
printf("\nb=%f",b) // Печатает rezult1=222,000000
getch();
}
Кроме классической записи оператора присваивания, в языке C++ можно использовать операции увеличения ++ и уменьшения --. Операция увеличения увеличивает свой операнд на 1, а операция уменьшения уменьшает свой операнд на 1. Существует две формы этих операций: постфиксная и префиксная. Разница между ними заключается в том, что они показывают, в какой момент осуществляется увеличение или уменьшение операнда:
х++, х-- постфиксная запись;
++х, --х префиксная запись.
В данных примерах форма записи никак не отражается на результате, а следующий пример ргЗ иллюстрирует разницу:
// Пример ргЗ
#include <stdto.h>
#include <conio.h>
void main()
{int a,b,x;
x=0;
a=5+x++;
b=5+ ++x;
printf("a = %d\nb = %d",a,b);
getch();
}
Р
19
а = 5
b = 7
При вычислении а сначала к 5 добавляется х=0, а потом х увеличивается на 1. При вычислении b сначала х увеличивается на 1 и становится равным 2, а затем значение х добавляется к 5.
В операторах присваивания можно использовать укороченную форму записи, например, запись a+=%5 эквивалентна записи а=а+5:
// Пример рг4
#include <stdio.h>
#include <conio.h>
void main()
{float a,b,x;
а=b=x=1;
a+=5; // эквивалентно а=а+5
b/=5+x; // эквивалентно b=b/(5+x)
printf("\na=%f\nb=%f",a,b);
a-=5; // эквивалентно a=a-5
b*=5+x; // эквивалентно b=b*(5+х)
printf("\na=%f\nb=%f",a,b);
getch();
}
Использование укороченной формы записи в операторах присваивания с небольшими выражениями делает их более "прозрачными", а операторы со сложными выражениями становятся более запутанными. Поэтому рекомендуется использовать эту возможность осторожно.
Функции ввода и вывода
Ввод/вывод связан с обменом информацией между оперативной памятью и внешними устройствами. Как уже говорилось, в языке C++ нет встроенных функций ввода и вывода. Поэтому, чтобы воспользоваться функциями ввода и вывода, необходимо с помощью директивы препроцессора подключить файл, содержащий соответствующие функции. Функций ввода/вывода много, но в данный момент рассматриваются функции ввода scanf и вывода printf. Функция ввода scanf служит для чтения информации с клавиатуры и имеет следующий синтаксис;
scanf (<управляющая строка><список ввода>);
<Управляюи1ая строка> - строка символов, содержащая спецификации преобразования. Каждому идентификатору из списка ввода должна соответствовать строго одна спецификация преобразования.
Спецификацию преобразования можно формально определить следующим образом [1]:
%[флаг][ширина][.точность][1,L] символ_формата
В
20
- выровнять значение по левому краю поля (т.е. добавить пробелы справа);
+ выровнять значение по правому краю поля, вывести обязательно знак значения.
При отсутствии флага выравнивание идет по правому краю и для неотрицательных значений знак не выводится. Ширина определяет минимальный размер поля вывода. Точность используется для определения количества выводимых позиций после запятой в поле вывода вещественного числа. 1 или L служат для указания целых длинных типов,
Назначение некоторых спецификаций преобразования приведены в табл.5.
Таблица 5
<Список ввода> - это последовательность из одного или более идентификаторов переменных строкового типа, а также любого целого или вещественного типа. Перед каждым идентификатором должен стоять символ &, который означает, что в функцию передается адрес переменной, а не значение. Подробнее о передаче параметров в функции читайте в разд.5. При вводе числовых переменных функция scanf вначале выделяет подстроку во входном потоке по следующему правилу: все ведущие пробелы, символы табуляции и маркеры конца строки пропускаются, выделяется первый значащий символ, признаком конца подстроки является любой из вышеперечисленных символов или символ конец файла. Выделенная таким образом подстрока рассматривается как символьное представление числовой константы, которое преобразуется в соответствии с типом переменной, и полученное значение присваивается переменной. Если значащих символов в строке нет, а список ввода еще не исчерпан, то автоматически осуществляется переход к новой строке.
p
21
<Управляющая строка> - это строка символов, содержащая информацию, печатаемую текстуально, спецификации преобразования и специальные символы. Управляющая строка определяет, каким образом будет распечатана информация.
В C++ чаще всего используются следующие специальные символы:
\n - перевод курсора на новую строку;
\t - символ табуляции;
\b -шаг назад;
\r —возврат каретки.
Также можно использовать константы \007 (выдается короткий звуковой сигнал).
<Список вывода> - это последовательность идентификаторов переменных, констант, выражений, вычисляемых перед выводом на печать. Каждому аргументу из списка вывода должна соответствовать одна спецификация преобразования. В рr5 показано различное использование операторов ввода и вывода, но чтобы разобраться во всех нюансах, необходимо провести эксперименты.
// Пример рг5
#include <stdio.h>
#include <conio.h>
void main()
{ float a, b;
int x,y;
printf("Bведите целые х и у");
scanf("%d%d",&x,&y); // При вводе числа разделяются
// пробелами или символом конец строки
printf("x=%d y=%d \n x=%7d y=%2d",x,y,x,y);
printf("Bведите вещественные a и b);
scanf("%g%f",&a,&b); // нажимается клавиша Enter
//Вывод с различными спецификациями преобразования
printf("a=%g b=%g\na=%f b=%f\na=%е b=%е \n",a,b,a,b,a,b);
//Вывод с различной точностью
printf("a=%10.3f b=%10.3f\na=%7.2e b=%7.2e\n",a, b, a, b);
getch();
}
Если введем х=12345, у=6789, а=1.2345 и b=0.0000007, то получим следующий результат:
х=12345 у=6789
х=12345 у=6789
а=1.2345 b=1e-07
а=1.234500 b=0.000000
а=1234500e+00 b=1.000000e-07
а=1.2345 b=1е-07
а
22
а=1.23е+00 b=1.00е-07
Если для чисел с плавающей точкой указывается только количество позиций в числе, без указания числа позиций после запятой, то в этом случае выводится шесть знаков после запятой, занимая указанное количество позиций. Если длина поля не указывается совсем, то каждое число будет иметь шесть знаков после запятой, а ширина будет достаточной, чтобы напечатать число целиком.
Пример линейной программы
Теперь, когда мы ознакомились с операторами, необходимыми для составления линейной программы, рассмотрим пример такой Программы. Пусть дано два числа а и b - длины сторон прямоугольника. Найти площадь s и периметр р прямоугольника. На рис.7 представлена графическая схема алгоритма решения данной задачи, а программа приведена в примере pr6.
//Пример рr6
#include <stdio.h>
#include <conio.h>
main()
{ float a,b,s,p;
printf("Введите длины сторон
прямоугольника:");
scanf("%f%f",&a,&b);
s=a*b;
р=(а+b)*2;
printf ("Площадь =%5.3f ",s);
printf ("Периметр =%5.3f",p);
getch();
}
В этой программе все операторы выполняются последовательно друг за другом. Выполнение программы начинается с вызова функции вывода printf, которая выводит на экран подсказку "Введите длины сторон прямоугольника:", что обеспечивает удобный интерфейс с пользователем. Вызов функции scanf приводит к прерыванию программы до тех пор, пока пользователь не введет два числа. Далее вычисляются площадь и периметр прямоугольника и выводятся результаты на экран.
23
Рис.7
Контрольные вопросы
1. Что значит отладить программу?
2. Что такое транслятор?
3. Чем управляющая строка функции scanf отличается от управляющей строки функции printf?
4. Для чего предназначена спецификация преобразования?
5. Как будет выведено число 12345.6789, если для него использовалась спецификация преобразования %7.2f?
6. Что значит описать переменную?
7. Для чего предназначен символ \n?
8. Как записать на языке C++ выражение
9. Этапы решения задачи на ЭВМ.
10. Назначение оператора присваивания.
11. Чем отличается постфиксная операция увеличения от префиксной?
12. Какое значение х будет напечатано в результате работы следующей программы:
#include <stdio.h>
main()
{
float x=1, y=2;
int a=3, b=4;
x
24
printf ("x=%5.3f ",x);
}
Варианты заданий
1. Смешано v1 литров вода температуры t1 с v2 литрами воды температуры t2. Написать программу вычисления объема и температуры образовавшейся смеси.
2. Поменять местами значения целых переменных х и у, не используя дополнительных переменных (х < 1000 и y < 1000).
3. Идет k-я секунда суток. Определить, сколько полных часов (h) и полных минут (m) прошло к этому моменту (например, h=3 и m=40, если
4. Вычислить расстояние между двумя точками с координатами x1, y1, x2, y2.
5. Треугольник задан координатами своих вершин. Найти периметр треугольника.
6. Присвоить целой переменной h третью от конца цифру в записи целого положительного числа k (k больше 100. Например, если k=130985, то h=9).
7. Присвоить целой переменной d первую цифру из дробной части положительно вещественного числа х (так, если х=32.597, то d=5).
8. Целой переменной s присвоить сумму цифр трехзначного целого числа k.
9. Определить f - угол (в градусах) между положением часовой стрелки в начале суток и ее положением в h часов, m минут и s секунд (0≤ h ≤ 11,0 ≤ m,s ≤ 59).
10. Определить h — полное количество часов и m полное количество минут, прошедших от начала суток до того момента (в первой половине дня), когда часовая стрелка повернулась на f градусов;(0 ≤ f ≤ 360, f - вещественное число).
11. Пусть k - целое число от 1 до 365. Присвоить целой переменной n значение 1,2, ..,6 или 7 в зависимости от того, в какой день недели (понедельник, вторник, ..., суббота или воскресенье) приходится к-ый день не високосного года, в котором 1 января - понедельник.
12. Три сопротивления R1,R2,R3, соединены параллельно. Найти сопротивление соединения.
13. Определить силу притяжения F между телами массы m1, m2, находящимися на расстоянии r друг от друга.
1
25
15. Треугольник задан координатами своих вершин. Найти площадь треугольника.
16. Дано вещественное число х. Вычислить
17. Дано вещественное число х. Вычислить
18. Дано вещественное число х. Вычислить
19. Дано вещественное число х. Вычислить
20. Дано вещественное число х. Вычислить
21. Дано вещественное число х. Вычислить
22. Дано вещественное число х. Вычислить
23. Дано вещественное число х. Вычислить
24. Дано вещественное число х. Вычислить
25. Дано вещественное число х. Вычислить
26
ЛАБОРАТОРНАЯ РАБОТА № 2
РАЗВЕТВЛЯЮЩИЕСЯ ПРОГРАММЫ
Цель работы:
продолжить знакомство с работой в среде C++;
изучить операцию условия;
изучить условный Оператор;
изучить оператор множественного выбора.
Порядок выполнения работы:
В соответствии с поставленной задачей необходимо разработать графическую схему алгоритма, составить программу и отладить её в среде C++, подготовить отчет, ответить на контрольные вопросы и защитить, лабораторную работу перед преподавателем.
Общие сведения
К разветвляющимся программам приводят задачи, в которых в зависимости от некоторого условия, вычисления производятся тем или иным путем. Пусть нам необходимо вычислить значение у по формуле
На рис.8 приведена графическая схема алгоритма, а программа - в примере рr 7.
27
//Пример рr7
#include <stdio.h>
#include <conio.h>
#include <math.h>
void main()
{
float x,y;
printf ("Bвeдитe x:");
scanf ("%f",&x);
if (x>0)
y=x*x*x+3;
else
y=х*sin(x);
printf ("y=%4.2 f\n",y);
getch();
}
В этой программе впервые встречается условный оператор, который служит для выбора формулы вычисления y в зависимости от введенного значения x.
Условный оператор
Условный оператор служит для ветвлений в программе и имеет следующий синтаксис:
if(<условие>) <onepamop1>; else <onepamop2>.
Здесь if, else - ключевые слова (пер. с англ.: если, иначе соответственно);
<условие> - это условное выражение типа сравнения (например, а>b, c<=d, f=1);
<оператор1> и < оператор2> любой оператор С++.
Оператор работает следующим образом: если условие истинно, то выполняется <оператор1> и управление передается на следующий за условным оператор; если условие ложно, то выполняется <оператор2> и управление передается на следующий за условным оператор. Таким образом, всегда выполняется один из двух операторов: либо <оператор1>, либо <оператор2>.
Кроме вышеприведенной формы условного оператора, существует сокращенная форма условного оператора, в которой отсутствует ветвь else:
If <условие> <оператор1>.
О
28
Рассмотрим фрагменты схем алгоритмов и соответствующие им фрагменты программ.
if(a>b)
if(a>c)
max-a;
else
max=c;
if(a>b)
if(a>c)
max-a;
else
max=c;
if(a>b)
max = a;
else
max = b;
if(k>0)
s=s+k;
if(a>b)
if(a>c)
max = a;
else
max = c;
29
if(a>b)
if(a>c)
max=a;
else max=c;
else
if(b>c)
max=b;
else max=c;
В первом фрагменте программы приведена полная форма условного оператора, во втором - сокращенная, в третьем - сокращенная с вложенным условным оператором и в четвертом — полная форма с вложенными в каждой ветви условными операторами. Вложенные условные операторы уменьшают число необходимых проверок, обеспечивают большую эффективность, но ухудшают читаемость программы, поэтому не рекомендуется слишком увлекаться вложением условных операторов.
При определении последовательности выполнения вложенных условных операторов следует учесть, что каждое else соответствует тому if, которое ему непосредственно предшествует. Таким образом исключается всякая двусмысленность.
Подробнее остановимся на понятии условное выражение. В С++ используются следующие операции отношения:
< меньше;
<= меньше равно;
> больше;
>= больше равно;
== равно;
!
30
В языке C++ нет логического типа, но любое выражение имеет значение, в том числе и условное. "Истина" - это все ненулевые значения, и только 0 -"ложь" [5]. В программе рr8 это иллюстрируется:
// Пример рr8
#include <stdio.h>
#include <conio.h>
void main()
{
int true false;
true=10>2;
false=10=2;
printf("true=%d; false=%d\n",true,false);
if(200)
printf("200 - это истина \n");
if(-200)
printf("-200 - это истина \n");
if(0);
else
printf("0 - это ложь \n");
getch();
}
В результате работы этой программы будут выведены следующие сообщения:
true=1; false=0;
200 - это истина
-200 - это истина
0 - это ложь
В последнем условном операторе после условного выражения стоит так называемый пустой оператор, о чем свидетельствует знак точка с запятой при отсутствии какого-либо оператора. Исходя из предыдущих рассуждений, можно фрагмент if(a!=0) k++; заменить фрагментом if(a) k++;.
Если нужно проверить несколько условий, то можно воспользоваться булевыми операциями. Эти операции образуют инструментальный фундамент булевой логики, алгебры логики, разработанной в Х1Хв, математиком Джорджем Булем. Рассмотрим три основные булевы операции.
Операция && - логическое пересечение (умножение, операция "и"). Если а и b - условные выражения, например k>l или d==5, то выражение а && b дает значение истина только в том случае, если а и b имеют значения истина, в остальных случаях - ложь.
Операция || - логическое сложение (объединение, операция "или"). Выражение а || b дает ложное значение в том и только в том случае, если а и b имеют значения ложь, в остальных случаях – результат истина.
31
if(a>b && a>c)
max=а;
if(x==y || x==z)
z=y;
Операция ! - отрицание (операция "не"). Выражение !а имеет значение, противоположное значению а.
Эти операции полезны, если нужно проверить сложное условие:
Е
сли
исследовать приоритеты выполнения
операций, то самый высокий приоритет у
операций сравнения, затем идет операция
логического отрицания, затем -
логическое умножение, а потом - логическое
сложение.
Условный оператор может оказаться негибким, так как выполняемые действия могут быть описаны только одним оператором. Если необходимо выполнить в ветви условного оператора несколько операторов, то, в этом случае можно использовать составной оператор.
Составной оператор
К
32
if(c>0)
{ s=s+c;
k=k+1;
}
else c=c-1;
if(n<m)
{ n=n+1;
m=m-1;
}
else
{ n=n-1;
m=m+1;
}
Здесь следует обратить внимание на правила употребления точки с запятой:
каждое описание переменных и определение константы заканчивается точкой с запятой;
каждый оператор в теле программы завершается точкой с запятой.
33
Оператор условия
Оператор условия - это короткий способ записи условного оператора. В общем случае синтаксис этого оператора следующий:
<выражение1>?<выражение2>:<выражениеЗ>
Здесь <выражение1> - условное выражение и, если оно истинно, то вычисляется <выражение2>, которое становится результатом. Если <выражение1> - ложно, то результатом будет <выражениеЗ>. Классический пример:
х=(у<0)?-у: у;
Выражение возвращает абсолютное значение переменной у.
Оператор switch
Оператор switch предназначен для организации выбора из множества различных вариантов. В общем случае оператор switch выглядит следующим образом: switch (<выражение>)
{
case <выражение_1>:<операторы>;
case <выражение_2>: <операторы>;
…
case <выражение_n>: <операторы>;
default: <операторы>;
}
Здесь switch, case, default - ключевые слова (пер. с англ.: переключатель, состояние, невыполнение обязательств); <выражение> - выражение любого целого типа;
<выражние_1>, <выражение_2>, <выражение_n> - константа или константное выражение того же типа, что и <выражение>;
<операторы> - один или несколько операторов C++.
Р
34
Рассмотрим примеры, демонстрирующие работу: оператора выбора. В примере рr9 определяется, является ли введенное число n четным.
// Пример рr9
#include <stdio.h>
#include <conio.h>
void main()
{
int n;
printf("Bведите число");
scanf("%d",&n);
switch (n%2)
{ case 1: printf("%d - нечетное\n",n); break;
case 0: printf("%d - четное\n",n);
}
getch();
}
Следующая программа prl0 по номеру месяца определяет время года:
// Пример prl0
#include <stdio.h>
#include <conio.h>
void main()
{
int month; printf("Bведите число - номер месяца: ");
scanf("%d",&month); switch (month)
{case 12:
case 1:
case 2: printf("%d - зимний месяц",month); break;
case 3:
case 4:
case 5: printf("%d - весенний месяц",month); break;
case 6:
case 7:
case 8: printf("%d- Летний месяц ", month); break;
case 9:
case 10:
case 11: printf("%d - осенний месяц'',month); break;
default: printf("Про это мне неизвестно!");
}
getch();
35
Составим программу pr11, имитирующую работу простейшего калькулятора, выполняющего четыре арифметических действия.
// Пример pr11
#include <stdio.h>
#include <conio.h>
void main()
{
char op; // Знак арифметической операции
float x,y,z; //Операнды и результат
printf("\n Введите операнды х,у:");
scanf("%f%f ",&x,&y);
vvhile(getchar()!='\n'); // Очистка входного потока
printf("Введите знак арифметической операции:")
scanf(''%c",&op); switch(op)
{
case '*' z = x*y; printf("z=%f ", z); break;
case '/ ' if (y) { z = x/y; printf("z=%f ", z); }
else printf("Деление на ноль"); break;
case '+' z = x+y; printf("z=%f ", z); break;
case '-' z = x-y; printf("z=%f ", z); break;
default: printf("Увы! Это не арифметическая операция! ");
}
getch();
}
Здесь следует отметить, что функция scanf не является самой удачной функцией ввода хотя бы потому, что нам пришлось очищать входной поток. Несколько позже будут рассмотрены другие функции ввода и вывода.
Оператор перехода
В языке C++ имеются различные управляющие операторы, позволяющие написать любую программу. Тем не менее, в языке имеется оператор безусловного перехода.
Безусловный переход приводит к передаче управления из одного места программы в другое. Структура оператора перехода следующая:
goto <метка>
Здесь goto- ключевое слово (англ.: перейти на [метку]).
М
36
...............
goto 1;
m: ………
goto loop;
l: ..............
goto m;
Пример разветвляющейся программы
Как и в разделе с линейной программой, после разбора всех операторов и типов, необходимых для разветвляющейся программы, рассмотрим пример такой программы.
Поле шахматной доски определяется парой натуральных чисел, каждое из которых не превосходит восьми: первое число - номер вертикали (при счете слева направо), второе - номер горизонтали (при счете снизу вверх). Даны натуральные числа k,l,m,n, каждое из которых не превосходит восьми. Требуется выяснить, являются ли поля (k,l) и (m,n) полями одного цвета.
Прежде чем приступать к составлению алгоритма и программы, необходимо внимательно рассмотреть шахматную доску и прийти к выводу, что поля будут иметь одинаковый цвет, если сумма номеров горизонтали (k+l) и вертикали (n+m) того и другого поля будет четной или того (k+l) и другого (n+m) поля нечетной. Схема алгоритма приведена на рис.9, а программа на языке C++ - в примере pr13.
// Пример pr13
#include <stdio.h>
#include <conio.h>
void main()
{ int k,l,n,m;
printf("\nBведите координаты полей k,l,n,m:");
scanf("%d%d%d%d",&k,&l,&n,&m);
if((k+l)%2==0 && (n+m)%2==0 || (k+l)%2!=0 &&
(n+m)%2!=0)
printf("\nПоля однго цвета");
else printf("\nПоля разного цвета");
getch();
}
37
Рис. 9
Контрольные вопросы
1. Для чего служит условный оператор? Как он работает?
2. Какое значение х будет напечатано в результате работы следующей программы:
#include <stdio.h>
main()
{
float x=l,y=2;
int a=3, b=4;
if(a<b)
if(x<y)
x=x/a + у/x + a/b;
printf("x=%5.3f ",x);
}
3. Какие ошибки допущены в следующей программе:
#include <stdio.h>
main()
{
float x=l,y=2;
int a=3,b=4;
if(a<b) x=x+1
else
if(0<x<y)
x= x/a+ y/x +a/b;
38
4. Для следующего фрагмента схемы алгоритма составьте фрагмент программы на языке С++:
5. Что такое истина в С++?
6. Для чего используется оператор множественного выбора?
7. Написать на языке C++ программу, определяющую большее из трех заданных вещественных чисел.
Варианты заданий
1. Дано вещественное х. Составить программу вычисления z=f(x), если
Предусмотреть разрешение аварийных ситуаций.
2. Дано вещественное х. Составить программу вычисления y=f(x), если
Предусмотреть разрешение аварийных ситуаций.
3. Дано вещественное х. Составить программу вычисления y=f(x), если
Предусмотреть разрешение аварийных ситуаций.
4
39
Предусмотреть разрешение аварийных ситуаций.
5. Дано вещественное х. Составить программу вычисления y=f(x), если
Предусмотреть разрешение аварийных ситуаций.
6. Дано вещественное х. Составить программу вычисления y=f(x), если
Предусмотреть разрешение аварийных ситуаций.
7. Дано вещественное х. Составить программу вычисления y=f(x), если
Предусмотреть разрешение аварийных ситуаций.
8. Дано вещественное х. Составить программу вычисления z=f(x), если
Предусмотреть разрешение аварийных ситуаций.
9. Дано вещественное х. Составить программу вычисления z=f(x), если
Предусмотреть разрешение аварийных ситуаций.
10. Дано вещественное х. Составить программу вычисления z=f(x), если
Предусмотреть разрешение аварийных ситуаций.
11. Дано вещественное х. Составить программу вычисления y=f(x), если
Предусмотреть разрешение аварийных ситуаций.
1
40
Предусмотреть разрешение аварийных ситуаций.
13. Дано вещественное х. Составить программу вычисления y=f(x), если
Предусмотреть разрешение аварийных ситуаций.
14. Поле шахматной доски определяется парой натуральных чисел, каждое из которых не превосходит восьми: первое число - номер вертикали (при счете слева направо), второе - номер горизонтали (при счете сверху вниз). Даны натуральные числа k, l, m, n, каждое из которых не превосходит восьми. Требуется выяснить, угрожает ли ферзь полю (k, l), если он расположен на поле (m, n).
15. Поле шахматной доски определяется парой натуральных чисел, каждое из которых не превосходит восьми: первое число - номер вертикали (при счете слева направо), второе - номер горизонтали (при cчете сверху вниз). Даны натуральные числа k, I, m, n, каждое из которых не превосходит восьми. Требуется выяснить, угрожает ли конь полю (k, l), если он расположен на поле (m, n).
16. Даны целые числа m и n (0 < m <= 12, 0 <= n < 60), указывающие момент времени: "m часов, n минут". Определить наименьшее время (число полных минут), которое должно пройти до того момента, когда часовая и минутная стрелки на циферблате совпадут.
17. Даны целые числа m и n (0 < m <= 12, 0 <= n < 60), указывающие момент времени: "m часов, n минут". Определить наименьшее время (число полных минут), которое должно пройти до того момента, когда часовая и минутная стрелки на циферблате расположатся перпендикулярно друг к другу.
18. Составить программу, определяющую, лежит ли точка c координатами х1,у1 на прямой у=4х-3, выше или ниже прямой.
19. Дано: х и у - произвольные вещественные числа. Определить z по следующей формуле:
20. Определить, принадлежит ли точка с координатами (х,у) кругу радиуса r с центром в начале координат.
21. Написать программу определения суммы большего и меньшего из трех заданных чисел.
2
41
23. Даны три точки, заданные своим координатами, определить принадлежат ли эти точки одной прямой.
24. Дано вещественное x. Составить программу вычисления f(x), если f(x) задана графически на рис.10.
25. Дано вещественное x. Составить программу вычисления f(x), если f(x) задана графически на рис.11.
Рис. 10
Рис. 11
42
ЛАБОРАТОРНАЯ РАБОТА № 3
ЦИКЛИЧЕСКИЕ ПРОГРАММЫ
Цель работы:
ознакомиться с операторами цикла;
научиться пользоваться отладочным режимом в среде C++;
научиться выполнять программу по шагам.
Порядок выполнения работы:
В соответствии с поставленной задачей: разработать графическую схему алгоритма, составить программу и отладить её в среде C++, продемонстрировать преподавателю, как изменяются основные переменные в отладочном окне при выполнении программы по шагам, подготовить отчет, ответить на контрольные вопросы и защитить лабораторную работу перед преподавателем.
Примечание. Для открытия отладочного окна выбираем "в главном меню Debug, пункт Watches, а в нём пункт Add watch (или CTRL+F7). В открывшемся окне нужно набрать имя переменной, изменение которой вы намерены контролировать. Для выполнения программы по шагам выбираем в главном меню Run, пункт Trace into (F7) или Step over (F8) в зависимости от того, собираетесь ли вы выполнять по шагам написанные вами функции.
Все задачи решаются без вложенных циклов.