Типовая структура программы на языке СИ
В отличие от других языков программирования высокого уровня в языке Си нет деления на процедуры, подпрограммы и функции. В Си программа строится только из функций.
Функция – это независимая совокупность объявлений и операторов, предназначенная для выполнения определенной задачи. Каждая функция должна иметь имя, которое используется для вызова функции. Имя главной функции main(), которая должна присутствовать в каждой программе, зарезервировано. Функция main() не обязательно должна быть первой, однако с нее всегда начинается выполнение Си-программы. Приведем типовой пример записи программы
# include < > /* директивы препроцессора */
# define NAME значение // макроопределение или макрос
/* объявление функций */
int func_1 (список параметров ) ;
void func_2 (список параметров );
...
float func_n (список параметров );
/* описание глобальных переменных */
float a,b,c char ch;
/* определение функций */
int func_1 (список параметров );
{
int i,j ; /*описание локальных переменных */
тело функции;
}
void func_2 (список параметров )
{
тело функции;
}
float func_3 (список параметров )
{
тело функции;
}
void main(void)
{
описание главной функции
}
С пользованием функций в языке Си связаны три понятия: объявление функции, определение функции и вызов функции.
Объявление или прототип функции задает ее имя, типы и число формальных параметров, тип значения, возращаемого функцией, и класс памяти. В объявлении формальные параметры могут иметь имена, однако это не является необходимым. Объявление оканчивается символом ‘;’ (точка с запятой).
Примеры объявлений:
int func_1(char*, int, float); //объявление о функции func_1()
char* func_2(int a, int b, char* ch); //объявление о функции func_2()
Из примеров видно, что сначала указывается тип значения, возвращаемого функцией (по умолчанию тип int), затем следует имя функции, после чего в круглых скобках указываются типы формальных параметров, разделяемых запятыми. В том случае, если формальные параметры отсутствуют, либо функция не возвращает никакого значения, используется служебное слово void:
void func_3(int, int); //отсутствует возвращаемое значение
void func_4(void); // отсутствуют формальные параметры и возвращаемое значение
Имена функций должны быть уникальными.
Список формальных параметров может оканчиваться запятой и многоточием (,…):
int func_5(int* ,int,…);
Это означает, что число аргументов функций переменно, но не менее числа аргументов, заданных перед последней запятой. Контроль типов не указанных переменных возлагается на программиста.
Определение функции задает ее заголовок, объявления локальных объектов (констант, переменных) и операторы, которые определяют действие функции. Тело функции заключается в фигурные скобки.
Заголовок функции синтаксически имеет такой же формат, как и прототип функции, с той лишь разницей, что, кроме типов, указываются имена формальных параметров и отсутствует символ ‘;’ в конце заголовка.
Пример определения функции:
char* func(int param_1, int param_2, char* param_3)
//тело функции
{
int i, j, k; //объявления локальных объектов
char buff [80];
…
оператор;
оператор;
…
return buff; //возвращаемое значение
}
Вызов функции определяет действия, выполняемые функцией. При вызове функции ей могут быть переданы данные посредством аргументов функции, называемых фактическими параметрами. Если функция возвращает значение, то это и есть основной результат выполнения функции, который при выполнении программы подставляется в точку ее вызова. Если функция не возвращает никакого значения ее действие может состоять из выполнения операций, не связанных с обработкой данных.
Существует два способа вызова функции:
1. имя_функции (список фактических параметров);
2. (* указатель_на_функцию) (список фактических параметров),
здесь круглые скобки обязательны.
Указатель_на_функцию - это переменная, содержащая адрес функции, Адрес функции может быть присвоен указателю оператором:
указатель_на_функцию = имя_функции ;
Примеры вызовов:
func (a,b ) ;
func (&a, &b ) ;
func () ;
( *func) (&a, &b ) ; и т.д.
Вызов функции может являться частью выражения, стоящего справа от операции присваивания, например:
Y = func_1 (a, b) + func_2 (c, d) ;
Операция присваивания «сохраняет» значение, возвращаемое функцией. Если же просто написать func_1 (a, b), то значение не будет сохранено.
Операция func_1 (a, b) правомерна, если функция не возвращает значения, т.е. имеет тип void.
Функция, не имеющая параметров и не возвращающая значения должна быть описана как void func(void); ее вызов будет иметь вид func ();
Оператор return
Этот оператор имеет два варианта применения:
1. Если некоторая функция возвращает некоторый результат (значение) в точку вызова, то в тексте функции должен обязательно быть оператор вида
return (выражение);
(круглые скобки здесь не обязательны).
Пример 5.1: Функция нахождения большего из двух чисел.
int max (int a, int b);
{
if (a > b)
return (a);
else
return (b);
}
Можно еще короче:
int max (int a, int b);
{
if (a > b) return (a);
return (b);
}
А можно использовать оператор “?”:
max (int a, int b);
{
return (a > b)? a : b ;
}
Если функция не возвращает никакого значения, она может также заканчиваться оператором return.
Отсутствие этого оператора не вызывает никаких неприятностей, т.к. при достижения закрывающей скобки ‘}’ компилятор автоматически генерирует код возврата.
2. Если требуется возврат в точку вызова до исполнения всех операторов тела функции в результате выполнения какого – либо условия. Например,
{
…
if (ch = =’\0’)
return 0;
…
}