Пятница, 29.03.2024, 00:58
Приветствую Вас Гость | RSS

Кузница миров

Меню сайта
Категории раздела
Мои статьи [2]
Курс : "Основы С++ для начинающих программистов игр." [25]
WindMill Engine [3]
XNA4 RPG [0]
Перевод туториалов но созданию RPG на C# c XNA4.
C# & Leadwerks [5]
Программирование Leadwerks Engine на языке С# с помощью врапера Le.NET.

Каталог статей и уроков

Главная » Статьи » Курс : "Основы С++ для начинающих программистов игр."

5.1. Знакомьтесь - Функции.
5. Знакомьтесь - Функции.


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

5.1. Функции


Когда программы становятся очень большими в коде реально можно потеряться. Единственный способ избежать подобных неприятностей, это разделить программу на несколько частей, и работать с ними по отдельности. Этими частями и будут функции. Такой способ программирования называют Процедурным программированием.(Процедура и функция это одно и тоже).
Что же такое функция, по-простому это отдельный блок кода, имеющий определенное назначение, то есть выполняющий какую-то задуманную программистом работу.
Вообще-то с функциями мы уже встречались. Вспомните, когда мы работали с генератором случайных чисел, мы получали системное время с помощью функции time(), устанавливали начальное значение генератора с помощью функции srand(), ну а само число получали с помощью rand().

Использование функции можно разделить на три этапа:
1. Объявление функции
2. Определение функции
3. Вызов.


Объявление функции

Объявление сообщает компилятору о существовании некой функции. Вот синтаксис:

Code

Тип_возвращаемого_значения  имя_функции(список агрументов);


Здесь:
Тип возвращаемого значения – это тип переменной, которую возвращает функция по завершению своей работы. Как я уже сказал, у каждой функции есть свое назначение, она выполняет определенную работу. Возьмем простой пример – функция умеет суммировать два целых числа. Результат этого сложения и будет возвращен в виде целого числа.
Имя функции – это и есть имя. Ведь к функции как то нужно обращаться. К именам функций применимы те же требования что и к именам переменной. Помните главное - имя должно быть понятным.
Список аргументов(еще называют параметры функции) - это записанные в скобках передаваемые функции значения, попросту говоря это список переменных над которыми эта функция будет совершать определенные действия. Объявляются эти аргументы так же как и обычные переменные, и дальнейшем используются внутри функции. Несколько аргументов отделяются друг от друга запятыми. Количество аргументов не ограничено, но им может и не быть вовсе.
И обращаю ваше внимание, что завершает объявление уже знакомые нам точка с запятой.
Пример объявления функций:

Code

void print();


Подобную запись еще называют прототипом функции. Здесь у нас объявлена функция которая не возвращает никакого значения( тип void – пустой тип) и не принимающая ни одного аргумента. Судя из названия, функция умеет что-то там печатать.

Code

int sum(int a, int b);


Это уже немного описанный пример. Функция имеет два аргумента типа int. В результате своей работы она возвращает целочисленное значение (int).
При объявлении в списке аргументов функции имя переменной можно не указывать, то есть достаточно только указать тип данных. Вот так:

Code

int sum(int, int);


Здесь имена a и b отсутствуют, но они в прототипе не очень-то и нужны. Функций мы еще наобъявляемся, так что не будем тратить время и двигаемся дальше.

Определение функции


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

Code

Тип_возвращаемого_значения  имя_функции(список аргументов)
{
   Блок кода;
}


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

Code

int sum(int a, int b)
{
   return a + b;
}


Аргументы int a, int b используются в функции как обычные переменные.
Как мы уже знаем, функция возвращает определенное значение. Для этих целей в примере мы и видим оператор возврата - return.
Синтаксис оператора следующий:

Code
return возвращаемое значение;


Возвращаемым значением также может быть и любое выражение, как в нашем примере это a + b. Оператор возврата имеет самый низкий приоритет, то есть будет выполнен только после того, как все выражение будет вычислено.
Запомните, тип возвращаемого значения обязательно должен соответствовать типу, указанному в объявлении функции.
В одной функции может содержаться несколько операторов return. Чаще всего в следующей конструкции:

Code

if(условие)
{
   return значение;
}
else   
{
   return значение2;
}


Здесь возвращенное значение зависит от заданного условия.

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


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

Code

имя_функции (значение1, значение2, …)


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

Code

int sum(int a, int b);


вызов будет таким:

Code

sum(5, 8);


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

Code

int x=10;
sum(x, 156);


Использование функций.


Ну а теперь напишем небольшую программу, в которой используем все, с чем познакомились ранее.
Code

#include <iostream>
using namespace std;

int sum(int, int);    //обьявление(прототип) функции

void main()
{
   setlocale(0,"");

   int a;
   int a2;
   int b;
   cout<<"Введите первое число ";
   cin>>a;
   cout<<"Введите второе число ";
   cin>>a2;
   b = sum(a,a2);    // вызов функции
   cout<<"Сума двух чисел "<<b;
   cin.get();
   cin.get();
}

int sum(int a, int b)    //определение(реализация) функции
{
   return a + b;
}


В этом примере мы видим все, о чем говорили ранее. Объявление, определение и вызов.
В строке:
Code

b = sum(a,a2);    // вызов функции


возвращенный функцией результат присваивается переменной b.

Пример неплохо иллюстрирует учебный материал, но созданная нами функция бесполезная. Более того, код примера неэффективный и некорректный, поэтому далее, чтобы получше освоить функции и получить еще крупицу опыта, мы его улучшим.
Говоря об эффективности, я имел в виду, что в примере есть бесполезные строки кода, ненужное объявление переменных и другое. От всего этого можно и даже нужно избавится, сделав нашу программу компактнее и быстрее(чисто теоретически, поскольку кода мало и повышение производительности никто не заметит.)
Теперь о корректности. В программе наличествует ввод данных. Подразумевается, что будет ведено какое-то число. Но что если пользователь случайно введет какое-то левое значение?
В программе произойдет сбой. А это не есть хорошо. Поэтому сейчас нам необходимо сделать соответствующую проверку. Поскольку, в случае ввода неверного значения программа должна запросить его повторно и вводить нам нужно несколько значений, получение и проверка данных от пользователя будет производиться внутри одной функции GetDigit(). Вот ее код:
Code

int GetDigit()
{   
   bool r=true;    
   char c[20];
   cout<<"Введите число ";
   while (r)   // основной цикл    
   {
    cin>>c;    // ввод
    for(int i=0;c[i]!='\0';i++)    // цикл анализа
    {
     if(isdigit(c[i]))  // проверка цифра или символ
     {
      r=false;
     }
     else
     {
      r=true;
      cout<<"Повторите ввод (число давай) ";
      break;    // принудительное завершение цикла анализа
     }
    }
   }
int i= atoi(c);
   return i;    // возврат числа
}


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

Code
for(int i=0;c[i]!='\0';i++)    // цикл анализа
    {
     if(isdigit(c[i]))  // проверка цифра или символ
     {
      r=false;
     }
     else
     {
      r=true;
      cout<<"Повторите ввод (число давай) ";
      break;    // принудительное завершение цикла анализа
     }
    }

до тех пор, пока не встретится конец строки(нулевой символ '\0' ) производится анализ массива. Выполняется проверка каждого элемента на то, является ли он числом или символом. Делается это с помощью стандартной функции isdigit(), возвращающей true если проверяемый символ – цифра. В этом случае анализ продолжается, и если все символы цифры, условие продолжения основного цикла (переменная r) становится ложным.

Если же функция isdigit(), возвращает false, условие продолжения основного цикла вновь становится истинным, выводится предложение повторно ввести число, и цикл анализа принудительно завершается оператором break. Принудительное завершение необходимо потому, что после символа может встретится опять цифра и условие станет ложным, тогда как на самом деле ввод то некорректный.

После завершения основного цикла мы должны возвратить значения.

Поскольку с это массив символов(строка), а нам нужно число, чтобы выполнить соответствующее преобразование, используется еще одна стандартная функция atoi().
(Прототип int atoi(const char *str); Функция принимает указатель на строку, а возвращает число)
Она умеет превращать последовательность символов в число, при условии что символы – цифры. Иначе будет возвращен 0. Здесь нужно быть осторожным, поскольку можно запутаться, ведь строка тоже может быть «0». (Можете сами добавить соответствующую проверку, я этого делать не буду, а ниже приведу более сложный вариант функции GetDigit().)

Code

int i= atoi(c);
   return i;    // возврат числа

здесь с – имя массива, по совместительству являющееся также и указателем.

Эту запись можно сократить, ведь абсолютно незачем использовать лишнюю переменную
Code

   return atoi(c);    // возврат числа


Здесь напрямую возвращается результат работы функции atoi©. То есть, можно сказать, что после выполнения работы функция замещается значением возвращаемого ею типа. Поэтому ее и можно использовать в тексте программы непосредственно как значение:
Code

b = sum(5,10)* sum(5,3);


аналогом этой записи будет

Code
b = 15 * 8;


то есть:

Code
b = (5+10) * (5+3);


Надеюсь это уяснили. Теперь внесем в нашу программу изменения, задействуем созданную нами функцию GetDigit(). Не забудьте добавить ее объявление. Теперь функция main() примет такой вид:

Code

void main()
{
   setlocale(0,"");
   int a, a2;
   a=GetDigit();    // ввод первого числа
   a2=GetDigit();    // ввод второго числа
   cout<<"Сума двух чисел "<< sum(a,a2);    // вызов функции
   cin.get();
   cin.get();
}


Здесь переменные a и a2 получают корректное значение, возвращенное нашей функцией.

ЗАДАЧКА.
До сих пор я не давал вам домашних заданий. Пора это менять. Итак, небольшая задачка. Измените приведенный выше пример так, чтобы переменная а2 оказалась ненужной.


Ну а теперь обещанный мной более продвинутый вариант функции GetDigit().
Code

int GetDigit()
{
   int d;
   cout<<"Введите число ";
   while (true)
   {
    cin >> d;
    if ((cin.peek() == '\n'))
     break;
    else
    {
     cout << "Повторите ввод (ожидается число ) " << "\n";
     cin.clear();
     while (cin.get() != '\n')
     {

}
    }
   }
   return d;
}


Я не буду вам объяснять как она работает. Вы должны попытаться разобраться в ней сами. В этом вам поможет встроенная в студию справка, или если у вас нелады с английским то Интернет.
Основное внимание в этом примере следует уделить новым функциям:
cin.peek()
cin.clear()
cin.get()

Правда с последней вы уже знакомы, но вот что она делает на самом деле вряд ли знаете.

Ах да. Я же на протяжении стольких уроков так и не рассказал, как пользоваться справкой . Виноват. Исправляюсь. Хотя там и рассказывать особо нечего.
Как и во всех других Windows приложениях, справка в студии вызывается нажатием клавиши F1. При этом справка здесь умная. Во вновь открывшемся окне выдается информация об элементе, который в данный момент является активным. Чтобы получить информацию о неизвестной вам стандартной функции языка, достаточно поместить на нее курсор и нажать вышеупомянутую клавишу.

$IMAGE1$

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

$IMAGE2$

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

$IMAGE3$

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

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

#include <iostream>
using namespace std;

int sum(int a, int b)    //определение(реализация) функции вместо ее обьявления.
{
   return a + b;
}

void main()
{
   setlocale(0,"");

. . .
   cin.get();
   cin.get();
}


Возникает вопрос, зачем же тогда оно нужно. Это вы сможете понять со следующего урока.
Категория: Курс : "Основы С++ для начинающих программистов игр." | Добавил: nilrem (11.05.2012)
Просмотров: 1376 | Комментарии: 1 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0