Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
BOOK_С_INTUIT.doc
Скачиваний:
4
Добавлен:
19.09.2019
Размер:
7.91 Mб
Скачать

Тип_возвращаемый_функцией(*имя_указателя_на_функцию)(аргументы);

В круглых скобках определяется указатель на функцию, которая возвращает тот или иной тип – тип_возвращаемый_функцией. Хотя знак * обозначает префиксную операцию, он имеет более низкий приоритет, чем функциональные круглые функции, поэтому для правильного комбинирования частей объявления необходимы дополнительные скобки [1]. При этом аргументы – это аргументы той или иной функции с заданным типом возвращаемого значения, для которой определяется указатель *имя_указателя-_на_функцию. Очевидно, что возможны сложные объявления функций.

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

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

ПРАКТИЧЕСКАЯ ЧАСТЬ

Пример 1. Написать программу с функцией пузырьковой сортировки, использующей вызов по ссылке.

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

Программный код решения примера

#include <stdio.h>

#include <conio.h>

// Прототип функции

void bsort (int* const, const int);

int main (void) {

int A[] = {56, 34, 2, 0, 1, -21, 6, 8, 7};

int i, n;

//Размерность массива

n = sizeof(A)/sizeof(A[0]);

puts("\n Data items in original order:");

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

printf(" %3d", A[i]);

// Вызов функции сортировки - bsort()

bsort (A, n);

puts("\n\n Data items in ascending order:");

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

printf(" %3d", A[i]);

printf("\n\n ... Press any key: ");

_getch();

return 0;

}

// Определение функции

void swap(int *pa, int *pb) {

int temp;

temp = *pa;

*pa = *pb;

*pb = temp;

}

void bsort (int *const arr, const int size) {

int pass,j; //счетчик проходов и счетчик сравнений

// Прототип функции обмена - swap()

void swap (int*, int*);

// Цикл для контроля проходов

for (pass = 0; pass < size - 1; pass++ )

{

// цикл для контроля сравнений на данном проходе

for (j = 0; j < size - 1; j++)

{

// обмен значений при нарушении порядка возрастания

if (arr[j] > arr[j + 1])

{

swap(&arr[j], &arr[j+1]);

}

}

}

}

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

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

П ример выполнения программы представлен на рис. 11.2.

Рис. 11.2. Пример сортировки массива методом пузырька

Задание 1

  1. Напишите программу сортировки семи вещественных, которые должны быть случайными по равномерному закону из интервала [–Х, +Х], где Х – номер компьютера, на котором выполняется лабораторная работа.

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

Пример 2. Написать программу, в которой используется функция по расчету среднего значения (среднего арифметического) одномерного числового массива, его исправленной выборочной дисперсии и среднего квадратичного отклонения (стандартного отклонения). Эти значения должны быть выведены на консоль в главной функции программы main().

Приведем расчетные формулы.

Среднее выборочное значение (mean) одномерного массива размерностью N

где – элементы массива.

Исправленная выборочная дисперсия (D) одномерного массива

Исправленное среднеквадратичное отклонение есть плюс корень квадратный из дисперсии.

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#include <math.h>

// Прототип функции

double *mean_D_S(int arr[], int n);

int main(void)

{

int mass[] = {2, -3, 5, 6, 7, 8, 9,-1};

int i, n;

double *R;

n = sizeof(mass)/sizeof(mass[0]);

puts("\n\t Initial array:");

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

printf(" %3d", mass[i]);

R = mean_D_S(mass, n); // вызов функции

// Вывод расчтных характеристик массива

printf("\n\n The average value of an array: %g\n", R[0]);

printf(" The dispersion of the array: %g\n", R[1]);

printf(" The standard deviation of the array: %g\n", R[2]);

free(R); // освобождение памяти

printf("\n ... Press any key: ");

_getch();

return 0;

}

// Определение функции

double *mean_D_S(int arr[], int N) {

int j;

double *PTR3 = (double *)calloc(N, sizeof(double));

double D, S, mean; mean = D = 0.0;

for (j = 0; j < N; j++)

mean += arr[j];

mean /= N; // среднее арифметическое

for (j = 0; j < N; j++)

D += (arr[j] - mean)*(arr[j] - mean);

D /= (N-1); // дисперсия

S = sqrt(D); // среднее квадратическое отклонение

PTR3[0] = mean;

PTR3[1] = D;

PTR3[2] = S;

return PTR3;

}

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

Р езультат выполнения программы показан на рис. 11.3.

Рис. 11.3. Расчет статистических характеристик числового массива

Задание 2

  1. В качестве первого аргумента функции mean_D_S() используйте указатель на числовой массив.

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

  3. Дополните возврат функцией mean_D_S() исходного массива, поэлементно возведенного в квадрат. В главной функции main() результаты выведите на консоль.

Пример 3. Написать программу с указателем на функции, которые рассчитывают следующие статистические характеристики одномерного числового массива: среднее арифметическое значение, медиану и модус (моду).

Среднее арифметическое рассчитывалось в предыдущем примере.

Приведем определения медианы и модуса [3]. Медиана – это серединное значение в наборе данных – т. е. такое, что ровно половина значений располагается выше, и ровно половина ниже его. Модус – это значение, наиболее часто встречающееся в наборе данных.

Программный код решения примера

#include <stdio.h>

#include <conio.h>

double mean(int*, int);

double median(int*, int);

double mode(int*, int);

int main(void) {

int mass[] = {5, 6, 5, 5, 3,

6, 5, 3, 1, 4,

5, 3, 1, 6, 5,

2, 5, 2, 3, 4};

int temp, i, j, k, n, *ptr = mass;

// Указатель на функции

double (*fun[3])(int*, int) = {mean, median, mode};

n = sizeof(mass)/sizeof(mass[0]);

puts("\n The original array:");

j = 0;

for (i = 0; i < n; i++) {

j++;

if ( j%6 )

printf(" %2d", mass[i]);

else

{puts(""); printf(" %2d", mass[i]); j = 1;}

}

// Сортировка методом выбора

for (i = 0; i < (n - 1); ++i) {

temp = ptr[i]; k = i;

for (j = i + 1; j < n; ++j)

if (ptr[j] < temp) { k = j; temp = ptr[k]; }

ptr[k] = ptr[i]; ptr[i] = temp;

}

puts("\n\n Results - mean, mediana, modus: ");

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

printf("%6g\n",(*fun[i])(ptr, n));

printf("\n\n ... Press any key: ");

_getch();

return 0;

}

// Определения функций

double mean(int* arr, int N) {

int i;

double aver = 0.0;

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

aver += arr[i];

return (aver/N);

}

double median(int* arr, int N) {

int i;

double med = 0.0;

for (i = 0; (i < N/2); i++)

med = arr[i];

if ( N % 2)

med = arr[i];

else

med = (med + arr[i])/2;

return med;

}

double mode(int* arr, int N) {

int instances = 0, tempinst = 1, i = 1;

double tempmode, mode_return = 1.0;

tempmode = (double)arr[0];

while (i < N) {

while ((double)arr[i] == tempmode ) {

i++;

tempinst++;

}

if (tempinst > instances) {

mode_return = tempmode;

instances = tempinst;

}

tempinst = 1;

tempmode = (double)arr[i];

i++;

}

return (mode_return);

}

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

Для понимания работы функции по расчету модуса алгоритм вычислений рекомендуется формулировать следующим образом: «Разбить сортированный список значений на ряд меньших списков, каждый из которых содержит одинаковые значения. Пересчитать число элементов в этих списках, и список с наибольшим числом элементов будет соответствовать модусу данных» [3].

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

Рис. 11.4. Значения среднего, медианы и модуса

Задание 3

  1. В функции расчета модуса приведение типов примените только один раз.

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

  3. Объедините три функции – mean(), median(), mode() в одну и определите необходимый тип возвращаемого значения, чтобы в главной функции main() можно было распечатать результаты расчетов статистических характеристик.

Пример 4. Написать программу сортировки массива строк с использованием указателей на функции.

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#include <string.h>

// Прототипы функций

void bsort (char **arr, int size,

int (*comp) (const char *s1, const char *s2));

int less (const char *s1, const char *s2);

int greater (const char *s1, const char *s2);

int main (void) {

char *Lines[] = { "asd", "aza", "baza", "qwerty", "hello", "world", "aza" };

int i;

int n = sizeof (Lines) / sizeof (Lines[0]);

// Вызов функции сортировки по возрастанию в алфавитном порядке

puts("\n The sorting in ascending order:");

bsort (Lines, n, less);

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

printf("\t %s\n", Lines[i]);

// Вызов функции сортировки по убыванию в алфавитном порядке

puts("\n The sorting in descending order:");

bsort (Lines, n, greater);

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

printf("\t %s\n", Lines[i]);

printf("\n\n ... Press any key: ");

_getch();

return 0;

}

// Определение функции сортировки строк

void bsort (char **arr, int size,

int (*comp) (const char *s1, const char *s2))

{

int i, j;

for (i = 0; i < size - 1; ++i)

for (j = 0; j < size - 1; ++j)

if (comp (arr[j], arr[j + 1]) > 0) {

char *s = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = s;

}

}

// Определение функции сравнения строк по возрастанию

int less (const char *s1, const char *s2)

{

return strcmp (s1, s2);

}

// Определение функции сравнения строк по убыванию

int greater (const char *s1, const char *s2)

{

return -strcmp (s1, s2);

}

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

Р езультат выполнения программы показан на рис. 11.5.

Рис. 11.5. Пример сортировки строк

Задание 4

  1. Ввод массива строк осуществите с клавиатуры построчно.

  2. Ввод массива строк осуществите с клавиатуры одной строкой, содержащей несколько слов, разделенных пробелами, и заполните символьный массив так, чтобы в каждом элементе было по одному слову из исходной строки.

  3. Измените программу так, чтобы при сравнении строк не различались строчные и прописные буквы латинского алфавита.

Пример 5. Написать программу построения на экране дисплея графика функции

Предусмотреть возможность записи в текстовый файл графика данной функции.

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

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#include <math.h>

// Размеры диаграммы по ширине и высоте экрана

#define SCREENW 79

#define SCREENH 25

// Функция построения графика заданной функции

void plot (FILE *fout, double a, double b, double (*f) (double))

{

// Формальные параметры функции plot

// FILE *fout – указатель на поток вывода

// double a – левая граница оси абсцисс

// double b – правая граница оси абсцисс

// double (*f) (double) – указатель на функцию

char screen[SCREENW][SCREENH];

double x, y[SCREENW];

double hx, hy, ymin = 0, ymax = 0;

int i, j, xz, yz;

// hx – шаг по оси абсцисс

hx = (b - a) / (SCREENW - 1);

for (i = 0, x = a; i < SCREENW; ++i, x += hx) {

// вычисляем значение функции

y[i] = f (x);

// запоминаем минимальное и максимальное значения

if (y[i] < ymin) ymin = y[i];

if (y[i] > ymax) ymax = y[i];

}

hy = (ymax - ymin) / (SCREENH - 1);

yz = (int)floor (ymax / hy + 0.5);

xz = (int)floor (-a / hx + 0.5);

// Рисование осей координат

for (j = 0; j < SCREENH; ++j) {

for (i = 0; i < SCREENW; ++i) {

if (j == yz && i == xz)

screen[i][j] = '+'; // '.', '?', '+'

else if (j == yz)

screen[i][j] = '-';

else if (i == xz)

screen[i][j] = '|';

else

screen[i][j] = ' ';

}

}

// Рисование графика функции

for (i = 0; i < SCREENW; ++i) {

j = (int)floor ((ymax - y[i]) / hy + 0.5);

screen[i][j] = '.'; // символ начертания графика

}

// Вывод результата в файл или в стандартный поток stdout

for (j = 0; j < SCREENH; ++j) {

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

fputc (screen[i][j], fout);

fprintf (fout, "\n");

}

}

// Определение заданной функции

double f (double x)

{

return sin (3.0*x) * exp (-x / 3.0);

//return x * x - 3;

}

int main (void)

{

// Вывод графика в стандартный поток (консоль)

plot (stdout, 0.0, 10.0, f);

printf(“\n\n ... Press any key: “);

_getch();

return 0;

}

В программе используется указатель на файл, который может быть стандартным потоком, т. е. экраном дисплея. В главной функции main() происходит обращение к функции рисования графика plot(), в которую вводят фактические параметры, в частности файл – это stdout, т. е. стандартный поток, 0.0 – это левая граница оси абсцисс, 10.0 – правая граница оси абсцисс, f – имя функции с описанием зависимости y = f(x).

Пример выполнения программы представлен на рис. 11.6.

Р ис. 11.6. Пример построения графика функции на консоли

Задание 5

  1. Выполните вывод графика в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

  2. Проанализируйте программу с целью возможного улучшения вида графика заданной функции.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]