Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Практикум по программированию на языке Си

..pdf
Скачиваний:
24
Добавлен:
12.11.2023
Размер:
3.53 Mб
Скачать

ЗАДАЧА 08-11. Определите функцию с параметром-массивом. В теле функции напечатайте значение параметра-массива и попытайтесь вычислить его размер. В основной программе определите и инициализируйте массив с элементами long double. Напечатайте его размеры и число элементов. Обратитесь к функции, используя массив в качестве аргумента.

/* 08_11.c - значение параметра-массива в теле функции */

#include <stdio.h>

#define PRINTD(EXPRESSION) \ printf(#EXPRESSION"=%d\n",EXPRESSION)

void arrayTest(long double ar[], int n)

{

printf("\nParameter: address = %p\n", ar); PRINTD(sizeof(ar));

PRINTD(sizeof(ar[0]));

}

int main()

{

long double array[]={5.6,2.4,9.2,1.3,8.6,3.5}; int sizeArray = sizeof(array)/sizeof(array[0]); PRINTD(sizeof(array)); PRINTD(sizeof(array[0]));

printf("Array address = %p"

"\nNumber of elements: %d\n", array, sizeArray); arrayTest(array, sizeArray);

return 0;

}

Результаты выполнения программы:

sizeof(array)=72

sizeof(array[0])=12 Array address = 4c64c Number of elements: 6

Parameter: address = 4c64c sizeof(ar)=4 sizeof(ar[0])=12

291

Вфункции arrayTest() печатаются "известные внутри функции" сведения о параметре-массиве: адрес начала его размещения в памяти, размер этого адреса (размер указателя типа long double *) и размер нулевого элемента. Как видно из результатов, печатать значение выражения sizeof(ar)/sizeof(ar[0]) не имеет смысла – бесполезно делить размер адреса на размер элемента массива.

Восновной программе печатаются размеры и адрес массивааргумента array[], размер его нулевого элемента и число элементов в массиве. Важно отметить, что адрес массива-аргумента совпадает с адресом-значением массива-параметра. Но "ведут они себя" по-разному.

ЭКСПЕРИМЕНТ. Попытайтесь в программе 08_11.с напечатать значения следующих выражений:

*(++ar) – в функции arrayTest(); *(++array) – в основной программе;

Важное напоминание: для вывода значений типа long double используется любая из спецификаций преобразования %Le, %Lf, %Lg,

%LF, %LG.

Добавив в функцию arrayTest() оператор

printf("*(++ar)=%Le", *(++ar));

получим (см. текст программы 08_11_1.с):

sizeof(array)=72

sizeof(array[0])=12 Array address = 4c64c Number of elements: 6

Parameter: address = 4c64c sizeof(ar)=4 sizeof(ar[0])=12 *(++ar)=2.400000e+00

Все соответствует нашим ожиданиям – выражение ++ar – адресует второй элемент массива-аргумента с индексом 1.

Попытка напечатать значение (++array) в основной программе с помощью оператора

292

printf("(++array)=%le", *(++array));

воспринимается компилятором как ошибка (см. программу

08_11_2.с):

08_11_2.c: In function `main':

08_11_2.c:21: wrong type argument to increment

Это соответствует константности имени массива (в нашей программе – имя массива array[]).

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

Следующая программа решает задачу:

/* 08_12.c - Функция, нормирующая значения элементов массива-параметра */

#include <stdio.h> #include <float.h> #include <math.h>

void normalization(double array[], int n)

{

int i;

double mean=0.0; for (i=0; i<n; i++)

mean += array[i]; mean /= n;

printf("\nmean=%f",mean); if (fabs(mean) > DBL_MIN) for (i=0; i<n; i++)

array[i] /= mean;

}

int main()

{

double row[] = {5.6, 2.4, 9.2, 1.3, 8.6, 3.5};

293

int sizeRow = sizeof(row)/sizeof(row[0]); int i;

printf("\nBegin array:"); for (i=0; i<sizeRow; i++)

printf("%c[%d]=%5.2f",i%4?'\t':'\n',i,row[i]); normalization(row, sizeRow);

printf("\nResult array:"); for (i=0; i<sizeRow; i++)

printf("%c[%d]=%5.2f",i%4?'\t':'\n',i,row[i]); return 0;

}

Результаты выполнения программы:

Begin array:

[1]= 2.40

[2]= 9.20

[3]= 1.30

[0]= 5.60

[4]= 8.60

[5]= 3.50

 

 

mean=5.100000

 

 

 

Result array:

[1]= 0.47

[2]= 1.80

[3]= 0.25

[0]= 1.10

[4]= 1.69

[5]= 0.69

 

 

В функции normalization() вычисляется среднее арифметическое элементов массива-параметра (переменная mean). Его абсолютное значение сравнивается с препроцессорной константой DBL_MIN, определенной в заголовочном файле <float.h>. Если значение mean превышает DBL_MIN, то выполняется нормирование элементов массива. Остальное очевидно из текста программы и результатов.

Параметры-массивы специфицируются выражениями:

тип имя_параметра[] тип * имя_параметра

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

294

ЗАДАНИЕ. Измените спецификации массивов-параметров в функциях из программ 08_11.с и 08_12.с. Например, озаглавьте функцию нормализации массива таким образом:

void normalization(double * array, int n).

Откомпилируйте и выполните программы с указанными изменениями.

ЗАДАЧА 08-13. Напишите функцию для реверсирования, т.е. перестановки в обратном порядке значений элементов целочисленного массива-параметра. В качестве вспомогательной определите функцию для обмена значений двух элементов массива. В основной программе определите и инициализируйте массив, напечатайте значения его элементов до обращения к функции перестановки и после обращения.

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

void swap(int array[], int j, int k);

Функция реверсирования массива получает в качестве параметров его имя (указатель) и его размер (количество элементов):

void reverse(int array[], int size);

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

Следующая программа решает задачу:

/* 08_13.c - функция "реверсирования" массива-параметра */

#include <stdio.h>

void swap(int ar[], int j, int k)

{

295

int temp;

temp = ar[j]; ar[j] = ar[k]; ar[k] = temp;

}

void reverse(int array[], int size)

{

int i;

double mean=0.0;

for (i=0; i<size/2; i++) swap(array, i, (size-i-1));

}

int main()

{

int line[] = {5, 6, 2, 4, 9, 2, 1};

int sizeLine = sizeof(line)/sizeof(line[0]); int i;

printf("Begin array:\n"); for (i=0; i<sizeLine; i++)

printf("[%d]=%d\t",i,line[i]); reverse(line, sizeLine); printf("\nResult array:\n");

for (i=0; i<sizeLine; i++) printf("[%d]=%d\t",i,line[i]);

return 0;

}

Результаты выполнения программы:

Begin array:

 

[0]=5

[1]=6 [2]=2 [3]=4 [4]=9 [5]=2 [6]=1

Result

array:

[0]=1

[1]=2

[2]=9 [3]=4 [4]=2 [5]=6 [6]=5

ЗАДАНИЕ. Замените в предыдущей программе функцию обмена значений элементов массива функцией перестановки значений обычных (неиндексированных) переменных типа int.

Функция для перестановки значений переменных, адресованных аргументами-указателями, может быть такой:

296

void swapInt(int * a, int * b)

{

int temp;

temp

= *a;

*a

=

*b;

*b

=

temp;

}

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

swapInt(&array[i], &array[size-i-1]);

Программа с полным решением такого варианта задачи приведена в файле 08_13_1.с.

Функция с параметром-массивом может возвращать адрес како- го-либо из его элементов.

ЗАДАЧА 08-14. Определите функцию с параметром-массивом, которая возвращает адрес максимального элемента массива, заданного в качестве аргумента. В основной программе определите одномерный массив и, используя функцию, замените его положительные элементы нулевыми.

Функцию, возвращающую адрес максимального элемента масси- ва-параметра, можно написать по-разному, но выбор ее прототипа практически однозначен:

double * maxElement(double dar[], int size);

Втеле функции нужно определить вспомогательный указатель типа double * и, перебрав все элементы массива-параметра dar[], последовательно присваивать указателю адрес очередного кандидата

внаибольшие элементы.

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

297

/* 08_14.c - функция возвращает адрес максимального элемента массива-параметра.*/

#include <stdio.h>

double * maxElement(double dar[], int size)

{

int j;

pElement;

double *

pElement

= dar;

for(j=1;

j<size; j++)

if (* pElement < dar[j]) pElement = &dar[j]; return pElement;

}

int main()

{

double real[] = {5.6, -2.4, 9.2, -1.3, 8.6, 3.5}; int sizeArray = sizeof(real)/sizeof(real[0]);

int i;

printf("\nSource array:"); for (i=0; i<sizeArray; i++)

printf("%c[%d]=%5.2f",i%4?'\t':'\n',i,real[i]); for (i=0; i < sizeArray; i++)

if (*maxElement(real, sizeArray) <= 0.0) break; else *maxElement(real, sizeArray) = 0.0;

printf("\nResulting array:"); for (i=0; i<sizeArray; i++)

printf("%c[%d]=%5.2f",i%4?'\t':'\n',i,real[i]); return 0;

}

Результаты выполнения программы:

Source array:

[1]=-2.40

[2]= 9.20

[3]=-1.30

[0]= 5.60

[4]= 8.60

[5]= 3.50

 

 

Resulting array:

[2]= 0.00

[3]=-1.30

[0]= 0.00

[1]=-2.40

[4]= 0.00

[5]= 0.00

 

 

В программе отметим использование выражения

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

298

ЗАДАНИЕ. Измените тело функции maxElement(). Используйте вместо вспомогательного указателя индекс искомого максимального элемента массива.

Функция примет следующий вид:

double * maxElement(double dar[], int size)

{

int j;

int index 0; for(j=1; j<size; j++)

if (dar[index] < dar[j]) index = j; return &dar[index];

}

Остальная часть программы и, конечно, результаты останутся без изменений. Полный текст программы приведен в файле 08_14_1.c.

ЗАДАНИЕ. Дополните основную функцию main() программы 08_14.с печатью найденных максимальных элементов изменяемого массива-аргумента с их индексами.

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

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

{pMaxElement = maxElement(real, sizeArray); if (*pMaxElement <= 0.0) break; printf("\nMaxElement: [%d]=%5.2f",

pMaxElement - real,real[pMaxElement - real]); *pMaxElement = 0.0;

}

В приведенном фрагменте используется дополнительный указатель double * pMaxElement, позволяющий уменьшить количество обращений к функции maxElement(). Полный текст программы приведен в файле 08_14_2.c.

299

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

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

ЗАДАЧА 08-15. Определите функцию, которая возвращает через параметры индексы максимального и минимального элементов массива, заданного в качестве параметра. В основной программе определите одномерный массив и, используя функцию, замените найденные (максимальный и минимальный) элементы нулевыми.

Задачу решает следующая программа:

/* 08_15.c - индексы максимального и минимального элементов массива-параметра. */

#include <stdio.h>

void minMaxIndex(int mir[], int n, int * iMin, int * iMax)

{

int j;

* iMin = * iMax = 0; for(j=1; j<n; j++)

{ if (mir[* iMin] > mir[j]) * iMin = j; if (mir[* iMax] < mir[j]) * iMax = j;

}

}

int main()

{

int integer[]={5,6,2,4,9,2,1,3,8,6};

int sizeArray=sizeof(integer)/sizeof(integer[0]); int i, kMin, kMax;

printf("Source array:\n"); for (i=0; i<sizeArray; i++)

printf("%c[%d]=%d",i%5?'\t':'\n',i,integer[i]); minMaxIndex(integer, sizeArray, &kMin, &kMax); integer[kMin] = integer[kMax] = 0;

300