Функции в языке С
Переименование типов
Перечисления
Перечисление – это список именованных целых констант. Для описания перечисления используется следующий формат:
enum [имяПеречисления] {списокИменованныхКонстант};
Имя перечисления задается в том случае, если в программе требуется определять переменные этого типа. Каждая из именованных констант может быть инициализирована. Если инициализатор не указывается, он вычисляется прибавлением единицы к значению предыдущей константы. Первая константа при отсутствии инициализации получает значение ноль. При выполнении арифметических операций именованные константы заменяются соответствующими им целыми числами. Примеры:
enum boolean {NO, YES}; // NO = 0, YES = 1
boolean bool; //описали переменную bool типа boolean
bool = YES; //bool = 1
if (bool)
{
. . .
}
enum months {JAN=1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
months mon; // FEB=2, MAR=3, APR=4, . . . , DEC=12
mon = DEC; //mon = 12
if (mon > FEB && mon < JUN)
{
. . . //весна
}
enum {BELL=’a’, BACKSPACE=’’, NEWLINE=’ ’, TAB=’ ’, VTAB=’v’};
char ch;
while(1)
{
if ((ch = getchar()) == NEWLINE) break;
. . .
}
Для того, чтобы сделать программу более ясной, можно дать типу новое имя с помощью ключевого слова typedef:
typedef Тип НовоеИмяТипа[Размерность];
Размерность может отсутствовать. Примеры:
typedef unsigned int uint;
typedef char message[100];
typedef char * string;
Введенные таким образом имена можно использовать таким же образом, как и имена простых типов данных:
uint i, j ; //две переменные типа unsigned int
message str[10]; //массив из 10 строк по 100 символов в каждой строке
string p = str; //инициализированный указатель на char
Кроме задания типам с длинными описаниями более коротких имен, typedef используется для облегчения переносимости программ: если машинно-зависимые типы объявить с помощью операторов typedef, при переносе программы потребуется внести изменения только в эти операторы.
Функция – это именованная последовательность описаний и операторов, выполняющая какое-либо законченное действие. Функция может принимать параметры и возвращать значение.
Любая программа на языке С состоит из функций, одна из которых должна иметь имя main (с нее начинается выполнение программы). Другие функции выполняются в момент их вызова.
Любая функция должна быть определена. Определение функции состоит из заголовка и тела:
тип имя ([список параметров]) //заголовок функции
{
тело функции
}
Заголовок функции задает ее имя, тип возвращаемого значения (результата) и список передаваемых параметров. Тип возвращаемого функцией значения может быть любым, кроме массива и функции (но может быть указателем на массив или функцию). Если функция не должна возвращать значение, указывается тип void. Список параметров определяет величины, которые требуется передать в функцию при ее вызове. Элементы списка параметров разделяются запятыми. Для каждого параметра, передаваемого в функцию, указывается его тип и имя.
Тело функции представляет собой последовательность описаний и операторов в фигурных скобках. Пример:
int sumFunc(int n, int m, int p)
{
int result; //эту и 2 последующие строки можно
result = n + m + p; //заменить одной строкой:
return result; // return = n + m + p;
}
Эта простейшая функция, имя которой sumFunc, предназначена для нахождения суммы трех целых чисел n, m и p, которые передаются ей в качестве параметров. Возврат из функции подсчитанной суммы выполняется с помощью оператора, имеющего следующий формат:
return [выражение];
После того как функция определена, ее можно вызывать из других функций программы, например, из главной функции main. Для вызова функции нужно указать ее имя, за которым в круглых скобках через запятую перечисляются имена передаваемых в функцию аргументов. В определении и при вызове одной и той же функции типы и порядок следования параметров и аргументов должны совпадать:
void main()
{
int a = 10, b = 20, c = 30, res;
puts("a = 10, b = 20, c = 30");
res = sumFunc(a, b, c);
printf("a + b + c = %d", res);
}
Если в программе сначала определить главную функцию main, а затем – функцию sumFunc, то перед функцией main нужно будет поместить так называемый прототип функции sumFunc, иначе при выполнении оператора
res = sumFunc(a, b, c);
возникнет ошибка, т.к. функция sumFunc еще неизвестна программе ввиду того, что ее определение находится ниже. В этом случае программа должна выглядеть так:
#include <stdio.h>
int sumFunc(int n, int m, int p); //прототип функции sumFunc
void main() //определение функции main
{
int a = 10, b = 20, c = 30;
puts("a = 10, b = 20, c = 30");
printf("a + b + c = %d", sumFunc(a, b, c)); //вызов функции sumFunc
}
int sumFunc(int n, int m, int p) //определение функции sumFunc
{
return n + m + p;
}
В прототипе функции имена параметров можно не указывать, достаточно лишь указать их тип:
int sumFunc(int, int, int); //прототип функции sumFunc
Глобальные, локальные и статические переменные
Все величины, описанные внутри функции, а также ее параметры, являются локальными объектами. Областью их действия является функция. При выходе из функции локальные объекты разрушаются и, следовательно, значения локальных переменных между вызовами одной и той же функции не сохраняются. Если этого требуется избежать, при объявлении локальных переменных используется модификатор static. Статическая переменная инициализируется только один раз при первом выполнении оператора, содержащего ее описание, и сохраняет свое значение между вызовами содержащей ее функции:
#include <stdio.h>
void func(int n)
{
static int a = 0;
a += n;
printf("%d ", a);
}
void main()
{
func(5);
func(5);
func(5);
}
Результат работы программы:
5 10 15
Глобальными переменными называются переменные, которые описываются в начале программы (сразу же за директивами препроцессора) вне любых функций. Глобальные переменные видны во всех функциях, где не описаны локальные переменные с теми же именами, поэтому их очень легко можно использовать для передачи значений между функциями. Тем не менее, это не рекомендуется, поскольку затрудняет отладку программы и препятствует помещению функций в библиотеки общего пользования. Нужно стремиться к тому, чтобы функции были максимально независимы, а их интерфейс полностью определялся заголовком описания функции.