Здравствуй читатель, это 2 часть про функции в C++, и думаю даже не заключительная. И так, начнем.
Функции, определяемые пользователями
Нередко приходится писать собственные функции, в частности, при разработке классов. Я могу сказать, что конструировать собственные функции довольно интересно, и мы сейчас попробуем рассмотреть данный процесс. Давайте сначала рассмотрим пример программы:
*знак решетки*include
void simon(int); // прототип функции simon()
int main()
setlocale(LC_ALL,»RU»);
using namespace std;
simon(7); // вызов функции simon()
int count;
cin >> count;
simon(count) // вызов функции simon()
cout return 0;
)
void simon(int n) // определение функции simon()
using namespace std;
cout >
Результат в консоли таков:
Саймон говорит тебе нужно дотронуться до кончика носа 7 раз(-а)
Язык программирования Си. Урок 10. Функции
Выберите целое число: 666
Саймон говорит тебе нужно дотронуться до кончика носа 666 раз(-а)
Готово!
Напомню, что если вы забыли, что такое прототип функции и определение функции загляните в мою 1 часть по функциями — ссылка . Продолжаем, я предположил что нужно добавить еще одну функцию, которая определяется пользователем. Мы должна предоставить прототип функции перед ее использованием, обычно прототипы пишет выше функции main(). А теперь разберу, что делает сама программа, функция main() вызывает функцию simon() 2 раза:
1 раз — с аргументом 7
2 раз — с аргументом-переменной count
Между этими вызовами пользователь вводит целое число, которое присваивается переменной count.
Форма функции
Сначала идет заголовок функции. Затем в фигурных скобках тело функции. Форма определения функции может быть обобщена следующим образом:
тип имя_функции(список_аргументов)
операторы;
>
Заголовки функций
Функция simon() имеет такой заголовок:
void simon(int n)
Void означает, что функция simon() не имеет возвращаемого значения. Таким образом, первый вызов функции имеет вид:
Но так как присутствует void, simon() не возвращает значения и ее нельзя использовать таким образом:
simple = simon(3); // не допускается
Int n в скобках означает, что функция simon() будет вызываться с 1 аргументом типа int. В данном случае n — это новая переменная, которой присвоили значение переданное во время вызова функции. То есть ей присваивается значение 3.
Использование определяемых пользователем функций, имеющих возвращаемое значение
Рассмотрим такую программу:
*знак решетки*include
int stonelib(int); // прототип функции
int main()setlocale(LC_ALL,»RU»);
using namespace std;
int stone
cout
cin >> stone;
int pounds = stonetolb(stone);
cout
cout
5 Трюков Excel, о которых ты еще не знаешь!
return 0;
>
int stonetolb(int sts)return 14 * sts;
>
Результат данной программы:
Введите вес в стоунах: 15
15 стоун(-ов) = 210 фунт(-ов)
Данная программа переводит стоуны в фунты.
В функции main() программа используется объект cin для ввода значения целочисленной переменной stone. Это значение передается функции stonetolb() в качестве аргумента и присваивается переменной sts в этой функции. Функция stonetolb() используется ключевое слово return для возврата значения 14*sts в функцию main().
Это как раз пример того, что после оператор return не обязательно должно следовать просто число. Как можно было видеть в приведенных примерах, прототип функции описывает ее интерфейс, по-другому способ взаимодействия функции с остальной частью программы. Список аргументов показывает, какой тип информации передается функции, а тип функции указывает на тип возвращаемого ею значения.
Местоположение директивы using в программах с множеством функций
В приведенных мной примерах директива using присутствует в каждом примере. Это объясняется тем, что каждая функция использует объект cout и потому должна иметь доступ к определению cout в пространстве std. (Если не знаете, что это такое то прочитайте мою первую статью — ссылка ). Еще один способ сделать пространство имен std доступным для обеих функций — это размещение директивы за пределами функций(перед ними), там где и заголовочные файлы. Предпочтительней поступать так, что у всех функция был доступ к пространству имен.
Конец
Спасибо если вы дочитали до этого текста. Я пытался изложить понятно. Дайте знать если вы открыли для себя что-то новое или что-то поняли. Советую прочитать 1 часть про функции в С++, если вы не знаете некоторые термины, ссылки ниже.
Моя самая первая статья — ссылка
Моя вторая статья — ссылка
Моя статья про функции(часть 1) — ссылка
Спасибо за прочтение, до свидания
Источник: dzen.ru
4.1. Общие сведения о функциях
< Операторы основной функции , среди которых могут операторы вызова функций f1, f2, . fn >Тип _ результата f1( Список _ переменных ) < Операторы >Тип _ результата f2( Список _ переменных ) < Операторы >. Тип _ результата fn( Список _ переменных ) < Операторы >Для того , чтобы функция вернула какое — либо значение , в ней должен быть оператор return значение ; Для вызова функции необходимо указать имя функции и в круглых скобках список передаваемых в функцию значений . 4.2. Передача параме тров в С/С++ Параметры , указанные в заголовке функции , называются формальными . Параметры , передаваемые в функцию , называются фактическими . При обращении к функции фактические параметры передают свое значение формальным и больше не изменяются . Типы , количество и порядок следования формальных и фактических параметров должны совпадать . С помощью оператора return из функции возвращается единственное значение . Для того чтобы функция возвращала не только скалярное значение , то в качестве передаваемого в функцию значения можно использовать указатель . Рассмотрим все выше изложенные теоретические положения на примере решения практических задач . ЗАДАЧА 4.1. Вводится последовательность целых чисел , 0 конец последовательности . Найти минимальное среди простых чисел и максимальное , среди чисел , не являющихся простыми . Целое число называется простым , если оно делится нацело только на самого себя и единицу . Напомним , что алгоритм проверки , что число N является простым состоит в следующем : если разделим N без остатка хотя бы на одно число в диапазоне от 2 до N/2, то число не является простым . Если не найдем ни одного делителя числа , число N простое . Проверку является ли число N простым оформим в виде отдельной функции с именем prostoe . Входным параметром функции будет целое число N, функция будет возвращать значение 1, если число простое и 0 в противном случае . #include using namespace std; int prostoe(int N) < int i,pr; if (N<1) pr=0; else for(pr=1,i=2;i<=N/2;i++) if (N%i==0) return pr;
> int main(int argc, char* argv[]) < int kp=0,knp=0,min,max,N; for (cout << «N=», cin>>N; N!=0; cout < kp++; if (kp==1) min=N; else if (Nelse < knp++; if (knp==1) max=N; else if (N>max) max=N; > if (kp>0) cout 0) cout ЗАДАЧА 4.2. Вводится последовательность из N целых чисел , найти среднее арифметическое совершенных чисел и среднее геометрическое простых чисел . В этой программе кроме простых чисел будут фигурировать совершенные . Число называется совершенным , если сумма всех делителей , меньших его самого равна самому числу . При решении этой задачи понадобятся две функции : ● функция prostoe , ● функция soversh , которая определяет является ли число совершенным ; входным параметром функции будет целое число N, функция будет возвращать значение 1, если число совершенным и 0 в противном случае . #include #include using namespace std; int prostoe(int N) < int i,pr; if (N<1) pr=0; else for(pr=1,i=2;i<=N/2;i++) if (N%i==0) return pr; > int soversh(int N) < int i,S; if (N<1) return 0; else for(S=0,i=1;i<=N/2;i++) if (N%i==0) S+=i; if (S==N) return 1; else return 0; >int main(int argc, char* argv[]) < int i,N,X,S,kp,ks;
long int P; cout <<«N p19 ft30»>for(kp=ks=S=0,P=1,i=1;i<=N;i++) < cout <<«X p23 ft30»>if (prostoe(X)) < kp++;P*=X; >if (soversh(X)) < ks++;S+=X; >> if (kp>0) coutelse cout0) cout Рассмотрим уже известную задачу , но решим ее с использованием функций . ЗАДАЧА 4.3. Дано натуральное число N. Определить самую большую цифру и ее позицию в числе (N=573863, наибольшей является цифра 8, ее позиция четвертая слева ). Первым этапом решения этой задачи будет нахождение количества разрядов в числе , для нахождения можно составить функцию kol_raz, блок — схема которой представлена на рис . 4.1 Рисунок 4.1: Функция определения количества разрядов в числе Блок — схема основного алгоритма представлена на рис . 4.2. #include #include int kol_raz(int M) < int k=1; while(M>9)
Рисунок 4.2: Блок — схема решения задачи 4.3 < k++; M/=10; >return k; > int main()
< long int N,M,kol=1; int max,pos,i; printf(«n N p51 ft30»>// Ввод числа N. scanf(«%ld», // Вычисление количества позиций в числе (kol). kol=kol_raz(N); printf(«V chisle %ld — %ld razryadovn»,N,kol); // Вычисление максимальной цифры в числе, и ее номера. for(M=N, max=-1, i=kol;i>0;i—) < if (M%10>max) < max=M%10; pos=i; >M/=10; > // Вывод на экран максимальной цифры в числе, и ее номера. printf(«V chisle %ld maximalnaya tsifra %d, ee nomer %dn»,N,max,pos); >
4.3. Рекурсивные функции в С/С++
Под рекурсией в программировании понимается вызов функции из тела ее самой . В рекурсивных алгоритмах функция вызывает саму себя до выполнения какого — то условия . Рассмотрим реализацию несколько хорошо известных алгоритмов с помощью рекурсивных функций . 1. Функция long int factoial(int n) предназначена для вычисления факториала числа n. Рисунок 4.3: Блок — схема функции вычисления факториала #include using namespace std; long int factorial(int n) < if (n<=1) return n;
else return n*factorial(n-1); > int main() < int i; long int f; cout<<«i p62 ft34»>cout> 2. Функция float stepen(float a, int n) предназначена для возведения числа a в целую степень n. Рисунок 4.4: Блок — схема рекурсивной функции возведения числа в целую степень #include using namespace std; float stepen(float a, int n) < if (n==0) return(1); else if (n<0) return(1/stepen(a,-n)); else return(a*stepen(a,n-1)); >int main() < int i; float s,b; long int f; coutcin>>b; cout<<«i p19 ft30»>cin>>i; s=stepen(b,i); cout> 3. Функция long int fibonachi(int n) предназначена для вычисления n- го числа Фибоначчи . Если нулевой элемент последовательности равен 0, первый 1, а каждый последующий равен сумме двух предыдущих , то это последовательность чисел Фибоначчи (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . ). #include using namespace std; long int fibonachi(unsigned int n) < if ((n==0)||(n==1)) return(n); else return(fibonachi(n-1)+fibonachi(n-2)); >int main(int argc, char* argv[]) < int i; long int f; cout<<«i p68 ft29»>cout> 4.4. Облас ть видимос ти переменных в функциях С/С++, расширение облас ти видимос ти переменных По месту объявления переменные в языке Си можно разделить на три класса : ● локальные переменные , которые объявляются внутри функции и доступны только в ней . Например : int main() < float s; s=4.5; >int f1() < int s; s=6; >int f2() < long int s; s=25; >В функции main определена вещественная переменная s ( типа float ), ей присвоено значение 4.5, в функции f1 есть другая переменная s ( типа int ), ей присвоено значение 6, а в функции f2 есть еще одна переменная s ( типа long int ), ей присвоено значение 25. ● глобальные переменные , которые описаны до всех функций , они доступны из любой
функции . Например : #include float s; int main() < s=4.5; >int f1() < s=6; >int f2() < s=25; >Определена глобальная переменная s ( типа float ), в функции main ей присваивается значение 4.5, в функции f1 присваивается значение 6, а в функции f2 присваивается значение 25. ● формальные параметры функций описываются в списке параметров функции . Рассмотрим особенности использования локальных и глобальных переменных в программах на С ++: 1. Область видимости и использования локальной переменной ограничена функцией , где она определена . 2. Глобальные переменные объявляются вне любых функций и их областью видимостью является весь файл . 3. Одно и тоже имя может использоваться при определении глобальной и локальной переменной . В этом случае в функции , где определена локальная переменная действует локальное описание , вне этой функции « работает » глобальное описание . Из функции , где действует локальное описание переменной можно обратиться к глобальной переменной с таким же именем , используя оператор расширения области видимости :: переменная . Рассмотрим это на примере #include using namespace std; float pr=100.678; int prostoe (int n) < int pr=1,i; if (n<0) pr=0; else for (i=2;i<=n/2;i++) if (n%i==0)// Вывод локальной переменной cout // Вывод глобальной переменной cout> int main() < int g; coutif (prostoe(g)) cout
Результаты работы программы g=7 local pr=1 global pr=100.678 g — prostoe Press any key to continue
4.5. Перегрузка и шаблоны функций
Язык С ++ позволяет связать с одним и тем же именем функции различные определения , т . е . возможно существование нескольких функций с одним и тем же именем . У этих функций может быть разное количество параметров или разные типы параметров . Создание двух или более функций с одним и тем же именем называется перегрузкой имени функции . Перегруженные функции следует создавать , когда одно и то же действие следует выполнить над разными типами входных данных , а иногда одна и также функция над разными типами входных данных выполняется с помощью разных алгоритмов . Функция возведения в степень не определена при 0 0 и при возведении отрицательного x в дробную степень n=k/m в случае четного m. Попробуем с использованием механизма перегрузки написать более универсальную , чем функция pow ( из библиотеки math.h) функцию Pow. Наша функция в случаях неопределенности операции возведения в степень будет возвращать 0. #include #include using namespace std; float Pow(float a, int k, int m) //Функция возведения вещественного числа в степень k/m. < cout0) return(exp((float)k/m*log(a))); else if (m%2!=0) return (-(exp((float)k/m*log(-a)))); > float Pow(float a, int n) //Функция возведения вещественного числа в целую степень n. < if (a==0) else if (n==0) else if (n <0) return(1/pow(a,-n)); else return(a*pow(a,n-1)); >int Pow(int a, int n) //Функция возведения целого числа в целую степень n.
Источник: studfile.net
Объявление и описание функций в C++ Builder
Функции представляют собой программные блоки, которые могут вызываться из разных частей программы. При вызове в них передаются некоторые переменные, константы, выражения, являющиеся аргументами, которые в самих процедурах и функциях воспринимаются как формальные параметры. При этом функции возвращают значение определенного типа, которое замещает в вызвавшем выражении имя вызванной функции. Например, оператор:
I = 5*F(X);
вызывает функцию Fс аргументом X, умножает возвращенное ею значение на 5 и присваивает результат переменной I.
Допускается также вызов функции, не использующий возвращаемого ею значения. Например:
В этом случае возвращаемое функцией значение игнорируется. Функция описывается следующим образом:
тип_возвращаемого_значения имя_функции(список_параметров)
Первая строка этого описания, содержащая тип возвращаемого значения, имя функции и список параметров, называется заголовком функции. Тип возвращаемого значения может быть любым, кроме массива и функции. Могут быть также функции, не возвращающие никакого значения. В заголовке таких функций тип возвращаемого значения объявляется void.
Если тип возвращаемого значения не указан, он по умолчанию считается равным int.
Хотя тип возвращаемого значения int можно не указывать в заголовке функции, не следует использовать эту возможность. Всегда указывайте тип возвращаемого значения, кроме главной функции main. Указание типа делает программу более наглядной и предотвращает возможные ошибки, связанные с неправильным преобразованием типов.
Список параметров, заключаемый в скобки, в простейшем случае (более сложные формы задания списка параметров будут рассмотрены позднее) представляет собой разделяемый запятыми список вида:
тип_параметра идентификатор_параметра
double FSum(double X1, double X2, int h)
объявляет функцию с именем FSum, с тремя параметрами X1, X2 и А, из которых первые два имеют тип double, а последний int. Тип возвращаемого результата — double.
Имена параметров X1, X2 и А локальные, т.е. они имеют значение только внутри данной функции и никак не связаны с именами аргументов, переданных при вызове функции. Значения этих параметров в начале выполнения функции равны значениям аргументов на момент вызова функции.
Ниже приведен заголовок функции, не возвращающей никакого значения:
void SPrint(AnsiString S)
Она принимает один параметр типа строки и, например, отображает его в каком-нибудь окне приложения.
Если функция не принимает никаких параметров, то скобки или оставляются пустыми, или в них записывается ключевое слово void. Например:
void F1(void)
void F1()
Всегда указывайте void в списке параметров, если функция не получает никаких параметров. Эта делает программу более переносимой.
Роль пустого списка параметров функции в С++ существенно отличается от аналогичного списка в языке С. В С это означает, что все проверки аргументов отсутствуют (т.е. вызов функции может передать любой аргумент, который требуется). А в С++ пустой список означает отсутствие аргументов. Таким образом, программа на С, использующая эту особенность, может сообщить о синтаксической ошибке при компиляции в С++.
Как правило (хотя формально не обязательно), помимо описания функции в текст программы включается также прототип функции ее предварительное объявление. Прототип представляет собой тот же заголовок функции, но с точкой с запятой «;» в конце. Кроме того, в прототипе можно не указывать имена параметров.
Если вы все-таки указываете имена, то их областью действия является только этот прототип функции. Вы можете использовать те же идентификаторы в любом месте программы в любом качестве. Таким образом, указание имен параметров в прототипе обычно преследует только одну цель — документирование программы, напоминание вам или сопровождающему программу человеку, какой параметр что именно обозначает.
Примеры прототипов приведенных выше заголовков функций:
double FSum(double X1,double X2, int A); void SPrint(AnsiString S); void F1(void);
double FSum(double, double, int); void SPrint(AnsiString); void F1();
Введение в программу прототипов функций преследует несколько целей. Во-первых, это позволяет использовать в данном модуле функцию, описанную в каком-нибудь другом модуле.
Тогда из прототипа компилятор получает сведения, сколько параметров, какого типа и в какой последовательности получает данная функция. Во-вторых, если в начале модуля вы определили прототипы функций, то последовательность размещения в модуле описания функций безразлична. При отсутствии прототипов любая используемая функция должна быть описана до ее первого вызова в тексте.
Это прибавляет вам хлопот, а иногда при взаимных вызовах функций друг из друга вообще невозможно. И, наконец, прототипы, размещенные в одном месте (обычно в начале модуля), делают программу более наглядной и самодокументированной. Особенно в случае, если вы снабжаете прототипы хотя бы краткими комментариями.
Если предполагается, что какие-то из описанных в модуле функций могут использоваться в других модулях, прототипы этих функций следует включать в заголовочный файл. Тогда в модулях, использующих данные функции, достаточно будет написать директиву #include, включающую данный заголовочный файл, и не надо будет повторять прототипы функций.
Включайте в модуль где-то в одном месте (обычно в начале) прототипы всех описанных в нем ваших функций с краткими комментариями. Это хорошо документирует программу, делает ее нагляднее, позволяет вам не заботиться о последовательности описаний функций. Бели вы хотите, чтобы какие-то из описанных в модуле функций могли использовать другие модули, включайте прототипы этих функций в заголовочный файл.
Обычно функции принимают указанное в прототипе число параметров указанных типов. Однако могут быть функции, принимающие различное число параметров (например, библиотечная функция printf) или параметры неопределенных заранее типов. В этом случае в прототипе вместо неизвестного числа параметров или вместо параметров неизвестного типа ставится многоточие «. «. Многоточие может помещаться только в конце списка параметров после известного числа параметров известного типа или полностью заменять список параметров. Например:
int prf(char* format, . );
Функция с подобным прототипом принимает один параметр format типа char* (например, строку форматирования) и произвольное число параметров произвольного типа. Функция с прототипом:
void Fp(. );
может принимать произвольное число параметров произвольного типа.
Если в прототипе встречается многоточие, то типы соответствующих параметров и их количество компилятором не проверяются.
Объявлению функции могут предшествовать спецификаторы класса памяти extern или static. Спецификатор extern предполагается по умолчанию, так что записывать его не имеет смысла. К функциям, объявленным как extern, можно получить доступ из других модулей программы. Если же объявить функцию со спецификатором static, например:
static void F(void);
то доступ к ней из других модулей невозможен. Это надо использовать в крупных проектах во избежание недоразумений при случайных совпадениях имен функций в различных модулях.
Теперь рассмотрим описание тела функции. Тело функции пишется по тем же правилам, что и любой код программы, и может содержать объявления типов, констант, переменных и любые выполняемые операторы. Не допускается объявление и описание в теле других функций. Таким образом, функции не могут быть вложены друг в друга.
Надо иметь в виду, что все объявления в теле функции носят локальный характер. Объявленные переменные доступны только внутри данной функции. Если их идентификаторы совпадают с идентификаторами каких-то глобальных переменных модуля, то эти внешние переменные становятся невидимыми и недоступными. В этих случаях получить доступ к глобальной переменной можно, поставив перед ее именем два двоеточия «::», т.е. применив унарную операцию разрешения области действия.
Локальные переменные не просто видны только в теле функции, но по умолчанию они и существуют только внутри функции, создаваясь в момент вызова функции и уничтожаясь в момент выхода из функции. Если требуется этого избежать, соответствующие переменные должны объявляться со спецификацией static.
Выход на функции может осуществляться следующими способами. Если функции по должна возвращать никакого значения, то выход из нее происходит или по достижении закрывающей ее тело фигурной скобки, или при выполнении оператора return. Если же функция должна возвращать некоторое значение, то нормальный выход из нее осуществляется оператором return выражение, где выражение должно формировать возвращаемое значение и соответствовать типу, объявленному в заголовке функции. Например:
double FSum(double X1,double X2, int A)
Ниже приведен пример функции, не возвращающей никакого значения:
void SPrint(AnsiString S)
Здесь возврат из функции происходит по достижении закрывающейся фигурной скобки тела функции. Приведем вариант той же функции, использующий оператор return:
void SPrint(AnsiString S)
Прервать выполнение функции можно также генерацией какого-то исключения. Наиболее часто в этих целях используется процедура Abort, генерирующая «молчаливое» исключение EAbort, не связанное с каким-то сообщением об ошибке. Если в программе не предусмотрен перехват этого исключения, то применение функции Abort выводит управление сразу наверх из всех вложенных друг в друга вызовов функций.
Возвращаемое функцией значение может включать в себя вызов каких-то функций. В том числе функция может вызывать и саму себя, т.е. допускается рекурсия. В качестве примера приведем функцию, рекурсивно вычисляющую факториал.
Как известно, значение факториала равно n! = n (n-1) (n-2) . 1, причем считается, что 1! = 1 и 0! = 1. Факториал можно вычислить с помощью простого цикла for (и это, конечно, проще). Но можно факториал вычислять и с помощью рекуррентного соотношения n! = n(n-1)!. Для иллюстрации рекурсии воспользуемся именно этим соотношением. Тогда функция factorial вычисления факториала может быть описана следующим образом:
unsigned long factorial (unsigned long n)
Если значение параметра n равно 0 или 1, то функция возвращает значение 1. В противном случае функция умножает текущее значение n на результат, возвращаемый вызовом той же функции factorial, но со значением параметра n, уменьшенным на единицу. Поскольку при каждом вызове значение параметра уменьшается, рано или поздно оно станет равно 1. После этого цепочка рекурсивных вызовов начнет свертываться и в конце концов вернет значение факториала.
Источник: cubook.pro