Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
BOOK_С_INTUIT.docx
Скачиваний:
31
Добавлен:
11.02.2015
Размер:
6.34 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];

if (i < N) {

if ((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 %c\n", Lines[i]);

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

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

bsort (Lines, n, greater);

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

printf("\t %c\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. В программу добавьте описание кубической и параболической функций. Напишите необходимые строчки программного кода для запроса о построении графика соответствующей функции.

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