Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
ХЕРСОНСКИЙ НАЦИОНАЛЬНЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
КАФЕДРА ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ
Рег. №____________
для выполнения лабораторных работ
по дисциплине «Программирование»
для студентов направления подготовки 6050102 «Компьютерная инженерия»
отрасли знаний 0501 «Информатика и вычислительная техника»
факультета кибернетики
Методические указания для выполнения лабораторных работ по дисциплине «Программирование» для студентов направления подготовки 6050102 «Компьютерная инженерия» /Е.А. Дроздова. Херсон: ХНТУ, 2010. 75 с.
Рецензент: Бражник А.М., к.т.н., доцент кафедры Технической кибернетики ХНТУ
Утверждено
на заседании кафедры ИТ
протокол № 1 от «_30_» августа 2010 г.
Зав. кафедрой _____________проф. В.Е.Ходаков
Целью данных методических указаний является предоставление студенту методических материалов для выполнения лабораторных работ, предусмотренных рабочей программой изучения дисциплины «Программирование».
Данный цикл лабораторных работ выполняется в ходе изучения курса с целью закрепления теоретических знаний, полученных на лекциях, и приобретения практических навыков программирования на языке С.
Лабораторные работы выполняются в отведенное для этой цели аудиторное время, в соответствии с расписанием учебных занятий, в дисплейном классе, оборудованном персональными компьютерами типа IBM PC.
Как правило, выполнение каждой лабораторной работы требует от студента следующих действий:
Отчеты о выполнении лабораторных работ оформляются в ученической тетради или в виде сшитых листов формата А4, могут быть напечатаны или написаны от руки. Отчет о каждой работе должен содержать следующие разделы:
Защита лабораторных работ выполняется каждым студентом персонально. Для успешной защиты необходимо:
К лабораторным занятиям допускаются студенты, прошедшие инструктаж по технике безопасной работы в дисплейном классе. Студенты, нарушающие дисциплину или не соблюдающие технику безопасности, удаляются из дисплейного класса.
Лабораторная работа №1
Цель работы: Изучение интегрированной среды разработки программ Borland C.
Теоретические сведения
Borland C упрощает процесс программирования и делает его более эффективным. При работе в Borland C весь комплекс инструментальных средств, необходимых для написания, редактирования, компиляции, компоновки и отладки программ, оказывается под рукой у пользователя.
Весь этот комплекс возможностей заключен в Интегрированной Среде Разработки (ИСР).
Кроме того, Среда разработки программ Borland C предоставляет следующие дополнительные возможности, которые еще больше упрощают процесс написания программ:
ИСР содержит три визуальных компоненты: строку меню у верхнего края экрана, оконную область в средней части экрана и строку состояния у нижнего края экрана. В результате выбора некоторых элементов меню на экран будут выдаваться блоки диалога.
Строка меню и меню
Строка меню представляет собой основное средство доступа ко всем командам меню. Строка меню оказывается невидимой лишь во время просмотра информации, отображаемой программой и во время перехода к другой программе.
Окна Borland C
Большая часть того, что видно и делается в среде Borland C, происходит в окне. Окно - это область экрана, которую можно перемещать , размеры которой можно перемещать, изменять, которую можно распахивать на весь экран, ориентировать встык с другими окнами.
В Borland C может существовать произвольное число окон, но в каждый момент активно только одно окно. Активным является то окно, в котором в настоящий момент происходит работа.
Любые вводимые команды или вводимый текст, как правило, относятся только к активному окну.
Существует несколько типов окон, но большая их часть имеет следующие общие элементы:
Строка состояния
Строка состояния, расположенная у нижнего края экрана, выполняет следующие функции:
Блоки диалога
Если за элементом меню располагается многоточие, то в результате выбора данной команды будет открыт блок диалога , обеспечивающий удобный способ просмотра и задания многочисленных параметров.
При задании значения в блоке диалога работа происходит с пятью базовыми типами средств управления: указателями выбора, переключателями состояния, кнопками действия, блоками ввода и блоками списка.
Работа с экранным меню Borland C
МЕНЮ (системное)
Отображается у левого края строки меню. Для вызова следует нажать ALT -пробел. При вызове этого меню отображаются команды:
About
При выборе данной команды появляется блок диалога, в котором содержится информация по авторским правам и номер версии Borland C. Данное окно закрывается нажатием клавиши ESC или ENTER.
Clear Desktop
Закрывает все окна и стирает все списки предысторий. Эта команда полезна в тех случаях, когда начинается работа над новым проектом.
Repaint Desktop
Осуществляет регенерацию изображения на экране.
Элементы подменю Transfer
В этом подменю показаны имена всех программ, которые установлены с помощью блока диалога Transfer, вызываемого командой Options/Transfer. Для запуска программы необходимо выбрать ее имя из системного меню.
Меню File(ALT F)
Это МЕНЮ позволяет открывать в окнах EDIT и создавать исходные файлы программ, сохранять внесенные изменения, выполнять другие действия над файлами, выходить в оболочку DOS и завершать работу с Borland C.
Open(F3)
Команда FILE OPEN отображает блок диалога, в котором выбирается исходный файл программы, который будет открыт в окне EDIT.
Этот блок диалога содержит блок ввода, список файлов, и кнопки OPEN, REPLACE, CANCEL и HELP, а также информационную панель.
Здесь можно выполнить одно из действий:
1) Ввести полное имя файла и выбрать указатель REPLACE или OPEN.
В результате выбора Open файл загружается в новое окно Edit. Для выбора Replace должно иметься активное окно Edit; в результате выполнения Replace содержимое окна заменяется выбранным файлом.
2) Ввести имя файла с метасимволами. Это позволяет отфильтровать список файлов в соответствии со спецификацией.
Нажать , чтобы выбрать спецификацию файла из списка предыстории, который содержит введенные ранее спецификации файлов.
3) Просмотреть содержимое других каталогов, выбрав имя каталога из списка файлов.
Блок ввода позволяет явно ввести имя файла или ввести имя файла с метасимволами DOS (* и ?). Если ввести имя полностью и нажать Enter, Borland C откроет указанный файл. (Если ввести имя файла, который система Borland C не может обнаружить, она автоматически создаст и откроет новый файл с таким именем.)
Если нажать ? , когда курсор находится в блоке ввода, то под этим блоком появляется список предыстории, содержащий последние восемь имен файлов, которые были введены ранее.
New
Команда File New позволяет открывать новое окно Edit со стандартным именем NONAMExx.С (где вместо букв хх задается число в диапазоне от 00 до 99). Файлы с именем NONAME используются в качестве временного буфера для редактирования; когда файл с подобным именем сохраняется на диске, Borland C запрашивает действительное имя файла.
Save (F2)
Команда File Save записывает на диск файл, находящийся в активном окне Edit (если активно окно Edit в настоящий момент, если нет, то данным элементом меню нельзя воспользоваться.) Если файл имеет использованное по умолчанию имя (NONAME00.C и т.п.) Borland C откроет блок диалога Save Editor File, который позволяет переименовать данный файл и сохранять его в другом каталоге или на другом дисководе.
Save As
Команда File Save As позволяет сохранить файл в активном окне Edit под другим именем, в другом каталоге или на другом дисководе.
Change Dir
Команда File Change Dir позволяет задать идентификатор и имя каталога, которые следует сделать текущими. Текущим является тот каталог, который используется в Borland C для сохранения и поиска файлов. (При использовании относительных маршрутов в Options Directories они задаются только относительно текущего каталога).
Команда File Print печатает содержимое активного окна Edit Borland C "раскрывает" символы табуляции (заменяет их соответствующим числом пробелов), а затем посылает файл на устройство печати, заданное в DOS. Данная команда будет "запрещена", если содержимое активного окна не может быть выведено на печать. Для вывода на печать только выделенного текста следует использовать Ctrl-K P.
Get Info
Команда File Get Info отображает блок, в котором содержится информация относительно текущего файла.
ЗНАЧЕНИЕ |
СМЫСЛ |
Current directory |
Имя каталога по умолчанию |
Current file |
Имя файла в активном окне |
Extended memory usage |
Объем дополнительной памяти, зарезервированной для Borland C |
Expanded memory usage |
Объем расширенной памяти, зарезервированной для Borland C |
Lines compiled |
Число откомпилированных строк |
Total warnings |
Число выданных системой предупреждающих сообщений |
Totals errors |
Число сгенерированных ошибок |
Total time |
Время последнего выполнения программы |
Program loaded |
Статус отладки |
Program exit |
Код возврата от последней завершившейся программы |
Available memory |
Объем доступной памяти DOS (640 К) |
Last step time |
Время выполнения последнего шага отладки |
DOS Shell
Команда File DOS Shell позволяет временно выйти из Borland C, чтобы выполнить команду DOS или запустить программу. Для возврата в Borland C необходимо ввести с клавиатуры EXIT и нажать Enter.
Иногда можно обнаружить, что во время отладки не хватает памяти для выполнения этой команды. В этом случае необходимо завершить сеанс отладки командой Run Program Reset (Ctrl-F2).
Quit (Alt-x)
Команда File Quit осуществляет выход из системы Borland C, удаляет ее из памяти и передает управление DOS. Если внесены изменения, которые еще не были сохранены, то перед выходом Borland C выдаст запрос на их сохранение.
Меню Edit(Alt-E)
Позволяет выполнять удаления, копирование и вставку текста в окнах Edit. Можно также открыть окно текстового буфера для просмотра или редактирования его содержимого. Выбрать текст это значит выделить его цветом:
1) Нажать Shift с одновременным нажатием стрелки.
2) Нажать Ctrl-K B, чтобы пометить начало выделяемого блока.
Затем переместить курсор в конец фрагмента текста и нажать Ctrl-K K.
3)Для выбора строки необходимо нажать Ctrl-K L.
После выделения фрагмента текста становятся доступными команды, расположенные в меню Edit, и можно использовать текстовый буфер (Clipboard).Он взаимодействует с командами меню Edit:
Restore Line
Эта команда отменяет действие последней команды редактирования, примененной к какой-либо строке. Она действует только над последней отредактированной строкой.
Cut (Shift-Del)
Удаляет выделенный фрагмент текста из документа и заносит его в текстовый буфер. Затем можно вставить текст в другой документ путем выбора Paste.
Copy (Ctrl-Ins)
Эта команда не изменяет выделенный текст, но заносит в текстовый буфер его точную копию. Затем можно вставить текст в другой документ командой Paste. Можно скопировать текст из окна Help; следует использовать Shift и клавиши управления курсором.
Paste (Shift-Ins)
Эта команда вставляет текст из текстового буфера в текущее окно в позиции курсора.
Show Clipboard
Эта команда открывает окно Clipboard, в котором хранятся фрагменты текста, удаленного и скопированного из других окон.
Clear (Ctrl-Del)
Эта команда удаляет выбранный фрагмент текста, но не заносит его в текстовый буфер. Это означает, что восстановить удаленный текст нельзя.
Меню Search (Alt-S)
Меню Search выполняет поиск текста, объявлений функций, а также местоположение ошибок в файлах.
Команда Search Find отображает блок диалога Find, который позволяет ввести образец поиска и задать параметры, влияющие на процесс поиска. Эта команда может быть также вызвана с помощью (Ctrl-Q-F).
Replace (Ctrl Q A)
Команда Search Replace отображает блок диалога для ввода искомого текста и текста, на который его следует заменить.
Search Again (Ctrl L)
Команда Search Again повторяет действие последней команды Find или Replace. Все параметры, которые были заданы при последнем обращении к использованному блоку диалога(Find или Replace), остаются действительными при выборе данной команды.
Меню Run (Alt-R)
Команды этого меню выполняют программу, а также инициализируют и завершают сеанс отладки.
Run(Ctrl-F9)
Команда Run выполняет программу, используя те аргументы, которые переданы программе с помощью команды Run Arguments.
Тrace Into(F7)
Эта команда выполняет программу по операторам. По достижению вызова функции будет выполняться каждый ее оператор вместо того, чтобы выполнить эту функцию за один шаг. Этой командой следует пользоваться для перемещения выполнения в функцию, которая вызывается из отлаживаемой функции.
Program Reset(Ctrl-F2)
Команда Run Program Reset прекращает текущий сеанс отладки, освобождает память программы и закрывает все открытые файлы, которые использовались в программе.
Over
Команда Run Step Over выполняет следующий оператор в текущей функции без вхождения в функции более низкого уровня, даже если эти функции доступны отладчику. Командой Step Over следует пользоваться в случаях, когда необходимо отладить функцию в пооператорном режиме выполнения без вхождения в другие функции.
Arguments
Команда Run Arguments позволяет задать выполняемой программе аргументы командной строки точно так же, как если бы они вводились в командной строке DOS. Команды переназначения ввода/вывода DOS будут игнорироваться.
Compile (C)
Команды из меню Compile используются для компиляции программы в активном окне, а также для полной или избирательной компиляции проекта:
EXE File
Команда Compile Make EXE File вызывает Менеджер проектов для создания EXE-файла.
Link EXE File Только при полном наборе меню
Команда Compile Link EXE File использует текущие OBJ и LIB-файлы и компонует их, не производя избирательной компиляции.
Меню Debug (Alt F9)
Команды меню Debug управляют всеми возможностями интегрированного отладчика.
Inspect (Alt F4)
Команда Debug Inspect открывает окно Inspector, которому позволяет проанализировать и модифицировать значения элемента данных.
Меню Options(Alt-O)
Меню Oрtions содержит команды, которые позволяют просматривать и модифицировать стандартные параметры, определяющие функционирование Borland C.
Задание:
1. Используя команды экранного меню File, найти, открыть и переименовать какой-либо файл из каталога примеров пакета Borland C.
2. Используя команды экранного меню Edit, отработать приемы редактирования.
Контрольные вопросы
Лабораторная работа №2
Организация размещения данных при выводе на экран.
Использование функции printf()
Цель работы: Научиться использовать функцию printf() для вывода на экран.
Теоретические сведения
Трудно себе представить программу без функций ввода/вывода. Чаще всего для вывода информации используется функция вывода printf(), одна из множества имеющихся в С. Функция printf() отвечает за форматный вывод. Её синтаксис выглядит следующим образом:
#include <stdio.h>
int printf (char *format-string [, argument...]);
Функция формирует и печатает наборы символов и значений в стандартный выводной поток, stdout, которым по умолчанию является монитор. Format-string состоит из обычных символов, escape-последовательностей, и, если за format-string следуют аргументы, спецификации форматов. Обычные символы и escape-последовательности просто копируются в stdout (на монитор) в порядке их появления. Например, строка
printf(" Первая строка\n\t\t Вторая строка\n");
выводит
Первая строка
Вторая строка
Если за format-string следуют аргументы arguments, то format-string должна содержать спецификацию форматов, определяющих выводной формат для этих аргументов. Спецификации форматов начинаются с символа процента (%) и описываются ниже. Format-string считывается слева направо. Когда первая спецификация формата (если их несколько) встречается, значение первого аргумента после format-string преобразуется и выводится согласно спецификации формата. Вторая спецификация формата преобразует и выводит второй аргумент, и таким образом продолжается до конца format-string. Если задано больше аргументов, чем спецификаций формата, лишние аргументы игнорируются. Результат будет неопределенным, если нет достаточного количества аргументов для всех спецификаций форматов.
Cпецификаторы помещаются внутри печатаемой строки. Вслед за этой строкой должны стоять нуль или более значений (констант, переменных или выражений), разделенных запятыми. Каждому спецификатору в операторе вызова функции printf должно соответствовать значение соответствующего типа.
Более формально спецификатор % можно определить следующим образом:
%[flags] [width] [.precision] [l,L] type
Обязательными являются только символы «%» и type.
Символ % означает, что в данном месте строки должно быть напечатано значение из следующего далее списка.
Символ формата type служит для указания типа выводимого значения и может принимать значения в соответствии с таблицей 2.1:
Таблица 2.1 Символы формата
Символ type |
Пример выводимого значения |
Назначение |
%c |
? |
Одиночный символ |
%d |
123 |
Десятичное целое число |
%e |
3.50000e+00 |
Число с плавающей точкой в экспоненциальном представлении |
%Е |
3.50000E+00 |
Число с плавающей точкой в экспоненциальном представлении |
%f |
3.500000 |
Число с плавающей точкой в десятичном представлении |
%g |
для числа 0.00314 вывод 0.00314 для числа 0.0000314 вывод 3.14e-05 |
Число в форме f или e в зависимости от значения. Форма e используется, если показатель меньше чем -4 или больше либо равен заданной точности. |
%G |
Аналогично %g |
То же, что и %g, но при выводе в экспоненциальной форме используется символ E. |
%i |
6 |
Десятичное целое число со знаком |
%o |
13 |
Восьмеричное целое число без знака |
%p |
5B74 |
Указатель (адрес памяти) |
%s |
Str |
Строка символов |
%u |
18 |
Десятичное целое число без знака |
%x |
1f |
Шестнадцатиричное целое число без знака |
%X |
1F |
Шестнадцатиричное целое число без знака |
%% |
% |
Печать знака процента |
Все прочие элементы строки формата называются модификаторами и служат для уточнения формы представления информации при выводе.
Символы l или L используются для указания целых длинных типов.
Модификатор формата width (ширина) представляется целым положительным числом и служит для указания минимального количества выводимых символов. Если количество символов выводимого значения меньше width, поле будет дополняться символами в соответствии с указанными флагами. Значение width никогда не ограничивает выводимое значение.
Варианты элемента flags представлены в таблице 2.2.
Таблица 2.2 Значения модификатора flags
Значение флага |
Пример |
Назначение |
- |
%-20s |
Значение выравнивается по левому краю поля |
+ |
%+d |
Выводится знак значения - как плюс, так и минус |
Пробел |
% 6.2f |
Положительные значения печатаются без знака, но с пробелом, отрицательные со знаком "минус" |
0 |
%010d %08.3f |
Для числовых форм поле вывода заполняется по ширине нулями вместо пробелов. Этот флаг игнорируется, если указан флаг "-" или указана точность для целочисленной формы |
# |
%#o %#8.0f %+#10.3E |
Вывод первого 0 для восьмеричных, 0x или 0X для шестнадцатиричных. Для всех форм с плавающей точкой гарантируется вывод символа десятичной точки. Для форм %g и %G предотвращается удаление заключительных нулей. |
Модификатор формата .precision (точность) используется для чисел с плавающей точкой. Точность представляется неотрицательным целым числом, следующим за точкой и задает либо количество символов, которое должно быть выведено (для строк), либо количество цифр в дробной части числа (для значения с плавающей точкой), либо количество значащих цифр (для целого). Так "%5.2f" определяет вывод вещественного числа в поле шириной пять символов с двумя цифрами после десятичной точки.
Задание:
Контрольные вопросы
Лабораторная работа №3
Цель работы: Научиться использовать функцию scanf() для ввода данных с клавиатуры.
Функция scanf() является одной из многих функций ввода, хранящихся во внешних библиотеках. Синтаксис этой функции рассмотрим на конкретном примере. Приведём пример программы, осуществляющей ввод с клавиатуры некоторого числа и запись его в переменную с последующим выводом её значения на экран.
#include<stdio.h>
main()
{
int a;
printf("\n Введите целое число:");
scanf("%d", &a);
printf("\n Вы ввели число %d", a);
}
В этой программе помимо известной уже функции printf() содержится функция scanf(). Каждой вводимой величине, а их может быть несколько, в строке функции scanf() должен соответствовать спецификатор типа (для целых %d, для вещественных %f, для символьных %c, для строковых %s и др.). Перед именем переменной, которой присваивается вводимое значение, в строке функции scanf() должен стоять символ & (операция взятия адреса). Спецификаторы функции scanf() полностью совпадают со спецификаторами функции printf().
При вводе нескольких значений с помощью одной функции scanf() следует помнить, что в символьной строке, являющейся параметром функции, спецификаторы вводимых переменных должны отделяться друг от друга разделителями (пробелами, запятыми и др.). Теми же разделителями должны отделяться друг от друга значения, вводимые с клавиатуры. Приведём пример программы ввода нескольких чисел.
#include<stdio.h>
main()
{
int a, b;
float c, d;
printf("\n Введите целые числа:");
scanf("%d,%d", &a, &b);
printf("\n Введите вещественные числа:");
scanf("%f %f", &c, &d);
printf("\n Вы ввели числа %d %d %f %f", a, b, c, d);
}
В данной программе при вводе целых чисел их необходимо разделять запятыми, а при вводе вещественных чисел - пробелами.
Как правило, функция scanf() используется для ввода только числовых значений или одиночных символов. Для ввода строк она неудобна, т.к. не воспринимает символы пробела и конца строки.
Задание:
а) Целое, вещественное, символьное.
б) Вещественное, символьное.
в) Символьное, целое.
Контрольные вопросы
Лабораторная работа №4
Типы констант. Использование констант в языке С
Цель работы: Изучение использования констант различных типов в языке С.
В языке С имеется четыре типа констант: целые, вещественные (с плавающей точкой), символьные и строковые.
Константы целого типа
Константы целого типа могут задаваться в десятичной, двоичной, восьмеричной или шестнадцатеричной системах счисления.
Десятичные целые константы образуются из цифр. Первой цифрой не должен быть нуль.
Восьмеричные константы всегда начинаются с цифры нуль, вслед за которой либо не стоит ни одной цифры, либо стоят несколько цифр от нуля до семерки.
Шестнадцатеричные константы всегда начинаются с цифры нуль и символа х или Х, все, за которыми может стоять одна или более шестнадцатеричных цифр.
Шестнадцатеричные цифры - это десятичные цифры от 0 до 9 и латинские буквы: a, b, c, d, e, f, или A, B, C, D, E, F.
Например: задание константы 3478 в десятичном, восьмеричном и шестнадцатеричном виде:
int a = 3478,
b = 06626,
c = 0хD96;
К любой целой константе можно справа приписать символ l или L, и это будет означать, что константа - длинная целая (long integer). Символ u или U, приписанный к константе справа, указывает на то, что константа целая без знака (unsigned long).
Считается, что значение любой целой константы всегда неотрицательно. Если константе предшествует знак минус, то он трактуется как операция смены знака, а не как часть константы.
Константы вещественного типа
Константы с плавающей точкой (называемые вещественными) состоят из цифр, десятичной точки и знаков десятичного порядка е или Е. Ниже приведены все возможные варианты записи констант вещественного типа:
1. 2e1 .1234 .1e3
.1 2E1 1.234 0.0035e-6
1.0 2e-1 2.1e-12 .234
Cимвольные константы
Cимвольные константы заключаются в апострофы (кавычки). Все символьные константы имеют в (Турбо) С значение типа int (целое), совпадающее с кодом символа в кодировке ASCII.
Одни символьные константы соответствуют символам, которые можно вывести на печать, другие - управляющим символам, задаваемым с помощью esc - последовательности, третьи - форматирующими символами, также задаваемым с помощью esc - последовательности.
Например:
символ " апостроф " задается как '\'', переход на новую строку - как '\', а обратный слэш - как '\\'.
Каждая esc - последовательность должна быть заключена в кавычки.
Управляющие коды
\n Новая строка
\t Горизонтальная табуляция
\v Вертикальная табуляция
\b Возврат на символ
\r Возврат в начало строки
\f Прогон бумаги до конца страницы
\\ Обратный слэш
\' Одинарная кавычка
\" Двойная кавычка
\а Звуковой сигнал
\? Знал вопроса
\ddd Код символа в ASCII от одной до трех восьмеричных цифр
\xhhh Код символа в ASCII от одной до трех шестнадцатеричных цифр.
Строковые константы
Строковые константы состоят из нуля или более символов, заключенных в двойные кавычки. В строковых константах управляющие коды задаются с помощью esc - последовательности. Обратный слэш используется как символ переноса текста на новую строку.
Пример описания строковых констант:
# include <stdio.h>
main( )
{
char *str1, *str2;
str1=“ Пример использования\n\n”;
str2=“строковых\
констант.\n\n”;
printf(str1);
printf(str2);
}
Программа выведет следующий текст:
Пример использования
строковых констант.
Задание:
Написать программу, выводящую на экран строковую константу, заключенную в кавычки (символ кавычек должен быть выведен на экран) и число, состоящее из цифр вашего дня рождения, заданное в виде десятичной, восьмеричной и шестнадцатеричной константы. Каждую константу напечатать с новой строки. В начале каждой строки вывести символ горизонтальной табуляции. После этих действий вывести 3 раза звуковой сигнал.
Контрольные вопросы
Лабораторная работа № 5
Работа с автоматизированной
обучающей системой AOS_C
Цель работы: получить навыки в использовании основных операций и функций языка С в автоматизированной обучающей системе.
Автоматизированная обучающая система (АОС) является законченным программным продуктом, предназначенным для получения студентами навыков в использовании основных функций и операторов языка С. Работа в АОС предусматривает два основных режима: самостоятельной и контрольной работы.
В режиме самостоятельной работы студент может получить исчерпывающую информацию по выбранной теме, выполнить предложенные задания и сверить полученные результаты с ответами.
Режим контрольной работы предусматривает проверку на практике полученных студентом знаний и навыков с выставлением соответствующей оценки.
В работе с АОС рекомендуется придерживаться следующей последовательности действий:
Темы для самостоятельной проработки в АОС:
№ |
Тема |
АОС |
|
Тема |
Упражнение |
||
|
Арифметические опера-ции, операции при-сваивания. |
Операции |
Операции присваивания |
|
Логические и условные операции. |
Операции |
|
|
Управление, конструкции выбора. |
Управление |
|
|
Управление, циклы |
Управление |
|
Пример работы с АОС:
Запустить программу и нажать несколько раз <Enter> до появления меню:
Выбрать тему «операции» и нажать дважды <F10>, до появления меню:
Нажать <>:
Выбрать «операции присваивания», нажать <F10>:
Вычислить предложенные упражнения, нажать <F1>, ввести результаты.
Следует заметить, что при выполнении заданий в некоторых разделах АОС примеры программ могут не вмещаются на один экран, о чем сигнализирует надпись в нижнем правом углу после нажатия <F1>. Используя предложенные клавиши (Home,End, ,,PgUp, PgDown) можно просмотреть всё задание.
При необходимости повторить вычисления и ввод результатов:
Для выхода из АОС несколько раз нажать <F10> до появления меню выбора возможностей АОС, нажать <> (выход), и несколько раз <ESC>, до выхода в оболочку.
Лабораторная работа № 6
Работа с автоматизированной обучающей системой:
арифметические операции, операции присваивания
Цель работы: получить навыки в использовании арифметических операций и операций присваивания языка С в автоматизированной обучающей системе.
Арифметические операции
Числа можно складывать, вычитать, умножать и проделывать над ними другие действия, обозначаемые специальными знаками, называемые операциями; объект, на который действует операция, называется операндом.
Каждая операция определяет количество операндов, их типы и тип результата, при этом по количеству операндов операции делятся на следующие типы:
К арифметическим операциям относят:
Унарные операции:
Унарный минус
Формат: -E;
где E выражение, имеющее тип signed, char, int, float, long, short, double, long double.
Результат операции по абсолютному значению совпадает с E, но имеет противоположный знак; тип результата совпадает с типом E.
Унарный плюс
Формат: +E;
где E выражение, имеющее тип signed, char, int, float, long, short, double, long double.
Результат операции и тип результата совпадает с E. Как правило, для того чтобы не засорять программу, унарный плюс опускают.
Инкремент и декремент
Формат: префиксная форма ++E; --E;
постфиксная форма E++; E--;
где E может быть переменной любого целочисленного типа, причем E обязательно должно быть переменной, а не константой, т.е. операции 1++ или --7 некорректны.
Операция инкремент (декремент) увеличивает (уменьшает) переменную на единицу, при этом префиксная запись изменяет переменную до её использования в выражении, а постфиксная после.
Бинарные операции:
Формат:
E1 + E2; E1 E2; E1 * E2; E1 / E2; E1 % E2;
где E1 и E2 выражения любого типа: целого или вещественного, кроме операции % - её операндами могут быть только выражения целого типа.
Результат имеет такой же тип, как и у операндов. Если тип левой и правой части различны, то тип правой приводится к типу левой.
Специфической операцией является «%», которая называется операцией определения остатка от деления. Её операнды всегда должны иметь целый тип; знак результата совпадает со знаком E1, если используются знаковые числа.
При вычислении выражений порядок выполнения операций можно изменить, расставив круглые скобки.
Операции простого присваивания
Формат: E1 = E2;
При выполнении операции переменная E1 получает значение выражения E2, тип и значение результата операции совпадают с типом и значением E2. Можно выполнять также многократные присваивания:
E1=E2=E3=…=En=K;
где K значение n переменных.
Операции присваивания могут применяться также и в правой части выражения:
a = (b = c)*d;
где в правой части переменной b присваивается значение переменной c, затем это значение умножается на d и присваивается переменной a.
Составные операции присваивания
Формат:
E1+=E2; E1=E2; E1*=E2; E1/=E2; E1%=E2;
где E1 переменная любого типа; E2 выражение того же типа.
При выполнении операции сначала вычисляется значение E2, а затем:
Задание:
Пример работы с АОС:
Через ОПЕРАЦИИ | РЕЖИМ САМОСТОЯТЕЛЬНОЙ РАБОТЫ | ОПЕРАЦИИ ПРИСВАИВАНИЯ выйти к меню (вариант может отличаться):
Внимательно прочесть теорию (<F2>).
Вычислить предложенные примеры, например:
Следуя вышеизложенным правилам и учитывая, что x уже задано, вычисляем
1*8=8; 8-8=0; x=x+0;
таким образом
x=4;
Далее
Здесь в правой части производится многократное присваивание, другими словами переменные z и y приравниваются -3
z=-3; y=z; x=x*y;
т.е.
x=-12;
Здесь, учитывая приоритет операций, сначала происходит сравнение на неравенство чисел 19 и 48, после чего значение выражения присваивается переменной x:
-19!=-48; (=1)
т.е.
x=1;
Здесь сначала вычисляется выражение в правой части, а именно: переменной y присваивается значение 58. Далее происходит нестрогое сравнение значения x и значения y, при этом никого присваивания НЕ происходит (операция >= - операция сравнения), таким образом, переменная x не изменяет своего значения
y=58; x>y;
т.е.
x=1;
После того, как все предложенные программой задания будут вычислены, нажать <F1> и ввести полученные ответы, при этом программа, после ввода всех ответов, должна подтвердить правильность расчетов:
Лабораторная работа № 7
Работа с автоматизированной обучающей системой:
логические и условные операции
Цель работы: получить навыки в использовании логических и условных операций языка С в автоматизированной обучающей системе.
Логические операции и операции увеличения
В языке С имеется три логические операции И, ИЛИ, НЕ.
Таблицы истинности этих операций приведены ниже:
И(&&) |
ИЛИ(||) |
НЕ(!) |
|||
0 |
1 |
0 |
1 |
1 |
|
0 |
0 |
0 |
0 |
1 |
|
1 |
0 |
1 |
1 |
1 |
0 |
Формат записи: E1&&E2; E1||E2; !E1;
где E1 и E2 выражения целого или вещественного типа. Следует учесть то, что выражение считается равным 1, если оно не равно 0, другими словами, если значение какого либо выражения равно, например 21, то оно считается равным 1 или истинно. Аргументами логических операций могут быть также и аргументы типа char.
Используя круглые скобки, можно изменить порядок выполнения логических операций.
При вычислении логических операций имеет место следующие правило, позволяющее ускорить вычисление (правило усечения):
Операции увеличения (или инкремент и декремент)
Подробно рассмотрены в лабораторной работе «Арифметические операции, операции присваивания».
Операции отношения
В языке С имеют место следующие операции отношения:
< (меньше);
<= (меньше либо равно);
== (равенство);
!= (не равно);
>= (больше либо равно);
> (больше).
Формат записи:
E1<E2; E1<=E2; E1==E2; E1!=E2; E1>=E2; E1>E2;
где E1 и E2 выражения целого или вещественного типа, при этом результат имеет всегда тип int.
Результат операции равен 1, если:
в противном случае для каждой операции результат равен 0.
Следует учитывать также, что, как и для логических операций, любое выражение не равное 0 считается равным 1, т.е. верным.
Условная операция ?: (тернарная операция)
Формат записи:
E1 ? E2 : E3;
где E1 выражение целочисленного или вещественного типа; типы E1 и E2 должны совпадать и могут быть любыми.
Выполнение данной операции зависит от истинности E1:
Логические выражения
Логические выражения вычисляются так же, как и арифметические в соответствии с приоритетами. В них можно так же изменять порядок выполнения операций расстановкой круглых скобок.
Порядок и направление выполнения операций
В выражении различные операции можно комбинировать. Рассмотрим некоторые из них.
Например, выражение 2+2*2 будет равно 8 или 6? Операции, приведенные в таблице выше, будут вычислены раньше, или, как говорят, имеют более высокий приоритет, чем те, которые расположены ниже.
Рассмотрим ещё один пример: какой результат даст выражение 40/5*2? Приоритет выполнения операций “/” и “*” одинаков, но в зависимости от того, какая операция будет вычислена первой, в данном случае можно получить два ответа: 16 или 4. Таким образом, при выполнении операций необходимо учитывать их направление: слева на право или наоборот. Эти данные также приведены в таблице.
Операция |
Направление |
!, - (унарный), +(унарный), ++, -- |
Справа налево |
*, /, % |
Слева направо |
<, <=, >, >= |
Слева направо |
==, != |
Слева направо |
&& |
Слева направо |
|| |
Слева направо |
? : |
Справа налево |
=,+=,-=,*=,/=,%= |
Справа налево |
Таким образом, при выполнении операций слева направо, первой из двух, имеющих одинаковый приоритет, будет выполнена левая операция, при выполнении справа налево правая.
Задание:
Пример работы с АОС:
Через ОПЕРАЦИИ | РЕЖИМ САМОСТОЯТЕЛЬНОЙ РАБОТЫ | (ОПЕРАЦИИ: ЛОГИЧЕСКИЕ И УВЕЛИЧЕНИЯ + ОПЕРАЦИИ ОТНОШЕНИЯ И УСЛОВИЯ + ЛОГИЧЕСКИЕ ВЫРАЖЕНИЯ) выйти к меню (цифры могут отличаться):
Внимательно прочесть теорию (<F2>).
Вычислить предложенные примеры, например:
Следуя вышеизложенным правилам и учитывая, что x, y, z уже заданы, имеем:
0||0||!2 т.е. 0||0||0, что равно 0.
имеем: z = 5 + 2 (x=5 при вычислении, т.к. префиксная форма записи указывает на инкремент до использования переменной в выражении). При выполнении этой строки переменные x и z принимают значения, равные 5 и 7 соответственно.
Значение последней строки равно 2, проверьте.
Переписать задание и ответы в тетрадь для лабораторных работ и перейти к выполнению следующего задания (нажать любую клавишу). Таким образом выполнить все предложенные задания.
Для перехода к следующей теме («Операции отношения и условия») нажать <F10>.
Переписать задание и ответы в тетрадь для лабораторных работ и перейти к выполнению следующего задания (нажать любую клавишу). Таким образом выполнить все предложенные задания. Для перехода к следующей теме (Логические выражения) нажать <F10>:
Лабораторная работа №8
Операторы и операции
Цель работы: Изучение арифметических, логических операций и операций отношения и присваивания.
Основу языка С составляют операторы. Оператором выражения называют выражение, вслед за которым стоит точка с запятой. В С точки с запятой используются для разделения операторов. Принято группировать все операторы в следующие классы: присваивания, вызов функции, ветвления и цикла.
В операторе присваивания используется операция присваивания = ,
Например:
c = a * b;
Действие такого оператора можно описать следующими словами: " с присваивается значение а, умножение на b ". Значение, присваиваемое переменной с, равняется произведению текущих значений переменных а и b.
Операторы часто относятся более чем к одному из четырех классов.
Например: оператор:
if ( ( c = cube( a * b ) ) > d )
...
составлен из представителей следующих классов: присваивания, вызов функции, и ветвление.
К понятию оператора вплотную примыкает понятие операции.
Различают следующие группы операций С: арифметические операции, операции отношения, операции присваивания, логические операции, побитовые операции, операция вычисления размера (sizeof) и операция следования (запятая).
Арифметические операции
К арифметическим операциям относятся: сложение (+), вычитание (-), деление (/) , умножение (*) и остаток (%). Все операции (за исключением остатка) определены для переменных типа int , char , float. Остаток не определен для переменных типа float. Все арифметические операции с плавающей точкой производятся над операндами двойной точности.
Операции отношения
В языке определены следующие операции отношения: проверка на равенство (==), проверка на неравенство (!=), меньше (<), меньше или равно (<=), больше (>), больше или равно (>=).
Все перечисленные операции вырабатывают результат типа int. Если данное отношение между операндами истинно, то значение этого целого - единица, а если ложно, то нуль.
Все операции типа больше-меньше имеют равный приоритет, причем он выше , чем приоритет операций == и !=. Приоритет операции присваивания ниже приоритета всех операций отношений. Для задания правильного порядка вычислений используются скобки.
Логические операции
В языке имеются три логические операции:
&& операции И (and)
|| операции ИЛИ (or)
! отрицание
Аргументами логических операций могут быть любые числа, включая задаваемые аргументами типа char. Результат логической операции - единица, если истина, и нуль, если ложь. Вообще все значения, отличные от нуля, интерпретируются как истинные.
Логические операции имеют низкий приоритет, и поэтому в выражениях с такими операциями скобки используются редко.
Вычисление выражений, содержащих логические операции, производится слева направо и прекращается (усекается), как только удается определить результат. Если выражение составлено из логических утверждений (т.е. выражения, вырабатывающие значения типа int), соединенных между собой операцией И (&&), то вычисление выражения прекращается, как только хотя бы в одном логическом утверждении вырабатывается значение нуль. Если выражение составлено из логических утверждений, соединенных между собой операцией ИЛИ (||), то вычисление выражения прекращается, как только хотя бы в одном логическом утверждении вырабатывается ненулевое значение.
Вот несколько примеров, в которых используются логические операции:
if( i > 50 && j == 24)
...
if( value1 < value2 && (value3 > 50 || value4 < 20) )
...
Операции присваивания
К операциям присваивания относятся =, +=, -=, *= и /=, а также префиксные и постфиксные операции ++ и --. Все операции присваивания присваивают переменной результат вычисления выражения. Если тип левой части присваивания отличается от типа правой части, то тип правой части приводится к типу левой.
В одном операторе операция присваивания может встречаться несколько раз. Вычисления производятся справа налево.
Например:
a = ( b = c ) * d;
Вначале переменной d присваивается значение с, затем выполняется операция умножения на d, и результат присваивается переменной а.
Операции +=, -=, *= и /= являются укороченной формой записи операции присваивания. Их применение проиллюстрируем при помощи следующего описания:
a += b означает a = a + b.
a -= b означает a = a - b.
a *= b означает a = a * b.
a /= b означает a = a / b.
Префиксные и постфиксные операции ++ и -- используют для увеличения (инкремент) и уменьшения (декремент) на единицу значения переменной.
Семантика указанных операций следующая:
++a увеличивает значение переменной а на единицу до использования этой переменной в выражении.
а++ увеличивает значение переменной а на единицу после использования этой переменной в выражении.
--a уменьшает значение переменной а на единицу до использования этой переменной в выражении.
a-- уменьшает значение переменной а на единицу после использования этой переменной в выражении.
Операцию sizeof (размер) можно применить к константе, типу или переменной. В результате будет получено число байтов, занимаемых операндом.
Например:
printf ( "\nРазмер памяти под целое %d", sizeof( int) );
printf ( "\nРазмер памяти под cимвол %d", sizeof( сhar) );
Задание:
Cоставить программу, использующую оператор присваивания, все арифметические операции, инкремент и декремент для вычислния какой-либо переменной по заданной самостоятельно формуле, а также операцию sizeof для определения занимаемого этой переменной объема памяти.
Лабораторная работа № 9
Работа с автоматизированной обучающей системой:
условный оператор IF-ELSE
Цель работы: получить навыки в использовании операций управления языка С в автоматизированной обучающей системе.
В программировании часто встречаются такие ситуации, когда выполнение какого-нибудь действия зависит от определённых условий. Для разрешения этой проблемы в языке С существуют условные операторы if и switch.
Операторы if, if…else
Формат: if (условие) оператор
[else оператор]
где условие это любое вычисляемое выражение. Если условие истинно, т.е. результат вычисления этого выражения отличен от нуля, то выполняется оператор (возможно, составной), стоящий после круглых скобок. После его выполнения вычисления продолжаются с первого оператора, стоящего сразу после оператора if. Если присутствует ветвь else, то при истинности условия оператор, стоящий после ключевого else, не выполняется. Он выполняется только в том случае, если условие ложно, т.е. результат вычисления условия равен нулю. Если условие ложно, а ветвь else отсутствует, то весь оператор if не выполнит никаких действий.
Следует обратить внимание на то, что условие обязательно заключается в круглые скобки!!!
В некоторых случаях возникает необходимость в совместном использовании нескольких операторов if, что может привести к неоднозначности типа «висящего else». Например:
if (условие1) if (условие2) else оператор
Подобную запись можно интерпретировать двояко: else выполняется при невыполнении условие1 либо условие2. Для устранения этой неоднозначности существует правило:
else всегда относится к ближайшему if.
Таким образом, в нашем случае, ветвь else выполнится при невыполнении условие2.
Задание:
Пример работы с АОС (см. также л.р. «Работа с автоматизированной обучающей системой»): Через УПРАВЛЕНИЕ | РЕЖИМ САМОСТОЯТЕЛЬНОЙ РАБОТЫ | УСЛОВНЫЙ ОПЕРАТОР IF-ELSE + ПЕРЕКЛЮЧАТЕЛЬ (ОПЕРАТОР SWITCH) выйти к меню
Внимательно прочесть теорию (<F2>).
Вычислить предложенные примеры, например:
Начинается с проверки условия (y!=1) результат проверки которой равен 0, т.к. y=1, следовательно результатом всей строки будет x=36 .
Начинается с проверки условия (y<=1), т.к. в данном случае оно выполняется, происходит переход ко второй части строки: if (y==1) x=18; else x=20; в которой условие (y==1) выполняется (т.к. у=1). Следовательно, выполняется присваивание x=18 и дальнейшее выполнение строки прекращается. Следующие строки программы выполняются аналогично.
Следует заметить, что при выполнении заданий в этом разделе АОС, примеры программ, как правило, не помещаются на один экран, о чем сигнализирует надпись в нижнем правом углу после нажатия <F1>. Используя предложенные клавиши (Home ,End, ,, PgUp, PgDown) можно просмотреть всё задание.
Переписать задание и ответы в тетрадь для лабораторных работ.
Лабораторная работа №10
Цель работы: Изучить оператор if-else и ознакомиться с правилами его использования в программах.
В разветвляющихся вычислительных процессах отдельные этапы вычислений (операторы) выполняются не всегда в одном и том же порядке, а в зависимости от некоторых условий, проверяемых уже по ходу вычислений, выбираются для исполнения различные их последовательности.
Если, например, в программе используются вещественные переменные X, Y и Z, и на каком-то этапе решения задачи требуется вычислить Z, равное максимальному из чисел X и Y, то желаемый результат получается в результате выполнения оператора присваивания Z=X, либо оператора присваивания Z=Y. Поскольку значения переменных X и Y заранее не известны, а определяются в процессе вычислений, то в программе необходимо предусмотреть оба эти оператора присваивания.
Это указание естественно сформулировать с использованием отношения X>Y: если это отношение при текущих значениях X и Y справедливо, то для исполнения должен выбираться оператор Z=Y (при X = Y безразлично, какой оператор выполнять, так что выполнение в данном случае оператора Z=Y дает правильный результат).
Для задания подобного рода разветвляющихся вычислительных процессов служит условный оператор.
Синтаксис оператора:
Вариант 1
if(<выражение>) <оператор>
Если <выражение> определено и не равно 0 , то выполняется <оператор>.
Вариант 2
if(<выражение>)
<оператор1>
else
<оператор2>
Если <выражение> определено и не равно 0 , то выполняется <оператор1>,иначе (т.е. если <выражение> равно нулю) выполняется <оператор2>.
Таким образом, алгоритм решения упомянутой выше задачи вычисления максимального из двух чисел можно задать в виде условного оператора
if (X<Y)
Z=X;
else
Z=Y;
Первый вариант применяется в тех случаях, когда при выполнении (истинности) некоего условия, определяемого ключевым выражением, требуется выполнить некоторые действия. В противном же случае, при невыполнении данного условия, никаких действий предпринимать не нужно.
Второй вариант применяется в тех случаях, когда при невыполнении условия определенного ключевым выражением, нужно предпринять какие либо действия.
При формулировании алгоритма типичной является такая ситуация, когда на определенном этапе вычислительного процесса какие-либо действия надо выполнить при выполнении некоторого условия, а если это условие не выполняется, то на данном этапе вообще не нужно выполнять никаких действий. Простейшим примером такой ситуации является замена текущего значения переменной X на абсолютную величину этого значения: если X<0, то необходимо выполнить оператор присваивания X=-X: если же X>=0 , то текущее значение X должно оставаться без изменений, т.е. на данном этапе вообще не нужно выполнять каких-либо действий.
В таких ситуациях удобна сокращенная форма условного оператора.
Рассмотрим, к примеру, такую задачу:
Вычислить квадратный корень из числа определяемого переменной Angle, если значение этой переменной не отрицательное.
#include <stdio.h>
#include <math.h>
main()
{
double Angle,Result = 0;
printf("Введите значение переменной :");
scanf("%lf",&Angle);
if(Angle >= 0)
{
Result=sqrt(Angle);
printf("Квадратный корень = %lf",Result);
}
}
Рассмотрим теперь задачу, похожую на прежнюю, но немного расширенную: Вычислить квадратный корень из числа, определяемого переменной Angle, если значение этой переменной не отрицательное. Если же значение отрицательное, то сообщить об этом.
#include <stdio.h>
#include <math.h>
main()
{
double Angle,Result=0;
printf("Введите значение переменной :");
scanf("%lf",&Angle);
if(Angle >=0)
{
Result=sqrt(Angle);
printf("Квадратный корень = %lf",Result);
}
else
printf("Квадратный корень из %lf не извлекается", Angle);
}
Из приведенных выше примеров можно сделать вывод, что во втором примере задача рассмотрена шире, чем в первом, так как предусматривает выдачу сообщения о причине невыполнения определенного действия (в данном случае о невозможности извлечь квадратный корень из отрицательного числа).
Примечания:
1. Ключевые слова else или if могу иметь только по одному оператору, причем он может быть простым или составным. Все другие операторы будут интерпретироваться как независимые.
Например, конструкция
if(<выражение>)
<оператор1>
<оператор2>
else
<оператор3>
является ошибочной, так как <оператор2> будет рассматриваться компилятором как независимый , не относящийся к ключевому слову if, а наличие ветви else в данном случае воспринимается как ошибка. В подобных случаях следует применять составные операторы. Тогда рассмотренная конструкция будет выглядеть следующим образом:
if(<выражение>)
{
<оператор1>
<оператор2>
}
else
<оператор3>
2. Внутри одного блока каждое ключевое слово else относится к первому из предшествующих if, которое еще не имеет соответствующего else.
Например:
if(<выражение1>)
if(<выражение2>)
{
<оператор3a>
<оператор3b>
}
else
{
<оператор4a>
<оператор4b>
}
эквивалентна следующей:
if(<выражение1> && <выражение2>)
{
<оператор3a>
<оператор3b>
}
if(!<выражение1> && !<выражение2>)
{
<оператор4a>
<оператор4b>
}
3. В сложных конструкциях, содержащих много if и else, иногда явно указываются все else, после которых ставится пустой оператор.
Например, выражение
if(<выражение1> && <выражение2>)
{
<оператор3a>
<оператор3b>
}
if(!<выражение1>)
{
<оператор4a>
<оператор4b>
}
можно записать так:
if(<выражение1>)
if(<выражение2>)
{
<оператор3a>
<оператор3b>
}
else
;
else
{
<оператор4a>
<оператор4b>
}
4. При формировании условного выражения следует обращать внимание на приоритет операций.
5. Следует помнить, что проверка на равенство осуществляется с помощью оператора ==, а оператор = в условном выражении интерпретируется как оператор присваивания. Обращайте внимание на предупреждения компилятора, которые указывают на условное выражение в операторе if.
*** Все значения величин должны быть введены с клавиатуры. ***
Контрольные вопросы
Лабораторная работа №11
Использование конструкций выбора switch
Цель работы: научиться использовать при программировании на С конструкцию switch.
Вложенный набор операторов if-else может крайне затруднить понимание программы. Рассмотрим следующую серию операторов if-else, каждый из которых сравнивает выражение с определенным значением.
if (выражение = =значение1)
оператор1;
else if (выражение= =значение2)
оператор2;
else /*необязательно*/
оператор_умолчания /*необязательно*/ ;
Конструкцию можно сократить с помощью оператора switch:
switch (выражение) {
case значение1 : /* выполняется if (выражение = =значение1)*/
break ; /* выход из оператора switch*/
case значение2 : /* выполняется else if (выражение= = значение1)*/
break ; /* выход из оператора switch */
default :
На первый взгляд эта запись может показаться длиннее, но на практике оператор switch использовать проще, чем эквивалентную конструкцию if-else. За ключевым словом switch следует выражение, которое будет сравниваться с множеством значений внутри блока switch. Селекторы case сравнивают выражение с заданными значениями . Cтрока
case значение1:
сравнивает значение1 с результатом вычисления выражения оператора switch. Если результат сравнения дает значение “истина”, то будет выполнен оператор (или блок операторов), следующих за строкой case. Если же результатом сравнения будет “ложь”, аналогичным образом будет обрабатываться следующая строка case. Последняя строка оператора switch default- необязательная строка выбора. Она задает действия, выполняемые в случае, если ни одно из значений строк case не совпало со значениями выражениями оператора switch.
Листинг программы, создающей меню выбора:
# include <stdio.h>
# include <ctype.h>
main( )
{int choice;
printf(“ Menu: A(dd D(elete S(ort Q(uit :“);
choice=toupper(getchar()); /*Функция toupper() переводит символ в верхний регистр
(делает прописным)*/
switch(choice){
case A: printf (“You selected Add \n”);
break;
case D: printf (“You selected Delete\n”);
break;
case S: printf (“You selected Sort \n”);
break;
case Q: : printf (“You selected Quit \n”);
break;
default : printf (“\n illegal choice !!!\n”);
}
return choice;
}
Задание:
Написать программу, которая выполняла бы функции простейшего калькулятора (+, -, *, /, %). (Нужно ввести 2 числа и знак действия, которое необходимо выполнить. Для операций / и % предусмотреть проверку на равенство нулю знаменателя).
Лабораторная работа № 12
Работа с автоматизированной обучающей системой:
операторы цикла WHILE и DO-WHILE, оператор цикла FOR
Цель работы: получить навыки в использовании операторов цикла языка С в автоматизированной обучающей системе.
В программировании часто возникают такие ситуации, когда какое-то действие необходимо выполнить несколько раз. Для их описания в языке С существуют циклы или итерационные структуры, позволяющие повторять выполнение отдельных операторов или групп операторов. Число таких повторений в некоторых случаях фиксировано, в других определяется в процессе счета.
Язык С поддерживает два оператора цикла, первый из которых оператор while, который имеет две формы записи:
while (условие) [оператор];
и
do [оператор] while (условие);
где условие здесь имеет тот же смысл, что и операторе if.
В первой и второй формах оператора while оператор выполняется, пока условие не станет ложным, с одним отличием: в первом случае проверка производится до выполнения оператора, во втором после. Другими словами, во второй форме записи тело цикла выполнится всегда как минимум один раз. Следует обратить внимание на то, что оператор или группа операторов должна модифицировать значения переменных, входящих в условие, для того, чтобы оно в конце концов приняло значение 0 и цикл прекратился.
Частой ошибкой при программировании циклов любого типа является запись такого условного выражения, которое никогда не обращается в 0. Такой цикл называется бесконечным.
Вторым оператором цикла в С является оператор for:
for ([оператор1]; [выражение]; [оператор2])
[тело_цикла];
где оператор1 простой или сложный оператор, оператор2 простой оператор; выражение любое вычисляемое выражение; тело цикла это простой или сложный оператор, который будет выполняться в цикле. Каждое из трёх выражений в заголовке цикла может быть опущено программистом или использовано как угодно.
Формально алгоритм выполнения оператора for записывается так:
Появление в любом месте цикла оператора continue приводит к немедленному переходу к шагу 4.
Появление в любом месте цикла оператора break приводит к прекращению выполнения цикла и переходу к следующему за ним оператору.
Следует заметить также, что отсутствие в заголовке цикла оператор1 или выражение не означает отсутствия знака `;` после него.
Как правило, в цикле for оператор1 используется для инициализации переменной цикла, выражение для проверки на окончание цикла, а оператор2 для модификации переменной цикла.
Нетрудно заметить, что оператор for является упрощённой формой записи оператора while:
[оператор1];
while ([оператор2])
{[тело цикла];[оператор3];}
Простейшим примером использования цикла for может служить программа вывода всех четных чисел от 106 до 0 в порядке убывания:
#include <stdio.h>
void main(void)
{long i;
for (i=1E6;i>=0;i-=2)
printf("\n%ld",i);
}
Эту же программу можно записать, поместив все действия в заголовок цикла:
#include <stdio.h>
void main(void)
{for (long i=1E6;i>=0;printf("\n%ld",i),i-=2);}
Пример работы с АОС (см. также л.р. «Работа с автоматизированной обучающей системой»):
Через УПРАВЛЕНИЕ | РЕЖИМ САМОСТОЯТЕЛЬНОЙ РАБОТЫ | ОПЕРАТОРЫ ЦИКЛА WHILE И DO-WHILE + ОПЕРАТОР ЦИКЛА FOR выйти к меню (задания могут отличаться):
Внимательно прочесть теорию (<F2>).
Вычислить предложенные примеры, например:
первая строка с циклом while (y<10) ++y; будет выполняться пока у будет меньше 10. При у=10 произойдёт переход к оператору x-=y; в котором переменная х примет значение 4 (14-10).
В следующей строке while (y<11) x+=++y; цикл будет выполняться 10 раз. Очевидно, что при начальных x=1 и y=0 первое действие цикла можно записать как x=1+0, а последнее x=57+10. Таким образом, будет выведено значение x, равное 67 и y=11. Следующая строка do z-=y; while (++y<9); будет выполняться до тех пор, пока y будет меньше 9. При первом проходе вначале переменная z не будет уменьшена, т.к. y в этом случае равен 0. Далее происходит проверка условия (++y<9); после чего переменная y увеличивается на 1 и происходит возврат к оператору z-=y; где переменная z уже уменьшается на 1 и т.д.
Следует заметить, что при выполнении заданий в этом разделе АОС, примеры программ могут не помещаться на один экран, о чем сигнализирует надпись в нижнем правом углу после нажатия <F1>. Используя предложенные клавиши (Home, End, ,, PgUp, PgDown) можно просмотреть всё задание.
Переписать задание и ответы в тетрадь для лабораторных работ и перейти к выполнению следующего задания (нажать любую клавишу). Таким образом выполнить все предложенные задания. Для перехода к следующей теме («ОПЕРАТОР ЦИКЛА FOR») нажать <F10>:
Внимательно прочесть теорию (<F2>).
Вычислить предложенные примеры, например:
строка for (y=8; y>0; y--) x=y; будет выполняться до тех пор, пока значение переменной y будет больше 0. Очевидно, что при выходе из цикла переменная x будет равна 1, а y будет равна нулю, так как после выполнения y-- (при у=1) происходит переход к y>0, где вырабатывается значение 0 и цикл прекращается. Следующая строка for (y=12; (x=y)>1; y--) ; аналогична предыдущей, за одним исключением присваивание (x=y) происходит при проверке условия, т.е. при выходе из цикла переменная x будет равна переменной y, а так как цикл закончится при y равном 1, то переменная x при выходе из цикла также примет значение 1.
Переписать задание и ответы в тетрадь для лабораторных работ и перейти к выполнению следующего задания (нажать любую клавишу). Таким образом выполнить все предложенные задания, выйти из АОС, предоставить отчет преподавателю.
Лабораторная работа №13
Разработка и отладка программы циклического процесса
с использованием оператора do-while
Цель работы: Научиться использовать на практике циклические процессы с использованием оператора do-while.
Оператор do-while является в некотором роде перевернутым циклом while. Его формат выглядит следующим образом:
do
{
оператор;
}
while (выражение);
Выполняется оператор, затем проверяется выражение. До тех пор, пока значение этого выражения будет истинным, оператор будет выполняться. В отличие от while do-while всегда выполняет свои операторы, по крайней мере, один раз, т.к. проверка выражения осуществляется по завершении итерации цикла. Из этого следует основное правило, необходимое при выборе между while и do-while: если есть такое условие, при котором операторы не должны выполняться, то следует выбирать while, иначе - do-while.
Многооператорные циклы do-while записываются следующим образом:
do
{
оператор 1;
оператор 2;
...
оператор n;
}
while (выражение);
Следующий листинг использует do-while для счета от одного до десяти:
#include <stdio.h>
main()
{
int number=0;
printf(“Цикл do-while \n”);
do
{
++number;
printf(“%d \n”, number);
}
while (number<10);
}
Для цикла do-while можно использовать любое средство проверки логического выражения. Чтобы продемонстрировать такую многогранность, ниже приводится пример, использующий цикл do-while для вывода на экран алфавита:
#include <stdio.h>
main()
{
int c;
printf(”Алфавит do-while \n”);
c=A-1;
do
{
++c;
printf(“%c”, c);
}
while (c<Z);
}
Выражение c<Z истинно, если ASCII-значение текущего символа меньше ASCII-значения буквы Z.
Лабораторная работа №14
Помещение тела цикла for в заголовок
Цель работы: ознакомиться с особенностями цикла for и научиться помещать простое тело цикла в заголовок.
Циклы (итерационные структуры) позволяют повторять выполнение отдельных операторов или групп операторов.
Число таких повторений в некоторых случаях фиксировано, в других случаях определяется в процессе счета.
Наиболее общей формой цикла в С является
for ( [необязательное выражение1; необязательное выражение 2; необязательное выражение 3] );
оператор;
Каждое выражение в заголовке цикла можно опускать. Хотя в принципе каждое выражение может быть использовано программой как угодно, обычно 1е выражение служит для инициализации переменной цикла, 2-е выражение служит для проверки на окончание цикла, 3-е - для изменения значения переменной цикла.
Формально алгоритм for можно описать так :
Появление оператора continue приводит к немедленному переходу к шагу 4.
Цикл for можно свести к циклу while следующим образом :
for (выражение 1; выражение 2; выражение 3);
оператор;
приводится к:
выражение 1;
while ( выражение 2);
{ оператор;
выражение 3;
}
Поскольку все 3 выражения в цикле for можно опустить, то
for ( ; ; )
;
представляет собой бесконечный цикл.
Листинг программы, отображающей ASCII-символы
# include <stdio.h>
main()
{ unsigned char c;
for (c=32; c<128; c++)
{ if ((c%128)= =0 )
printf (“%c”, c);
}
return 0;
}
Тело цикла можно поместить в заголовок цикла.
Пример:
Программа, выводящая четные числа от 10 до 0
# include <stdio.h>
main ()
{ int i;
for (i=10; i>=0;i-=2)
printf (“\n %d “,i);
}
Эту программу можно записать, поместив все действия в заголовок :
#include <stdio.h>
main ()
{
int i;
for (i=10; i>=0; printf (“\n %d “,i),i-=2)
;
}
Задание:
Контрольные вопросы
Лабораторная работа №15
Одномерные массивы
Цель работы: Изучение приемов объявления и обращения к массивам, использования директивы define при работе с массивами.
Массивы это набор объектов одинакового типа, доступ к которым осуществляется прямо по индексу в массиве. Обращение к массивам в С осуществляется и с помощью указателей.
Массивы можно описывать следующим образом:
тип_данных имя_массива [ размер массива ];
Используя имя массива и индекс, можно адресоваться к элементам массива:
имя_массива [ значение индекса ]
Значения индекса должны лежать в диапазоне от нуля до величины, на единицу меньшей, чем размер массива, указанный при его описании.
Вот несколько примеров описания массивов:
char name [ 20 ];
int grades [ 125 ];
float income [ 30 ];
double measurements [ 1500 ];
Первый из массивов ( name ) содержит 20 символов. Обращением к элементам массива может быть name [0], name [1], ...,name[19].
Второй массив ( grades ) содержит 125 целых чисел. Обращением к элементам массива может быть grades [0],grades [1],...,grades[124].
Третий массив ( incomе ) содержит 30 вещественных чисел. Обращением к элементам массива может быть income [0], incom[1],...,income[29].
Четвертый массив (measurements) содержит 1500 вещественных чисел с двойной точностью. Обращением к элементам массива может быть measurements[0], measurements[1],...,measurements[1499].
/* Программа, иллюстрирующая использование массивов */
/*Файл array.с*/
#include <stdio.h>
#define size 1000
int data [size];
main ( )
{
extern float average (int a[ ], int s );
int i;
for ( i=0; i<size ; i++)
data [ i ]= i;
printf ( “\nСреднее значение массива data =%f\n”,average (data,size));
}
float average (int a[ ] ,int s )
{
float sum=0.0;
int i;
for ( i=0; i<s ; i ++)
sum+=a[ i ];
return sum/s;
}
В программе заводится массив на 1000 целых чисел. При помощи функции average подсчитывается сумма элементов этого массива. Первым формальным параметром функции average является массив. В качестве второго параметра функции передается число суммируемых значений в массиве a. Обратите внимание на использование константы size (размер). Если изменяется размерность массива, задаваемая этой константой, то это не приводит к необходимости менять что-либо в самом коде программы.
Задание:
Составить программу, решающую задачу определения максимального и минимального значений в одномерном массиве, введенном с клавиатуры. В качестве исходных значений задаются массив чисел с плавающей точкой и размер такого массива.
Лабораторная работа №16
Программирование с использованием указателей
Цель работы: ознакомиться с понятием указателя, научиться использовать их при программировании на С.
Теоретические сведения
Указатель это переменная, которая содержит в памяти адрес данных. Переменная-указатель содержит местоположение значения. То есть, переменная-указатель указывает на значение, так как она содержит его адрес.
Указатели предоставляют эффективные средства доступа и изменения данных. Так как указатели содержат адреса данных, то при поиске значений в памяти у компьютера сокращается объем работы. Указатели не привязывают данные к какому-либо определенному имени переменной. Они могут содержать адрес любого не именованного значения.
Суть переменных-указателей
Так как указатели являются обычными переменными, для них действительны все правила именования обычных переменных. Как и в случае с обычной переменной, нужно сначала объявить указатель и только потом его использовать. В С указатели могут быть на все существующие в языке типы данных; можно создать указатель на целое, символьное данное, и так далее. В зависимости от того, в каком месте программы объявлен указатель, он может быть локальным или глобальным (как и для обычных переменных, использовать глобальные без нужды не рекомендуется).
Единственная разница между обычными переменными и указателями заключается в их содержимом. Указатели содержат не само значение, а его адрес.
В С имеет два оператора, относящихся к указателям:
& - оператор "адрес значения"
* - оператор "значение по адресу"
Объявление указателей
Если нужно объявить переменную для хранения, например, возраста, то можно сделать это следующим образом:
int age = 20;
Такое объявление переменной age подразумевает несколько моментов. Во-первых, сообщается С, что нужна переменная с именем age, и С резервирует для этой переменной место в памяти. Во-вторых, С узнает, что age будет использоваться для хранения только целых чисел. В-третьих, при объявлении эта переменная инициализируется значением 20.
Пусть нужно объявить переменную-указатель, которая не содержит возраст, а указывает на age, переменную, где находятся нужные данные. Для объявления указателя на переменную age нужно сделать следующее:
int *p_age;
В этой строке резервируется место для переменной с именем p_age. Однако это не обычная целочисленная переменная. Так как перед ней стоит *, С определит, что это переменная-указатель.
Присваивание значений указателям
Указатель может содержать адреса значений только соответствующего ему типа. Например, p_age может указывать только на целочисленные переменные. С не инициализирует указатели при их объявлении. Если age объявина как показано выше, и нужно, чтобы p_age содержала адрес age, нужно присвоить его переменной p_age:
p_age=&age;
Вместо занесения адреса переменной age в переменную p_age при помощи оператора присваивания можно одновременно объявлять и инициализировать указатели.
int age=20;
int *p_age=&age;
Можно присваивать различные значения переменной age следующим оператором:
age=35;
Либо можно сделать то же самое другим путем:
*p_age=35;
Эта строка подразумевает "взять ячейку памяти, на которую указывает p_age и занести туда значение 35".
Объявление массивов указателей
Если нужно зарезервировать большое количество указателей для различных данных, можно объявить массив указателей, причем каждый его элемент будет являться указателем одного и того же указанного типа. Следующий пример резервирует массив из 10 указателей на переменную целого типа:
int *iptr[10];
Можно присвоить адрес любому элементу из iptr таким же образом, как и любому другому указателю, не входящему в массив:
iptr[4]=&age;
В следующей строке резервируется массив из 20 указателей на переменные символьного типа:
char *cpoint[20];
Задание:
Написать программу, демонстрирующую отличие между значением указателя и значением, на которое ссылается указатель. Для этого объявить переменную-указатель, зарезервировать под значение динамическую память, присвоить по адресу, содержащемуся в указателе, какое-либо значение. Напечатать значение указателя, размер памяти, занимаемой указателем, значение указателя со снятой ссылкой и размер памяти, занимаемой этим значением. Программу выполнить с использованием моделей памяти small и large.
Контрольные вопросы
int *a;
char *c;
float b;
*p_age=35;?
Лабораторная работа №17
Строковые константы и символьные массивы
Цель работы: исследовать особенности применения символьных массивов и констант и научиться использовать их при написании программ.
Любая строка символов или одиночный символ, заключенный в двойные кавычки, интерпретируется как строковая константа. Двойные кавычки не являются частью строковой константы. Они выделяют строку и сообщают компилятору, что она является константой. Строку можно вывести на экран следующим образом:
puts(“Это строка”);
Все строковые константы заканчиваются двоичным нулем или нулевым символом \0, который компилятор добавляет в конец строки автоматически при задании строковой константы. Этот символ очень важен для компилятора, так как без него было бы неизвестно, где в памяти заканчивается строка.
В С не существует переменной строкового типа, но можно хранить строки в массивах символов. Например, можно создать массив для хранения имени:
char name[10];
Этот оператор резервирует в памяти место для хранения массива символов. Можно инициализировать строку, присвоив ей начальное значение при объявлении:
char name[10]=”Michael”;
Эта строка состоит из 7 значащих символов, однако в памяти она занимает 8 байт, так как компилятор добавляет в конец строки нулевой символ ограничитель строки. Можно получить доступ к каждому отдельному элементу массива обычным способом, например:
name[3]=k;
Содержимое массива можно вывести на экран при помощи оператора:
puts(name);
Нельзя помещать значение строки в массив символов обычным оператором присваивания, исключая инициализацию при объявлении. Символьный массив не является строковой переменной, и не является леводопустимым выражением.
Часто строки задаются при помощи указателей, например:
char *name;
Если в этом случае строка не инициализируется сразу же при объявлении, то требуется выделить память для ее хранения и инициализировать указатель следующим образом:
name=(char*)malloc(sizeof(char)*10);
После этого имя name можно использовать как обычный указатель, а также использовать его в многочисленных функциях манипуляции со строками, которые находятся в системной библиотеке string.h. При помощи этих функций можно копировать строки, сравнивать, присоединять одну строку к другой и выполнять множество других полезных действий.
Задание:
Написать программы, которые без использования стандартных функций манипуляции со строками выполняют следующие действия:
Лабораторная работа №18
Программирование с помощью функций.
Вызов функций и возврат из них
Цель работы: Научиться программировать на С с использованием функций. На практике освоить методику вызова функций и возврата из них.
Теоретические сведения
Когда необходимо запрограммировать прикладную задачу, то лучше не начинать сразу писать программу. Вместо этого следует подумать о самой программе и ее назначении. Сначала следует сформулировать ее главную цель, а затем разбить на несколько более мелких задач. Необходимо все время помнить о главной цели всей программы. В то же время следует подумать, как отдельные объекты взаимодействуют друг с другом для выполнения этой задачи. Не следует делать программу в виде одного огромного модуля. Лучше разрабатывать отдельные объекты функции.
Каждая функция должна выполнять одну задачу. Например, если нужно написать программу на C, которая принимает символы с клавиатуры, затем упорядочивает их в алфавитном порядке и выводит на экран, то все это можно сделать в одной большой функции main ( ) . Ниже показана схема (набросок программы) того, как это делается.
main ( )
{
//
//Код на C для ввода символов
// Код на C для сортировки символов в
// алфавитном порядке
// Код на C для вывода отсортированных
// символов на экран
//
return 0;
}
Схема, представленная в этом примере, не представляет собой хороший способ написания программ. Не следует использовать main() для выполнения всех действий. Фактически, кроме вызова других функций, она должна выполнять лишь незначительную часть работы. Намного лучше написать эту же программу в виде отдельных функций, каждая из которых выполняет отдельную задачу. Ниже следующая программа демонстрирует намного лучший способ написания рассмотренной программы.
main ()
{
getletters(); // Вызов функции ввода букв
alphabetize(); // Вызов функции сортировки
// букв по алфавиту
printletters(); // Вызов функции вывода
// букв на экран
return 0; // Возврат в DOS
}
getletters ( )
{ // Код на C для ввода символов
return; // Возврат в функцию main() }
alphabetize ( )
{ // Код на C для сортировки символов в алфавитном
// порядке
return; // Возврат в функцию main() }
printietters ()
{ // Код на C для вывода отсортированных символов
// на экран
return; // Возврат в функцию main() }
Такая программа имеет больший размер, чем предыдущая. Однако она намного лучше структурирована. Единственной задачей функции main() в этом случае является вызов в определенном порядке других функций. Каждая из функций выполняет определенную задачу, после чего управление передается в main( ). Затем функция main( ) вызывает следующую, и так происходит до тех пор, пока не будут вызваны все функции. В конце main передает управление в DOS. Назначение функции main( ) состоит, главным образом, в управлении более мелкими функциями, которые и выполняют всю основную работу.
Функция, написанная на C, обычно имеет следующие свойства:
Не в каждой функции действительно необходимо наличие оператора return. Однако рекомендуется всегда включать его в тело функции. Этот оператор помогает показать то, что вы собираетесь возвращать в вызывающую функцию.
Обычно вызывающая функция управляет вызовами функций и их порядком. Вызываемые функции управляются вызывающей.
Полная программа с функциями, написанная на Cи, это прояснит. Следующая программа, выводит на экран несколько сообщений. Выводимые сообщения определяются порядком вызова функций. В программе определены три функции: main(), next_fun() и third_fun(). Тело каждой из них заключено в фигурные скобки. В конце каждой функции стоит оператор return.
// Эта программа демонстрирует вызовы функций
#include <stdio.h>
void next fun (void)
// Вторая функция
{
puts( "Inside next fun()");
return; // Теперь управление возвращается функции main()
}
void third_fun (void)
// Последняя функция, вызываемая в программе
{
puts( "Inside third_fun ()");
return;
}
main()
// main() ВСЕГДА первая выполняемая функция
{
puts( "First function called main()");
next fun(); // Здесь вызывается вторая функция
third fun(); // Третья функция вызывается здесь
puts("main() is completed"); //Управление возвращается сюда
return 0; // Возврат управления в DOS
}
Результаты выполнения этой программы следующие:
First function called main()
Inside next_fun()
Inside third_fun()
main() is completed
Функция main( ) определяет, какую функцию вызвать, а также порядок вызова всех функций. Управление сразу же передается в вызывающую функцию, как только отработала вызываемая.
Перед именами функций стоит ключевое слово void, так же, как и в круглых скобках за именем функции. Это необходимо, так как Cи является строго типизированным языком.
Для вызова функции нужно написать ее имя вместе с круглыми скобками, и после этого поставить точку с запятой. Этот знак ставится в конце каждого выполнимого оператора в Cи, а вызов функции является выполнимым оператором. В этом случае выполняется код функции, которую вызывали. Каждая функция может вызвать любую другую функцию. В рассмотренном примере только main () вызывала другие функции.
Нельзя определять одну функцию внутри другой. Тексты всех функций должны быть записаны последовательно, один за другим. Необходимо, чтобы перед началом определения следующей функции была поставлена закрывающая фигурная скобка, заканчивающая тело предыдущей.
Читаемость программы является очень важным свойством. Намного легче читать те программы, которые разбиты на отдельные функции. Можно написать и сразу же полностью проверить каждую функцию. Как только составлен общий план программы, то можно подсчитать количество функций, вызываемых в main( ), и определить их схемы после main().
Первоначально тела функций состоят из операторов return. Поэтому программа может компилироваться даже в таком схематичном виде, Заканчивая каждую функцию, можно компилировать и проверять программу по ходу ее написания. Этот подход приводит к более структурированным программам. Разделение программы на функции позволит позже другим программистам при необходимости модифицировать отдельные ее части, не изменяя ничего больше.
Можно выполнить функцию более, чем один раз, просто вызвав ее из нескольких мест программы. Если функция вызывается в теле цикла, то она будет выполняться многократно до окончания цикла.
Таким образом, вместо того, чтобы писать большие программы в виде одной функции, можно разбить их на несколько. Таким образом, можно скомпоновать программу так, что при рассмотрении отдельной ее части все остальное не будет отвлекать внимание.
Задание:
void cal_ it (void)
{ puts( "Getting ready to calculate the square of 25 ");
sq_25( )
{
puts( "The square of 25 is :”);
printf(“%d”, 25 * 25 );
return; }
puts( "That is a big number! ");
return;
}
scan names ();
Лабораторная работа №19
Цель работы: научиться правильно использовать при программировании локальные и глобальные переменные и передавать в функции переменные по значению и по ссылке.
Теоретические сведения
Понятие области видимости переменных является наиболее важным при написании функций. Область видимости определяет, какие функции имени доступ к определенным переменным. Если функция имеет доступ к переменной, то говорят, что эта переменная доступна для данной функции. Эта концепция защищает переменные от случайного изменения их значений другими функциями. Функция не может модифицировать переменную, к которой она не имеет доступа
Глобальные переменные, к которым программа имеет доступ и может изменить любую из них, заключают в себе опасность. Некоторые части программы могут случайно изменять значение переменной, которая не должна меняться. Глобальные переменные видны из всех функций программы. И такого рода переменные могут быть изменены функцией, даже если они были проинициализированы в другом месте программы.
Лучше в этом случае объявлять локальные переменные. Тогда только те функции, которые должны изменять их значение, смогут это делать. Локальные переменные видимы и могут быть изменены только в пределах тех функций, в которых они определены. Они не могут использоваться и изменяться другими функциями без специального разрешения на это.
При написании функций необходимо знать, как определить переменные так, чтобы они были локальными для них.
Определение области видимости переменных:
Необходимость различать эти два метода становится очень важной при написании программ с несколькими функциями. Локальные переменные видимы только из того блока, в котором они определены. Эти два способа определения переменных и описывают определение локальных и глобальных переменных. Следующие правила, которые являются характерными для этих обоих типов переменных, являются важными:
Как только функция (или блок) заканчиваются, локальные переменные уничтожаются. Глобальные переменные видимы от точки их определения до конца файла. Поэтому если определяется глобальная переменная, то можно использовать ее в любом месте программы ниже ее определения (не важно, сколько функций и строк программы идет дальше).
Локальная переменная удаляется сразу после завершения блока, в котором она объявлена (то есть при достижении закрывающейся фигурной скобки). С всегда использует переменные, которые он видит как «самые локальные».
Следует использовать глобальные переменные как можно реже: глобальные переменные могут быть очень опасны. Программа может нечаянно изменить значение переменной, которая была проинициализирована в другом месте. Если функции нужен доступ к некоторым переменным, то лучше объявлять их локальными по отношению к ней.
Необходимость передачи переменных
Может возникнуть необходимость использовать локальную переменную в других функциях. Например, пусть нужно ввести значение некоторой переменной в одной функции, а вывести ее же значение на экран в другой. Если переменная является локальной по отношению к первой функции, то каким образом вторая получит к ней доступ?
Если двум функциям нужен доступ к одной переменной, то есть две альтернативы. Первый способ это объявить глобальную переменную. Но это не является наилучшим выходом, так как доступ к данной переменной нужен только двум функциям, а в этом случае она становится видимой для всех. Лучшим вариантом является передача локальной переменной из одной функции в другую. У этого способа есть большое преимущество переменная становится видимой только для двух функций, и в остальной части программы она никак не может быть изменена.
Никогда не передают глобальные переменные. Для этого нет никаких причин, так как они уже видимы для всех функций.
Когда передается локальная переменная из одной функции в другую, то передается аргумент. Можно передать более одного аргумента за один раз, если нужно переслать несколько локальных переменных из одной функции в другую. Принимающая функция получает параметры (переменные) от той функции, которая их передала.
Функция, передающая параметры, называется вызывающей функцией. Функция, которая принимает эти аргументы (которые в ней называются параметрами), называется принимающей функцией.
При передаче локальной переменной из одной функции в другую ее нужно заключать в круглые скобки как в вызывающей, так и принимающей функциях. Если в круглых скобках после имени функции ничего не стоит, то ничего не передается.
Передаваемый параметр обрабатывается как локальная переменная в принимающей функции. Когда аргументы передаются в функцию, она ничего не знает о типе данных принимаемых переменных. Поэтому перед именем параметра нужно указать их тип.
Передача значений
С поддерживает два способа передачи переменных между функциями, Какой из них использовать, зависит от того, каким образом нужно изменять переменные
Передача по значению (или копированием)
Выражения «передача по значению» и «передача копированием» означают одно и то же. Они характеризуют . один и тот же метод передачи аргументов принимающим функциям. Когда аргумент (локальная переменная) передается по значению, копия значения переменной присваивается параметру принимающей функции. Если по значению передаются более, чем одна переменная, то копии каждой из них присваиваются соответствующим параметрам принимающей функции.
Так как здесь происходит передача значения переменной (а не самой переменной), то при изменении ее в принимающей функции будет изменена только копия этой переменной, а не сама.она. Используя этот метод, можно передавать копию переменной в принимающую функцию, но она не может изменить значения этой переменной в вызывающей функции. Таким образом, налицо разделение функций и переменных. Все переменные языка С, не являющиеся массивами и указателями, передаются по значению. Для передачи переменных по значению нужно только указать их в списке аргументов вызывающей функции и в списке параметров принимающей функции.
Массивы и указатели всегда передаются по адресу.
Передача по адресу (или по ссылке)
Фразы «передача по адресу» и «передача по ссылке» означают одно и то же. Когда передается аргумент (локальную переменную) по адресу, то параметру в принимающей функции присваивается адрес указанной переменной, (если передается более одной переменной, то адреса каждой из них присваиваются параметрам принимающей функции.)
При передаче переменной по адресу принимающей функции происходит копирование ее адреса, а не значения. В С все массивы передаются по адресу. Фактически, передается копия адреса массива.
Если принимающая функция изменяет переменную, которая была передана в нее по адресу, то данная переменная изменяется и в вызывающей функции.
Если передается в функцию массив, и он там изменяется, то при возврате в вызывающую функцию все изменения сохранятся. В отличие от передачи по значению: в этом случае можно изменять значение переменной в принимающей функции, и это будет изменять значение переменной вызывающей функции.
Задание:
Контрольные вопросы
Лабораторная работа №20
Цель работы: научиться программировать с использованием функций, возвращающих значения.
Теоретические сведения
До сих пор все переменные в функции передавались в одном направлении: и вызывающей функции в вызываемую. Теперь изучить, как данные передаются назад из вызываемой функции в вызывающую. Когда переменные передаются по адресу, данные изменяются в обеих функциях, но это отличается от фактической передачи данных обратно. Можно писать функции, возвращающие значения, что, помогает создавать более качественные программы.
Хорошим стилем программирования на С является описание прототипа каждой написанной функции. Прототипы гарантируют соответствие типов данных передаваемых параметров и возвращаемых значений функции.
Возвращаемые значения функции
Функции, возвращающие значения, предоставляют новую возможность: передавать данные не только в одном направлении из вызывающей функции в вызываемую, но и в обратном из вызываемой функции в вызывавшую ее функцию.
Если нужно вернуть значение в вызывающую функцию, то следует поместить возвращаемое значение после оператора return. Для большей ясности заключают возвращаемое значение в круглые скобки:
return(возвращаемое_значение);
Предупреждение: Нет необходимости возвращать глобальные переменные, потому что значения глобальных переменных уже известны во всех участках программы.
Вызывающая функция должна использовать возвращаемое значение. Например, есть функция для вычисления среднего значения трех целых чисел, переданных как параметры в эту функцию. Если возвращается среднее значение, вызывающая функция должна получить это значение и как-либо использовать его. Следующий пример демонстрирует этот принцип:
/* Вычисление среднего значения трех введенных пользователем чисел */
#include <stdio.h>
float calc_av(int num1, int num2, int num3)
{
float local_avg; /* Содержит среднее значение этих чисел*/
local_avg=(num1+num2+num3)/3;
return (local_avg);
}
main ( )
{
int num1, num2, num3;
float avg; /* Будет содержать возвращаемое значение */
puts(“ Введи три числа через пробел”);
scanf(“%d %d %d”, &num1, &num2, &num3);
/* Вызов функции, передача параметров и получение возвращаемого значения */
avg = calc_avg(num1, num2, num3);
printf (“\n Их среднее это %f”, avg);
return 0;
}
Cледует обратить внимание на дополнительные моменты программы, связанные с тем, что функция возвращает значение. Начальная часть функции main() обычна. Описываются локальные переменные три для входных данных пользователя и одна для вычисленного среднего значения. Вызов функции calc_av () также обычен; он передает по значению три переменные num1, num2, num3 в функцию calc_av () (если бы функция принимала их по адресу, каждому аргументу должен был предшествовать амперсанд (&)).
Принимающая функция calc_av () выглядит так же, как и другие функции, за исключением первой строки строки описания функции, которая имеет одно дополнение: ключевое слово float перед ее именем. Так указывается тип возвращаемого значения. Нужно всегда указывать тип возвращаемого функцией значения. Если тип не указан, С установит его по умолчанию как int, но от этого пострадает четкость программы.
Так как переменная local_avg, которая возвращается из функции calc_av (), является вещественной, именно ключевое слово float, означающее вещественный тип, помещено перед именем этой функции.
Нужно обратить внимание на то, что оператор возврата функции calc_av () включает возвращаемое значение local_avg. Эта переменная будет передана назад в вызывающую функцию main(). Можно возвратить только единственное значение в вызывающую функцию.
Замечание: хотя функция может получать более одного параметра, она возвращает только одно значение в вызывающую функцию. Если вызываемая функция должна изменять более одного значения вызывающей функции, нужно передавать параметры по адресу; оператор return не может возвращать несколько значений.
После того, как вызываемая функция calc_av () вернет значение, функция main() должна с ним что-либо сделать. До сих пор в строке располагались только сами по себе вызовы функций. В функции main( ) вызов функции расположен справа от знака присваивания:
avg = calc_avg(num1, num2, num3);
Когда функция calc_av () возвращает значение (среднее арифметическое трех чисел), то это значение как бы заменяет вызов функции. Если среднее арифметическое, вычисленное функцией calc_av (), равно 40, выполняемая программа «видит» такой оператор на месте вызова функции:
avg=40;
Вызов функции расположен справа от знака присваивания, но программа заменяет вызов функции на возвращаемое посредством оператора return значение. Другими словами, функция, которая возвращает значение, становится этим значением. Можно поместить такую функцию везде, где вы можете поместить любую переменную или константу данного типа обычно справа от знака присваивания или в выражении, или при выводе с помощью printf().
Такой способ вызова функции calc_av () является некорректным:
calc_av ( num1, num2, num3);
Если программа содержит такую строку, С ничего не будет делать с возвращаемым значением (игнорирует его).
Вызовы функций, возвращающих значение, редко появляются в строках программы одни, сами по себе. Так как вызов функции заменяется возвращаемым значением, нужно сделать что-либо с этим возвращаемым значением - например, присвоить его переменной или использовать его в выражении. Возвращаемые значения могут быть проигнорированы, но это обычно противоречит целям их использования.
Прототипы функций
Слово «прототип» при использовании его применительно к функциям является синонимом слова «модель». Прототип функции является моделью настоящей функции.
При программировании на С желательно, а при использовании для разработки программ среды С++ ( например, Borland C++) обязательно описывать прототипы всех функций, которые используются в программе. Описывая прототип, программист сообщает компилятору типы параметров функций, и, если необходимо, типы возвращаемых значений.
Описание прототипов защищает от возможных ошибок при программировании. Они позволяют компилятору отслеживать типы параметров функций и типы возвращаемых значений.
Файлы заголовков (например, stdio.h) содержат прототипы стандартных функций, поэтому прототипы библиотечных функций пользователю описывать не требуется. Все остальные функции должны содержать прототип, который строится по следующему шаблону:
тип_возвращаемого_значения имя_функции (тип_ параметра имя_параметра, …);
Только в том случае, когда определение функции находится выше ее первого вызова, описание прототипов необязательно, однако, во избежание ошибок, лучше описывать прототипы всех функций.
Задание:
Контрольные вопросы
Лабораторная работа №21
Программирование с использованием рекурсивных функций
Цель работы: Научиться программировать на С, используя рекурсивные функции.
Теоретические сведения
В теле функции доступны все объекты, описанные в этой функции или как глобальные, в том числе и имя самой функции. Таким образом, внутри тела функции возможен вызов самой функции. Функции, использующие вызовы "самих себя", называют рекурсивными. Допустима также косвенная рекурсия, при которой, например, функция А вызывает функцию В, та, в свою очередь, вызывает С, которая вызывает первоначальную функцию А.
Рекурсия широко применяется в программировании, что основано на рекурсивной природе многих математических алгоритмов (например, факториал). Можно написать рекурсивную функцию для вычисления факториала следующим образом:
double Factorial (int number)
{
if (number>1) return number*Factorial(number-1);
reurn 1;
}
Функция Factorial() возвращает значение типа double и объявляет единственный параметр number типа int. Функция начинается с оператора if, который проверяет значение параметра number. Если number больше 1, функция возвращает значение number, умноженное на факториал number-1.
В языке С нет ограничений на рекурсивные вызовы функций, необходимо только хорошо понимать, что каждый очередной рекурсивный вызов приводит к образованию новой копии локальных объектов функции и все эти копии, соответствующие цепочке активизированных и незавершенных рекурсивных вызовов, существуют независимо друг от друга.
Поскольку такие функции, как Factorial(), прямо вызывают сами себя, они являются включительно рекурсивными. Но иногда встречаются менее распространенные формы рекурсии, когда одна функция вызывает другую, которая в конце концов снова приходит к вызову первой функции. Такая рекурсия называется взаимной. Она полезна для написания сопрограмм-функций, которые зависят одна от другой, но не требуют, чтобы одна функция обязательно вызывалась другой. Примером может служить следующая программа, которая выводит на экран алфавит.
#include <stdio.h>
void A(int c);
void B(int c);
main()
{
A(Z);
puts(“”);
}
void A(int c)
{
if (c>A)
B(c);
putchar(c);
}
void B(int c)
{
A(--c);
}
Основная функция начинает рекурсию в строке 8, вызывая функцию А() с аргументом Z. Функция А() проверяет свой параметр с. Если с в алфавитном порядке больше A, то происходит вызов функции В(), которая немедленно вызывает опять-таки функцию А(), передавая ей предшественника параметра с. Это заставляет функцию А() снова проверить параметр с и снова вызвать В(), пока значение с не сравняется с A.
Этот эффект демонстрирует важную характеристику рекурсии. Значения параметров запоминаются в стеке для каждого рекурсивного входа в функцию. Это говорит о том, что рекурсия требует большого объема стековой памяти. Действительно, несмотря на то, что рекурсия всегда заканчивается, слишком большое количество вызовов функций может истощить стек, вызвав ошибку его переполнения, что обычно приводит к аварийному останову программы.
Задание:
Контрольные вопросы
Лабораторная работа №22
Программирование с использованием структур
Цель работы: ознакомиться с понятием структуры в языке С и научиться применять структуры при написании программ.
Структура это набор из одной или более переменных, возможно различных типов, сгруппированных под одним именем для удобства обработки.
Традиционным примером структуры является учетная карточка работающего: «служащий» описывается набором таких атрибутов, как: фамилия, имя, отчество, адрес, зарплата и т. д. Некоторые из этих атрибутов сами могут оказаться структурами: Ф.И.О. имеет несколько компонентов, как и адрес, и даже зарплата.
Структуры полезны при организации сложных данных, особенно в больших программах, поскольку во многих ситуациях они позволяют сгруппировать связанные данные таким образом, что с ними можно обращаться как с одним целым, а не как с отдельным объектами.
Рассмотрим структуру, описывающую дату. Она состоит из нескольких частей: день, месяц, год, день года и имя месяца.
struct date {
int day;
int month;
int year;
int yearday;
char monthname[4];
};
Описание структуры, состоящие из заключенного в фигурные скобки списка описаний, начинается с ключевого слова struct.
За ним может следовать необязательное имя (иногда называемое ярлыком структуры или тегом) date. Такой ярлык именует структуры этого вида и его можно использовать в дальнейшем как сокращенную запись подробного описания.
Элементы или переменные, упомянутые в структуре, называются членами. Ярлыки и члены структур могут иметь такие же имена, что и обычные переменные. Член определенной структуры может быть указан в выражении с помощи конструкции вида: имя структуры.член.
Операция указания члена структуры «.» связывает имя структуры и имя члена.
Структуры могут быть вложенными. Например, учетная карточка служащего может выглядеть так:
struct person{
char name[ namesize ];
char address [ adrsize ];
long zipcode; /*почтовый индекс*/
double salary; /*зарплата*/
struct date birthday; /* дата рождения */
struct date hiredate; /* дата поступления на работу */
};
Структура person содержит 2 структуры типа date. Если определить экземпляр структуры
struct person emp;
то
emp.birthdate.mouth
будет ссылаться на месяц рождения.
Операция указания члена структуры «.» ассоциируется слева направо.
Так как при описании переменной структурного типа требуется использование спецификатора struct, обычно полное имя структурного типа оформляют в виде макро.
Например, пусть нужно выполнять действия над комплексными числами. Поскольку комплексное число может быть представлено двумя вещественными, то можно воспользоваться структурой.
#define COMPLEX struct complex type
COMPLEX{
float real;
float image;
};
Такое макроопределение COMPLEX позволяет описывать комплексные переменные в естественной форме.
Если переменные с1, с2 и с3 описаны как комплексные, то операция умножения с1 на с2 для получения с3 может быть реализована следующим образом:
COMPLEX c1, c2, c3;
c3.real = c1.real * c2.real c1.image*c2.image;
c3.image= c1.image*c2.real + c1.real*c2.image;
Структурную переменную можно инициализировать подобно переменным или массивам. Например, можно инициализировать структурную переменную типа COMPLEX следующим образом:
COMPLEX с1 = { 1.15; -3.1 };
Можно создать указатель на структуру, например:
COMPLEX *ptс1;
В этом случае для размещения по этому адресу структуры нужно выделить память следующим образом:
ptc1 = (COMPLEX*) malloc(sizeof(float*2));
Теперь к полям структуры, хранящейся по адресу ptc, можно получить доступ с помощью операции доступа к полям структуры по указателю ->:
ptc1->real = 12.5;
ptc1->image=-3.7;
Лабораторная работа №23
Массивы структур
Цель работы: ознакомиться с понятием массива структур, научиться использовать их в программах.
Теоретические сведения
Массивы структур удобны для хранения информации о служащих, покупателях, некоторых пунктах, инвентаризационной ведомости, а также любого другого множества данных, для которых пригоден формат структуры.
Объявить массив структур просто. При объявлении массива структурных переменных в квадратных скобках нужно ввести количество резервируемых структур.
struct store
{
int employees;
int registers;
doublе sales;
}stores[1000];
При помощи этого кода быстро и компактно создается 1000 структур с информацией о магазинах, каждая из которых содержит 3 элемента. Обращение к элементам происходит следующим образом:
stores[8].sales=10;
или
(*(stores+8)).sales=10;
Двойные скобки требуются потому, что приоритет операции "." выше, чем "*".
Задание:
Написать программу, которая будет запоминать имена и номера телефонов ваших друзей, а затем выводить их. Добавьте поиск по имени и номеру телефона.
Контрольные вопросы
Лабораторная работа №24
Передача структур в функции и структуры
как возвращаемые значения функций
Цель работы: изучить правила передачи структур в функции и научиться использовать структурные переменные как возвращаемые значения функций.
Теоретические сведения
Структурные переменные могут передаваться в функции и возвращаться функциями подобно обычным переменным. Если структурная переменная передается в качестве параметра функции, которая изменяет отдельные компоненты этой структуры, то данные в вызывающей функции автоматически не обновляются, т.к. структуры передаются по значению, а не по ссылке.
Если нужно изменять элементы структуры в функции, то в функцию можно передать указатель на структуру, или передать значение структурной переменной в вызывающую функцию через оператор return, или объявить структурную переменную глобальной. Для первых двух случаев структурный шаблон должен быть глобальным, а структурные переменные - локальными.
Например, программа, которая использует структуру, описывающую студента:
#include <stdio.h>
#include<string.h>
struct students{
char name[25];
int age;
float average;
};
struct students fill( students sv)
{
fflush(stdin);
puts(“Имя студента?”);
gets(sv.name);
puts(“Возраст студента?”);
scanf(“%d”, sv.age);
puts(“Средний балл?”);
scanf(“%f”, sv.average);
return (sv);
}
void pr (students sv)
{
puts(“Имя студента:”);
puts(cv.name);
puts(“Возраст студента:”);
printf (“%d\n”, sv.age);
puts(“Средний балл:”);
printf (“%f\n”, sv.average);
}
main()
{
struct students sv1, sv2;
sv1=fill(sv1);
sv2=fill(sv2);
puts(“Вот информация о студентах:”);
pr(sv1);
pr(sv2);
}
Из определения функции fill следует, что она должна возвращать значение, тип которого представляет собой struct students, и имеет один аргумент такого же типа. Две локальные переменные такого типа sv1 и sv2 объявляются в main(), а затем передаются в функцию fill() по значению, и изменения, которые происходят с ними в fill(), в main() не видны. Поэтому эти переменные нужно вернуть в вызывающую функцию.
Задание:
Задать структуру, определяющую работника для отдела кадров. Хранить поля: ФИО, год рождения, пол, оклад. Создать функцию, которая получает структурную переменную в качестве параметра и определяет размер пенсии работника (80% от оклада), если в текущем году он достиг пенсионного возраста (55 лет для женщин и 60 лет для мужчин).
Контрольные вопросы
Лабораторная работа №25
Использование файлов в программе на C.
Функции fopen() и fclose()
Цель работы: научиться работать с файлами в программе на Cи.
Теоретические сведения
В стандартной библиотеке языка С существует специальный тип данных. Это тип FILE. Переменные этого типа данных используются для обращения к файлам. Описание функций для работы с файлами и типа FILE находятся в файле заголовка stdio.h.
Для того, чтобы производить какие-либо операции с файлом, его надо открыть. Это производиться с помощью функции fopen. Ее описание выглядит так:
FILE * fopen(char *path, char *mode);
Функция fopen принимает два параметра: path и mode:
path имя открываемого файла;
mode режим открытия файла.
Функция, получив необходимые параметры, производит открытие файла и заполняет поля структурной переменной типа FILE, указатель на которую она и возвращает. При этом эта функция производит самостоятельное выделение необходимого количества памяти под переменную. Так как чтение и запись происходят с определенной позиции, функция fopen модифицирует значение этой позиции в соответствии с режимом открытия. Если открытие файла не произошло по какой-либо причине, то функция fopen возвращает 0. Поэтому после ее вызова необходима проверка на успешное открытие файла.
Фрагмент кода, выполняющий открытие файла, будет иметь вид:
FILE *fl; // указатель на файловую переменную.
fl=fopen("somef.dat","w+"); // открытие файла somef.dat для чтения и записи
if(fl==0)
{
printf("\nПроизошла ошибка открытия файла somef.dat");
return;
}
Файл может быть открыт в следующих режимах:
r - открыть только для чтения. Позиция, с которой будет производиться чтение, устанавливается на начало файла.
w - создать для записи. Позиционирование на начало файла. Если файл существует, он будет переписан.
a - добавление. Открытие для записи в конец файла. Создание, если файл не существовал.
r+ - открытие существующего файла для изменения (и чтение, и запись)
w+ - создание нового для чтения и записи. Если файл существует, он будет дописан.
a+ - идентично a.
Кроме того, файл может быть открыт в текстовом и двоичном режиме - это устанавливается добавлением к параметрам в строке mode следующих букв: t-текстовый режим , b-двоичный режим. Например, строка mode может иметь вид: "rt" или "wt+", "w+t", "ab", и т.д.
Для записи используются такие функции:
int fputc(int byte, FILE *stream);
Запись байта byte в файл stream. Если файл был открыт для только чтения, то функция fputc не произведет записи в файл. Если запись не была успешной, то fputc возвращает EOF. Фрагмент программы, выполняющей запись байта в файл:
int c=90;
// fl - ранее успешно открытый файл
if (fputc (c, fl)==EOF)
{
printf("Невозможно записать файл");
}
Когда требуется запись в файл строки, побайтовая запись оказывается невыгодной, для этого существует функция: fwrite.
size_t fwrite(void *ptr, size_t size, size_t n,FILE *stream);
ptr - указатель на данные которые необходимо записать;
size - длина одной единицы данных;
n - количество единиц данных;
stream файл, в который производится запись.
Функция fwrite записывает в файл stream n единиц данных, каждая из которых имеет длину size, данные берутся по указателю ptr. Возвращается количество действительно записанных единиц.
Фрагмент программы, выполняющий запись в файл массива int длиной 10:
int array[10];
for(int c=0;c<10;c++) array[c]=c;
// fl- заранее открытый файл
if(fwrite(array,sizeof(int),10,fl)!=10)
{
printf("\nВо время записи произошла ошибка");
};
// Можно также записать так
//if(fwrite(array,sizeof(int)*10,1,fl)!=10)
Иногда целесообразно использовать функцию fprintf.
int fprintf(FILE *stream, char *format, ...);
Ее действия полностью аналогичны действиям функции printf, с тем отличием, что printf выводит данные на экран, а fprintf в заданный параметром stream файл. Задание значений всех параметров, кроме значения stream, функции fprintf аналогично заданию значений параметров функции printf. В результате записи значение позиции в файле изменяется на количество записанных байт.
Для чтения одного байта из файла можно использовать функцию: fgetc.
int fgetc(FILE *stream);
Эта функция читает байт из файла stream, и возвращает его. Позиция чтения сдвигается на 1. В случае ошибки чтения возвращается EOF.
int c;
// fl - заранее открытый файл
if((c=fgetc(fl))==EOF)
{
printf("Чего-то не читается");
return;
}
else
{
printf("Прочитан байт значение:%d",c);
}
Чтобы прочитать последовательность байт используется функция fread().
size_t fread(void *ptr, size_t size, size_t n,FILE *stream);
fread читает из файла stream n единиц данных, длиной size каждая, данные помещаются в память, начиная с адреса, сохраненного в указателе ptr. Функция не выделяет память под данные, потому ответственность за их размещение в памяти ложится на пользователя.
После работы с файлом он должен быть закрыт. Это осуществляет функция fclose(FILE *). Для закрытия файла надо вызвать функцию fclose, параметром передать указатель на файловую переменную. После закрытия любые операции чтения/записи станут невозможны до следующего открытия.
Задание:
Контрольные вопросы
Лабораторная работа №26
Использование имени файла в качестве параметра командной строки
Цель работы: научиться получать и обрабатывать параметры командной строки
В операционной системе МS DOS существует возможность запуска исполняемой программы с одним или несколькими параметрами. Каждый из этих параметров записывается после имени исполняемого файла. Все они разделяются пробелами. Например:
В данном случае программе format передаются два параметра: “a:” и “/s”.
Язык программирования С позволяет получать и обрабатывать переданные в программу параметры. Для этого функция main() должна быть описана следующим образом (идентификаторы переменных могут быть другими):
[тип возвращаемого значения] main(int argc, char **argv);
где int argc количество параметров, char **argv указатель на строки, содержащие эти параметры. Следует отметить, что первым параметром всегда является полное имя исполняемого файла, к которому принадлежит функция main. Например, для приведенного выше вызова программы format переменные будут иметь следующие значения: argc=3, *argv=”c:\dos\format.com”, *(argv+1)=”a:”, *(argv+2)=”/s” (путь к format.com может отличаться от приведенного).
Работа с параметрами функции main() ведется точно так же, как и с обычными параметрами функций языка С.
Очень часто параметром программы является имя файла. Например:
Такой прием используется для указания программе файла, над которым она должна выполнять определенные действия или брать из него нужные данные.
Лабораторная работа №27
Использование функций преобразования символов
К функциям преобразования символов относятся следующие функции:
atoi преобразование строки в целое число;
atof преобразование строки в число с плавающей точкой;
atol преобразование строки в длинное целое;
gcvt преобразование значения с плавающей точкой в строку.
Все эти функции описаны в файле stdlib.h.
Получает ASCII строку и преобразует ее в значение типа int.
Получает ASCII строку и преобразует ее в значение типа float.
Получает ASCII строку и преобразует ее в значение типа long.
Пример программы, использующей функции для преобразования строки в целое и вещественное числа:
#include <stdio.h>
int main(void)
{
int n;
float f;
char *str = "12345.67";
n = atoi(str);
f = atof(str);
printf("string = %s integer = %d float = %f\n", str, n,f);
return 0;
}
На экране будет такая строка:
string = 12345.67 integer = 12345 float = 12345.67
Обратное преобразование производится с помощью функций gcvt и ecvt;
value число которое необходимо преобразовать в строку.
ndig максимальное число знаков в результирующей строке.
dec указатель на переменную типа int, в которую нужно произвести запись количества цифр слева от запятой.
sign указатель на переменную типа int, в которую функцией производится запись 1, если value < 0, и 0, если value > 0
Эта функция проще, чем ecvt. Она производит запись в память, начиная с адреса, сохраненного в указателе buf, числа value, переведенного в строку, ndec максимальная длина строки.
В приведенном ниже примере программа осуществляет перевод заданного в программе числа с плавающей точкой в строку символов.
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
int main(void)
{
char *string;
double value;
int dec, sign;
int ndig = 10;
char str[25];
double num;
int sig = 5;
value = -98.76;
string = ecvt(value, ndig, &dec, &sign);
clrscr();
printf("string = %s dec = %d sign = %d\n", string, dec, sign);
num = -9.876;
gcvt(num, sig, str);
printf("string = %s\n", str);
}
На экране будет:
string = 9876 dec = 2 sign = 1
string = -9.876
1. Какие существуют функции преобразования строки в число?
2. Какие существуют функции преобразования числа в строку?
СПИСОК РЕКОМЕНДОВАННОЙ ЛИТЕРАТУРЫ
EMBED Word.Picture.8
EMBED Word.Picture.8
EMBED Word.Picture.8
EMBED Word.Picture.8
ОТВЕТ ВЕРЕН
Press any key
ВЕРНО
ВЕРНО
ВЕРНО
ВЕРНО
4
-12
1
1
#define PRINTX printf("%d\n",x)
main()
{
int x=4, y, z;
x+=1*8-8; PRINTX;
x*=y=z=-3; PRINTX;
x=-19!=-48; PRINTX;
x>=(y=58); PRINTX;
}
ДИАГН.
СИСТЕМЫ
АШ ОТВЕТ
ЧТО НАПЕЧАТАЕТ СЛЕДУЮЩАЯ ПРОГРАММА?
F10-ВЫХОД
F2-ТЕОРИЯ
F1-ПОМОЩЬ
#define PRINTX printf("%d\n",x)
main()
{
int x=4, y, z;
x+=1*8-8; PRINTX;
x*=y=z=-3; PRINTX;
x=-19!=-48; PRINTX;
x>=(y=58); PRINTX;
}
ДИАГН.
СИСТЕМЫ
ВАШ ОТВЕТ
ЧТО НАПЕЧАТАЕТ СЛЕДУЮЩАЯ ПРОГРАММА ?
F10-ВЫХОД
F2-ТЕОРИЯ
F1-ПОМОЩЬ
#define PRINT(int) printf("%d\n",int)
main()
{
int x=0,y=0,z=2;
PRINT(x||y||!z);
x=4; y=8;
z=++x + 2; PRINT(x); PRINT(z);
z/=++x - ++y; PRINT(z);
}
ДИАГН.
СИСТЕМЫ
ВАШ ОТВЕТ
ЧТО НАПЕЧАТАЕТ СЛЕДУЮЩАЯ ПРОГРАММА?
ЧТО НАПЕЧАТАЕТ СЛЕДУЮЩАЯ ПРОГРАММА ?
ВАШ ОТВЕТ
ДИАГН.
СИСТЕМЫ
#define PRINT(int) printf("%d\n",x)
main()
{
int x, y=1, z;
if (y!=1) x=36; else x=34;
PRINT(x);
if (y<=1) if (y==1) x=18;
else x=20;
PRINT(x);
if (z=y<2) x=28;
PRINT(x);
F1-ПОМОЩЬ
F2-ТЕОРИЯ
F10-ВЫХОД
ЧТО НАПЕЧАТАЕТ СЛЕДУЮЩАЯ ПРОГРАММА ?
ВАШ ОТВЕТ
ДИАГН.
СИСТЕМЫ
#define PRINT(int) printf("%d\n",x)
main()
{ int x=14, y=3;
while (y<10) ++y; x-=y; PRINT(x);
x=1; y=0;
while (y<11) x+=++y;
PRINT(x); PRINT(y);
y=1; z=0;
do z-=y;
while (++y<9); PRINT(z);
}
F1-ПОМОЩЬ
F2-ТЕОРИЯ
F10-ВЫХОД
ЧТО НАПЕЧАТАЕТ СЛЕДУЮЩАЯ ПРОГРАММА ?
ВАШ ОТВЕТ
ДИАГН.
СИСТЕМЫ
#define PRINT(int) printf("%d\n",x)
main()
{
int x=0, y;
for (y=8; y>0; y--) x=y;
PRINT(x);
for (y=12; (x=y)>1; y--) ;
PRINT(x);
for (x=1,y=13; y>x; ++x,--y );
PRINT(x); PRINT(y);
}
F1-ПОМОЩЬ
F2-ТЕОРИЯ
F10-ВЫХОД