рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Циклы и другие управляющие средства.

Циклы и другие управляющие средства. - раздел Образование, Общая характеристика языка Си в сравнении с другими процедурными языками Цикл С Предусловием   Существует Три Вида Циклов: Whil...

Цикл с предусловием

 

Существует три вида циклов: while, for и do. Цикл while имеет следующую форму:

while (e) s;

 

Оператор s выполняется до тех пор, пока значение выражения e равно "истина". Значение e вычисляется перед каждым выполнением оператора s.

 

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

/* угадывание числа */

# include <stdio.h>

main( )

{

int i = 1;

char res;

printf("Задумайте целое число от 1 до 100.

Компьютер попытается угадать его. n");

printf ("Отвечайте y если догадка правильна и");

printf("n n, если программа ошибается n");

printf("И так, ваше число %d?n",i);

/*получение ответа */

while((res = getchar( )) !='y')

if(res !='n')

/* пропуск символа новая строка */

printf("Ну тогда оно равно %dn" ,++i);

printf("Число угадано!n");

}

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

 

 

В наших примерах до сих пор использовались условные выражения, но вообще говоря, это могут быть выражения произвольного типа. В качестве оператора можно использовать простой оператор с символом "точка с запятой" в конце или составной оператор, заключенный в фигурные скобки. Если выражение истинно (или в общем случае равно единице), то оператор, входящий в цикл while, выполняется один раз, а затем выражение проверяется снова. Эта последовательность действий, состоящая из проверки и выполнения оператора, периодически повторяется до тех пор, пока выражение не станет ложным (или в общем случае равным нулю). Каждый такой шаг называется итерация. Данная структура аналогична структуре оператора if. Основное отличие заключается в том, что в операторе if проверка условия и (возможное) выполнение оператора осуществляется только один раз, а в цикле while эти действия производятся, вообще говоря, неоднократно.

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

 

 

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

 

Цикл со счетчиком

 

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

for(e1; e2; e3) s

 

является удобной сокращенной записью для цикла while вида

e1;

while(e2) {

s;

e3;

}

 

Выражение e1 служит для задания начальных условий выполнения цикла, выражение e2 обеспечивает проверку условия выхода из цикла, а выражение e3 модифицирует условия, заданные выражением e1. Любое из выражений e1, e2, e3 может быть опущено. Если опущено e2, то по умолчанию вместо него подставляется значение TRUE. Например, цикл for

for(;e2;) s;

 

с опущенными e1,e3 эквивалентен циклу

while(e2) s;

 

Цикл

for(;;) s;

 

со всеми опущенными выражениями эквивалентен циклу

while(TRUE) s;

 

т.е. эквивалентен бесконечному циклу. Такой цикл может быть прерван только явным выходом из него с помощью операторов break, goto, return, содержащихся в теле цикла s.

 

Несмотря на внешнее сходство с итеративными циклами for языков Паскаль и Ада или итеративными циклами do языков Фортран или ПЛ/1, цикл for языка Си не является их семантической копией. Цикл for языка Си обладает большей общностью, чем циклы for и do других языков. В отличии от этих циклов, в общем случае число итераций в цикле for языка Си не может быть определено до выполнения этого цикла.

 

Цикл for и его альтернатива цикл while семантически почти эквивалентны, но, как указывается в работе (Ritchie, D.M. 1980. The Programming Language - Reference Manual/. AT&T Bell Laboratories, Murray Hill, N.J. 07974), не идентичны. Например, рассмотрим случай, когда оператор s является оператором continue или составным оператором, содержащим оператор continue. Действие оператора continue состоит в переходе к концу цикла, что имеет различные последствия для цикла for и его эквивалента в форме цикла while. В случае с циклом for выражение e3 выполняется до вычисления значения выражения e2, в то время как в эквивалентном цикле while выражение e3 пропускается.

 

Цикл с постусловием

 

Цикл

do оператор while(e);

 

выполняется до тех пор, пока выражение e имеет значение "истина". В отличие от цикла while , в котором проверка условия окончания цикла делается до выполнения тела цикла, в цикле do такая проверка имеет место после выполнения тела цикла. Следовательно, тело цикла do будет выполнено хотя бы один раз, даже если выражение e имеет значение "ложь" c самого начала. Цикл do аналогичен циклу repeat в языке Паскаль, отличаясь от него лишь тем, что цикл repeat выполняется до тех пор, пока некоторое условие выходa из цикла не становится истинным, а цикл do выполняется все время, пока некоторое условие остается истинным!

!

Цикл do while - это конструкция с условием на выходе.

 

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

do {

выдвиньте предположение

получите ответ вида y,n

} while(ответ не совпадает с y);

 

!

Вы должны избегать использование цикла do while, структура которого аналогична представленной ниже операции: cпросите пользователя, хочет ли он продолжать

do

оператор

while (ответ будет да)

 

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

 

 

Пример:

do

scanf("%d", &number);

while(number!=50);

 

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

Аргументы функции

 

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

 

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

print_num(i,j)

int i,j;

{

printf("значение i=%d. Значение j=%d.", i,j);

}

 

Обращение в программе к данной функции будет таковым:

print_num(6,19);

 

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

При компиляции функции выделяются участки памяти для формальных параметров. Формальные параметры оказываются внутренними объектами функции. При этом для параметров типа float формируются объекты типа double. Для параметров типа char, short int создаются объекты типа int. Если параметром является массив, то формируется указатель на начало этого массива и он служит представлением массива-параметра в теле функции (об указателе массивов описано в 12 лекции данного курса).

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

Значения выражений-фактических параметров заносятся в участки памяти, выделенные для формальных параметров функции. При этом float преобразуется в double, a char, short int - в тип int.

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

Никакого влияния на фактические параметры функция не оказывает.

Возвращение значений

 

Напишем функцию, вычисляющую абсолютную величину числа. Абсолютная величина числа - это его значение, если отбросить знак. Например, абсолютная величина 125 - это 125, а абсолютная величина числа (-125) - это тоже 125. Назовем эту функцию abs( ). Входом для этой функции будет любое число, для которого мы хотим найти абсолютную величину. Выходная величина возвращается при помощи ключевого слова языка Си - return. Поскольку функция abs( ) должна быть вызвана другой функцией, мы создадим простую функцию main( ), основной целью которой будет проверка, работает ли функция abs( ). Программа, спроектированная для того, чтобы проверить работу функции именно таким образом, называется драйвером. Драйвер подвергает функцию последовательным проверкам. Если результаты оказываются удовлетворительными, то ее можно поместить в программу, заслуживающую большего внимания. Термин драйвер обычно относиттся к программам, управляющим работой устройств:

/*драйвер*/

main( )

{

int a=100, b=0, c=-122;

int d,e,f;

d=abs(a); e=abs(b); f=abs(c);

printf("%d, %d, %dn",d,e,f);

}

abs(x) /* функция, вычисляющая величину числа */

int x;

{

int y;

y = (x < 0) ? -x : x;

/*возвращает значение y вызывающей программе*/

return(y);

}

 

Результат работы программы выглядит так:

100 0 122

 

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

 

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

d=abs(a);

 

по другому можно выразить так:

abs(a);

d=y;

 

Такой записью мы воспользоваться не можем! Вызывающая программа даже не подозревает о том, что переменная y существует.

 

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

/* Функция, вычисляющая абсолютную величину числа, вторая версия */

abs(x)

int x;

{

if(x < 0)

return(-x);

else

return(x);

}

 

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

/* третья версия функции abs( ) */

abs(x)

int (x);

{

if(x < 0) return(-x);

else return(x);

printf("Работа завершена!n");

}

 

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

 

Можно пользоваться оператором

return;

 

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

 

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

 

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

 

Каждая функция может вызвать саму себя. Действие, состоящее в том, что функция вызывает сама себя, называется рекурсией.

 

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

! Так как при каждом обращении к рекурсивной функции создается новый набор объектов автоматической памяти, локализованных в теле функции, то при использовании рекурсивных алгоритмов с глубокой вложенностью рекурсии может быстро произойти переполнение стека реализации рекурсий, поэтому надежнее использовать итерационные алгоритмы. Например, пусть нужно реализовать "салфетку Серпинского" (геометрический фрактал). Как она образуется? Рисуется треугольник и в нем средние линии. В образованных при углах исходного треугольника новых треугольниках опять рисуются средние линии и так далее до заданного порядка вложенности рекурсии. Полученная "салфетка Серпинского" допускает другое, не рекурсивное, построение с помощью моделирования методом Монте-Карло.

 

Локальные переменные

 

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

 

Нахождение адресов

 

В результате выполнения операции & определяется адрес ячейки памяти, которая соответствует переменной. Если age - имя переменной, то &age - ее адрес. Можно представить себе адрес как ячейку памяти, но можно рассматривать его и как метку, которая используется компилятором для идентификации переменной. Предположим, мы имеем оператор

age=105;

 

Пусть также адрес ячейки, где размещается переменная age - 15125. В результате выполнения оператора

printf("%d %dn", age, &age);

 

получим 105 15125.

Указатели, первое знакомство

 

Указатель - некоторое символическое представление адреса. В описанном примере &age означает указатель на переменную age. Фактический адрес - это число, а символическое представление адреса &age является константой типа указатель. Адрес ячейки, отводимой переменной age, в процессе выполнения программы не меняется. В языке Си имеются и переменные типа указатель. Точно так же как значением переменной типа char является символ, а значением переменной типа int -целое число, значением переменной типа указатель служит адрес некоторой величины. Если мы дадим указателю имя ptr, то сможем написать, например, такой оператор:

ptr = &age;

/* присваивает адрес age переменной ptr */

 

Мы говорим в этом случае, что ptr указывает на age. Различие между двумя формами записи, ptr и &age, заключается в том, что ptr - это переменная, в то в то время как &age - константа. В случае необходимости мы можем сделать так, чтобы переменная ptr указывала на какой-нибудь другой объект:

ptr = &name;

/*ptr указывает на name, а не на age*/

 

Теперь значением переменной ptr является адрес переменной name.

Операция косвенной адресации *

 

Предположим, мы знаем, что в переменной ptr содержится ссылка на переменную name. Тогда для доступа к значению этой переменной можно воспользоваться операцией косвенной адресации *:

val = *ptr;

/* определение значения, на которое указывает ptr */

 

Последние два оператора, взятые вместе, эквивалентны следующему:

val = name;

Описание указателей

 

Примеры описания указателей:

int *pi; /*указатель на переменную типа целого*/

char *pc; /*указатель на символьную переменную*/

float *pf, *pg;

/* указатель на переменные с плавающей точкой*/

 

Спецификация типа задает тип переменной, на которую ссылается указатель, а символ звездочка (*) определяет саму переменную как указатель. Описание вида int *pi говорит , что pi - это указатель и что *pi - величина типа int.

 

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

function1(x);

 

происходит передача значения переменной x. Если же мы используем форму обращения

function2(&x);

 

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

function1(num)

int num;

 

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

function2(ptr)

int *ptr;

 

– Конец работы –

Эта тема принадлежит разделу:

Общая характеристика языка Си в сравнении с другими процедурными языками

Операции языка Си... Любое выражение языка состоит из операндов переменных констант и др соединенных знаками операций Знак операции...

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

Что будем делать с полученным материалом:

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

Все темы данного раздела:

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

Основные типы данных, переменные и константы. Препроцессор языка Си.
  В алфавит языка программирования Си включаются латинские буквы (прописные и строчные), цифры и некоторые специальные знаки: скобки круглые “(“ и “)” , квадратные “[“ и “]” , фигурны

Ввод-вывод чисел, символов и строк на консоль. Переключение ввода-вывода, работа с файлами.
Под функциями ввода-вывода подразумеваются функции, которые выполняют транспортировку данных в программу и из нее. Мы уже использовали две такие функции: printf( ) и scanf( ). Теперь рассмотрим нес

Строковые константы, массивы символьных строк и их инициализация. Указатели и строки, ввод-вывод и обработка строк.
В языке C, в отличие от языка Pascal, отсутствует специальный строковый тип данных. Строка представляет собой последовательность (одномерный массив) из одного или более символов, последним из котор

Определение структурных переменных. Доступ к компонентам структуры.
Структура объединяет логически связанные данные разных типов. Структурный тип данных определяется следующим описанием:   struct имя_структуры {   Описа

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

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

Динамические структуры данных (стек, список, дерево, граф).
  Стек (англ. stack — стопка) — структура данных с методом доступа к элементам LIFO (англ. Last In — First Out, «последним пришел — первым вышел»). Чаще всего принцип работы стека сра

Графический интерфейс пользователя (GUI). Типы данных Win32.
Графи́ческий интерфе́йс по́льзователя (ГИП), графический пользовательский интерфейс (ГПИ) (англ. Graphical user interface, GUI; сленг. ГУИ или Гуй) — разновидность пользовательского

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

Однострочное и многострочное поле для ввода текста.
Можно создавать одну или несколько строк текста, каждая из которых является отдельным объектом. Строки можно по отдельности перемещать, форматировать или редактировать иным образом.  

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

Графический интерфейс устройства (CDI). Контекст устройства. Регионы и отсечение.
Графический интерфейс пользователя (Graphical User Interface, GUI) это система средств для взаимодействия пользователя с устройством, основанная на представлении всех доступных пользователю системн

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

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

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги