// Done by TheTutor -- 10/8/01
// Перевод © 2005 Евгений Казеко
// www.gamecoder.kazeko.com
// evgeniy@kazeko.com
/*
Этот "урок" посвящен указателям на функции -- Подразумевается, что вы знаете,
что такое указатель и представляете в общих чертах, как работают указатели.
Итак, мы напишем функцию "printName", параметром которой и будет указатель
на функцию. Это позволит нам добиться от "printName" возможности печати имени
одним из нескольких желаемых способов.
Вдобавок, мы напишем еще две функции:
horzPrint() -- Печатает имя по горизонтали
vertPrint() -- Печатает имя по вертикали
Пока что все просто, верно? Если вы слегка запутались, не беспокойтесь,
все станет понятным :)
*/
#include <stdio.h>
// Эта функция принимает char*, передаваемый как параметр, и печатает его по
// горизонтали (то есть так, как обычно печатается текст)
void horzPrint(char*);
void vertPrint(char*); // Эта функция принимает char*, передаваемый как параметр, и печатает его
// по вертикали -- Если передать "game", то слово напечатается вот так:
// g
// a
// m
// e
// Вот здесь и происходит все "волшебство"
// Первый параметр (char*) это имя, которое будет напечатано
// А это что еще за мешанина -- void (*print)(char*) ???
// Это как раз то место, про которое мы говорим, что функция принимает указатель на функцию.
// "void" это возвращаемый тип указателя на функцию (обратите внимание, что horzPrint()
// и vertPrint() обе возвращают void)
// (*print) это "имя" указателя на функцию. Что здесь важно, это '*'
// перед "print" -- '*' означает, что это указатель на функцию.
// Мы могли бы назвать функцию "spitOutToScreen", если бы захотели
// (т.е. заменить "print" на "spitOutToScreen")
// И наконец, "char*" это то, что наша "функция" принимает в качестве параметра (параметров)
// Это очень похоже на "нормальное" объявление функции.
// Еще раз, обратите внимание что horzPrint() и vertPrint() принимают char* и ТОЛЬКО char*
// в качестве входных параметров.
void printName(char*, void (*print)(char*));
int main()
{
char name[] = "TheTutor"; // Это имя -- классное имя, по мнению автора обучалки :)
// Сперва напечатаем его вертикально
printName(name,vertPrint);
// А теперь напечатаем его горизонтально
printName(name,horzPrint);
return 0; // И все -- программа завершена
}
// Эта функция принимает "имя" ("name") и печатает его горизонтально (т.е. просто
// печатает его на экран)
void horzPrint(char *name)
{
// Проверка на ошибку -- Убедимся, что мы получили существующий указатель
if(!name)
return;
printf("%s",name); // Просто печатаем имя
}
// Эта функция принимает "имя" ("name") и печатает его вертикально
// (т.е. печатает каждую букву на новой строке)
void vertPrint(char *name)
{
int index = 0; // Это индекс печатаемой буквы в "name"
// Проверка на ошибку -- Убедимся, что мы получили существующий указатель
if(!name)
return;
// Пока мы НЕ достигли конца "name"
while(name[index] != '\0')
{
printf("%c",name[index++]); // Печатаем "текущую букву" имени
// и увеличиваем index на 1 ПОСЛЕ того, как
// буква напечатана
printf("\n"); // Переходим на следующую строку
}
}
// Эта функция принимает печатаемое имя "name" и указатель на функцию, который
// указывает на функцию, реализующую способ, которым следует печатать "name".
void printName(char *name, void (*print)(char*))
{
print(name); // Печатаем имя (оно будет напечатано тем стилем, который
// определен указателем функции).
printf("\n"); // После этого напечатаем "переход строки"
}
/*
Давайте повторим:
Надеюсь, очевидно то, что синтаксис указателей на функции ОЧЕНЬ ПОХОЖ
на "нормальные объявления функции" -- Рассмотрим функцию еще раз:
void printName(char*, void (*print)(char*));
|
|__ Тип, возвращаемый функцией printName() (т.е. нет возвращаемого типа)
void printName(char*, void (*print)(char*));
|
|__ Имя функции (как и для любой объявляемой вами функции, вы выбираете его)
void printName(char*, void (*print)(char*));
|
|__ Первый "входной параметр" функции, она принимает char* (массив char)
void printName(char*, void (*print)(char*));
|
|__ Эта мешанина "void (*print)(char*)" определяет
второй входной параметр printName(), которым
является указатель на функцию
/////////////////// А теперь рассмотрим подробно указатель на функцию
void (*print)(char*)
|
|__ Возвращаемый тип указателя на функцию (т.е. нет возвращаемого типа)
void (*print)(char*)
|
|__ Имя указателя на функцию. Здесь важен символ '*'. Этот символ
говорит компилятору, что "это указатель на функцию" -- Имя "print"
мы выбираем, как и для любой другой "функции".
void (*print)(char*)
|
|__ Это первый (и единственный) параметр, передаваемый указателю
на функцию. Им является char* (массив char)
Надеюсь, что эта обучалка прояснила запутанный синтакс того, что программисты
называют "указатели на функции".
*/
// Перевод © 2005 Евгений Казеко
// www.gamecoder.kazeko.com
// evgeniy@kazeko.com
|