Добавил:
Upload
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Информатика_1 / C / lecture3 / lecture3
.html<HTML
><HEAD
><TITLE
>Лекция 3. Операторы языка Си.</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.56"></HEAD
><BODY
CLASS="BOOK"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="BOOK"
><A
NAME="AEN1"
></A>
<P><H1>Лекция 3. Операторы языка Си.</H1>
<DIV
CLASS="TOC"
><DL
><DT
><B
>Table of Contents</B> <PRE>
</DT>
<A HREF="#AEN2"> 1. Оператор цикла for. </A>
<A HREF="#AEN3"> 2. Оператор цикла while. </A>
<A HREF="#AEN11"> 3. Применение оператора while для суммирования рядов. </A>
<A HREF="#AEN4"> 4. Оператор цикла do. </A>
<A HREF="#AEN5"> 5. Условный оператор if. </A>
<A HREF="#AEN6"> 6. Оператор switch. </A>
<A HREF="#AEN7"> 7. Оператор goto. </A>
<A HREF="#AEN8"> 8. Оператор continue. </A>
<A HREF="#AEN9"> 9. Работа с клавиатурой персонального компьютера,
или как с помощью клавиатуры остановить работу программы. </A>
<A HREF="#AEN10"> 10. Директива препроцессора define </A>
<A HREF="#AEN12"> 11. Задача </A>
</DL></DIV>
<DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN2">
<P
><B
> Оператор цикла for
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Оператор цикла for предназначен для выполнения какого-либо
оператора (простого или составного) заданное число раз.
Синтаксис:
for([<выражение 1>];[<выражение 2 целого типа>];[<выражение 3])<оператор>
Оператор цикла for работает следующим образом:
1. Вычисляется выражение 1, если оно присутствует.
2. Вычисляется выражение 2, если оно присутствует.
Если значение выражения 2 не ноль , тогда выполняется <оператор>.
Затем вычисляется <выражение 3>. Далее процесс продолжается
вновь с вычисления <выражения 2 >.
Цикл for заканчивается когда <выражение 2> становится равным
нулю .
<I> Если <выражение 2> отсутствует, тогда оно считается всегда
отличным от нуля и цикл в этом случае может быть остановлен при
выполнении операторов break, goto или return. </I> Например , используем
цикл for для суммирования первых 100 целых чисел
int i,s;
for(i=1,s=0;i<=100;i++)s+=i;
Здесь в качестве <выражения 1> взято выражение составленное
из двух простых выражений с использованием операции
последовательного вычисления ','. Это типичный пример , когда
с помощью операции последовательного вычисления несколько
простых выражений объединяются в одно в тех местах прграммы,
где по синтаксису должно присутствовать одно выражение.
Предположим мы хотим просмотреть на экране все промежуточные
значения суммы:
int i,s;
for(i=1,s=0;i<=100;i++){ s+=i; printf("s=%d\n",s); }
Здесь в качестве <оператора > цикла применен составной оператор
{ }, позволяющий объединить несколько простых операторов в один
в тех местах программы, где по синтаксису требуется один оператор.
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN3">
<P
><B
> Оператор цикла while.
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
> Оператор цикла while позволяет выполнять некоторый оператор
( простой или составной) до тех пор пока выполняется некоторое
условие. Синтаксис:
while(<выражение целого типа>)<оператор>
Например решим задачу суммирования первых ста целых чисел
с использованием оператора while:
int i=1,s=0;
while(i<=100){s+=i; i++; }
В этом примере в качестве <оператора> цикла использован составной
оператор { }, объединяющий два простых оператора в один в тех
местах программы , где по синтаксису языка должен стоять один оператор.
</PRE
><DIV
CLASS="FORMALPARA" >
<HR><A NAME="AEN11">
<P
><B
> Применение оператора while для суммирования рядов.
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Предположим требуется просуммировать бесконечный ряд:
</PRE
><IMG
SRC="./formula1.jpeg"><PRE
CLASS="PROGRAMLISTING"
>При попытке прямого подсчета слагаемых вы столкнетесь с тем , что
уже восьмое слагаемое требует вычисления 17! - число , которое
превышает максимально представимое в машине число. Чтобы обойти
эту проблему обратим внимание на то , что каждое последующее
слагаемое в ряду может быть получено из предыдущего по формуле:
</PRE
><IMG
SRC="./formula2.jpeg"><PRE
CLASS="PROGRAMLISTING"
>Поэтому для суммирования ряда необходимо лишь задать первое
слагаемое, а все последующие получать используя рекуррентное
соотношение , приведенное выше. Осталось только определить
критерий остановки процесса суммирования. Будем считать , что
процесс суммирования может быть остановлен ,когда очередное
слагаемое по модулю станет меньше заданного малого числа eps.
Блок-схема для суммирования ряда выглядит так:
</PRE
><IMG
SRC="./formula4.jpeg"><PRE
CLASS="PROGRAMLISTING"
>А вот пример программы , реализующей указанный алгоритм:
<A HREF=l3.c> (файл l3.c) </A>
#include<stdio.h> //включить заголовки функций для ввода-вывода
#include<math.h> // Включить заголовки математических функций
int main(void){
double x,a,s,eps;
int n=0;
printf("input x,eps-->");
scanf("%le%le",&x,&eps); //прочитать с консоли x,eps
a=x; s=a;
while(fabs(a)>eps){
a=-a*x*x/(2*n+2)/(2*n+3);
s+=a;
n++;
}
printf("sum=%e sin=%e\n",s,sin(x));
return 0;
}
В этой программе использована функция scanf для ввода данных с
консоли ( консолью называется пара - клавиатура + монитор).
В данной программе функция scanf использунтся для ввода с консоли
значений переменных x и eps. Первым аргументом функции scanf
всегда является строка, называемая строкой формата
преобразований. Функция scanf начинает свою работу с чтения строки
формата. В данном случае %le в строке формата означает, что
что первые введенные символы с консоли должны быть
преобразованы в число типа double (le oзначает именно тип double), а
&x означает, что это число должно быть положено в ячейки памяти по
адресу, где хранится переменная x. В данном для получения адреса
переменной x используется унарная операция взятия адреса - &.
Второй %le в строке формата означает , что второй набор символов,
полученный с консоли должен быть преобразован в число типа
double (спецификация формата le), а &eps означает , что полученное
число должно быть положено в ячейки памяти с адресом , где
должна храниться переменная eps. При чтении символов с консоли
функция scanf читает все символы до первого пробела или до
нажатия клавиши ENTER. Следует отметить , что <I> число спецификаций
формата (спецификация формата начинается с символа %) в строке
формата функции scanf должно строго соответствовать числу адресов,
пердаваемых в качестве аргументов функции scanf. </I> В случае
несоответствия никакой диагностики не выдается , но результаты
работы программы непредсказуемы.
В программе использована функция fabs, заголовок которой описан в
заголовочном файле math.h, предназначенная для вычисления абсолютного
значения переменной.
В конце программы на экран выводится подсчитанная сумма
для заданного значения x и значение sin(x) для оценки точности
вычисления суммы, т.к. приведенный ряд представляет разложение
функции синус.
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN5">
<P
><B
> Условный оператор if
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Условный оператор if применяется когда выполнение какого-либо
оператора зависит от выполнения некоторого условия. Если условие
выполняется то оператор выполняется , если условие не выполнено
то либо не выполняется вообще никакой оператор , либо выполняется
другой оператор. Синтаксическая диаграмма оператора if:
if(<выражение целого типа>)<оператор 1> [else <оператор 2>].
Если выражение стоящее в скобках оператора if принимает ненулевое
значение, то выполняется <оператор 1>, если это выражение имеет
нулевое значение то , если имеется необязательная часть else -
выполняется <оператор 2>, если части else нет - вообще никакой
оператор не выполняется. Например:
if(i>0){i++; printf("i=%d\n",i);} else i--;.
В приведенном примере если значение переменной i больше нуля -
выполняется составной оператор {i++; printf("i=%d\n",i);}, а если
i не больше нуля - выполняется оператор i--.
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN6">
<P
><B
> Оператор переключатель switch.
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Оператор switch используется тогда, когда надо передать управление в
программе на один из оператораторов, в зависимости от значения
целого выражения . Синтаксическая диаграмма оператора switch:
switch(<выражение целого типа>){
case <константное выражение целого типа 1>: <оператор 1>;
case <константное выражение целого типа 2>: <оператор 2>;
.
.
.
[default: <оператор n>;]
}
Например:
switch(i) {
case 0: i++;
case 1; j+=i; printf("j=%d\n",j);
default: i--;
}.
В этом примере если i==0 то выполнение передается на оператор ,
следующий за 0:, если i==1 - управление передаетя на оператор,
следующий за 1:, если i не совпадает ни с одним из значений ,
перечисленных в case - тогда управление передается на оператор,
следующий за лексемой default. Если значение целого выражения,
стоящего в круглых скобках оператора switch, не совпадает ни с одним
из значений case, а лексема defdault oтсутствует, тогда не
выполняется ни один опаратор.
Следует отметить, что после передачи управления на какой-либо
оператор из группы операторов, стоящих в фигурных скобках оператора switch,
далее выполняются все операторы, стоящие за
оператором, на который было передано управление. Прервать работу
оператора switch можно оператором break. Например:
switch(i) {
case 0: i++; break;
case 1; j+=i; printf("j=%d\n",j);break;
default: i--;
}.
<I> Оператор break применяется для прерывания работы операторов - for,while,do
и swicth. </I>
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN7">
<P
><B
> Оператор goto.
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Оператор goto передает управление на оператор, следующий за
меткой. Синтаксис:
goto <метка>;
.
.
.
<метка>: ...
Метка должна начинаться с буквы и может содержать любое число
символов , допусимых при написании идентификаторов.
Например:
met1: i=k+u;
.
.
.
goto met1;
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN8">
<P
><B
> Оператор continue.
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Оператор continue передает управление очередной итерации
цикла while, for или do, пропуская все стоящие после него операторы
в теле цикла. Например:
while(i++<0){
y=f(i);
if(i>-5)continue;
printf("y=%d\n",y);
}.
В приведенном примере опретор printf("y=%d\n",y); при i>-5
пропускается в теле цикла.
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN4">
<P
><B
> Оператор цикла do.
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Работа оператора цикла do похожа на работу цикла while с той лишь
разницей , что в цикле while сначала проверяется условие, а затем
выполняется оператор, а в цикле do - сначала выполняется оператор,
а затем проверяется условие. Таким образом в цикле do оператор
выполняется хотя-бы один раз, в то время, как в цикле while , он
может вообще не выполняться. Синтаксис:
do <оператор>; while(<выражение целого типа>);
Например:
do {i++; x=g(i);} while(i<=10);
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN9">
<P
><B
> Работа клавиатуры персонального компьютера или как с помощью клавиатуры можно управлять работой программы
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Представьте себе, что условие работы цикла while в предыдущей программе
cуммирования ряда <A HREF=l3.c> (файл l3.c) </A>
(fabs(a)>eps), всегда выполняется. Это может произойти либо если
вы допустили ошибку при написании выражения для вычисления
очередного слагаемого a, либо ряд просто не сходится. Тогда
цикл будет работать бесконечно и возникает вопрос о том ,
как прервать его работу используя клавиатуру. Несколько слов
о том , как работает клавиатура персонального компьютера.
Когда Вы нажимаете какую-либо клавишу на клавиатуре ,
в область памяти персонального компьютера, называемую буфером,
записывается два байта. Один байт ascii код нажатой клавиши,
второй - scan код клавиши.
Полная таблица символов , которые могут быть представлены на
экране персонального компьютера называется таблицей ascii
символов (Unicode символы рассматриваются позже в 11-ой лекции).
Аббревиатура ascii происходит от английских слов american standart
code information interchange. В таблице ascii символов все символы
пронумерованы числами от 0 до 255 - все числа , которые можно
записать в один байт. Ascii код - это номер символа в таблице.
В последующих лекциях мы разберем программу для вывода всех
ascii символов на экран вашего монитора. А пока нам достаточно
знать , что ascii код - это просто число из интервала от 0 до 255.
Все клавищи клавиатуры персонального компьютера
пронумерованы. scan код клавиши - это фактически номер клавиши
на клавиатуре. Sсan код клавиши необходимо писать в буфер
клавиатуры для полной идентификации нажатой клавиши, т.к.
не все клавиши на клавиатуре имеют ascii код - это клавиши
со стрелочками, PgUp, PgDn ,End и т.д. Если Вы нажимаете
клавишу без ascii кода, тогда вместо ascii кода в буфер клавиатуры
пишется 0 и единственная возможность определить какая клавиша
была нажата - это прочитать ее scan код.
Всего в буфере клавиатуры зарезервировано 32 байта.
Из них лишь 30 используются для хранения ascii и scan кодов.
Два байта используются в служебных целях. Когда все байты в буфере
заняты , дальнейшие нажатия клавишей никак не фиксируются ,
а динамик при этом издает звуковой сигнал. Чистка буфера
клавиатуры - задача программиста.
В этом параграфе мы рассмотрим две функции для работы с
буфером клавиатуры. Их заголовки так описаны в заголовочном
файле conio.h:
int kbhit(void);
int getch(void);
Обе функции не имеют аргументов , о чем говорит лексема void
(пустой) в списке аргументов. Функция kbhit возвращает значение
0 если в буфере клавиатуры нет символов и 1 если буфер не пуст.
Функция getch при первом вызове возвращает ascii код последнего
веденнного в буфер клавиатуры символа . Если это не нулевой код,
то оба байта - scan код и ascii код из буфера клавиатуры
удаляются. Если getch взяла нулевой ascii код , то при повторном
вызове она вернет scan код последней нажатой клавиши. После
этого оба байта удаляются из буфера клавиатуры.
Если при вызове getch буфер клавиатуры был пуст - работа
программы будет остановлена до тех пор , пока Вы не нажмете
какую-либо клавишу на клавиатуре. Это может быть использовано
для организации паузы в работе программы.
Используя две рассмотренные функции можно написать код,
который прерывает работу цикла при нажатии определенной клавиши
на клавиатуре. Например , если вставить такую строку кода
в тело оператора цикла
if( kbhit() ) if( getch()=='q' ) break; ,
то работа вашего цикла может быть прервана в любой момент
нажатием клавиши 'q' на клавиатуре вашего компьютера.
Рассмотрим как работает приведенный оператор выражение.
Сначала функция kbhit проверяет есть-ли символы в буфере
клавиатуры . Если буфер пуст - kbhit вернет 0 и оператор
if( getch()=='q' ) break не будет выполняться и ваша программа
продолжит работу. Если -же в буфере клавиатуры имеются символы,
тогда kbhit возвращает 1 и выполняется оператор
if( getch()=='q' ) break. В этом операторе ascii код, который считает из
буфера клавиатуры функция getch, сравнивается с ascii кодом
символа 'q'. Если эти коды совпадают, то выполняется оператор break,
который прервет работу цикла.
</PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN10">
<P
><B
> Директива препроцессора define - опреледеление макроса.
. </B
>
</P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>Давайте немного изменим текст программы для суммирования ряда,
добавив в него пару строк <A HREF=l3_1.c> (файл l3_1.c) </A>
#include<stdio.h> //включить заголовки функций для ввода-вывода
#include<math.h> // Включить заголовки математических функций
#include<conio.h> //Включили заголовки функций kbhit и getch
//Определение макроса QUIT для прерывания работы цикла
// при нажатии клавиши 'q' на клавиатуре
#define QUIT if( kbhit() ) if( getch()=='q' )break
int main(void){
double x,a,s,eps;
int n=0;
printf("input x,eps-->");
scanf("%le%le",&x,&eps); //прочитать с консоли x,eps
a=x; s=a;
while(fabs(a)>eps){
a=-a*x*x/(2*n+2)/(2*n+3);
s+=a;
n++;
// Следующая строка обеспечит возможнсть остановить работу
//цикла по нажатию клавиши 'q'
QUIT;
}
printf("sum=%e sin=%e\n",s,sin(x));
return 0;
}
В шестой строке программы я добавил директиву препроцессора
define, которая называется - определение макроса.
С одной директивой препроцессора мы уже знакомы - это директива
include, включающая текст некоторого файла в вашу программу.
Вы помните , что препроцессор - это программа, которая производит
обработку текста Вашей программы до ее компиляции.
В нашем случае директива define в шестой строке нашей программы
предписывает препроцессору просмотреть весь текст программы,
седующий за шестой строкой и макрос QUIT , везде где он будет
найден заменить на его определение - if( kbhit() ) if( getch()=='q' )break.
Таким образом определение макроса можно считать просто
возможностью сократить код Вашей программы. Следует отметить,
что макросы весьма популярны в среде программистов на Си.
Cуществует негласное правило в среде программистов - писать
макросы заглавными буквами.
<HR><A NAME="AEN12">
Задача. Написать программу для вывода на экран таблицы значений
функции, заданной рядом:
</A>
</PRE
><IMG
SRC="./formula3.jpeg"></DIV>
<PRE>
<A HREF="../lecture2/lecture2.html" >previous</A> <A HREF="../lecture4/lecture4.html" >next</A> <A HREF="../index.html">home</A>
</PRE>
</BODY
></HTML
>
Соседние файлы в папке lecture3