Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_по_программированию.doc
Скачиваний:
79
Добавлен:
02.04.2015
Размер:
4.77 Mб
Скачать

Подпрограмма с несколькими результатами

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

Постановка задачи

Вычислить значение функции:

если .

Формирование математической модели

Ввиду того, что общая математическая формулировка выполнена в постановке задачи, дополним её конкретными размерами массивов (n = 5, m = 6) и численными значениями элементов:

x1=1; x2=1,6; x3=1,8; x4=15; x5=23;

y1=0,7; y2=0,76; y3=0,99; y4=180; y5=67,7; y6=200.

Выбор метода решения

Анализ показывает, что решение задачи требует двукратного вычисления суммы ипроизведенияэлементов массива. В первом случае n элементов массива X, во втором – m элементов массива Y. Такое вычисление удобно выполнить в циклическом процессе, оформленном дополнительным алгоритмом. Так как результат вычислений в дополнительном алгоритме (подпрограмме) – две величины, то решение задачи требует использования дополнительной функции, возвращающей более одного результата.

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

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

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

Для рассматриваемой задачи в качестве входных формальных параметров выберем, например, имя массива Z и его размер k. Тогда в качестве выходных параметров можно использовать SZ (сумма Z) и PZ (произведение Z). Следовательно, в качестве формальных параметров выбраны Z, k, SZ, PZ.

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

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

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

Поэтому, задавшись именем подпрограммы sp, сформируем два обращения к ней: для расчёта суммы и произведения элементов массива X – sp(X(n), SX, PX) и для тех же вычислений с массивом Y – sp(Y(m), SY, PY). Первый параметр в каждом обращении является входным и определяет имя и размер передаваемого в подпрограмму массива. Остальные являются выходными, предназначенными для получения значений суммы и произведения из подпрограммы.

Составление алгоритма решения

Характерной особенностью основного алгоритма при работе с подпрограммой с несколькими возвращаемыми результатами является, как правило, организация каждого обращения к ней отдельным блоком «предопределённый процесс». Эта особенность учтена в схеме основного алгоритма (рис. 6.5). В дополнительном алгоритме локальная переменная i используется для организации цикла перебора текущих значений формального параметра Z.

Рис. 6.5. Схемы основного и дополнительного алгоритмов примера 6.3

Программирование задачи

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

Каждая из функций Си представляется одной из упрощенных структур

[тип] имя([тип b1,. . .,типbi,. . .,типbn,тип *d1,. . .,тип *dj,. . .,тип *dm])

{

тело

функции

[returnРВ;]

}

где имя – идентификатор (название) функции;

тип – описатель типа функции (результата);

bi– список входных формальных параметров с указанием типа каждого;

dj– список выходных формальных параметров – указателей, определяющих возвращаемые результаты, с указанием типа каждого и признака указателя при описании (*);

( ) – ограничители списка формальных параметров;

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

returnРВ; – оператор возврата (return) результата вычислений;

РВ – результат вычислений (выражение);

[ ] – признак необязательности содержимого;

{ } – ограничители тела функции.

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

Структура вызова функции:

имя ([a1, . . . ,ai, . . . ,an,c1, . . . ,cj, . . . ,cm])[;]

где имя – идентификатор функции;

a1,ai,an– список входных фактических параметров (аргументов), численные значения которых требуется передать в дополнительную функцию (подпрограмму);

c1,cj,cm– список адресов выходных фактических параметров (аргументов), численные значения которых требуется получить из дополнительной функции (подпрограммы);

( ) – ограничители аргументов;

[ ] – признак необязательности содержимого.

Прототип функции аналогичен ее заголовку и имеет структуру

[тип] имя([тип b1,. . .,типbi,. . .,типbn,тип *d1,. . .,тип *dj,. . .,тип *dm]);

где имя – идентификатор (название) функции;

тип – описатель типа функции (результата);

bi– список входных формальных параметров с указанием типа каждого;

dj– список выходных формальных параметров – указателей, определяющих возвращаемые результаты, с указанием типа каждого и признака указателя при описании (*);

( ) – ограничители списка формальных параметров;

[ ] – признак необязательности содержимого;

; – признак оператора.

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

  1. количества и типы входных и выходных формальных параметров должны соответствовать аналогичным фактическим, т.е. каждый aiимеет свойbi, а каждыйcj– свойdj, при этом тип и взаимное расположение их в списке определяется программистом;

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

  3. в качестве выходных формальных параметров используются указатели;

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

  5. в качестве выходных фактических параметров используются адреса переменных и адреса массивов;

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

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

  8. при использовании структуры с оператором return, вызов функции может служить операндом выражения в вызываемой функции;

  9. если логика задачи не позволяет выделить основной результат, то использование оператора returnнеобязательно. В этом случае в заголовке дополнительной функции в качестве описателя типа необходимо указывать ключевое словоvoid;

  10. вызов функции, оформленный простым оператором, заканчивается символом «;», если является операндом выражения – признак оператора не указывается;

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

  12. в списке формальных параметров прототипа допускается опускать их имена, оставляя для входных их типы, а для выходных типы с последующими символами «*».

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

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

Рис. 6.6. Передача параметра по значению

Рис. 6.7. Передача параметра по адресу

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

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

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

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

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

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

. . .

main( )

{ int j = 1, i = 1;

. . .

printf("j=%d i=%d", j, i );

func(j, &i);

printf("j=%d i=%d", j, i );

. . .

}

void func(int j, int *pi)

{ . . .

*pi= 0.5 *j+ 1.;

j= 2;

. . .

}

Так фрагмент программы в качестве фактических параметров использует входной – переменнуюjи выходной – адрес переменнойi. Этим параметрам в вызываемой подпрограмме соответствуют одноименный входной формальный параметр – переменнаяjи выходной – указательpi. В теле подпрограммы численные значения обрабатываемых переменныхiиjизменены (i– с помощью разадресации указателяpi,j– напрямую). Выполнение программы приведет к выводу исходных значенийjиi(j=1i=1), а затем их же значений после обращения к дополнительной функции (j=1i=1.5). Значение входного фактического параметраjне изменилось, а выходного (i) – приняло новое значение. Это произошло потому, что обработка параметраjвелась по схеме 1 (разные ячейки), а обработка параметраi– по схеме 2.

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

Перед составлением программы решения примера 6.3 выполним идентификацию переменных (табл. 6.3).

Таблица 6.3

Обозначение в алгоритме

1

n

m

i

j

xi

yj

Обозначение в программе

2

n

m

i

j

x[ i ]

y[ j ]

Окончание табл. 6.3

1

SX

PX

SY

PY

d

k

z i

SZ

PZ

2

sx

px

sy

py

d

k

z[ i ]

sz

pz

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

sp(x, n, &sx, &px); и sp(y, m, &sy, &py);

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

voidsp(float*z,intk,float*sz, *pz)

т. е. входные параметры передаются по значению, а выходные через адреса.

Программа решения примера 6.3

#include<stdio.h> /*stdio.h- файл с прототипами функций ввода-вывода */

#include<conio.h> /*conio.h- файл с прототипом функцииgetch( ),clrscr( ) */

#include<math.h> /*math.h- файл с прототипами математических функций*/

voidsp(float*z,intk,float*sz,float*pz); /*прототип функцииsp*/

main( ) /* заголовок головной функции */

{

floatd,sx,px,sy,py,x[30],y[50]; /* описатели локальных */

inti,j,n,m; /* переменных и массивов */

clrscr( );

printf("\nВведите значенияn,m: ");

scanf("%d%d", &n, &m);

fprintf(stdout,"\nn=%dm=%d\n",n,m);

for( i = 0 ; i < n ; i++ ) /* заголовок цикла ввода x[ i ] */

{

printf(" Введите значениеx(%d): ",i+1);

scanf("%f", &x[i]);

}

for( i = 0 ; i < n ; i++ ) /* заголовок цикла вывода x[ i ] */

fprintf(stdout," %.2f",x[i]);

printf("\n"); /* перевод курсора в начало следующей строки */

for(j= 0 ;j<m;j++ ) /* заголовок цикла вводаy[j] */

{

printf(" Введите значение y(%d): ",j+1);

scanf("%f", &y[j]);

}

for(j= 0 ;j<m;j++ ) /* заголовок цикла выводаy[j] */

fprintf(stdout," %f",y[j]);

sp(x, n, &sx, &px); /* вызовы дополнительной функции */

sp(y, m, &sy, &py); /* оформленные простыми операторами */

d= (sx+sqrt(fabs(py) ) ) / (log(px) -sy); /* вычислениеd*/

fprintf(stdout,"\nsx=%.2fpx=%.2fsy=%.2fpy=%.2fd=%.2f\n",

sx ,px, sy, py, d);

getch( );

}

/* определение функции sp */

void sp(float *z, int k, float *sz, float *pz)

{

int i; /* описание локальной переменной i*/

*sz= 0;

*pz= 1;

for(i= 0 ;i<k;i++ ) /* заголовок цикла расчета суммы */

{

*sz = *sz + z[ i ];

*pz = *pz * z[ i ];

fprintf(stdout,"\n %2d %6.2f %8.2f %12.2f ",

i+1, z[ i ], *sz, *pz);

}

}

5 6

1 1.6 1.8 15 23

0.6 0.76 0.99 180 67.7 200

В программе использованы только два массива – на 30 и 50 элементов. Первый из них используется как фактический под именем xи формальный под именемz, второй, аналогично, под именамиyиz. Отсутствие оператораreturnопределяется равнозначностью возвращаемых значений.