Опубликован: 05.07.2006 | Уровень: для всех | Доступ: платный
Лекция 2:

Учебное введение

1.7. Функции

В языке "C" функции эквивалентны подпрограммам или функциям в фортране или процедурам в PL/1, паскале и т.д. функции дают удобный способ заключения некоторой части вычислений в черный ящик, который в дальнейшем можно использовать, не интересуясь его внутренним содержанием. Использование функций является фактически единственным способом справиться с потенциальной сложностью больших программ. Если функции организованы должным образом, то можно игнорировать то, как делается работа; достаточно знание того, что делается. Язык "C" разработан таким образом, чтобы сделать использование функций легким, удобным и эффективным. Вам будут часто встречаться функции длиной всего в несколько строчек, вызываемые только один раз, и они используются только потому, что это проясняет некоторую часть программы.

До сих пор мы использовали только предоставленные нам функции типа printf, getchar и putchar ; теперь пора написать несколько наших собственных. так как в "C" нет операции возведения в степень, подобной операции ** в фортране или PL/1, давайте проиллюстрируем механику определения функции на примере функции power(m,n), возводящей целое m в целую положительную степень n. Так значение power(2,5) равно 32. Конечно, эта функция не выполняет всей работы операции **, поскольку она действует только с положительными степенями небольших чисел, но лучше не создавать дополнительных затруднений, смешивая несколько различных вопросов.

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

main()  /* test power function */
{
   int i;

   for(i = 0; i < 10; ++i)
    printf("%d %d %d\n",i,power(2,i),power(-3,i));
}

power(x,n)  /* raise  x  n-th power; n > 0  */
int x,n;
{
   int i, p;
   p = 1;
   for (i =1; i <= n; ++i)
   p = p * x;
   return (p);
}
   Все функции имеют одинаковый вид:
имя (список аргументов, если они имеются)
описание аргументов, если они имеются
{
описания
   операторы
}

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

функция power вызывается дважды в строке

printf("%d %d %d\n",i,power(2,i),power(-3,i));

при каждом обращении функция power, получив два аргумента, возвращает целое значение, которое печатается в заданном формате. В выражениях power(2,i) является точно таким же целым, как 2 и i. /Не все функции выдают целое значение; мы займемся этим вопросом в "лекции № 4" /.

Аргументы функции power должны быть описаны соответствующим образом, так как их типы известны. Это сделано в строке

int x,n;

которая следует за именем функции.

описания аргументов помещаются между списком аргументов и открывающейся левой фигурной скобкой ; каждое описание заканчивается точкой с запятой. Имена, использованные для аргументов функции power, являются чисто локальными и недоступны никаким другим функциям: другие процедуры могут использовать те же самые имена без возникновения конфликта. Это верно и для переменных i и p ; i в функции power никак не связано с i в функции main.

Значение, вычисленное функцией power, передаются в main с помощью оператора return, точно такого же, как в PL/1. Внутри круглых скобок можно написать любое выражение. функция не обязана возвращать какое-либо значение; оператор return, не содержащий никакого выражения, приводит к такой же передаче управления, как "сваливание на конец" функции при достижении конечной правой фигурной скобки, но при этом в вызывающую функцию не возвращается никакого полезного значения.

Упражнение 1-13

Напишите программу преобразования прописных букв из файла ввода в строчные, используя при этом функцию power(c), которая возвращает значение 'c', если 'c' - не буква, и значение соответствующей строчной буквы, если 'c' - буква.

1.8. Аргументы - вызов по значению

Один аспект в "C" может оказаться непривычным для программистов, которые использовали другие языки, в частности, фортран и PL/1. В языке "C" все аргументы функций передаются "по значению". это означает, что вызванная функция получает значения своих аргументов с помощью временных переменных /фактически через стек /, а не их адреса. Это приводит к некоторым особенностям, отличным от тех, с которыми мы сталкивались в языках типа фортрана и PL/1, использующих " вызов по ссылке ", где вызванная процедура работает с адресом аргумента, а не с его значением.

Главное отличие состоит в том, что в "C" вызванная функция не может изменить переменную из вызывающей функции ; она может менять только свою собственную временную копию.

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

power(x,n)  /* raise  x  n-th power; n > 0;
          version 2 */
int x,n;
{
int p;

for (p = 1; n > 0; --n)
     p = p * x;
return (p);
}

аргумент n используется как временная переменная ; из него вычитается единица до тех пор, пока он не станет нулем. переменная i здесь больше не нужна. чтобы ни происходило с n внутри power это никак не влияет на аргумент, с которым первоначально обратились к функции power.

При необходимости все же можно добиться, чтобы функция изменила переменную из вызывающей программы. Эта программа должна обеспечить установление адреса переменной /технически, через указатель на переменную /, а в вызываемой функции надо описать соответствующий аргумент как указатель и ссылаться к фактической переменной косвенно через него. Мы рассмотрим это подробно в "лекции № 5" .

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

Ярослав Воробей
Ярослав Воробей
Россия
Дмитрий Левин
Дмитрий Левин
Россия