Давайте проиллюстрируем механику определения функции на примере функции power(m,n), возводящей целое m в целую положительную степень n. Так значение power(2,5) равно 32.
Ниже приводится функция power и использующая ее основная программа, так что вы можете видеть целиком всю структуру.
main() /* тест функции */
{
int i;
for(i = 0; i < 10; ++i)
printf("%d %d %d\n",i,power(2,i),power(-3,i));
}
power(x,n) /* возведение x в n-ую степень; 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.
Аргументы функции power должны быть описаны соответствующим образом, так как их типы известны. Это сделано в строке
int x,n;которая следует за именем функции.
Описания аргументов помещаются между списком аргументов и открывающейся левой фигурной скобкой; каждое описание заканчивается точкой с запятой. Имена, использованные для аргументов функции power, являются чисто локальными и недоступны никаким другим функциям: другие процедуры могут использовать те же самые имена без возникновения конфликта. Это верно и для переменных i и p; i в функции power никак не связано с i в функции main.
Значение, вычисленное функцией power, передаются в main с помощью оператора return. Внутри круглых скобок можно написать любое выражение. функция не обязана возвращать какое-либо значение; оператор return, не содержащий никакого выражения, приводит к выходу из функции , но при этом в вызывающую функцию не возвращается никакого значения.
Главное отличие состоит в том, что в "C" вызванная функция не может изменить переменную из вызывающей функции; она может менять только свою собственную временную копию.
Вызов по значению, однако, не помеха, а весьма ценное качество. Оно обычно приводит к более компактным программам, содержащим меньше не относящихся к делу переменных, потому что с аргументами можно обращаться как с удобно инициализированными локальными переменными вызванной процедуры. Вот, например, вариант функции power использующей это обстоятельство
power(x,n) /* возведение x в n-ую степень; n > 0
версия 2 */
int x,n;
{
int p;
for (p = 1; n > 0; --n)
p = p * x;
return (p);
}
Аргумент n используется как временная переменная; из него вычитается единица до тех пор, пока он не станет нулем.
Переменная i здесь больше не нужна. чтобы ни происходило с n внутри power
это никак не влияет на аргумент, с которым первоначально обратились к функции power.
При необходимости все же можно добиться, чтобы функция изменила переменную из вызывающей программы. Такая программа должна обеспечить установление адреса переменной /технически, через указатель на переменную/, а в вызываемой функции надо описать соответствующий аргумент как указатель и ссылаться к фактической переменной косвенно через него.
Когда в качестве аргумента выступает имя массива, то фактическим значением, передаваемым функции, является адрес начала массива. /Здесь нет никакого копирования элементов массива/. С помощью индексации и адреса начала функция может найти и изменить любой элемент массива.