Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Составление алгоритма решения. Характерная особенность основного алгоритма при работе с подпрограммой с несколькими возвращаемыми результатами – организация каждого обращения к ней




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

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

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

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

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

{

тело

функции

[return РВ;]

}

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

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

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

dj – список выходных формальных параметров – указателей, определяющих возвращаемые результа-

Рис. 10.13. Схемы основного и дополнительного алгоритмов задачи о суммах и произведениях

ты, с указанием типа каждого и признака указателя при описании (*);

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

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

return РВ; – оператор возврата в вызывающую функцию результата вычислений РВ (выражения);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Рис. 10.14. Схема 1 – передача параметра по значению

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

Рис. 10.15. Схема 2 – передача параметра по адресу

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

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

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

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

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

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

... 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=1 i=1), а затем их же значений после обращения к дополнительной функции (j=1 i=1.5). Значение входного фактического параметра j не изменилось, а выходного (i) – приняло новое значение. Это произошло потому, что обработка параметра j велась по схеме 1 (разные ячейки), а обработка параметра i – по схеме 2.

С учетом изложенного выполним программирование задачи о суммах и произведениях.

Идентификация переменных представлена в табл. 10.3.

Таблица 10.3

Имя в алгоритме n m i j xi yj SX PX SY PY d k z i SZ PZ
Имя в программе n m i j x[i] y[j] sx px sy py d k z[i] sz pz

Предусмотренная алгоритмом обработка двух массивов (на 30 и 50 элементов) позволяет в программе первый из них использовать как фактический под именем x и формальный под именем z, второй, аналогично, под именами y и z.

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

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

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

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

т. е. входные параметры передаются по значению, а выходные через адреса. Равнозначность возвращаемых значений определяет отсутствие оператора return.

Классический вариант программирования задачи

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

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

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

#include <windows.h> /*файл с прототипом функции CharToOem*/

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

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

{

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

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

char buf[30];

clrscr();

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

printf("\n %s ",buf);

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

printf("\n n=%d m=%d\n", n, m);

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

{

CharToOem(" Введите значение x ",buf);

printf("\n %s (%d): ",buf,i+1);

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

}

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

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

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

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

{

CharToOem(" Введите значение y ",buf);

printf("\n %s (%d): ",buf,j+1);

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

}

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

printf(" %.2f", y[j]);

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

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

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

printf("\n sx=%.2f px=%.2f sy=%.2f py=%.2f d=%.2f \n",

sx,px, sy, py, d);

getch();

}

void sp(float *z, int k, float *sz, float *pz)/*определение ф-ции sp*/

{

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

*sz = 0;

*pz = 1;

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

{

*sz = *sz + z[ i ];

*pz = *pz * z[ i ];

}

}

5 6 – реальные размеры массивов Х и У;

1 1.6 1.8 15 23 – значения элементов массива Х;

0.6 0.76 0.99 180 67.7 200 – значения элементов массива Y;

Под закрывающей скобкой приведены исходные данные для решения задачи.

Результаты решения представлены в приложении 10.5.

Программирование задачи с графическим интерфейсом

Программирование задачи при использовании графического интерфейса предварим его разработкой. Для ввода значений n, m планируем однострочные поля редактирования (EditN, EditM). Для ввода элементов массивов X и Y используем многострочные поля редактирования (EditХ, EditY).

Вывод расчетных значений sx, px, sy, py, d реализуем в однострочные поля редактирования (EditSx, EditPx, EditSy, EditPy, EditD).

Управление процессом решения реализуем двумя командными кнопками, расположенными в нижней части окна. Назначение каждой определяется ее названием.

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

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

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

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

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

void TSumprDlgClient::BNClickedOk()

{

// INSERT>> Your code here.

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

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

char buf[30];

EditN->GetText(buf,10); /*ввод */

n=atoi(buf); /*значения n*/

EditM->GetText(buf,10); /*ввод */

m=atoi(buf); /*значения m*/

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

{

EditX->GetLine(buf, sizeof(buf),i);

x[i]=atof(buf);

}

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

{

EditY->GetLine(buf, sizeof(buf),j);

y[j]=atof(buf);

}

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

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

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

sprintf(buf,"%.2f ",sx); /* вывод */

EditSx->SetText(buf); /*значения sx*/

sprintf(buf,"%.2f ", px); /* вывод */

EditPx->SetText(buf); /*значения px*/

sprintf(buf,"%.2f ",sy); /* вывод */

EditSy->SetText(buf); /* значения sy*/

sprintf(buf,"%.2f ", py); /* вывод */

EditPy->SetText(buf); /* значения py*/

sprintf(buf,"%.2f",d); /* вывод */

EditD->SetText(buf); /* значения d*/

}

/* определение функции 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 и PZ */

{

*sz = *sz + z[ i ];

*pz = *pz * z[ i ];

}

}

5 6 – реальные размеры массивов Х и У;

1 1.6 1.8 15 23 – значения элементов массива Х;

0.6 0.76 0.99 180 67.7 200 – значения элементов массива Y;

Под закрывающей скобкой приведены исходные данные для решения задачи.

Результаты решения представлены в приложении 10.6.

10.4. Подпроцесс с результатом – массивом

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

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

Вычислить суммы элементов каждой строки двумерных массивов A(m x n) и B(t x s). Положительные суммы каждой исходной матрицы сформировать в одномерные массивы.





Поделиться с друзьями:


Дата добавления: 2015-11-23; Мы поможем в написании ваших работ!; просмотров: 483 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Победа - это еще не все, все - это постоянное желание побеждать. © Винс Ломбарди
==> читать все изречения...

2214 - | 2048 -


© 2015-2024 lektsii.org - Контакты - Последнее добавление

Ген: 0.01 с.