ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 31.03.2021
Просмотров: 6823
Скачиваний: 51
326
Завершает выполнение данной функции и передает управление вызывающей функции
опе-
ратор return
; в
главной функции main он же вызывает завершение выполнения всей программы.
Оператор return может содержать любое выражение:
return (<выражение>);
Если выражение не пусто, то вычисляется его значение, которое и становится значением
данного вызова функции.
Достижение «конца» функции (правой закрывающей фигурной скобки) эквивалентно вы-
полнению оператора return без возвращаемого значения (т.е. оператор return в конце функции мо-
жет быть опущен).
Пример.
Данная программа вычисляет факториал, если число меньше 8; если вводимое
число больше или равно 8, то выводится сообщение «Очень большое число».
Программа 100
#include<stdio.h>
main()
{
int n, s() ;
printf("Введите число ");
scant("%d", &n) ;
if (n<8) printf(=%d", s(n)) ;
else printf("Очень большое число");
)
int s(x) /* определение функции с параметром */
int x;
{
int y,p=l;
for (y=x; y>0; y- ) p*=y;
return(p); /* Возвращает в основную программу значение р */
}
Результат работы программы:
1. Введите число 4
р=24
2.Введите число 9
Очень большое число
Пример:
предположим, что нужно вычислить x
2
(для некоторого неотрицательного целого
у) (очевидный способ реализации возведения в целочисленную степень -многократное умножение,
но существует более эффективный алгоритм, приведенный ниже).
Программа 101
#include<stdio.h>
main()
(
int а, Ь, x, у, z;
int odd() ;
printf("\nВведите x, у через пробел: ");
scanf("%d %d", &х, &у); а=х; Ь=у; z=l;
while (b!=0)
if (odd(b))
{ z=z*a; b- -;}
327
else
( a=a*a; b=b/2;}
printf("\n%d", z);
}
int odd(t)
int t;
(
return((t%2==0)? 0:1);
)
Результат работы программы:
Введите
x, у через пробел: 15 2
225
Если функции необходимо вернуть несколько значений, можно использовать два различ-
ных приема:
• применить глобальные переменные (в этом случае кроме изученных ранее характеристик
переменных (имени, типа, значения), используется еще одна – класс памяти, см.ниже);
• применить переменные типа «указатель» в качестве аргументов функции. При вызове
функции информация о переменной может передаваться функции в двух видах. Если мы исполь-
зуем форму обращения
function 1(х);
то происходит передача в функцию значения переменной х. Изменение этого значения в вызы-
вающую функцию не возвращается. Если мы используем форму обращения
function2(&x);
то происходит передача адреса переменной х. Теперь измененное значение переменной х может
использоваться в вызывающей функции. Первая форма обращения требует, чтобы определение
функции включало в себя формальный аргумент того же типа,что и х:
function l(num)
int num;
Вторая форма обращения требует, чтобы определение функции включало в себя формаль-
ный аргумент, являющийся указателем на один из объектов соответствующего
типа:
function2(x)
int *x;
Обычно пользуются первой формой, если входное значение необходимо функции для неко-
торых вычислений или действий, и второй формой, если функция должна будет изменять значения
переменных в вызывающей программе. Выше вторая форма вызова \же применялась при обраще-
нии к ф\нкции scanf(). Когда мы хотим ввести некоторое значение в переменную num, мы пишем
scanf(''%d",&num). Данная функция читает значение, затем, используя адрес, который ей дается,
помещает это значение в память.
Пример:
пусть необходимо поменять местами заданные значения переменных х и у.
Программа 102
#include<stdio.h>
main()
328
{
int х, у;
int interchange(); /* описание функции типа int */
x=l; y=3;
printf("Имели... x=l y=3\n") ;
interchange(&x, &y); /* обращение к функции (в данном случае пере-
даются адреса переменных) */
printf("Получили... x=%d y=%d", х, у);
}
/* вызываемая функция */
int interchange(u, v)
int *u, *v;
(
int p;
p=*\i; *u=*v; *v=p;
}
Результат работы программы:
Имели х=1 у=3
Получили х=3
у=1
В этой программе в вызове функции interchange(&x,&y) вместо передачи значений х и у мы
передаем их адреса. Это означает, что формальные аргументы и и v, имеющиеся в спецификации
interchanage(u,v), при обращении будут заменены адресами и, следовательно, они должны быть
описаны как указатели.
Поскольку х и у целого типа, u и v являются указателями на переменные целого типа, и мы
вводим следующее описание:
int *u,*v; int p;
Оператор описания используется с целью резервирования памяти. Мы хотим поместить
значение переменной х в переменную р, поэтому пишем: р=*u; Вспомните, что значение перемен-
ной u - это &х, поэтому переменная и ссылается на х. Это означает, что операция *u дает значение
х, которое как раз нам и требуется. Мы не должны писать, например, так:
р = u; /* неправильно */
поскольку при этом происходит запоминание адреса переменной
х, а не ее значения.
Аналогично,
оператор *u = *v соответствует оператору х = у.
Тип функции определяется типом возвращаемого ею значения, а не типом ее аргументов.
Если указание типа отсутствует, то по умолчанию считается, что функция имеет тип int. Если зна-
чения функции не принадлежат типу int, то необходимо указать ее тип в двух местах.
1. Описать тип функции в ее определении:
char pun(ch,n) /* функция возвращает символ */
int n;
char ch;
2. Описать тип функции также в вызывающей программе. Описание функции должно быть
проведено наряду с описаниями переменных программы; необходимо только указать скобки (но
не аргументы) для идентификации данного объекта как функции.
main()
{
char rch,pun();
329
6.6. КЛАССЫ ПАМЯТИ
Помимо изученных ранее характеристик переменных (имени, типа, значения), в ряде случа-
ев оказывается важной еще одна - класс памяти. Класс памяти характеризует время существования
и место хранения объекта в программе.
Для обозначения класса памяти в языке Си используются следующие служебные слова:
auto
extern
register
static
Автоматические объекты (auto) являются локальными по отношению к блоку и хранятся
внутри того блока, где они описаны. Автоматические переменные можно инициализировать про-
извольными выражениями, включающими константы и ранее описанные переменные и функции.
Автоматические объекты существуют только во время выполнения данного блока и теряют
свои значения при выходе из него. При каждом вхождении в блок им присваиваются начальные
значения, заданные в описании. Если начальные значения не заданы, то значения автоматических
объектов при входе в блок не определены. До сих пор в этом параграфе рассматривались именно
автоматические объекты.
Объекты, описанные внутри блока с классом памяти register, называются регистровыми пе-
ременными. Они подчиняются всем правилам, касающимся автоматических переменных. Описа-
ние register указывает компилятору, что данная переменная будет часто использоваться. Когда это
возможно, переменные, описанные как register, располагаются в машинных регистрах. Это приво-
дит к меньшим по размерам и более быстрым программам.
Объекты, описанные внутри функции с добавлением класса памяти extern или описанные
вне функции без оказания класса памяти, относятся к внешним объектам. Внешние объекты хра-
нятся вне любой функции, входящей в состав программы, и существуют в течение выполнения
всей программы. Они могут быть использованы для передачи значений между различными, в том
числе и отдельно компилируемыми, функциями. Сами функции также являются внешними объек-
тами, поскольку правила языка Си не позволяют определять одни функции внутри других. Внеш-
ние переменные можно инициализировать только выражениями с константами и указателями на
ранее описанные объекты. По умолчанию (если не задана инициализация) внешние объекты полу-
чают нулевые начальные значения.
Внешние объекты делятся на внешние глобальные и внешние статические.
Важно различать описание внешнего объекта и его определение. Описание указывает свой-
ства объекта (тип, размеры и т.д.); определение же вызывает еще и отведение памяти установке
начального значения, если используется инициализация.
Например, появившиеся вне определения какой-либо функции строчки
int max;
char save[maxline];
определяют внешние переменные max и save, вызывают отведение для них места в памяти и слу-
жат в качестве описания для остальной части этого файла. В то
же
время строчки
extern int max;
extern char save[];
описывают в остальной части данного блока переменную max как int, a save как массив типа char
(размеры которого указаны в другом месте), но не создают переменных и не отводят для них места
в памяти.
Во всех блоках, составляющих исходную программу, должно содержаться только одно оп-
ределение внешней переменной; другие блоки могут содержать описания extern для доступа к ней.
Программа 103
330
#include<stdio.h>
int i=0;
/* Класс памяти переменной - внешний. Область действия переменной -любая про-
грамма, */
/* загружающаяся с данным файлом. Время существования
i=0 -
все время выпол-
нения программы. */
main()
/* Блок уровня 1. */
(
auto int i=l;
/* В блоке 1 область действия
i=l -
функция main(). Время */
/* существования i=l - все время выполнения главной функции /*
/* main(). /*
printf("%d\n", i) ;
/* Если две переменные имеют одно и то же имя, то по этому */
/* имени обращаются к внутренней переменной, внешняя */
/* непосредственно недоступна, поэтому после выполнения */
/* блока 1 программа напечатает i=l. */
{
/* Блок уровня 2. */
int i=2;
/* Класс памяти переменной i=2 - auto. Область */
/* действия i=2 - блок 2, время существования - время */
/* существования блока 2. блок 2, время существования -*/
/* время существования блока 2. */
printf("%d\n", i) ;
/* Программа напечатает i=2. */
{
/* Блок уровня 3. */
i+=l; printf("%d\n", i);
/* Печатается самая внутренняя переменная с именем i,/*
/* которая после выполнения операции данного блока */
/* становится равной 3. */
}
/* Возвращение к блоку уровня 2. */
printf("%d\n", i) ;
/* Опять печатается i=3. */
)
/* Возвращение к блоку уровня 1. */
printf("%d", i) ;
/* Переменная i=3 исчезает. Теперь самой внутренней переменной */
/* с именем i будет i=l. */
)
Программа 104
#include<stdio.h>
int a;
main()
(
extern int a;
int P ();
a=6; P();
)
int P()
(
extern int a;
printf("a=%d",a);
}
Результат работы программы:
a=6
Областью действия статического внешнего объекта является модуль, в котором описан