В ситуациях подобного рода можно использовать typedef. Например, в программе можно было бы предусмотреть следующие операторы:
typedef void (*V_FP_CHARP)(char *); void show (V_FP_CHARP fp, char *);
V_FP_CHARP pfun;
618 Глава 14
Если вы склонны к приключениям, можете объявить и инициализировать массив таких указателей:
V_FP_CHARP arpf[4] = {ToUpper, ToLower, Transpose, Dummy};
Если затем модифицировать функцию showmenu() так, чтобы она превратилась в тип int и возвращала значение 0, когда пользователь вводит символ и, значение 1 — когда 1, значение 2 — когда t и т.д., то цикл, содержащий switch, можно заменить приведенным ниже кодом:
index = showmenu();
while (index >= 0 && index <= 3)
{
strcpylcopy, line); /* сделать копию для show() */
show(arpf[index] , copy); /* использовать выбранную функцию */ index = showmenu();
}
Нельзя иметь массив функций, но можно иметь массив указателей на функции.
К этому моменту вы ознакомились со всеми четырьмя способами применения имени функции: в определении функции, в объявлении функции, в вызове функции и в качестве указателя (рис. 14.4).

Рж. 14.4. Использование имени функции
В плане поддержки меню функция showmenu() демонстрирует несколько приемов. Прежде всего, код
ans = getchar(); // получить ответ
ans = tolower(ans); // преобразовать в нижний регистр
и
ans = tolower(getchar());
отражает два способа преобразования пользовательского ввода в один регистр, так что не приходится выполнять проверку для ' и' и ' U' и т.д.
Функция eatline() избавляется от оставшейся части введенной строки. Это полезно по двум причинам. Во-первых, при выборе действия в меню пользователь набирает букву, а затем нажимает клавишу , что приводит к генерации символа новой строки. Если первым делом не избавиться от этого символа, он будет прочитан как следующий ответ. Во-вторых, предположим, что вместо буквы и пользователь вводит слово uppercase целиком. Без функции eatline() программа трактовала бы каждый символ слова uppercase как отдельный ответ. Благодаря eatline(), программа обрабатывает символ и и отбрасывает оставшуюся часть строки.
Структуры и другие формы данных 619
Далее, функция showmenu() спроектирована так, чтобы возвращать в программу только допустимые варианты выбора. Для содействия в этом применяется стандартная библиотечная функция strchr() из заголовочного файла string.h:
while (strchr("ulton", ans) == NULL)
Эта функция ищет местоположение первого вхождения символа ans в строке "ulton" и возвращает указатель на него. Если символ не найден, возвращается нулевой указатель. Таким образом, использованная нами в цикле while проверка удобнее конструкции следующего вида:
while (ans != [n] && ans != '1' && ans != ' t' && ans != 'o' && ans != 'n')
Чем больше вариантов приходится проверять, тем более удобным становится применение функции strchr().
Ключевые понятия
Информация, необходимая при решении задачи по программированию, часто выходит за рамки одиночного числа или списка чисел. Программа может иметь дело с сущностью или коллекцией сущностей, обладающих множеством свойств. Например, заказчик может быть представлен с помощью его имени, фамилии, адреса, номера телефона и других сведений; DVD-диск с фильмом может быть описан посредством его названия, продавца, длительности фильма, стоимости и прочих данных. Структура С позволяет собирать всю информацию вместе в одном элементе. Это очень удобно для организации программы. Вместо того чтобы хранить информацию в разрозненных переменных, все связанные данные сохраняются в одном месте.
При проектировании структуры часто полезно разработать пакет функций и в дальнейшем иметь дело только с ним. Например, вместо написания множества операторов printf() каждый раз, когда требуется отобразить содержимое структуры, можно написать функцию отображения, которая принимает структуру (или ее адрес) в качестве аргумента. Поскольку вся информация находится в структуре, для функции достаточно только одного аргумента. Если бы данные были помещены в отдельные переменные, для каждой порции данных пришлось бы предусмотреть свой аргумент. Кроме того, если вы, скажем, добавите в структуру еще один член, то нужно будет переписать функции, но не их вызовы, что является большим удобством во время модификации проектного решения.
Объявление объединения во многом похоже на объявление структуры. Однако члены объединения совместно используют одно и то же пространство памяти, и в каждый конкретный момент времени только один член может содержать данные. По существу объединение позволяет создать переменную, которая может содержать одно значение, но разных типов.
Читать дальше