Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Максимов_электронный_учебник_текст.doc
Скачиваний:
42
Добавлен:
01.06.2015
Размер:
3.24 Mб
Скачать

Void f3(float) (...) // Определение функции

Int* f4(char *){...} // Определение функции

char (*ptl)(int); // Указатель на функцию

char (*pt2)(int); // Указатель на функцию

void (*ptr3)(float) = f3; // Инициализированный указатель

void main(){

ptl — f1; // Ошибка - несоответствие сигнатур

pt2 = f3; // Ошибка - несоответствие типов

// (значений и сигнатур)

ptl = f4; // Ошибка - несоответствие типов

ptl = f2; // Правильно

pt2 = ptl; // Правильно

char с = (*ptl)(44); // Правильно

с = (*pt2)('\t'); // Ошибка - несоответствие сиг-натур

}

Указатели на функции могут быть объединены в массивы. Например, float (*ptrArray)(char)[4]; описание массива с именем ptrArray из четырех указателей на функции, каждая из которых имеет параметр типа char и возвращает значение типа float. Чтобы обратиться, например, к третьей из этих функций, потребуется такой оператор:

floatа = (*ptrArray[2])('f');

Как обычно, индексация массива начинается с 0, и поэтому третий элемент массива имеет индекс 2.

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

typedef float (*PTF)(float);

typedef char *(*PTC)(char);

typedef void (*PTFONC)(PTF, int, float);

Здесь ptf имя типа "указатель на функцию с параметром типа float, возвращающую значение типа float". ptcимя типа "указатель на, функцию с параметром типа char, возвращающую указатель на тип char”. ptfunc - имя типа "указатель на функцию, возвращающую пустое значение (типа void)". Параметрами для этой функции служат: ptfуказатель на функцию float имя (float), выражение типа int и выражение типа float. (В определение имени типа ptfunc вошел только что определенный тип с именем ptf.)

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

PTF ptfloat1, ptfloat2[5];//Указатель и массив указателей

//на функции float имя(float)

PTC ptchar;// Указатель на функцию char *(char)

PTFUNC ptfunc[8];// Массив указателей на функции

Опыт работы на языках Си и Си++ показал, что даже не новичок в области программирования испытывает серьезные неудобства, раз­бирая синтаксис определения конструкций, включающих указатели на функции. Например, не каждому сразу становится понятным такое определение прототипа функции [6,11]:

void qsort(void *base, size_t nelem, size_t width,

int (*fcmp)(const void *pl, const void *p2));

Это прототип функции быстрой сортировки, входящей в стандартную для системы UNIX и для языка ANSI Си библиотеку функций. Прототип находится в заголовочном файле stdlib.h. Разберем элементы прототипа и напишем программу, использующую указанную функцию. Функция qsort() сортирует содержимое таблицы однотипных элементов, постоянно вызывая функцию сравнения, подготовленную пользователем. Для вызова функции сравнения ее адрес должен заместить указатель fcmp, специфицированный как формальный параметр. Итак, для использования qsort() программист должен подготовить таблицу сортируемых элементов в виде одномерного массива фиксированной длины и написать функцию, позволяющую сравнивать два любых элемента сортируемой таблицы. Остановимся на параметрах функции qsort ():

baseуказатель на начало таблицы сортируемых элементов (адрес 0-го элемента массива);

nelem количество элементов в таблице (целая величина, не больше размера массива);

width размер элемента таблицы (целая величина, определяющая в байтах размер одного элемента массива);

fcmp указатель на функцию сравнения, получающую в качестве параметров два указателя pi, р2 на элементы таблицы и возвращающую в зависимости от результата сравнения целое число:

если *pl < *р2, femp возвращает целое < 0;

если *pl = *p2, fcmp возвращает 0;

если *pl > *p2, fcmp возвращает целое > 0.

При сравнении символ "меньше чем" (<) означает, что после сортировки левый элемент отношения *pl должен оказаться в таблице перед правым элементом *р2, т.е. значение *pi должно иметь меньшее значение индекса в массиве, нежели *р2. Аналогично (но обратно) определяется расположение элементов при выполнении соотношения "больше чем" (>).

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

//Программа 6.14

#include "stdafx.h"

#include <iostream>

#include <stdlib.h> // Для функции qsort()

#include <string.h> // Для сравнения строк- .strcmpO

// Определение функции для сравнения:

int sravni(const void *a, const void *b) {

unsigned long *pa = (unsigned long *)a,

*pb = (unsigned long *)b;

return strcmp((char *)*pa, (char *)*pb);

}

void main() {

char *pc[] = {"Ivanov", "Cidorov", "Petrov", "Antonov"};

int i, n = sizeof(pc)/sizeof(pc[0]);

std::cout << "\n before sorter:\n";

for(int i = 0; i < n; i++) std::cout<<"\t"<< pc[i];

qsort((void *)pc, // Адрес начала сортируемой "Таблицы

n, // Количество элементов сортируемой таблицы

sizeof(pc[0]), // Размер одного элементе

sravni); // Имя функции сравнения (указатель)

std::cout << "\n After sorter:\n";

for(i = 0; i < n; i++) std::cout<<"\t"<< pc[i];

getchar();

}

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

До сортировки:

Иванов Сидоров Петров Антонов

После сортировки:

Антонов Иванов Петров Сидоров

Для выполнения сравнения строк (а не элементов массива рс[ ]) в функции sravni() использована библиотечная функция strcmp(), прототип которой в заголовочном файле string. h имеет вид

int strcmp(const char *sl, const char *s2) ;

Функция strcmp() выполняет беззнаковое сравнение строк, связанных с указателями s1 и s2. Сравнение выполняется без учета регистров набора букв латинского алфавита. Функция выполняет сравнение посимвольно, начиная с начальных символов строк и до тех пор, пока не встретятся несовпадающие символы либо не закончится одна из строк.

Прототип функции strcmp() требует, чтобы параметры имели тип (const char *). Входные параметры функции sravni() имеют тип (const void *), как предусматривает определение функции qsort(). Необходимые преобразования для наглядности выполнены в два этапа. В теле функции sravni() определены два вспомогательных указателя типа (unsigned long *), которым присваиваются значения адресов элементов сортируемой таблицы (элементов массива рс[ ]) указателей). В свою очередь, функция strcmp() получает адреса символьных строк. Таким образом, выполняется сравнение не элементов массива char* рс[ ], а тех строк, адреса которых являются значениями pc[i]. Однако функция qsort() работает с массивом рс[] и меняет местами только значения его элементов. Последовательный перебор массива рс[] позволяет в дальнейшем получить строки в алфавитном порядке, что иллюстрирует результат выполнения программы. Так как pc[i] указатель на некоторую строку, то его разыменование в операции вывода « в поток cout выполняется автоматически.

Если не использовать вспомогательных указателей ра, рb, то функцию сравнения строк можно вызвать из тела функции sravni() таким оператором:

return strcmp((char *)(*(unsigned long *)a), (char *)(*(unsigned long *)b));

Здесь каждый родовой указатель (void *) вначале преобразуется к типу (unsigned long *). Последующее разыменование "достает" из четырех смежных байтов значение соответствующего указателя pc[i]. И уж затем преобразование (char *) формирует указатель на строку, который нужен функции strcmp().