Второй: мы хотели показать, что не забыли те новые операции присваивания, которые ввели в гл. 8.
Третий: в соответствии с алгебраическими правилами возведение в отрицательную степень было преобразовано в деление. Это внесло опасность деления на нуль, но в данном случае мы предусмотрели выдачу сообщения об ошибке и возврат значения 0, чтобы работа программы не прекращалась.
Мы можем воспользоваться тем же драйвером при условии, что тип функции power( ) там тоже описан.
/* проверка возведения в степень*/
main( )
{
double x;
double power( ); /* это пример oписания функции */
x = power(2.0, 3);
printf(" %.0f \n", x);x = power(-3.0, 3);
printf(" %.0f\n" , x);x = power(4.0, -2);
printf(" %.4f\n", x);x = power(5.0, 10);
print f ("%.0f \n", x);
}
На этот раз результаты работы программы выглядят вполне удовлетворительно.
8
-27
0.0625
9765625
Данный пример побуждает нас ввести следующий короткий раздел.
ОПИСАНИЕ ТИПОВ ФУНКЦИЙ
Тип функции определяется типом возвращаемого ею значения, а не типом ее аргументов. Если указание типа отсутствует, то по умолчанию считается, что функция имеет тип int. Если значения функции не принадлежат типу int, то необходимо указать ее тип в двух местах.
1. Описать тип функции в ее определении:
char pun(ch, n) /* функция возвращает символ */
int n;
char ch;
float raft(num) /* функция возвращает величину типа float */
int num;
2. Описать тип функции также в вызывающей программе. Описание функции должно быть приведено наряду с описаниями переменных программы; необходимо только указать скобки (но не аргументы) для идентификации данного объекта как функции.
main( )
{
char rch, pun( );
float raft;
}
Запомните! Если функция возвращает величину не типа int, указывайте тип функции там, где она определяется, и там, где она используется.
Резюме: функции
1. Форма записи
Типичное определение функции имеет следующий вид:
имя (список аргументов)
описание аргументов
тело функции
Наличие списка аргументов и описаний не является обязательным. Переменные, отличные от аргументов, описываются внутри тела, которое заключается в фигурные скобки.
Пример:
diff(x, у) /* имя функции и список аргументов */
ini x, у; /* описание аргументов */
{ /* начало тела функции */
int z; /* описание локальной переменной */
z = х - у;return(z);
} /* конец тела функции */
II. Передача значений функции:
Аргументы используются для передачи значений из вызывающей программы и функцию. Если значения переменных а и b будут 5 и 2, то при вызове
с = diff(а,b);
осуществляется передача этих значений переменным х и у. Значения 5 и 2 называют ся фактическими аргументами, а переменные х и у, указанные в описании функции: diff( ) - формальными аргументами.
Использование ключевого слова return позволяет передавать в вызывающую программу одно значение из вызываемой функции. В нашем примере переменной с присваивается значение переменной z, равное 3.
Обычно выполнение функции не оказывает никакого влияния на значения переменных вызывающей программы. Чтобы иметь возможность непосредственно изменять значения переменных вызывающей программы, необходимо использовать указатели в качестве аргументов. Это может оказаться необходимым в случае, если в вызывающую программу требуется передать более чем одно значение.
III. Тип функции
Функции должны иметь тот же тип, что и значения, которые они возвращают в качестве результатов. По умолчанию предполагается, что функции имеют тип int. Если функция имеет другой тип, он должен быть указан и в вызывающей программе, и в самом определении функции.
Пример
main( )
{
float q, x, duff( ); /* описание в вызывающей программе */
int n;
...
q = duff(х, n);
...
}
float duff(u, k); /* описание в определении функции */
float u;
int k;
{
float tor;
...
return(tor); /* возвращает значение типа float */
}
В ЯЗЫКЕ СИ ВСЕ ФУНКЦИИ РАВНОПРАВНЫ
Все функции в программе, написанной на языке Си, равноправны: каждая из них может вызывать любую другую функцию и в свою очередь каждая может быть вызвана любой другой функцией. Это делает функции языка Си несколько отличными от процедур Паскаля, поскольку процедуры в Паскале могут быть вложены в другие процедуры (причем, процедуры, содержащиеся в одном гнезде, являются недоступными для процедур, расположенных в другом).
Нет ли у функции main( ) какой-то специфики? Безусловно, есть; она заключается в том, что после "сборки" программы, состоящей из нескольких функций, ее выполнение начинается с первого оператора функции main( ). Но этим ее исключительность и граничивается. Даже функция main( ) может быть вызвана другими функциями, как показывает приведенный ниже пример:
/* вызовфункции main( ) */
#include
main( )
{
char ch;
printf (" Укажите произвольный символ. Q - признак конца работы. \n");
ch = getchar( );
printf ("Так! Вы указали %с!\n", ch);
if(ch != 'Q') more( );
}
more( );
{
main( );
}
Функция main( ) вызывает more(), а функция more() вызывает main()! После вызова функции main( ) ее выполнение начинается с самого начала; мы организовали цикл с взаимным вызовом.