Объявление и определение функций
Лекция №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 внутри круглых скобок, где обычно находится список параметров, сообщает компилятору, что функция не требует передачи аргументов.