- •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
- •Приложение коды клавиш
- •Краткий справочник по Си
- •Оператор вывода на принтер
- •Структура оператора
- •Структура оператора
- •Структура оператора
- •Библиографический список
Составление алгоритма решения
В основном алгоритме выполним ввод и вывод исходных двумерных матриц.
В дополнительном алгоритме произведём вычисление текущего значения суммы элементов каждой строки, проверку его знака с формирование положительных сумм в формальный одномерный массив. При формировании этого массива используется параметр цикла (индекс d), изменяющий своё значение от начального (d = 0) до конечного по закону изменения d = d + 1 для каждой положительной суммы. Полученное конечное значение индекса определяет искомые значения размеров формируемых массивов A(mp) и B(tp).
Обращение к дополнительному алгоритму произведем двукратно, что позволит последовательно передать в него каждый из исходных массивов. Алгоритмы представлены схемами рис. 6.8.
Рис. 6.8. Схемы основного и дополнительного алгоритмов примера 6.4
Программирование задачи
Особенность составленных алгоритмов в отличие от предыдущих заключается в необходимости передачи в дополнительный алгоритм многомерных массивов и возвращения в основной результатов в виде одномерных массивов.
Программно передача многомерного массива в дополнительную функцию в качестве входного осуществляется аналогично одномерному – указанием адреса первого элемента и размеров по каждому измерению (целых переменных).
-
Внимание ! Механизмы передачи входных и выходных массивов аналогичны.
Поэтому каждый выходной формальный массив, создаваемый в вызываемой функции для возвращения результатов, должен быть описан в вызывающей как один или несколько аналогичных массивов. Количество описываемых массивов определяет пользователь в зависимости от условий задачи с несколькими обращениями.
Описатели массивов определяют максимально возможные размеры каждого измерения и позволяют пользователю использовать зарезервированное пространство оперативной памяти полностью, либо частично, обеспечивая универсальность размеров в сторону уменьшения. Размеры, указанные в описателе, определяют количество зарезервированных в памяти ячеек. При этом ячейки создаваемого двумерного массива располагаются последовательно и линейно (построчно). Если в расчетах зарезервированное пространство используется частично (с меньшим числом строк и/или столбцов), то участки с хранимыми значениями будут чередоваться с неиспользуемыми, количество которых должно быть учтено при указании длины каждой строки в индексном выражении. Суммарное количество элементов каждой строки задано в описателе массива. Поэтому адрес любой ячейки определяется индексным выражением, использующим в качестве одного из операндов указанный в описателе размер.
Следовательно, в функцию необходимо наряду с используемым фактическим размером передавать и максимальный, указанный в описателе.
Если возвращаемые результаты не требуется хранить для последующего использования, достаточно описать один массив и использовать его многократно (последовательно при каждом обращении к функции). Если все возвращаемые массивы результатов требуется хранить, в вызывающей функции каждый из них должен быть описан как самостоятельный с уникальным именем и размером, определяемым логикой задачи. В этом случае в каждом обращении к дополнительной функции используется своё имя и размер. Если фактический размер выходного массива заранее известен, передача его осуществляется по значению, если рассчитывается в дополнительной функции – передаётся (возвращается) по адресу.
-
Внимание ! Если размер выходного массива совпадает с одним из параметров входного, то указывать его не требуется.
В рассматриваемом примере используются два входных двумерных (a, b) и два выходных одномерных (ssa, ssb) массива. Исходя из условий задачи, предполагаем хранение выходных массивов. Следовательно, в основной функции должны быть описаны четыре массива (a, b, ssa, ssb). Элементы входных будут определены вводом значений в этой же (основной) функции, выходных – после соответствующих обращений к подпрограмме.
Работа в дополнительной функции с элементами многомерного массива производится операцией разадресации определяющего их индексного выражения.
Методика хранения многомерных массивов (разд. «Программирование вложенных циклов») позволяет рассчитывать адрес каждого элемента через начальный адрес массива путем увеличения его на сумму произведений размеров увеличенных элементов на длину ячейки для хранения каждого из них.
Исходя из особенностей обращения к элементам многомерных массивов, с учетом максимальных значений размеров по каждому измерению, в вызове функции и её заголовке для каждого массива необходимо указывать его адрес, фактические размеры по каждому измерению и увеличенные размеры (исключая первое).
Так, при необходимости передачи в дополнительную функцию двумерного массива A(mхn) с максимально требуемым размером 10х15, фрагмент обращения имеет вид
float a[10][15];
. . .
func(a[0], m, n, 15);
. . .
а заголовок дополнительной функции запишется, например, следующим образом
void func(float *z, int k, int p, int t)
при этом обращение к текущему элементу zij имеет вид
*(z + i * t + j)
Составим таблицу идентификации переменных алгоритма и создаваемой программы (табл. 6.4).
Таблица 6.4
Обозначение в алгоритме |
1 |
m |
n |
t |
s |
i |
j |
aij |
bij |
Обозначение в программе |
2 |
m |
n |
t |
s |
i |
j |
a[i][j] |
b[i][j] |
Окончание табл. 6.4
1 |
ssai |
ssbi |
mp |
tp |
k |
p |
ss |
d |
sszd |
zij |
2 |
ssa[i] |
ssb[i] |
mp |
tp |
k |
p |
ss |
d |
ssz[d] |
z[i][j] |
Анализ алгоритма показывает, что выходные параметры равнозначны и оформлены в виде одномерного массива. Поэтому с учетом таблицы идентификации, рассмотренных выше правил и расчета в дополнительной функции размеров возвращаемых массивов, обращения примут вид
sum_str( a, m, n, 15, ssa, &mp); и sum_str( b, t, s, 7, ssb, &tp);
где m, n, t, s – фактические используемые размеры, а 15 и 7 – фактические максимальные размеры по второму измерению массивов A и B.
Заголовок дополнительной функции преобразуется к виду
void sum_str(float *z, int k, int p, int pmax, float *ssz, int *d)
где k и p – формальные используемые размеры, а pmax – формальный максимальный размер по второму измерению массива Z.
Универсальные размеры массивов зададим с помощью подстановочной директивы define, что позволит модифицировать увеличенные размеры массивов в одном месте – заголовке программы.
Программа решения примера 6.4
#include <stdio.h> /* stdio.h - файл с прототипами функций ввода-вывода */
#include <conio.h> /* conio.h - файл с прототипом функций getch( ), clrscr( )*/
#define M 10
#define N 15
#define T 9
#define S 7
void sum_str(float* z, int k, int p, int pmax, float *ssz, int *d);
main( ) /* заголовок головной функции */
{
float ap, bp, a[M][N], b[T][S], ssa[M], ssb[T]; /* описатели массивов */
int i, j, n, m, t, s, mp, tp; /* и переменных */
clrscr( );
printf("\n Введите значения m, n, t, s: ");
scanf("%d%d%d%d", &m, &n, &t, &s);
printf("\n m=%d n=%d \n t=%d s=%d \n", m, n, t, s);
printf(" Введите построчно массив A(%d*%d):\n", m, n);
for( i = 0 ; i < m ; i++ ) /* заголовок внешнего цикла ввода a[i][j]*/
for( j = 0 ; j < n ; j++ ) /* заголовок внутреннего цикла ввода a[i][j]*/
scanf("%f", a[0] + i * N + j );
printf("\n Массив A\n");
for( i = 0 ; i < m ; i++ ) /* заголовок внешнего цикла вывода a[i][j]*/
{
for( j = 0 ; j < n ; j++ ) /* заголовок внутреннего цикла вывода a[i][j]*/
printf(" %6.2f", a[i][j]);
printf("\n");
}
printf(" Введите построчно массив B(%d*%d):\n", t, s);
for( i = 0 ; i < t ; i++ ) /* заголовок внешнего цикла ввода b[i][j]*/
for( j = 0 ; j < s ; j++ ) /* заголовок внутреннего цикла ввода b[i][j]*/
scanf("%f", b[0] + i * S + j );
printf("\n Массив B\n");
for( i = 0 ; i < t ; i++ ) /* заголовок внешнего цикла вывода b[i][j]*/
{
for( j = 0 ; j < s ; j++ ) /* заголовок внутреннего цикла вывода b[i][j]*/
printf(" %6.2f", b[i][j]);
printf("\n");
}
sum_str( a[0], m, n, N, ssa, &mp);
printf("\n\n Массив SSA\n");
for( i = 0 ; i < mp ; i++ ) /* заголовок цикла вывода ssa[ i ] */
printf(" %.2f",ssa[i]);
printf("\n"); /* перевод курсора в начало следующей строки */
sum_str( b[0], t, s, S, ssb, &tp);
printf("\n\n Массив SSB\n");
for( i = 0 ; i < tp ; i++ ) /* заголовок цикла вывода ssb[ i ] */
printf(" %.2f",ssb[i]);
printf("\n"); /* перевод курсора в начало следующей строки */
getch( );
}
void sum_str(float *z, int k, int p, int pmax, float *ssz, int *d)
{
int i, j; /* описание локальных */
float ss; /* переменных */
*d = 0;
for( i = 0 ; i < k ; i++ ) /* заголовок внешнего цикла ввода a[i][j]*/
{
ss = 0;
for( j = 0 ; j < p ; j++ ) /* заголовок внутреннего цикла ввода a[i][j]*/
{
ss = ss + *(z + i * pmax + j);
printf("\n %2d %2d %6.2f %8.2f", i, j, *(z + i * pmax + j), ss);
}
if( ss >= 0 )
{
ssz[*d] = ss;
*d=*d + 1;
}
}
}
3 4 2 3
8.53 9.3 5.7 -3.5
46 -32.1 28.5 -52.6
4.7 56 65 -7.2
1.6 7.3 15
4.2 -10.18 12
Вопросы для контроля
1. Какой алгоритм называют основным, а какой – дополнительным ?
2. Что выносится в дополнительный алгоритм ?
3. Какова структура обращения к дополнительному алгоритму ?
4. Какие параметры называют фактическими ?
5. Что такое формальные параметры ?
6. Какова схема взаимодействия головного алгоритма с дополнительными ?
7. Чем головная программа отличается от подпрограммы ?
8. На какие типы делятся подпрограммы ?
9. Что такое функция ?
10. Что такое вызов функции ?
11. Для чего нужен прототип функции ?
12. Какова структура программы с подпрограммами ?
13. Какова структура определения функции ?
14. Какова структура вызова функции ?
15. Для чего нужен оператор return ?
16. Как осуществляется передача массивов в функцию ?
17. Что такое указатель ?
18. Какова структура описания указателя ?
19. Для чего нужны операции взятия адреса и разадресации ?
20. Чем отличаются входные параметры от выходных ?
21. Каков механизм передачи в функцию выходных параметров ?
22. Чем отличается передача параметров по значению от передачи по адресу ?
22. Почему при составлении индексного выражения используют размеры, указанные в операторе описания массива ?