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

Подпрограмма с аргументом – одномерным массивом

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

Постановка задачи примера

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

если a=0.96; b=1445, n<=10; m<=15.

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

Основная часть математической формулировки выполнена в постановке задачи. Дополним её описанием массивов.

X(n) – одномерный массив;

xi– значениеi-го элемента;

– диапазон изменения индекса i;

i=i+ 1 – шаг изменения индекса i.

Примем n = 5, зададимся x1=0,5; x2=1,3; x3=-0,8; x4=17; x5=0,3

Примем m = 4, зададимся y1=5,3; y2=-0,3; y3=1,7; y4=2,5

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

Анализ задачи рекомендует использование дополнительного алгоритма, в который необходимо вынести несколько формул для получения одного результата – суммы элементов одномерного массива. Особенность задачи заключается в необходимости передачи в дополнительный алгоритм, в качестве фактических параметров, одномерных массивов, X(n), а затемY(m). Математическое обозначение каждого массива фактически содержит два элемента: имя и размер, поэтому в программировании принято передавать каждый из них отдельно. Для их получения в дополнительном алгоритме в качестве формальных параметров зададимся именем массива Т и размером k.

Назвав подпрограмму sum, запишем два обращения к ней:

sum( X(n) ), sum(Y(m) ).

В первом фактическими параметрами являются имя массива X и его размер n, во втором – Y и m.

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

С учётом выбранных обозначений составим схемы основного и дополнительного алгоритмов (рис. 6.4). Используемые в дополнительном алгоритме переменные sи i являются локальными. Печать промежуточных значений i, ti,sпредусмотрена для облегчения отладки программы.

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

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

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

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

Следовательно, обращение, записанное в Си для передачи массива X(n), имеет видsum(x,n), а для массиваY(m) –sum(y,m).

  • Внимание! В списке фактических параметров идентификатор одномерного массива однозначно подразумевает адрес его первого элемента.

Поэтому имя может быть заменено адресом первого элемента массива, т. е. рассмотренные обращения можно записать как sum( &x[0] ,n) иsum( &y[0] ,m).

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

Указатель– переменная для хранения адреса.

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

Указатели, как и простые переменные, обозначаются именами (идентификаторами). Имена задаются самим пользователям по обычным для переменных правилам.

Указатели описываются аналогично переменным и массивам. Тип указателя определяется типом переменной (массива), на которую он ссылается.

Структура описания указателя:

описатель * иу1 [, * иу2, . . . , * иуN ];

где описатель – ключевое слово, определяющее тип указателя;

* – признак указателя при описании;

иу1... иуN – идентификаторы указателей;

, – разделитель списка идентификаторов;

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

; – символ окончания оператора описания.

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

Например, описатели

float*a, *b;

int*f;

описывают два указателя на вещественные переменные, адреса которых будут указаны в ячейках с именами aиb, и один – на целую переменную, адрес которой можно хранить в ячейкеf.

Описатели

floatx,y, *a, *b,

int*f,arr[10];

наряду с указателями задают типы переменных x,yи целочисленного массиваarr. Месторасположение указателя в списке совместного описания задается произвольно.

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

иу = &ип

где иу – идентификатор указателя;

& – операция взятия адреса;

ип – идентификатор переменной.

Например, оператор

b= &x;

определяет, что указатель bна переменную вещественного типа содержит адрес вещественной переменнойx.

Операторы

f= &arr[0]; илиf=arr;

задают указателю fзначение адреса массиваarr(его первого элемента).

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

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

Запись разадресации имеет вид

*иу

где иу – идентификатор указателя;

* – символ операции разадресации.

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

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

floatg,s, *t;

. . .

g= 15.3;

t= &g;

s=sqrt( *t) + *t+ 0.5;

. . .

описывает переменные g,sи указательtкак вещественные, присваивает указателюtадрес переменнойg, а затем, используя операцию разадресации указателяt, формирует операнды выраженияs– подкоренное выражение и второе слагаемое – как константы 15.3 (содержимое переменнойg).

Фрагмент

floatx,z, *d;

. . .

d= &z;

*d=pow(x, 2 ) + 5;

. . .

поясняет использование операции разадресации для записи константы (результата вычисления выражения pow(x, 2 ) + 5) в ячейку переменнойzс использованием указателяd.

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

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

Элементы переданного в дополнительную функцию массива могут использоваться напрямую (указанием индексного выражения) или с помощью операции разадресации.

. . .

floatfunk(float* ,int);

main( )

{ float t, x[10];

. . .

n = 10;

t = funk( x , n );

. . .

}

float funk( float *px, int n1 )

{ . . .

for( i=0 ; i <= n1 ; i++ )

f = . . . + *(px+i) + . . . .;

. . .

returnf;

}

Так, фрагменты программы

.. .

float funk( float *px , int n1 );

main( )

{ float t, x[10];

. . .

n = 10;

t = funk( x , n );

. . .

}

float funk( float *px, int n1 )

{ . . .

for( i=0 ; i <= n1 ; i++ )

f = . . . + px[i] + . . . .;

. . .

returnf;

}

поясняют варианты передачи одномерных массивов в функцию, использования её элементов и способы написания прототипа. Во втором варианте прототипа тип указателя дополнен обязательным элементом – знаком «*».

В дополнительной функции вызов i-го элемента массива осуществляется двумя способами:

  1. индексированной переменной;

  2. полным индексным выражением.

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

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

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

Таблица 6.2

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

1

a

b

n

m

i

j

xi

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

2

a

b

n

m

i

j

x[i]

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

1

yj

z1

z2

z

k

ti

s

2

y[j]

z1

z2

z

k

t[i]

s

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

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

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

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

floatsum(float*t,intk); /* прототип пользовательской функции */

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

{

floata,b,z1,z2,z,x[10],y[15]; /* описатели локальных */

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

clrscr( );

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

scanf("%f%f%d%d", &a, &b, &n, &m);

fprintf(stdout,"\n a=%.2f b=%.2f n=%d m=%d\n", a, b, 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]);

z1 =cos(a) +sum(x,n); /* вычисление с обращением к */

z2 =sum(y,m) -b; /* дополнительным функциям */

z=z1 /z2;

fprintf(stdout,"\n\nz1=%.2fz2=%.2fz=%.2f\n",z1,z2,z);

getch( );

}

/* определение дополнительной функции расчёта суммы элементов массива */

floatsum(float*t,intk) /* заголовок дополнительной функции */

{

floats; /* описание локальных */

int i; /* переменных sиi*/

s = 0;

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

{

s = s + t[ i ];

fprintf(stdout,"\n %2d %6.2f %8.2f ", i+1 , t[ i ], s);

}

returns; /* возвращение значенияsв вызывающую функцию */

}

0.96 35. 5 4

4.5 12.3 -0.8 17 0.3

45.3 -0.3 12.7 2.5