После заголовка функции в фигурных скобках пишется тело функции.
Здесь описано как должна эта функции работать. Если функция должна возвращать какое-то значение то в теле функции обязательно должна быть инструкция return. В нашем примере, так как функция main должна возвращать значение типа int, после того как программа вывела на экран Hello World, написана строка return (0); Т.е функция возвращает 0, в программу которая её вызвала.
Задавать и описывать функции мы уже научились. Теперь оформим нашу программу, из листинга 10.1 в виде функции, принимающей 2 значение типа int, и которая ничего не возвращает в результате своей работы
Листинг 10.5
void fun1(int a, int b)
{
if((a==0)&&(b!=0)) printf("no solution\n");
else {
if((a==0)&&(b==0)) printf("many solution\n");
else {
if (b%a!=0) printf("no solution\n");
else {
printf("%d\n",b/a);
}
}
}
}
Как можете видеть в заголовке мы определили функцию c именем fun1 которая принимает два аргумента целого типа, причем мы сразу дали им имена a и b. Теперь внутри функции мы можем их использовать как обычные переменные с именами a и b. Параметры которые описаны в заголовке функции называются формальнымипараметрами.
Теперь когда мы разобрались с объявлением функции, надо научится её использовать. Любая функция прежде чем быть использованной, должна быть объявлена. Функции объявляются после подключения библиотек, перед объявление функции main.
Напишем программу, в которой объявим нашу функцию и используем её.
Листинг 10.6
#include <stdio.h>
void fun1(int a, int b){
if((a==0)&&(b!=0)) printf("no solution\n");
else {
if((a==0)&&(b==0)) printf("many solution\n");
else {
if (b%a!=0) printf("no solution\n");
else {
printf("%d\n",b/a);
}
}
}
}
int main (void) {
int x,y;
scanf("%d %d",&x,&y);
fun1(x,y);
fun1(3,9);
return(0);
}
Разберем код нашей программы и заодно посмотрим как она работает.
В первой строке подключаем stdio.h.
Далее объявляем функцию c именем fun1 которая принимает два аргумента целого типа, причем мы сразу дали им имена a и b. Потом в фигурных скобках описано тело функции. Т.е как должна работать наша функция. Так как функции имеет тип возвращаемого значения void, значит она ничего не возвращает, поэтому нет оператора return в нашей функции.
После тела функции fun1, объявляем функцию main. Объявляем две переменные типа int. Считываем что в них значения которые введет пользователь. Далее вызываем функцию fun1 и передаем ей в качестве аргументов переменные х и у. После этого опять вызываем функцию, но уже передаем ей в качестве аргументов числа 3 и 9.
Результат работы этой программы, при вводе данных 2 и 5 представлен на рисунке ниже.
Разберемся как работает вызов функции. Начнем с более легкого, что происходит когда мы пишем
fun1(3,9);
После того как программа встречает эту строчку она начинает искать в выше функции main объявление функции с именем fun1 которая принимает два параметра. Параметры которые передаются в функцию в программе, называются фактическими параметрами. Если она не найдет такую функцию, то программа не скомпилируется, ну и следовательно не выполнится. Если такая функция есть, то программа передает управление в эту функцию.
Первым делом она создает две переменные целого типа с именами a и b. Которые указаны в заголовке. И присваивает им значения a=3, b=9.Далее выполняется тело функции. После того, как функция закончит работу, управление снова передается в основную программу. А переменные а и b удаляются. И выполняется строчка следующая за вызовом функции.
ВАЖНО!!!
Обратите внимание, что после того, как функция закончила свою работу, переменные a и b удаляются. Они доступны только внутри функции в которой они объявлены.
Теперь разберем случай с передачу в функцию переменных.
fun1(x,y);
После того как программа встречает эту строчку она начинает искать в выше функции main объявление функции с именем fun1 которая принимает два параметра. Если она не найдет такую функцию, то программа не скомпилируется, ну и следовательно не выполнится. Если такая функция есть, то программа передает управление в эту функцию.
Первым делом она создает две переменные целого типа с именами a и b. Которые указаны в заголовке. В эти значения копируются значения переменных, которые были переданы в функцию в качестве параметров. Далее выполняется тело функции. После того, как функция закончит работу, управление снова передается в основную программу. А переменные а и b удаляются. И выполняется строчка следующая за вызовом функции
ВАЖНО!!!
Обратите внимание, что в функцию передаются не сами переменные х и у, а только копии их значений. Т.е. любые действия производимые потом внутри функции на них никак не влияют.
Еще один важный момент. Область видимости переменных. Как уже говорилось выше переменные a и b доступны только внутри функции, в которой они объявлены. Их область видимости тело функции fun1. За пределами этой функции эти переменные не существуют.
Из этого следует интересный факт. Например, если мы перепишем код нашей программы вот так.
Листинг 10.7
#include <stdio.h>
void fun1(int a, int b){
if((a==0)&&(b!=0)) printf("no solution\n");
else {
if((a==0)&&(b==0)) printf("many solution\n");
else {
if (b%a!=0) printf("no solution\n");
else {
printf("%d\n",b/a);
}
}
}
}
int main (void) {
int a,b;
scanf("%d %d",&a,&b);
fun1(a,b);
return(0);
}
Переменные a и b которые объявлены в основной программе, и переменные a и b которые объявлены в функции fun1 это совершенно разные переменные. И ничего общего между собой не имеют.
Вот небольшой пример.Подумайте что выведет на экран эта программа а потом проверьте себя выполнив её на компьютере.
Листинг 10.8
#include <stdio.h>
void fun1(int a){
a=8;
}
int main (void) {
int a;
a=3;
fun1(a);
printf("%d\n",a);
return(0);
}
Теперь еще немного об объявлении функций. Мы можем объявить функцию в начале программы, а потом описать её например внизу программы.Для этого до функции main надо написать только заголовок функции и поставить точку с запятой. Для нашего примера это выглядело бы так.
Листинг 10.9
#include <stdio.h>
void fun1(int,int);
int main (void) {
int x,y;
scanf("%d %d",&x,&y);
fun1(x,y);
fun1(3,9);
return(0);
}
void fun1(int a, int b){
if((a==0)&&(b!=0)) printf("no solution\n");
else {
if((a==0)&&(b==0)) printf("many solution\n");
else {
if (b%a!=0) printf("no solution\n");
else {
printf("%d\n",b/a);
}
}
}
}
При таком объявлении можно вверху не указывать имена конкретных формальных параметров а только их типы и количество.
Такой тип записи удобен для программ с большим количеством функций. Вверху можно написать только заголовок, и в комментарии написать, что делает данная функция. А внизу уже сам код. Это очень удобно. Обычно любую программу разбивают на много небольших функций. А в основной программе уже пишут как взаимодействуют эти функции между собой.
Теперь когда мы стали почти что профессионалами в написании функций вернемся опять к нашему исходному примеру. Мы дошли до того, что оформили решение в виде функции на вход которой подается значения а и b. Листинг 10.9.
Теперь перепишем нашу функцию, так, чтобы она возвращала результат своей работы в виде целого числа. Условимся, что
30001 это ответ many solution.
30002 это ответno solution.
Цифры выбраны не случайно. Область решения у нас от -30000 до 30000, значит эти числа использовать нельзя. иначе реальный ответ может совпасть с одним из них. Например если many solution обозначить как 3. То тогда при а=3 b=9 ответ функция вернет 3, но мы условились это считать за many solution. И не понятно будет какой ответ.
if (b%a!=0)return (30002); //printf("no solution\n");
else {
return (b/a); //printf("%d\n",b/a);
}
}
}
}
Так как функция возвращает значение типа int, её можно использовать везде где допустимо использование типа int. В нашем примере мы записали её в оператор printf. Хотя могли бы сначала присвоить её значение какой-нибудь переменной, а потом выводить в printf её значение.
if (b%a!=0)return (30002); //printf("no solution\n");
else {
return (b/a); //printf("%d\n",b/a);
}
}
}
}
Кстати, как вы заметили в нашей функции несколько раз встречается оператор return. Это необязательно. Можно было сначала присваивать значение какой-то одной переменной, а потом выводить его в самом конце функции. Вообще он предназначен для немедленного прекращения выполнения функции. Как оператор break в циклах. И так его можно использовать в функциях которые не возвращают никаких значений.
А так же с помощью него можно возвращать значение которое должна возвращать функция. Так он используется в нашем примере.
Функции могут вызывать друг друга, главное чтобы они были определены перед их использованием.
Усовершенствуем нашу программу, и сделаем так, чтобы она выводила правильно ли работает программа или нет.А для этого опишем еще одну функцию с именем prov.
Листинг 10.12
void prov(void){
if ((fun1(0,0)== 30001)&&(fun1(0,3)==30002)&&(fun1(3,9)==3)&&(fun1(3,7)==30002))
printf("pravilno\n");
else
printf("nepravilno\n");
}
И добавим её в нашу программу.
Листинг 10.13
#include <stdio.h>
int fun1(int,int);
void prov(void);
int main (void) {
prov();
return(0);
}
void prov(void){
if ((fun1(0,0)== 30001)&&(fun1(0,3)==30002)&&(fun1(3,9)==3)&&(fun1(3,7)==30002))
if (b%a!=0)return (30002); //printf("no solution\n");
else {
return (b/a); //printf("%d\n",b/a);
}
}
}
}
Если вы запустите эту программу то, она выведет pravilno. Значит наша программа которую мы проверяли работает правильно. Теперь, для проверки чужой программы, нам останется скопировать часть её кода в функцию fun1 и немного подредактировать его.
На этом урок закончим. А то он и так поучился очень-очень большим.Разбирайтесь.
Резюме урока:
узнали что такое подпрограммы и чем отличаются функции от процедур
научились объявлять и описывать свои функции
узнали что такое фактические и формальные параметры
получили представление об области видимости переменных