Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информатика_1 / C / lecture3 / lecture3

.html
Скачиваний:
13
Добавлен:
09.06.2015
Размер:
18.55 Кб
Скачать
<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([&lt;выражение 1&#62;];[&lt;выражение 2 целого типа&#62;];[&lt;выражение 3])&lt;оператор&#62;
Оператор цикла  for работает следующим образом:
1. Вычисляется выражение 1, если оно присутствует.
2. Вычисляется выражение 2, если оно присутствует.
Если значение выражения 2 не ноль , тогда выполняется &lt;оператор&#62;.
Затем вычисляется &lt;выражение 3&#62;. Далее процесс продолжается 
вновь с вычисления &lt;выражения 2 &#62;.
Цикл for заканчивается когда &lt;выражение 2&#62; становится равным
нулю .
<I> Если &lt;выражение 2&#62; отсутствует, тогда оно считается всегда 
отличным от нуля и цикл в этом случае может быть остановлен при 
выполнении операторов break, goto или return. </I> Например , используем 
цикл for для суммирования первых 100 целых чисел
int i,s;
for(i=1,s=0;i&lt;=100;i++)s+=i;
Здесь в качестве &lt;выражения 1&#62; взято выражение составленное 
из двух простых выражений с использованием операции 
последовательного вычисления  ','. Это типичный пример , когда
с помощью операции последовательного вычисления несколько
простых выражений объединяются в одно в тех местах прграммы,
где по синтаксису должно присутствовать одно выражение. 
     Предположим мы хотим просмотреть на экране все промежуточные
значения  суммы:
int i,s;
for(i=1,s=0;i&lt;=100;i++){ s+=i; printf("s=%d\n",s); }
Здесь в качестве &lt;оператора &#62; цикла применен составной оператор
{ }, позволяющий объединить несколько простых операторов в один
в тех местах программы, где по синтаксису требуется один оператор.

  </PRE
><DIV
CLASS="FORMALPARA">
<HR><A NAME="AEN3">
<P
><B
>      Оператор цикла while.
    . </B
>      
    </P>
</A>
</DIV
><PRE
CLASS="PROGRAMLISTING"
>     Оператор цикла while позволяет выполнять некоторый оператор
( простой или составной) до тех пор пока выполняется некоторое 
условие. Синтаксис:
while(&lt;выражение целого типа&#62;)&lt;оператор&#62;
Например решим задачу суммирования первых ста целых чисел
с использованием оператора while:
int i=1,s=0;
while(i&lt;=100){s+=i; i++; }
В этом примере в качестве &lt;оператора&#62; цикла использован составной
оператор  { }, объединяющий два простых оператора в один в тех 
местах программы , где по синтаксису языка должен стоять один оператор. 


  </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&lt;stdio.h&#62; //включить заголовки функций для ввода-вывода
#include&lt;math.h&#62;  // Включить заголовки математических функций
int main(void){ 
	double x,a,s,eps;
	int n=0;
	printf("input x,eps--&#62;");
	scanf("%le%le",&amp;x,&amp;eps); //прочитать с консоли x,eps
	a=x; s=a;
	while(fabs(a)&#62;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), а 
&amp;x  означает, что это число должно быть положено в ячейки памяти по 
адресу, где хранится переменная x.  В данном для получения адреса 
переменной x используется унарная операция взятия адреса - &amp;.
Второй %le в строке формата означает , что второй набор символов,
полученный с консоли должен быть преобразован в число типа 
double (спецификация формата le), а &amp;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(&lt;выражение целого типа&#62;)&lt;оператор 1&#62; [else &lt;оператор 2&#62;].
Если выражение стоящее в скобках оператора if принимает ненулевое
значение, то выполняется &lt;оператор 1&#62;,  если это выражение имеет
нулевое значение то , если имеется  необязательная часть else - 
выполняется &lt;оператор 2&#62;, если части else нет - вообще никакой 
оператор не выполняется. Например:
if(i&#62;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(&lt;выражение целого типа&#62;){
case &lt;константное выражение целого типа 1&#62;: &lt;оператор 1&#62;;
case &lt;константное выражение целого типа 2&#62;: &lt;оператор 2&#62;;
.
.
.
[default: &lt;оператор n&#62;;]
}
Например:
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 &lt;метка&#62;;
.
.
.
&lt;метка&#62;: ...
Метка должна начинаться с буквы и может содержать любое число
символов , допусимых при написании идентификаторов.
Например:
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++&lt;0){
y=f(i);
if(i&#62;-5)continue;
printf("y=%d\n",y);
}.
В приведенном примере опретор printf("y=%d\n",y); при i&#62;-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 &lt;оператор&#62;; while(&lt;выражение целого типа&#62;);
Например:
do {i++; x=g(i);} while(i&lt;=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)&#62;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&lt;stdio.h&#62; //включить заголовки функций для ввода-вывода
#include&lt;math.h&#62;  // Включить заголовки математических функций
#include&lt;conio.h&#62; //Включили заголовки функций 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--&#62;");
	scanf("%le%le",&amp;x,&amp;eps); //прочитать с консоли x,eps
	a=x; s=a;
	while(fabs(a)&#62;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