Вопрос 40. Реализация циклических алгоритмов с заранее известным количеством повторений. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Вопрос 40. Реализация циклических алгоритмов с заранее известным количеством повторений.



Оператор for

Оператор for это наиболее общий способ организации цикла. Он имеет следующий формат:

for (выражение_1; выражение_2; выражение_3) тело

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

Любое из выражений, а также все сразу, могут быть опущены, при этом разделяющие их символы; пропускать нельзя. Схема выполнения оператора for:

1. Вычисляется выражение_1.

2. Вычисляется выражение_2.

3. Если значения выражения_2 отлично от нуля (истина), выполняется тело цикла, вычисляется выражение_3 и осуществляется переход к пункту 2, если выражение_2 равно нулю (ложь), выполнение оператора for завершается и управление передается на оператор, следующий за оператором for. При отсутствии выражения_2 оно подразумевается истинным.

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

int main ()

{ int i,b;

for (i=1; i<10; i++) b=i*i;

return 0;

}

В этом примере вычисляются квадраты чисел от 1 до 9.

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

Пример:

for (;;)

{...

if (некоторое условие) break;

... }

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

for (i=0; t[i]>=0; i++);

В данном примере переменная цикла i примет значение номера первого по порядку отрицательного элемента массива t.

 

Вопрос 41. Структура функции в языке С++. Прототип, заголовок и вызов функции.

Основные понятия

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

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

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

С использованием функций в языке C связаны три понятия: определение (описание действий, выполняемых функцией), объявление (задание формы обращения к функции) и вызов.

В определении (описании) функции должны присутствовать:

· имя;

· типы, имена и количество ее формальных параметров;

· объявления переменных и операторы (тело функции).

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

int rus(unsigned char c) /* Определение функции, проверяющей, является ли заданный символ заглавной русской буквой */

{

if (c>='А' && c<='Я')

return 1;

else

return 0;

}

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

Объявление функции называется прототипом функции.

В прототипе функции (в C++ прототип обязателен) должны присутствовать:

- имя функции;

- типы и число формальных параметров;

- тип возвращаемого значения.

Формат прототипа тот же, что и у определения функции, но прототип не имеет:

- тела функции;

- заголовок оканчивается точкой с запятой.

Формальные параметры прототипа могут иметь имена, но они компилятору не нужны. Так, например, прототип рассмотренной выше функции может иметь вид:

int rus(unsigned char);или int rus(unsigned char с);

Если прототип не задан, то он по умолчанию строится по определению функции или по ее вызову. Однако может возникнуть неадекватность представления, поэтому рекомендуется всегда задавать прототип функции.

Определение функции

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

Формат определения:

<тип> имя (список формальных параметров)

{

тело функции

}

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

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

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

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

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

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

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

void fn(unsigned c,float b,int a,…); т. е. число аргументов функции fn³3.

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

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

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

Пример передачи в функцию параметров-значений b и c:

int fn1(int b,float c);

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

В качестве такого параметра можно использовать указатель на некоторую переменную:

int fn2(int* pb);

Используя операцию косвенной адресации в теле функции, можно изменить значение этой переменной: *pb=6.

Другой способ передачи в функцию адреса переменной – передача параметра по ссылке, при этом в вызванной функции создается псевдоним исходной переменной, форма обращения к такому параметру-ссылке такая же, как и к обычной переменной, а сам параметр передается с помощью адреса, например, int fn3(int &ab);при этом обращение к переменной ab в теле функцииfn3() такое же, как к обычной переменной типа int.

Тело функции – это составной оператор, содержащий объявления переменных (если необходимо), и операторы.

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

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

В старом стиле типы параметров объявляются перед телом функции:

float root(x,E)

float x,E;

{

тело функции

}

В новом стиле типы параметров указываются в списке параметров:

float root(float x, float E)

{

тело функции

}

Прототип функции

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

Формат прототипа:

<класс памяти> <тип>имя (список формальных параметров);

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

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

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

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

Вызов функции

Для обращения к функции используется имя функции.

Формат вызова:

Имя_функции (список),

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

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

Выполнение вызова функции происходит следующим образом.

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

Пример программы

Найти корни уравнения x = sin2 x / 4 + 0,27 методом итераций с точностью e.

Расчетная формула x 1 = sin2 x 0 / 4 + 0,27, где условие нахождения искомого корня | x 1x 0| < e – x 0 - начальное значение корня уравнения (обычно принимается равным нулю), x 1 - значение корня уравнения на следующей итерации, e - заданная точность вычисления корня (например, 0.001).

В программе используется старый стиль определения функции:

#include <stdio.h>

#include <math.h> /*Подключение стандартных библиотек*/

#define EPS 0.001 /*Задание точности вычисления корня*/

float root(x, E) /*Заголовок функции с именем root*/

float x,E; /*Описание аргументов функции*/

{ /*Тело функции*/

float x1;

for (x1=pow(sin(x),2)*.25+.27;

fabs (x1−x)>E;

x=x1,

x1=pow(sin(x),2)*.25+.27);

return (x1);

} /*Завершение описания функции root*/

int main()

{

float x0;

printf ("\n Введите значение x0");

scanf ("%f",&x0);

printf ("\n Корень уравнения %f", root(x0,EPS));

//Вызов функции root()

return 0;

}

 

Функция состоит из заголовка (1) и тела (2). Заголовок функции – это ее интерфейсная (описательная) часть, которая не дает программного кода, а содержит описание входных и выходных параметров, необходимых при ее выполнении (вызове). Тело функции – это программный код (блок), ограниченный фигурными скобками. Тело функции при трансляции преобразуется во внутреннее (двоичное) представление и размещается в сегменте команд программы (см. 1.2). Существует также синтаксис, в котором присутствует только заголовок, ограниченный символом «;». В этом случае речь идет об объявлении функции – информировании транслятора о ее наличии и интерфейсе.

В заголовке находится имя функции (3), после которого в скобках – список формальных параметров, разделенных запятыми (4). Список может быть и пустым. Синтаксис формального параметра (5) – это синтаксис определения переменной (см. 1.3), что наводит на мысль, что формальные параметры – это особого рода переменные, которые используются для передачи параметров (значений) при вызове (выполнении) функции.

Внутри тела функции могут находиться определения обычных переменных (7), которые называются локальными (в терминологии Си - автоматическими). Тело каждой функции представляет собой отдельное изолированное пространство, в котором допустимо использование собственных переменных (9), составляющих неявное окружение – контекст функции. В него входят вышеуказанные формальные параметры и локальные переменные. Кроме того, контекст функции является короткоживущим: он создается при входе в функцию и разрушается при завершении ее выполнения.

Формальные параметры используются для передачи входных и выходных данных в функцию. Кроме них функция имеет еще одну неявную выходную переменную – результат функции. Результат функции - это временная переменная, которая возвращается функцией и может быть использована как операнд в той части выражения (13), где был произведен ее вызов (10).

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

 

int sum(... // Результат - целая переменная

char *FF(... // Результат - указатель на символ

 

Значение переменной - результатa устанавливается в операторе return (8), который производит это действие наряду с завершением выполнения функции и выходом из нее. Между ключевым словом return и ограничивающим символом ";" может стоять любое выражение, значение которого и становится результатом функции. Если вспомнить еще и о преобразованиях типов, то при таком «присваивании» результата таковое должно производиться от типа, соответствующего выражению к типу результата функции:

double FF()

{ int nn; // Эквивалент

return (nn+1); // FF = (double)(nn + 1)

 

Имеется специальный пустой тип результата - void, который обозначает, что функция не возвращает никакого результата и, соответственно, не может быть вызвана внутри выражения. Оператор return в такой функции также не содержит никакого выражения. При вызове этой функции ее результат не может быть использован.

void Nothing() { return; }

void main(){

Nothing(); // Просто вызов без использования результата

}

 

Определение функции представляет собой всего лишь статическую «заготовку» программы. Выполнение ее происходит тогда, когда в процессе вычисления выражения встречается вызов функции. Синтаксически вызовом функции называется упоминание имени этой функции в выражений (10), причем после имени функции в скобках следует список фактических параметров (12).

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

· между формальными и фактическими параметрами устанавливается «один-один» соответствие, которое действует только в течение текущего вызова функции (динамически);

· существуют различные способы установления соответствия, на настоящий момент реально распространенными в языках программирования являются способы передачи параметров по ссылке и по значению;

· фактические параметры имеются синтаксис выражения (см 1.4). Это значит, что в них не определяются, а используются переменные и их сочетания, определенные в текущем контексте (11). Например, если определение массива имеет вид int A[], и в таком виде оно будет присутствовать в списке формальных параметров, то при вызове функции фактическим параметром может быть имя массива C определенного аналогичным образом (т.е. переменная C, являющаяся массивом).

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

 

void main() {...}

void main(void) {...}

void main(int narg, char *argv[]) {...} // с интерфейсом командной строки

Прототип - это явное объявление функции, которое предшествует определению функции. Тип возвращаемого значения при объявлении функции должен соответствовать типу возвращаемого значения в определении функции.

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

Таким образом, прототип функции необходимо задавать в следующих случаях:

1. Функция возвращает значение типа, отличного от int.

2. Требуется проинициализировать некоторый указатель на функцию до того, как эта функция будет определена.

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

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

Вызов функции имеет следующий формат:

адресное-выражение ([список-выражений])

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

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

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

Выполнение вызова функции происходит следующим образом:

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

2. Происходит присваивание значений фактических параметров соответствующим формальным параметрам.

3. Управление передается на первый оператор функции.

4. Выполнение оператора return в теле функции возвращает управление и возможно, значение в вызывающую функцию. При отсутствии оператора return управление возвращается после выполнения последнего оператора тела функции, а возвращаемое значение не определено.

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

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

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

Для вызова функции достаточно написать ее имя со списком

передаваемых фактических аргументов.

Компилятор использует объявление заголовка функции

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

с формальными параметрами даже при отсутствии явного описания.

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

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

Назовем встроеными такие функции, которые включены в системную
биюлиотеку Тurbo-C и прототипы которых содержатся в include-файлах.

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

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

Функции, которые находятся в одном и том же файле трансляции, назовем вместе транслируемыми. Функции, которые находятся в разных файлах трансляции,

назовем раздельно транслируемыми.

 

 

Вопрос 42. Предварительное описание функции.

При внимательном рассмотрении каждой из предшествующих программ можно отметить, что определения функций всегда появляются в программном коде раньше, чем к ним выполняется обращение. Большинство современных Си-компиляторов требует, чтобы информация о типе возвращаемых значений и типах параметров функций была известна до вызова этих функций в программе. Расположение определения функции текстуально ранее первого ее использования обеспечивает Си-компилятор требуемой информацией. Однако, по мере усложнения программы размещение функций в исходном коде с соблюдением "правильного" порядка может оказаться невозможным. Для таких случаев языком Си предлагается использовать прототипы функций, описывающие возвращаемые значения и типы параметров функций. Например, рассмотрим программу, использующую функции i_cube и f_cube. До появления первого вызова этих функций в программу можно включать прототипы следующим образом:

int i_cube(int); // Возвращает int, параметр int

int f_cube(float); // Возвращает float, параметр float

Как можно видеть, прототип функции определяет тип возвращаемого значения и типы параметров функции.

 



Поделиться:


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

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