- •1. Основные этапы разработки программных продуктов
- •1.1 Постановка задачи
- •Словесная формулировка
- •Формульная постановка задачи
- •1.2 Создание программного продукта
- •1.2.1.Формирование математической модели
- •Формирование исходных данных
- •Составление расчётных зависимостей
- •Правила формирования математической модели.
- •1.2.2.Алгоритмизация задачи
- •Выбор метода решения
- •Составление алгоритма решения
- •Программирование задачи
- •1.2.3. Реализация программного продукта
- •1.2.4. Работа с результатами
- •1.2.5.Анализ результатов решения
- •1.2.6.Принятие решения
- •1.2.7.Составление технической документации
- •1.3.Полная обработки задачи пользователя
- •1.4.Обеспечение эффективности разработки программных продуктов
- •2.5 Идентификаторы
- •2.6 Описание операций
- •2.6.1 Унарные операции
- •2.6.2 Бинарные операции
- •2.6.3 Пунктуаторы
- •Программирование простых ветвлений
- •4.1.5. Программирование задачи
- •Правила составления и использования
- •4.1.5.2. Операторы условной передачи управления
- •Укороченный оператор условного перехода
- •Правила записи и выполнения
- •Условная операция
- •Технология программирования арифметических циклов
- •Циклы с аналитическим заданием аргумента
- •Постановка задачи
- •Формирование математической модели
- •Выбор метода решения
- •Составление алгоритма
- •Оператор цикла с предусловием
- •Правила записи и выполнения
- •Оператор цикла с постусловием
- •Правила записи и выполнения
- •Оператор пошагового цикла for
- •Правила записи и выполнения
- •Программа по алгоритму цикла с предусловием
- •Программа по алгоритму цикла с постусловием
- •Программа по алгоритму цикла с параметром
- •Циклы с табличным заданием аргумента
- •Описание массивов
- •Описатель имя[размер];
- •Обозначение элементов массива
- •Имя[индекс]
- •Описатель имя[разм_1] …[разм_i]… [разм_n];
- •Постановка задачи
- •Математическая формулировка
- •Выбор метода решения
- •Составление алгоритма решения
- •Алгоритмизация структурой цикла с предусловием
- •Алгоритмизация структурой цикла с постусловием
- •Алгоритмизация структурой цикла с параметром
- •Программирование задачи
- •Описание массивов
- •Обозначение элементов массива
- •Составление программ решения задачи
- •Улучшение качества программных продуктов
- •Организация ввода-вывода Использование укороченных спецификаторов
- •Ввод переменных
- •Вывод переменных
- •Организация ввода в диалоге
- •Варианты ввода массивов
- •Оформление выводимых величин
- •Управление выполнением программ Использование составных присваиваний
- •Выбор устройства вывода
- •Повторение расчётов
- •Приостановка вывода
- •Очистка экрана
- •Позиционирование курсора
- •Пример улучшения качества
- •Программирование с использованием подпрограмм
- •Имя (фактические параметры)
- •Подпрограмма с одним результатом
- •Формирование математической модели
- •Выбор метода решения
- •Составление алгоритма решения
- •Программирование задачи
- •Подпрограмма с аргументом – одномерным массивом
- •Постановка задачи примера
- •Формирование математической модели
- •Выбор метода решения
- •Составление алгоритма решения
- •Программирование задачи
- •Подпрограмма с несколькими результатами
- •Постановка задачи
- •Формирование математической модели
- •Выбор метода решения
- •Составление алгоритма решения
- •Программирование задачи
- •Подпрограмма с результатом – массивом
- •Постановка задачи
- •Математическая формулировка
- •Выбор метода решения
- •Составление алгоритма решения
- •Программирование задачи
- •Обработка текстовой информации в Си Символьные строки
- •Определение значения символьной строки
- •Массивы строк
- •Ввод строки
- •Выделение памяти
- •Функции ввода символьной строки
- •Функция ввода символьной строки gets( )
- •Функция ввода символьной строки scanf( )
- •Преобразование символьных строк
- •Функцияatoi( )
- •Функцияatol( )
- •Функцииatof( ) иatold( )
- •Методика ввода числовых данных с использованием функцииgets( )
- •Вывод строки
- •Вывод строки функциями printf( ) и fprintf( )
- •Вывод строки функциямиputs( ) и fputs( )
- •Перевод чисел в формат символьной строки
- •Обработка символьных строк
- •Определение длины строки
- •Объединение строк
- •Копирование строк
- •Сравнение строк
- •Функции по работе с датой и временем.
- •Структуры.
- •Работа с дисками.
- •Ввод-вывод потока.
- •Открытие потока.
- •Объектно−ориентированное программирование
- •Классы ObjectWindows
- •Приложение коды клавиш
- •Краткий справочник по Си
- •Оператор вывода на принтер
- •Структура оператора
- •Структура оператора
- •Структура оператора
- •Библиографический список
Подпрограмма с несколькими результатами
Этот вариант подпрограммы (дополнительной функции) применяют, когда в дополнительный алгоритм выносится участок вычислений с несколькими конечными результатами. Рассмотрим программирование подобного класса задач на конкретном примере 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– список выходных формальных параметров – указателей, определяющих возвращаемые результаты, с указанием типа каждого и признака указателя при описании (*);
( ) – ограничители списка формальных параметров;
[ ] – признак необязательности содержимого;
; – признак оператора.
Правила записи и использования функций с несколькими возвращаемыми значениями совпадают с указанными ранее для функций с одним результатом со следующими дополнениями:
количества и типы входных и выходных формальных параметров должны соответствовать аналогичным фактическим, т.е. каждый aiимеет свойbi, а каждыйcj– свойdj, при этом тип и взаимное расположение их в списке определяется программистом;
в качестве входных формальных параметров используются переменные;
в качестве выходных формальных параметров используются указатели;
в качестве входных фактических параметров используются константы, переменные, вызовы функций, выражения и адреса массивов;
в качестве выходных фактических параметров используются адреса переменных и адреса массивов;
каждое обращение к подпрограмме, как правило, оформляется как отдельный оператор, в соответствии с требованиями алгоритма;
использование выходных параметров освобождает от ограничения на возвращение только одного результата оператором return, основной результат рекомендуется возвращать операторомreturn, все остальные в качестве выходных параметров.
при использовании структуры с оператором return, вызов функции может служить операндом выражения в вызываемой функции;
если логика задачи не позволяет выделить основной результат, то использование оператора returnнеобязательно. В этом случае в заголовке дополнительной функции в качестве описателя типа необходимо указывать ключевое словоvoid;
вызов функции, оформленный простым оператором, заканчивается символом «;», если является операндом выражения – признак оператора не указывается;
формальные значения (кроме главного) возвращаются в ячейки вызывающей функции, адреса которых были переданы в вызываемую;
в списке формальных параметров прототипа допускается опускать их имена, оставляя для входных их типы, а для выходных типы с последующими символами «*».
Программная реализация задач с использованием входных и выходных параметров опирается на закономерности, описанные при алгоритмизации. В качестве выходных параметров используются адреса операндов и указатели на них.
Обращение по адресу определяет, что в дополнительной функции используется в качестве формального фактический параметр головной функции. Поэтому любые корректировки формального параметра в дополнительной функции есть автоматическое изменение фактического параметра в вызывающей функции. Принципиальные различия в обработке формальных параметров, заданных переменными или указателями, иллюстрируются схемами рис. 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;
. . .
}
Использование выходных параметров освобождает от ограничения на возвращение только одного результата оператором 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определяется равнозначностью возвращаемых значений.