ТОП 10:

Прикладной информатики и кибернетики



Язык программирования Си.

Лекции

Преподаватель: к.т.н., доцент кафедры

Прикладной информатики и кибернетики

Ситняковская Елена Игоревна

Новосибирск – 2011

Содержание

ВВЕДЕНИЕ

1. Правила записи программы на языке Си.. 7

2. Правила формального описания синтаксиса языка программирования.. 8

3. Идентификаторы языка Си.. 9

4. Понятие о типах данных. 9

4.1. Системы счисления. Представление данных в ЭВМ. 10

4.2. Основные типы данных языка Си.. 11

4.3. Правила записи констант различных типов. 12

4.4. Беззнаковый тип для целых данных.. 14

4.5. Символьные строки.. 14

5. Понятие функции.. 15

5.1. Стандартная функция printf. 15

5.2. Стандартная функция scanf. 16

6. Операции и выражения.. 17

6.1. Простейшие арифметические операции.. 17

6.2. Операция присваивания. 18

6.3. Оператор-выражение. 18

6.4. Использование в выражениях операндов разных типов. 18

6.5. Операции преобразования типов. 19

6.6. Стандартные математические функции.. 19

6.7. Простейшие функции, определяемые программистом.. 20

6.8. Дополнительные арифметические операции.. 21

6.9. Дополнительные операции присваивания. 22

6.10. Битовые операции.. 23

6.11. Операции отношения. 24

6.12. Логические операции.. 25

6.13. Операция определения размера данных.. 26

6.14. Приоритеты операций.. 26

7. Программирование алгоритма линейной структуры на языке Си.. 27

8. Понятие о препроцессоре языка Си.. 28

9. Операторы языка Си и приемы программирования.. 29

9.1. Оператор цикла while. 29

9.2. Условный оператор и условная операция. 30

9.3. Запись алгоритмов с помощью диаграмм Несси - Шнейдермана (структограмм ) 33

9.4. Некоторые приемы программирования. 34

9.5. Оператор прерывания цикла.. 37

9.6. Оператор продолжения цикла.. 38

9.7. Пример организации простейшего меню... 38

9.8. Множественный выбор. Оператор переключения. 39

9.9. Оператор цикла do-while. 40

9.10. Перечисления. Работа с клавиатурой IBM PC.. 41

9.11. Пример организации светового меню... 44

9. Массивы. Адресная арифметика языка Си.. 47

9.1. Описание массива.. 47

9.2. Ввод-вывод массива.. 48

9.3. Инициализация массива.. 49

9.4. Программа вычисления длины строки символов. 50

9.5. Двумерные массивы (массивы массивов) 51

9.6. Адресная арифметика языка Си.. 54

9.7. Указатели и одномерные массивы.. 58

9.8. Указатели и двумерные массивы.. 59

9.9. Указатели и функции.. 61

9.10. Оператор typedef. 62

9.11. Дополнительные описания указателей для IBM PC.. 63

9.12. Непосредственная работа с экранной памятью... 65

10. Дополнительные сведения о функциях.. 66

10.1. Области видимости и глобальные данные. 66

10.2. Время жизни переменных и классы памяти языка Си.. 69

10.3. Передача аргументов в функцию... 70

10.4. Возврат значений из функций.. 71

11. Работа с динамической памятью.... 73

11.1. Стандартные функции управления динамической памятью... 73

11.2. Пример использования динамической памяти.. 75

11.3. Особенности работы с двумерными массивами.. 76

11.3.1. Пересчет индексов вручную.. 76

11.3.2. Массивы с постоянной длиной строки. 78

11.3.3. Общий случай двумерного массива. 79

11.4. Особенности работы с массивами большого размера.. 84

12. Модульное программирование в системе Turbo C.. 87

12.1. Обеспечение корректной стыковки модулей.. 87

12.2. Создание библиотек функций.. 88

13. Некоторые библиотечные функции языка Си.. 89

13.1. Функции консольного ввода/вывода (уникальны для TC) 89

13.2. Функции обработки строк. 91

13.3. Функции распознавания вида символа.. 93

13.4. Функции преобразования данных.. 94

14. Структуры языка C. 95

14.1. Описание структуры.. 96

14.2. Трактовка имени структуры. 97

14.2.1. Доступ к элементу структуры. 97

14.3. Инициализация структур. 97

14.4. Структуры и функции. 98

14.5. Поля бит в структурах. 99

15. Объединения. 101

16. Дополнительные сведения о препроцессоре языка C. 101

22. Условное выражение. 103

22.1. Приоритеты и направления операций. 103

23. Динамические данные. 105

23.1. Линейные списки. 105

23.2. Организация данных в виде стека. 112

23.3. Организация данных в виде очереди. 113

23.4. Организация данных в виде деревьев. 114

24. Библиотека ввода-вывода языка C. 115

24.1. Открытие потока. 115

24.2. Закрытие потока. 116

24.3. Предопределенные указатели потоков. 117

24.4. Функции ввода-вывода. 117

Введение

Язык программирования Си создан в 1972 г. Деннисом Ритчи при разработке операционной системы UNIX. Язык проектировался как инструмент для системного программирования с ориентацией на разработку хорошо структурированных программ. Первоначально он появился в операционной системе UNIX, и развивался как основной язык систем, совместимых с ОС UNIX. Сам язык, однако, не связан с какой-либо одной операционной системой или машиной; и хотя его называют языком системного программирования, так как он удобен для написания операционных систем, он может использоваться для написания любых больших вычислительных программ, программ для обработки текстов и баз данных. Компиляторы языка Си работают почти на всех типах современных ЭВМ в операционных системах UNIX, MS-DOS, OS/2, Windows, Windows NT и т.д.


Зачем нужно программирование?

Иногда создается впечатление, что все существующие задачи могут быть решены с помощью готовых программ для компьютеров. Во многом это действительно так, но опыт показывает, что всегда находятся задачи, которые не решаются (или плохо решаются) стандартными средствами. В этих случаях приходится писать собственную программу, которая делает все так, как вы этого хотите.

Два этапа создания программ

Программа на языке Си, также как и на большинстве современных языков программиро-

вания, создается в два этапа

1) трансляция– перевод текста программы в машинные коды;

2) компоновка– сборка частей программы и подключение стандартных функций.

 

Исходный файл:

First.cpp

 
 


Транслятор

Компоновщик

 
 


Исполняемый файл:

First.exe

Почему же не сделать все за один шаг? Для простейших программ это действительно было бы проще, но для сложных проектов двухступенчатый процесс имеет явные преимущества:

• обычно сложная программа разбивается на несколько отдельных частей (модулей), которые отлаживаются отдельно и зачастую разными людьми; поэтому в завершении остается лишь собрать готовые модули в единый проект;

• при исправлении в одном модуле не надо снова транслировать (переводить в машинные коды) все остальные (это могут быть десятки тысяч строк);

• при компоновке во многих системах можно подключать модули, написанные на других

языках, например, на Ассемблере (в машинных кодах).

Трансляторы языка Си называются компиляторами: они переводят (транслируют) сразу

всю программу в машинный код, а не транслируют строчка за строчкой во время выполнения, как это делают интерпретаторы. Это позволяет значительно ускорить выполнение программы и не ставить интерпретатор на каждый компьютер, где программа будет выполняться.

Исходный файл программы на языке Си имеет расширение *.с или *.cpp (расширение

*.cpp говорит о том, что в программе могут быть использованы возможности языка Си++).

Это обычный текстовый файл, в который записывают текст программы в любом текстовом редакторе, например, в Блокноте.

Транслятор переводит исходный файл (вернее, записанную в нем программу) в машин-

ные коды и строит так называемый объектный файл с тем же именем и расширением *.o. Хотя в нем уже записан машинный код, объектный файл еще нельзя запускать на компьютере, потому что в нем не хватает стандартных функций (например, для ввода и вывода данных).

Компоновщик подключает стандартные функции, хранящиеся в библиотеках (они имеют

расширение *.a). В результате получается один файл с расширением *.exe, который и пред

ставляет собой готовую программу.

Простейшая программа на Си

Такая программа состоит всего из 8 символов. Вот она:

main()

{

}

Основная программа всегда называется именем main (будьте внимательны – Си различает

большие и маленькие буквы, а все стандартные операторы Си записываются маленькими буквами). Пустые скобки означают, что main не имеет аргументов. Фигурные скобки обозначают начало и конец основной программы – поскольку внутри них ничего нет, наша программа ничего не делает, она просто соответствует правилам языка Си, ее можно скомпилировать и получить exe-файл.

Вывод текста на экран

Составим теперь программу, которая делает что-нибудь полезное, например, выводит на

экран слово «Привет».

 

#include <stdio.h> подключение функций стандартного ввода и вывода,

описание которых находится в файле stdio.h

main() вызов функции

{

printf("Привет"); вывода на экран

}

Выводы:

• Чтобы использовать стандартные функции, необходимо сказать транслятору, что есть

функция с таким именем и перечислить тип ее аргументов – тогда он сможет определить,

верно ли мы ее используем. Это значит, что надо включить в программу описание этой

функции. Описания стандартных функций Си находятся в так называемых заголовочных

файлах с расширением *.h.

• Для подключения заголовочных файлов используется директива (команда) препроцессора #include, после которой в угловых скобках ставится имя файла. Внутри угловых скобок не должно быть пробелов. Для подключения еще каждого нового заголовочного файла надо использовать новую команду #include.

Препроцессор – это специальная программа, которая обрабатывает текст вашей программы раньше транслятора. Все команды препроцессора начиняются знаком #.

 

• Для вывода информации на экран используется функция printf. В простейшем случае

она принимает единственный аргумент – строку в кавычках, которую надо вывести на эк-

ран.

• Каждый оператор языка Си заканчивается точкой с запятой.

 

Как запустить программу?

Чтобы проверить эту программу, надо сначала «напустить» на нее транслятор, который

переведет ее в машинные коды, а затем – компоновщик, который подключит стандартные

функции и создаст исполняемый файл. Раньше все это делали, вводя команды в командной строке или с помощью так называемых пакетных файлов. На современном уровне все этапы создания, трансляции, компоновки, отладки и проверки программы объединены и выполняются внутри специальной программы-оболочки, которую называют интегрированная среда разработки (IDE integrated development environment). В нее входят:

• редактор текста

• транслятор

• компоновщик

• отладчик

В этой среде вам достаточно набрать текст программы и нажать на одну клавишу, чтобы она выполнилась (если нет ошибок).

В оболочке, например, Dev-C++ для запуска программы надо нажать клавишу F9. Если в программе есть ошибки, вы увидите в нижней части экрана оболочки сообщения об этих ошибках (к сожалению, на английском языке). Если щелкнуть по одной из этих строчек, в тексте программы выделяется строка, в которой транслятору что-то не понравилось.

При поиске ошибок надо помнить, что

• часто ошибка сделана не в выделенной строке, а в предыдущей – проверяйте и ее тоже;

• часто одна ошибка вызывает еще несколько, и появляются так называемые наведенные

ошибки.

Остановим мгновение

Если запускать рассмотренную выше программу, то обнаружится, что программа сразу

заканчивает работу и возвращается обратно в оболочку, не дав нам посмотреть результат ее работы на экране. Бороться с этим можно так – давайте скажем компьютеру, что в конце работы надо дождаться нажатия любой клавиши.

 

#include <stdio.h>

#include <conio.h> подключение заголовочного файла conio.h

 

main()

{

printf("Привет"); // вывод на экран

getch(); /*ждать нажатия клавиши*/

}

 

Выводы:

• Задержка до нажатия любой клавиши выполняется функцией getch().

• Описание этой функции находится в заголовочном файле conio.h.

Идентификаторы языка Си

Идентификаторы или имена служат для обозначения различных объектов программ: переменных (ячеек памяти), адресов, функций, файлов и т.д., иначе говоря - данных и действий над данными.

Имена должны начинаться с букв латинского алфавита или знака подчеркивания, далее допускается использовать и арабские цифры:

имя = ( буква | "_" ) { буква | цифра | "_" }

 

буква = |"A"|"B"|...|"Y"|"Z"|"a"|"b"|...|"y"|"z"

цифра = "0"|"1"|...|"9"

 

При этом прописные и строчные буквы считаются разными.

Длина имени в ANSI стандарте языка Си не ограничена. В Турбо Си имя не может быть длиннее 32 символов. Например: a, a1, _a, a_b.

Выбор имен должен производиться так, чтобы имя как можно точнее соответствовало смыслу объекта или действия, которое оно обозначает. Например: speed_of_body, SpeedOfBody, BodySpeed.

Экономия на длине имен - плохой стиль программирования.

Понятие о типах данных.

Тип данных определяет структуру объекта данных, множество его разрешенных значений и множество операций, которые можно над ним выполнять. Объекты различных типов требуют различного количества памяти для их хранения и различных команд процессора для выполнения действий над ними.

Символьные строки

Последовательность символов, заключенная в двойные кавычки, представляет собой символьную строку. Двойные кавычки в строку не входят. Например, "Это строка символов". Первая кавычка указывает на начало строки, последняя на ее окончание.

Строка символов хранится в памяти ЭВМ как массив символов.

Массив символов представляет собой последовательность символов, расположенных в непрерывной области памяти и объединенных общим именем:

 

Э т о   С т р о к а   с и м в о л о в \0

 

В конце строки символов компилятор ставит ноль-символ, т.е. символ, код которого равен 0. Он служит признаком конца строки.

Значение символьной строки - это адрес ее первого символа.

При трансляции программы компилятор разместит все символьные строки в памяти, а в программу вместо них подставит соответствующие адреса (т.е. значения символьных строк!).

Символьная строка является константой, т.е. ее невозможно изменить в процессе выполнения программы. На практике часто необходимо выполнять различные действия над символьными строками: например запросить ввод имени пользователя, которое затем используется в выводной информации. Подобные операции возможны, если описать переменную как массив символов.

 

описание_массива_символов =

"char " имя "["размер"]" { "," имя "["размер"]" } ";"

где размер - максимально возможное количество символов плюс 1 для размещения нуль символа.

Пример:

char name[50], fio[81];

 

Переменная name способна хранить строку из 49 символов, fio из 80. Значениями переменной name и fio являются адреса областей памяти, выделенных для хранения соответствующих строк.

 

Понятие функции

Под функцией понимают часть программы, которая реализует вполне законченный алгоритм, и может быть вызвана (то есть, запущена) из любого места программы. После окончания работы функции программы продолжается с места вызова функции.

Язык Си имеет мощные средства создания собственных функций пользователя. Однако на первых порах мы будем использовать стандартные готовые функции, предоставляемые нам библиотекой языка Си. Для вызова функции необходимо записать следующую конструкцию языка:

 

вызов_функции =

имя_ функции "(" [ аргумент { "," аргумент } ] ")"

 

Пример:

printf( "Это простое число %d", num );

 

Здесь имя функции "printf", функция имеет два аргумента, первый - строка символов, второй - переменная num.

Аргументы функции - это данные, которые передаются функции для обработки. Функция может не только получать аргументы, но и возвращать вычисленные значения:

A = sin( x );

Если функция возвращает значение, то ее вызов можно использовать в различных операциях:

A = sin(x) * cos(y);

n = printf( "%d", k ) + 5;

Функции sin и cos возвращают вычисленные значения синуса и косинуса, а функция printf возвращает количество выведенных на экран байт.

Основная функция, описанная как void main ( void ), не принимает аргументов и не возвращает значения (void - пусто).

Стандартная функция printf

Функция предназначена для вывода информации на стандартное устройство вывода (stdout), которым обычно является экран дисплея.

"printf" "(" формат { "," аргумент } ")"

Формат - это адрес строки символов, которая выводится в стандартное устройство вывода.

В строке символов могут присутствовать спецификации преобразования данных, каждой из которой должен соответствовать аргумент. Если имеются спецификации преобразования, то вместо них выводятся значения соответствующих аргументов. Для аргументов различных типов необходимо использовать соответствующие спецификации преобразования:

 

%d - для вывода целых чисел;

%c - для вывода образа символа, соответствующий аргумент должен содержать код символа;

%f - для вывода вещественного числа в виде целой и дробной части;

%e - для вывода вещественного числа в виде мантиссы и порядка;

%g - для вывода вещественного числа в виде %f или %e в зависимости от значения числа;

%u - для вывода беззнакового целого числа в десятичной системе счисления;

%o - для вывода беззнакового целого числа в восмеричной системе счисления;

%x - для вывода беззнакового целого числа в шестнадцатеричной системе счисления;

%s - для вывода на экран символьной строки, соответствующий аргумент должен быть адресом строки (т.е. именем символьного массива или строковой константой).

Для дополнительного управления преобразованием данных используются модификаторы преобразования. Они записываются между символом % и спецификацией преобразования.

 

модификатор = ["-"] {цифра1} [ "." {цифра2} ][l]

 

Примеры спецификаций преобразований с модификаторами:

 

%-20.6lf , %6d, %8.4f

 

Если присутствует "минус", то данные выравниваются по левой колонке поля, отведенного для вывода числа. Ширина этого поля определяется числом, составленным из цифр поля <цифра1>. Для вещественных чисел можно дополнительно задавать число знаков после запятой с помощью числа, составленного из цифр <цифра2>. Буква l в конце модификатора обозначает преобразование для длинных типов данных, т.е. long, unsigned long и double.

Функция printf возвращает число успешно выведенных байт информации.

Пример:

double a=-78.98;

int c=24;

printf("a=%8.4lf,c=%6d",a,c);

 

На экране:

a=-78.9800,с= 24

Стандартная функция scanf

Функция предназначена для ввода информации со стандартного устройства ввода (stdin), которым обычно является клавиатура.

 

"scanf" "(" формат { "," аргумент } ")"

Пример:

scanf( "%d", &n );

 

Перед именем аргумента функции подставляется знак &, который делает переменную n доступной для изменения. Строго говоря, операция & означает получение адреса объекта данных, т.е. мы сообщаем функции scanf информацию о том, где находится ячейка, в которую необходимо занести данные. При использовании функции scanf совместно с данными типа int, long, float, double, перед именем переменной всегда должен стоять знак &. При использовании функции для ввода символьной строки знак & не нужен, т.к. имя массива символов и так означает адрес.

Например:

 

char name[41];

scanf( "%s", name );

 

Функцию scanf рекомендуется использовать без лишних символов в формате, иначе может возникнуть непредсказуемая ситуация.

В формате должны быть только спецификации преобразования без всяких пробелов и других символов. Это связано с тем, что возможности функции scanf на самом деле значительно шире, чем описано в этом параграфе.

Функция scanf возвращает число успешно прочитанных элементов данных. Это свойство можно использовать для проверки правильности ввода.

Функцию scanf нужно использовать совместно с printf для вывода подсказки.

Например:

printf( "Введите ваше имя ");

scanf("%s", name );

Операции и выражения

Под операцией понимают некоторое действие, которое может быть выполнено над одним или несколькими операндами для получения результата. Операции и операнды могут объединяться в выражение. Каждое выражение вычисляется с учетом особенностей составляющих его операций и их приоритетов. В результате вычисляется значение выражения.

Существует большое количество операций различных видов: арифметические, логические, битовые и т.д. Наиболее просты для понимания арифметические операции. Каждая операция характеризуется выполняемыми действиями и результатом операции.

Операция присваивания

Операция присваивания выполняет действия по занесению результатов выражения, стоящего справа от знака присваивания = в область памяти, определяемую выражением, стоящим слева от знака присваивания. Чаще всего слева от знака присваивания стоит простая переменная. При выполнении присваивания происходит преобразование типа результата правого выражения к типу левого операнда.

Результат операции присваивания - значение присвоенной величины.

Поскольку присваивание является операцией, а не оператором, то в одном выражении допускается несколько присваиваний. В этом случае они выполняются справа налево

Например:

ab = ( c = d+5 ) * 6

Присваивание имеет самый низкий приоритет из всех операций.

Оператор-выражение

Выражение, оканчивающееся точкой с запятой, является оператором, т.е. наименьшей элементарной частью программы.

 

оператор = выражение ";"

 

Пример:

ab = ( c = d + 5 ) * 6; /* это оператор */

 

В дальнейшем будем строго придерживаться этой терминологии, т.е. выражением будем называть совокупность операндов, связанных операциями, а оператором - выражение заканчивающейся точкой с запятой.

Битовые операции

Любые данные, записанные в память ЭВМ, как известно, представляют собой последовательность бит, т.е. последовательность нулей и единиц. Например, любое число типа int будет занимать 2 байта в памяти, т.е 16 бит. Его можно рассматривать двояко: либо как целое число ( так и делается при выполнении операций *,/, +, - , % ), либо как последовательность бит, что возможно при использовании битовых операций.

Битовые операции выполняются независимо над каждым битом данных. Если операция двуместная, то она выполняется над соответствующими битами операндов.

В Си имеются следующие битовые операции:

 

~ битовое отрицание (одноместная),

& побитовое "и" (двуместная),

^ побитовое "исключающие или" (двуместная),

| побитовое "или" (двуместная).

 

Результат этих операций определяет таблица значений для всевозможных комбинаций бит двух операндов.

Результаты битовых операций

op1 op2 ~op1 op1 & op2 op1 ^ op2 op1 | op2

 

Рассмотрим несколько примеров.

Первый пример показывает, как с помощью операции | можно установить в единицу выбранные биты операнда:

 

/* a = 00001001 = 9 */

char a, b; /* 00011010 = 26 */

a = 9; /* -------- */

b = a | 26 /* b = 31 */ /* b = 00011011 = 31 */

 

Следующий пример показывает, как с помощью операции & можно обнулить старшую часть байта:

 

char a, b; /* a = 00101101 = 45 */

a = 45; /* 00001111 */

b = a & 0x0F; /* -------- */

/* b = 00001101 = 13 */

 

К битовым операциям относятся операции сдвига << и >> :

 

a << b сдвиг битов переменной a влево на b позиций,

a >> b сдвиг битов переменной a вправо на b позиций.

 

Например:

 

char a, b;

a = 26; /* a = 00011010 = 26 */

b = a << 2; /* b = 01101000 = 104 */

 

Сдвиг влево равносилен умножению на 2 в соответствующей степени. Сдвиг вправо - делению на 2 в соответствующей степени.

Все битовые операции выполняются слева направо. В следующей строке приведены битовые операции в порядке уменьшения их приоритета.

 

~, << >>, &, ^, |

 

Для двуместных битовых операций определены дополнительные операции присваивания:

 

a <<= b; эквивалентно a = a << b,

a >>= b; эквивалентно a = a >> b,

a &= b; эквивалентно a = a & b,

a ^= b; эквивалентно a = a ^ b,

a |= b; эквивалентно a = a | b.

Операции отношения

Представляют собой двуместные операции, предназначенные для сравнения операндов. В языке Си имеются шесть операций отношения:

 

> больше,

< меньше,

>= больше или равно,

<= меньше или равно,

== равно,

!= не равно.

 

Действие операций отношения заключается в сравнении первого и второго операнда. Если операнды не удовлетворяют условию отношения, то результат операции равен нулю, т.е. условие ложно. Если операнды удовлетворяют условию отношения, то результат отношения не равен нулю, т.е. условие истинно.

Например:

 

int a,b;

a = 5;

b = ( a + 5 <= 4 ); /* b = 0 */

 

Из сказанного выше следует, что в языке Cи отсутствует специальный логический тип данных. Его заменяет целый тип, причем логическому понятию "ложно" соответствует значение 0, а логическому понятию "истина" - любое отличное от 0 целое число.

Операции отношения выполняются слева направо. При нечетком понимании их действия возможно получение, вообще говоря, неверного результата. Например, с точки зрения синтаксиса языка Си выражение a<x<b записано совершенно правильно, но действия, выполняемые в соответствии с ним будут отличаться от принятых в математике: сначала будет вычислено выражение a<x, которое даст результат 0 или 1, а затем этот результат будет сравниваться с b.

Чтобы это выражение соответствовало математическому смыслу, его нужно разбить на две части a < x и x < b и связать его логической операцией && ("и"), т.е. (a < x) && (x < b). Такая запись читается так : если a меньше x и x меньше b, то результат - истина.

Логические операции

Логические операции служат для построения сложных условий, подобных приведенному в предыдущем параграфе. В языке Си определены следующие логические операции:

 

! логическое отрицание (одноместная),

&& логическое "и" (двуместная),

|| логическое "или" (двуместная).

 

В отличие от битовых операций, логические операции выполняются не над битами, а над значениями операндов. Результаты логических операций определяются следующей таблицей:

 

Приоритеты операций

Приоритеты и направление рассмотренных выше операций сведены в следующую таблицу. Операции одинакового приоритета объединены в группы, чем выше положение группы в таблице, тем выше приоритет операций группы.

 

Таблица приоритетов рассмотренных выше операций

Операции одного приоритета Направление выполнения операции.
! ~ ++ -- (тип) sizeof
* / %
+ -
<< >>
< <= > >=
== !=
&
^
|
&&
||
= *= /= %= += -= <<= >>= &= ^= |=

 

Оператор цикла while

Оператор цикла while предназначен для реализации циклических алгоритмов и имеет следующую форму записи

 

"while" "(" выражение ")" оператор

 

Пример :

while( a < 18 ) a = a+2;

 

При выполнении оператора цикла while вначале вычисляется выражение. Если оно не равно 0, то выполняется оператор. Далее снова вычисляется выражение и если оно не равно 0, то снова выполняется оператор. Такие циклические действия продолжаются до тех пор, пока выражение отлично от 0. Отсюда и название цикла while ( пока ). Как только выражение станет равным 0 цикл прекращает выполнятся и управление передается на следующий за циклом оператор.

Циклически выполняемый оператор обычно называют телом цикла. Если в теле цикла необходимо разместить не один, а несколько операторов, то в этом случае используют составной оператор.

Все операторы тела цикла должны быть записаны с отступом, обычно в три пробела.

Рассмотрим пример программы, которая выводит на экран таблицу функций sin(x) и cos(x):

 

#include <math.h>

#include <stdio.h>

 

void main( void )

{

double x = 0;

while( x < 3.0 )

{

printf( "%6.3lf %9.6lf %9.6lf\n",x, sin(x), cos(x) );

x += 0.2;

}

}

 

Если после while( x < 3.0 ) ошибочно поставить точку с запятой, то никаких сообщений об ошибках выдано не будет, но цикл станет бесконечным. Действительно, в этом случае тело цикла будет пустым оператором ";", переменная x не будет меняться, следовательно, результат выражения x < 3.0 всегда будет отличен от нуля.

В теле правильно организованного цикла обязательно должны содержатся операции, влияющие на выражение в заголовке цикла так, чтобы цикл рано или поздно завершился.

Оператор прерывания цикла

Предыдущая программа имеет существенный недостаток: перебираются все значения синуса, хотя цикл можно остановить, когда появится первое отрицательное значение. Этот недостаток можно исправить, как показано в следующем фрагменте:

 

x = xn;

minus = 0;

while( x < xk && !minus )

{

...

}

 

В языке Си есть специальный оператор для прерывания цикла. Это оператор "break;". Выполнение его в программе немедленно прерывает цикл, в котором он находится и управление передается на следующий за циклом оператор. Используя оператор break, цикл предыдущей программы можно переписать в виде:

 

x = xn;

minus = 0;

while( x < xn )

{

if( sin(x) < 0 ) { minus = 1; break; }

x += h;

}

 

Оператор продолжения цикла

Оператор "continue;" вызывает переход к следующей итерации цикла, т.е. к очередной проверке условия. Естественно, все операторы тела цикла, находящиеся между continue и концом тела цикла пропускаются:

 

while( ... )

{

...

if(...) continue;

... /* операторы пропускаются */

}

 

Операторы break и continue позволяют избавиться от необходимости применения оператора goto, поэтому последний в этом методическом пособии не рассматривается.

Пример организации простейшего меню

Современный стиль программирования предписывает использовать в программах различного рода меню, которые предоставляют пользователю возможность выбора одного из предложенных действий. Следующая программа вычисляет sin(x), cos(x), tan(x) в зависимости от выбора пользователя:

 

#include <math.h>

#include <stdio.h>

 

/* Организация простейшего меню */

void main ( void )

{

int loop; /* Флаг, который сигнализирует о конце работы */

int choice; /* Текущий выбор пункта меню */

double fun, x; /* Значения функции и аргумента */

printf( "\nВведите аргумент x=" );

scanf( "%lf", &x );

loop=1;

while ( loop )

{

printf ( "\n Введите номер функции:\n" );

printf ( "1. sin(x)\n2. cos(x)\n" );

printf ( "3. tan(x)\n4. Конец работы\n" );

scanf ( "%d", &choice );

if (choice==1) fun=sin(x);

else if (choice==2) fun=cos(x);

else if (choice==3) fun=tan(x);

else if (choice==4) { loop=0; continue; }

else { printf( "Неверный выбор\n" ); continue; }

printf( "Значение функции %lf\n", fun );

}

}

 

Данная программа выводит на экран дисплея список возможных действий. Пользователь должен выбрать нужное, введя его номер.

Для управления выходом из цикла и организации конца работы программы используется флаг loop.

Оператор цикла do-while.

Оператор цикла do-while предназначен для реализации циклических алгоритмов и имеет следующую форму записи

 

 

цикл_do-while =

"do" оператор "while" "("выражение")" ";"

 

Оператор выполняется циклически до тех пор, пока выражение отлично от нуля. В отличие от оператора while, тело оператора do-while выполняется хотя бы один раз до первого вычисления условия.

Работу оператора do-while проиллюстрируем на примере программы, которая определяет корень уравнения x-cos(sin(x))=0 методом итераций, который заключается в циклическом вычислении очередного приближения x_new по предыдущему приближению x_old, согласно выражению x_new=cos(sin(x_old)), вытекающему из исходного уравнения. Процесс итерации заканчивается тогда, когда x_new станет равен x_old. Программа, реализующая этот алгоритм, приведена ниже.

 

#include <stdio.h>

#include <math.h>

 

/* Решение уравнения x-cos(sin(x))=0 */

void main (void)

{

double x_new=0.9, x_old, eps=0.0001;

do

{

x_old = x_new;

x_new = cos(sin(x_old));

} while ( fabs( x_new - x_old ) > eps );

printf ( "x=%lf", x_new );

}

 

Сравнение двух вещественных чисел осуществляется с использованием точности eps. Это необходимо потому, что из-за погрешностей округления прямая проверка на равенство двух вещественных чисел скорее всего даст в результате 0 (ложь).

Пример организации светового меню

Меню современных программ, как правило, представляет собой набор строк по которому перемещается светлый прямоугольник - световое окно. Для написания программ с подобным меню необходимо уметь выводить в нужное место экрана информацию разными цветами.

Экран IBM PC имеет 25 строк и 80 позиций. Нумерация строк и позиций начинается с 1. Первая строка находится вверху, первая позиция слева. Все необходимые функции работы с экраном IBM PC имеются в библиотеке компилятора, их прототипы находятся в файле conio.h. Рассмотрим некоторые из этих функций:

 

void clrscr( void ); - осуществляет стирание экрана;

void gotoxy( int x, int y ); - перемещает курсор в позицию x строки y;

void cprintf( char *format, ... ); - выполняет то же самое, что и printf, но выводит информацию, используя установленный цвет фона и цвет символа;

void textcolor( int color ); - установка цвета символа с кодом color;







Последнее изменение этой страницы: 2016-04-08; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.231.220.225 (0.073 с.)