Понедельник, 29.04.2024, 17:15
Главная Регистрация RSS поиск
Приветствую Вас, Гость
Меню сайта
Категории раздела
HTML [44]
Visual C++ и MFC [21]
c++ [78]
php [19]
Javascript [15]
C# [51]
загрузки [0]
XNA [10]
создание игр с помощью xna
Наш опрос
Каким языком программирования вы увлекаетесь
Всего ответов: 2420
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Реклама
Главная » Статьи » c++

Введение в мир функций

Введение в мир функций

Всякая задача может быть разбита на подзадачи, каждую из которых можно либо непосредственно представить в виде кода, либо разбить на еще более мелкие подзадачи. Данный метод носит название пошагового уточнения (stepwise refinement). Функции в C++ служат для записи программного кода этих непосредственно решаемых подзадач. Такие функции используются другими функциями, и в конечном счете — функцией main () для решения исходной задачи, с которой, как вы уже знаете, всегда начинает выполняться программа на языке C++. Функции в C++ решают самые разнообразные задачи программирования. Некоторые функции, например getch () и rand (), поставляются в библиотеках. Другие могут быть написаны программистом.

В C++ код, описывающий, что делает функция, называется определением функции (function definition). Формально это выглядит так:

 заголовок_функции 
 {
 инструкции
 }

Все, что стоит перед первой фигурной скобкой, составляет заголовок определения функции, а то, что находится между фигурными скобками, является телом определе­ния функции.

Заголовок функции — это:

 тип имя(список_объявлений_параметров)

Спецификация типа, стоящая перед именем функции, является возвращаемым ти­пом. Он определяет тип значения, возвращаемого функцией (если оно вообще воз­вращается). Механизм возврата значений рассмотрим немного позже.

Имена функций подчиняются тем же ограничениям, что и имена переменных.

Давайте рассмотрим простейший пример создания своих функций. Вы уже писали свою первую программу, которая выводит на экран надпись "Hello, world!”. А теперь давайте напишем свою функцию, которую назовем Say,и которая выводит надпись "Hello, world!” на экран.

 void Say()
 {
 cout<<”Hello, world!”;
 }

В определении функции Say() из предыдущего примера список параметров пуст, то есть объявлений параметров нет. Тело функции состоит из единственной инструкции cout, которая выводит на экран приветствие "Hello, world!”.

В примере в заголовке функции Say() тип возвращаемого значения функции стоит void, с этим типом Вы встречаетесь впервые. Так вот, тип void применяется только для функций и для указателей, которые мы будем рассматривать немного позже; переменные типа void Вы объявлять не можете, компилятор Вам сразу же выведет ошибку. Если Вы указываете тип возвращаемого значения как void (то есть "пусто”) это означает, что Ваша функция не будет возвращать никакого значения. В предыдущем примере функция только выводила надпись на экран и все, то есть никаких значений она возвращать не должна, поэтому тип у нее и указан как void.

В последующем при создании своих функций внимательно разберите что Ваша функция будет делать и для чего она предназначена, определите будет ли функция возвращать какое-либо значение и, если будет, то какое, и после этого только укажите тип возвращаемого значения функции. Например, если Вам вдруг придется написать свою функцию, которая вычисляет косинус числа, то Вы для себя определяете, что функция косинуса должна принять число с плавающей точкой в списке параметров, для этого числа найти значение косинуса, которое тоже будет числом с плавающей точкой, и вернуть это значение туда, откуда функция вызывалась. То есть для данного примера тип функции должен быть float,так как необходимо будет вернуть число с плавающей точкой.

Синтаксически параметры — это идентификаторы, они могут использоваться внутри тела функции. В списке объявлений параметров параметры указываются через запятую. Иногда параметры в определении функции называют формальными параметрами. Тем самым подчеркивается их сущность: формальные параметры — это то, вместо чего будут подставлены фактические значения, передаваемые функции в момент ее вызова. После вызова функции значение аргумента, соответствующее формальному параметру и передаваемое при вызове функции, используется в теле выполняемой функции. В C++ такие параметры являются вызываемыми по значению (call-by-value). Когда применяется вызов по значению, переменные передаются функции как аргументы, их значения копируются в соответствующие параметры функции, а сами переменные не изменяются в вызывающем окружении. В сущности, вызываемые по значению параметры являются локальными в своей функции. Им могут передаваться выражения, значения которых присваиваются этим локальным переменным (параметрам).

Давайте рассмотрим небольшой пример создания функции, которая принимает некоторые параметры. Вы уже знаете, что оператора возведения в квадрат в языке C++ нет, и если какое-то значение нужно возвести в квадрат, то необходимо записывать это значение (например, какую-то переменную) умноженную на себя. Это не совсем удобно. Поэтому давайте напишем свою функцию, которая вычисляет квадрат какого-либо целочисленного значения и сообщает результат.

 int square (int a)
 {
 
 return a*a;
 }

Как видите, функция square() принимает один целочисленный параметр a, в который будет передаваться значение из вызывающей функции, которое необходимо возвести в квадрат. Тип возвращаемого значения для функции

square()- int, то есть функция должна будет вернуть целочисленное значение в вызывающую функцию, что и делает инструкция return с параметром a, в котором хранится результат работы функции (квадрат значения параметра a).

Как вы уже, наверно, догадались строка void main() есть объявление функции с именем main, и которая ничего не возвращает и ничего не принимает в списке параметров. А все программы, которые вы до сих пор писали между фигурных скобок после строки void main(), есть не что иное, как тело функции main.

Так вот, любой код вашей программы должен обязательно находиться в теле какой-либо функции (между фигурных скобок после заголовка функции), и не может "висеть” где-нибудь вне функций.

Еще одно существенное замечание: нельзя определять какую-либо функцию в теле другой функции


Вызов функции

Программа на C++ составляется из одной или более функций, одна из которых — main (). Выполнение программы всегда начинается с функции main (). Когда при выполнении программы встречается имя функции, происходит обращение к этой функции (она вызывается). То есть управление программой передается функции. После того как функция выполнила свою работу, управление возвращается в то место, откуда функция была вызвана — в вызывающее окружение (calling environment).

Обычно функция, которая вызывает какую-либо другую функцию, называется вызывающей функцией, а функция, которую вызывают на выполнение, называется вызываемой функцией.

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

Например вызов функции ожидания нажатия произвольной клавиши на клавиатуре - функция getch(), объявление которой находится в библиотеке conio.h, можно произвести следующим образом

 ....
 getch();
 ....

Некоторые функции возвращают значения, как, например, функция, вычисляющая квадратный корень от числа, возвращает значение этого корня. Если функция возвращает значение, Вы должны принять это значение в какую-либо переменную, вывести на экран либо использовать в составном выражении. Например, в библиотеке math.h определена функция извлекающая квадратный корень sqrt, которая принимает как параметр значение, из которого следует извлечь корень, и возвращает значение этого корня. Как ее можно использовать

 .... 
 int i=2;
 double dbl=sqrt(i);
 cout << sqrt(5);
 .... 

Вызов функции на самом деле является выражением, поэтому его можно использовать как составную часть более сложного выражения. Например:

 ....
 cout << 2*sqrt(3)+1;
 float res=sqrt(sqrt(7)/2)+10;
 ....

Вызвать функцию можно только после объявления функции (то есть ниже объявления).

Объявление функции из стандартной библиотеки выполняется при помощи подключения библиотеки директивой препроцессора #include.

Как объявить и определить свою функцию рассмотрим в следующем разделе



return

Существует несколько способов возврата управления к точке, из которой была вызвана функция:

      - Если функция не должна возвращать результат, управление возвращается либо просто при достижении правой фигурной скобки, завершающей функцию, либо
      - при выполнении оператора return.
      - Если функция должна возвращать результат, то оператор return выражение;

      возвращает значение выражение в обращение к функции.

Таким образом, оператор возврата имеет две формы:

return;

В этом случае, когда выполняется оператор возврата, управление программой немедленно передается обратно в вызвавшую среду. Используется когда функция не возвращает значение.

return выражение;

В этом случае, в вызвавшую среду возвращается также значение выражения, которое следует за ключевым словом return. Это значение должно быть конвертируемым к возвращаемому типу из заголовка определения функции.

Например:

return; не возвращает значения;
return 3; возвращаемое значение = 3;
return (a + b); возвращаемое значение = значению выражения (а + b);

скобки необязательны, используются для улучшения читаемости кода.

В качестве иллюстрации небольшой пример программы.

/* Программа для введеных с клавиатуры трех чисел предлагает 
выполнить след. действия:
проверить на четность, вычислить сумму,
вычислить сред. арифметическое нечетных чисел */


#include < iostream.h >


 // прототипы функции 
 bool IsEven(int ); /* функция проверяет число на четность*/

 int abcMultiple (int, int, int); /* функция вычисляет сумму трех чисел */
 float ArithMean(int, int, int); /* функция вычисляет среднее 
 арифметическое нечетных чисел*/
 // описания функций
 void OutputMenu() /* функция выводит на экран меню программы*/
 {
 cout << "1. Ввод чисел \n"
 "2. Проверка чисел на четность \n"
 "3. Вычислить произведение \n"
 "4. Вычислить среднее арифметическое нечетных чисел \n";
 cout << "\n \n Выберите пункт меню \n";
 return;
 }
 
 int InputNumber() /* функция ввода числа в заданном диапазоне */
 {
 int number = 0;
 do 
 {
 cout << "\n Введите целое число в диапозоне от 0 до 500: ";
 cin >> number;
 } while( number < 0 || number > 500);
 return number;
 }
 
 void main()
 {
 int a = 0, b = 0, c = 0, /* объявление и инициализация переменных 
 целого типа для хранения чисел, введенных пользователем с клавиатуры*/ 
 menuVal = 0; /* объявление и инициализация переменной целого 
 типа для хранения значения выбранного пункта меню */
 
 do 
 {
 OutputMenu(); /*вызов функции OutputMenu*/
 cin >> menuVal;
 switch (menuVal)
 {
 case 1: /* Метка соответствует задаче первого пункта меню */
 a = InputNumber();
 cout << " \n a = " << a;
 b = InputNumber();
 cout << " \n b = " << b;
 c = InputNumber();
 cout << " \n c = " << c;
 break;
 case 2: /* Метка соответствует задаче второго пункта меню */
 if ( IsEven(a) ) cout << "\n а = " << a << " - четное";
 if ( IsEven(b) ) cout << "\n b = " << b << " - четное";
 if ( IsEven(c) ) cout << "\n c = " << c << " - четное";
 break;
 case 3: /* Метка соответствует задаче третьего пункта меню */
 cout << "\n Произведение a*b*c = " 
 << abcMultiple(a, b, c);
 break;
 case 4: /* Метка соответствует 
 задаче четвертого пункта меню */
 cout << "\n Среднее арифметическое нечетных чисел = " 
 << ArithMean(a, b, c);
 break;
 default: /* В случае, 
 если пользователь ввел значение вне диапозона 1-4 */
 cout << "\n Будьте внимательней."
 " Имеется всего 4 пункта меню :)";
 }
 cout << "\n\n Дальше? "
 "\n 0 - Нет, 1 - Да ";
 cin >> menuVal; 
 }while(menuVal);
 return;
 }
 
  
 // описания функций, прототипы функций объявлены выше 
 
 bool IsEven(int val)
 {
 bool valIsEven = val%2 ? false : true;
 return valIsEven;
 }
 
 int abcMultiple (int a, int b, int c)
 {
 return a*b*c;
 }
 
 float ArithMean(int val1, int val2, int val3)
 {
 int Sum = 0, count = 0; /* объявляем вспомогательные переменные 
 для вычисления среднего арифметического Sum/count */
 if ( !IsEven(val1) )
 { 
 count ++;
 Sum += val1;
 }
 if ( !IsEven(val2) )
 {
 count ++;
 Sum += val2;
 }
 if ( !IsEven(val3) )
 {
 count ++;
 Sum += val3;
 }
 if ( count ) return float(Sum)/count; 
 else return 0;
 }

Прототипы функций

Язык C++ позволяет использовать прототипы функций. По сути, возвращаемый тип, идентификатор функции и типы параметров с обязательной точкой с запятой в конце составляют прототип функции. Прототип функции (function prototype) — это объявление функции, но не ее определение. Благодаря явному объявлению возвращаемого типа и списка типов аргументов, в C++ при обращении к функции возможны строгая проверка типов и неявные преобразования типов.

Итак, функция может быть объявлена до того, как она определена. Определение функции может идти позже в этом же файле, браться из библиотеки или из указанного пользователем файла. Прототип функции имеет следующую форму:

 тип имя(список_объявлений_аргументов);

список_объявлений_ аргументов может быть пустым, содержать единственное объявление или несколько объявлений, разделенных запятыми. Если функция не имеет параметров, допускается использование ключевого слова void. В C++ функ­ция с пустым списком параметров выглядит как имя_функции(). Такая информация позволяет компилятору отслеживать совместимость типов. Аргументы преобразуются к указанным в объявлении типам так же, как в случае присваивания.

Рассмотрим пример прототипа функции min, которая принимает два целочисленных параметра, находит минимальное из них и возвращает его

 int min(int, int) ;

И возвращаемый тип функции, и типы аргументов в списке указываются явно. Определение функции min () должно соответствовать этому объявлению. Прототип функции может также содержать имена аргументов. В случае min () это могло бы выгля­деть так:

 int min(int x, int у);

В C++ используется эллипсический символ (ellipsis) (...) для обозначения списка аргументов, который не указан, но подразумевается. Функция printf () из стандартной библиотеки stdio.h имеет следующий прототип:

 int printf(const char* cntrl_str, ...);

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

//Сложение трех целых — иллюстрация прототипов функций
 #include <iostream.h>

int add3(int, int, int);

double average(int);

void main() 
{
int score_l, score_2, score_3, sum;

cout << "\nEnter three marks: ";

cin >> score_l >> score_2 >> score_3;

sum = add3(score_l, score_2, score_3);

cout << "\nSum= " << sum;

cout << "\n Average= " << average(sum);

sum = add3(1.5 * score_l, score_2, 0.5 * score_3);

cout << "\nWeight sum= " << sum << ".";

cout << "\nWeight average= " << average(sum) << "." << "\n";
}

int add3(int a, int b, int с)
{ return (a + b + с); } 

double average(int s) 
{ return (s / 3.0); }

Разбор программы

 int add3(int, int, int) ;
 double average(int);

Эти объявления являются прототипами функций. Они информируют компилятор о типе и количестве аргументов, предполагаемых для каждой объявленной таким образом и определенной в другом месте функции.

 sum = add3(1.5 * score_l, score_2, 0.5 * score_3);

Вызов функции суммирования трех целочисленных параметров add3, параметры в скобках будут неявно преобразованы к целому типу.

 int add3(int a, int b, int с)
 {
 return (а + b + с) ;
 }

Это собственно определение функции. Оно соответствует объявлению прототипа функции перед main ().

Так как список аргументов в прототипе функции может включать имена переменных,

 int add3(int а, int b, int с) ;
тоже допустимо.

Категория: c++ | Добавил: slava (29.04.2011)
Просмотров: 8539 | Рейтинг: 4.0/1
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]