Объявление и определение функций

Лекция №11. ФУНКЦИИ В ЯЗЫКЕ С

Лекция №10. ОБЪЕДИНЕНИЯ

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

Объединения объявляются с помощью ключевого слова union, и подобно структурам объединяют несколько полей. Но в структурах поля следуют друг за другом, а в объединении поля перекрывают друг друга, так как располагаются по одному и тому же адресу.

Компилятор выделяет под объединение память, достаточную для размещения его наибольшего элемента.

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

Объединения могут входить в структуры, и наоборот:

struct {

char *string;

char flag;

union un{

int i;

flоat f;

char с; } my_u;

}my_s;

Доступ к полям объединения осуществляется следующим образом: my_s.my_u.f.

Подобно структурам объединения можно инициализировать в объявлении, но при этом можно задать значения только для первого члена объединения, т. e. в отличие от структуры нельзя проинициализировать сразу все значения объединения. Так как поля объединения начинаются по одним и тем же адресам, присваивание значения первому элементу одновременно является присваиванием значений всем другим элементам, перекрываемым этим значением. Однако это утверждение справедливо для объединений с полями одного и того же размера.

Пример. Дан массив структур, содержащий сведения об успеваемости по информатике группы из 20 студентов. Структура содержит следующие сведения: фамилию и инициалы студента, четыре оценки, отражающие его текущую успеваемость в течение семестра. Вывести на экран список неуспевающих студентов (имеющих хотя бы одну оценку "2").

#define GROUP 20

#include <stdio.h>

void main()

{int i, flag;

struct gruppa {

char *FAM;

int inform[4];

} Gruppa[GROUP];

printf ("Введите данные \n"); // запишем массив данных,

for (i=0; i<GROUP; i++)

{printf("фамилия");

scanf("%s", Gruppa[i].FAM);

for(int j=0; j<4; j++)

{printf("%d-я оценка",j+1);

scanf("%d", Gruppa[i].inform[j]);} }

// Теперь можно обработать введенный массив записей.

for (i=0; i<GROUP; i++)

{flag=0;

for(int j=0; j<4; j++)

if(Gruppa[i].inform[j]==2) flag=l;

if (flag==l) printf ("Gruppa[i].FAM\n");}}

Функция - логически завершенный и определенным образом оформленный фрагмент программы. Функции подразделяют большие вычислительные задачи на более мелкие и позволяют пользоваться уже написанными подпрограммами, в том числе и другими разработчиками, а не начинать создание программы каждый раз заново.

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

Обычно в программах присутствует описание функции, называемое прототипом и содержащее информацию о параметрах каждой функции:

тип имя_функции (инф.парl, инф.пар2,...),

где информация о параметре <инф.nap.> имеет один из форматов: тип или тип имя_параметра, т.e. параметры функций могут быть объявлены с использованием как именных, так и безымянных параметров при объявлении прототипов:

void My_Func (int Parl, float Par2, double Par3);

void My_Func (int, float, double);

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

Каждая функция должна быть определена где-нибудь в программе после ее объявления, но не внутри другой функции, в том числе и не внутри, main().

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

Формат определения функции имеет вид:

[тип] имя_функции (тип имя_параметра, ..., тип имя_параметра)

{/* тело_функции */}

Указание типа перед именем функции не является обязательным для программ на языке С, но необходимо для программ на языке С++. После имени функции приводится список формальных параметров с указанием их типов. У каждой С-программы есть, по крайней мере, одна функция - main(). На практике в сложных программах функций может быть много, и каждая выполняет свою задачу.

Допускается не объявлять прототип функции в программе, но тогда ее определение должно находиться перед функцией main().

Рассмотрим очень простой пример использования функций.

#include <stdio.h>

void CntUp(void); //объявление

void CntDown(void); //прототипов функций.

main()

{CntUp(); //использование функций

CntDown(); //в программе (т.e. их вызов)

return 0;}

void CntUp(void)

{int i;

printf("\n\n Считаем от 1 до 10\n”);

for(i=l; i<=10; i++)

printf("%4d", i);}

void CntDown(void)

{int i;

printf("\n\n Считаем от 10 до 1\n ");

for(i=10; i>=l; i--);

printf("%4d", i);}

Ключевое слово void, стоящее перед именем функции при объявлении ее прототипа, сообщает о том, что функция выполняет некоторые действия, но не возвращает никаких значений. Слово void внутри круглых скобок, где обычно находится список параметров, сообщает компилятору, что функция не требует передачи аргументов.