Смекни!
smekni.com

Структуры и объединения (стр. 1 из 3)

Кафедра: Автоматика и Информационные Технологии

Структуры и объединения


СОДЕРЖАНИЕ

1. СТРУКТУРЫ

Основные сведения о структурах

Структуры и функции

Указатели на структуры

Массивы структур

2. ОБЪЕДИНЕНИЯ

3. ПРАКТИЧЕСКИЕ ЗАДАНИЯ

Задание 3.1

Задание 3.2.

Задание 3.3.

4. ЛАБОРАТОРНЫЕ ЗАДАНИЯ

5. ДОПОЛНИТЕЛЬНЫЕ ЗАДАНИЯ

Задание 5.1.

Задание 5.2.

Задание 5.3.

БИБЛИОГРАФИЧЕСКИЙ СПИСОК


1. Структуры

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

Традиционный пример структуры - строка платежной ведомости. Она содержит такие сведения о служащем, как его полное имя, адрес, номер карточки социального страхования, зарплата и т. д. Некоторые из этих характеристик сами могут быть структурами: например, полное имя состоит из нескольких компонент (фамилии, имени и отчества); аналогично адрес, и даже зарплата. Другой пример (более типичный для Си) - из области графики: точка есть пара координат, прямоугольник есть пара точек и т. д.

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

Основные сведения о структурах

Объявление структуры начинается с ключевого слова struct и содержит список объявлений, заключенный в фигурные скобки:

struct имя_структуры {

список объявлений;

};

имя_структуры иногда называют тегом структуры.

Перечисленные в структуре переменные называются элементами. Элементами структур могут быть:

- переменные и массивы базовых типов,

- переменные и массивы пользовательских типов, кроме типа самой структуры имя_структуры,

- указатели на любые типы, включая и тип самой структуры имя_структуры,

- функции.

Включение в структуры элементов-функций не является общепринятым. Как правило, в этом случае переходят к понятию класса.

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

Приведем пример структуры time:

struct time {

int hour;

int minutes;

};

В нашем примере элементами структуры будут hour и minutes.

Объявление структуры не резервирует памяти. Оно является информацией компилятору о введении пользовательского типа данных. Память выделится при определении структурных переменных.

Если структурный тип в программе больше не будет использоваться, объявляют безымянную структуру одновременно с определением переменной. Например,

struct {

intx, y;

} q;

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

struct time t;

определяет структурную переменную t типа structtime. Принято использовать один и тот же термин структура применительно к пользовательскому типу данных и к структурной переменной. Однако, по фразам «объявление структуры» и «определение структуры» ситуация становится однозначной. Для структурной переменной, как и для массива при объявлении сразу выделяется память. Поэтому структурная переменная определяется, а тип объявляется.

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

Имя_структуры.элемент_структуры

Операция доступа к элементу структуры ‘.’ соединяет имя структуры и имя элемента.

Например,

struct time t = {21, 30};

printf("%d:%d", t.hour, t.minutes);

Структуры могут быть вложены друг в друга. Например, структура chronos содержит две структуры timebegin и end:

struct chronos {

struct time begin, end;

};

struct chronos timer = {{2,4}, {10, 10}};

Выражение timer.begin.minutesобращается к минутам minutesвремени beginиз timer.

В стандарте ANSIC ключевое слово struct при объявлении структурных переменных можно опускать, то есть допустима и общепринята запись .

chronos timer;

Размер структуры в байтах складывается из размера его элементов. Например, sizeof(timer) = 8 байт. Однако, если включена опция компилятора Options-Compiler-Code generation-Word allgnment, то все элементы будут располагаться по четным адресам. Поэтому в случае

struct FIO { char F[25], I[15], Otch[20]};

будем иметь sizeof(FIO) = 26 + 16 + 20 = 62.

Структуры и функции

Над структурами возможны следующие операции:

- присваивание,

- взятие адреса с помощью &,

- осуществление доступа к ее элементам.

Присваивание используется при передаче структуры в функцию по значению и возврат структуры по значению. Структуры нельзя сравнивать. Инициализировать структуру можно списком константных значений ее элементов; автоматическую структуру также можно инициализировать присваиванием.

Чтобы лучше познакомиться со структурами, напишем несколько функций, манипулирующих time и chronos. Возникает вопрос: а как передавать функциям названные объекты? Существует, по крайней мере, три подхода: передавать компоненты по отдельности, передавать всю структуру целиком и передавать указатель на структуру. Каждый подход имеет свои плюсы и минусы.

Первая функция, maketime, получает два целых значения и возвращает структуру time.

/* maketime: формирует время по компонентам hour и minutes */

time maketime(int hour, int minutes){

time temp;

temp.hour = hour;

temp.minutes = minutes;

return temp;

}

Заметим: никакого конфликта между именем аргумента и именем элемента структуры не возникает; более того, сходство подчеркивает родство обозначаемых им объектов.

Теперь с помощью maketime можно выполнять динамическую инициализацию структуры или формировать структурные аргументы для той или иной функции:

chronos timer;

timer.begin = maketime(0, 0);

timer.end = maketime(12, 5);

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

/* addtime: сложение времени */

time addtime (time tm1, time tm2)

{

tm1.minutes += tm2.minutes;

tm1.hour += tm2.hour + tm1.minutes/60;

tm1.minutes %= 60;

return tm1;

}

Здесь оба аргумента и возвращаемое значение - структуры.

В качестве другого примера приведем функцию tinchronos, которая проверяет: находится ли данный момент времени внутри нашего интервала.

/* tinchronos: возвращает 1, если t в c, и 0 в противном случае */

int tinchronos (struct time t, struct chronos c)

{

return t.hour >= c.begin.hour

&& t.hour < c.end.hour

&& t.minutes >= c.begin.minutes

&& t.minutes < c.end.minutes;

}

Указатели на структуры

Так как имя структурного типа обладает всеми правами имен типов, то разрешено определять указатели на структуры:

имя_структурного_типа * имя_указателя_на_структуру;

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

time *pt;

сообщает, что pt - это указатель на структуру типа struct time. Если pt указывает на структуру time, то *pt - это сама структура, а (*pt).hour и (*pt).minutes - ее элементы. Используя указатель pt, мы могли бы написать

time origin, *pt;

pt = &origin;

printf("origin: (%d,%d)&bsol;n", (*pt).hour, (*pt).minutes);

Скобки в (*pt).hour необходимы, поскольку приоритет операции «.» выше, чем приоритет операции разыменования «*». Выражение *pt.hour будет проинтерпретировано как *(pt.hour), что неверно, поскольку pt.hour не является указателем.

Указатели на структуры используются весьма часто, поэтому для доступа к ее элементам была придумана операция «обращение к элементу структуры по указателю», сокращенно «стрелка» с формой записи «->». Если t — указатель на структуру, то

t->элемент-структуры

есть ее отдельный элемент. Поэтому printf можно переписать в виде

printf("origin: (%d,%d)&bsol;n", pt->hour, pt->minutes);

Операции . и -> левоассоциативны, то есть выполняются слева направо. Таким образом, при наличии объявления

chronos ch, *cht = &ch;

следующие четыре выражения будут эквивалентны:

ch.begin.hour

cht->begin.hour

(ch.begin).hour

(cht ->begin).hour

Операции доступа к элементам структуры . и -> вместе с операторами вызова функции () и индексации массива [] занимают самое высокое положение в иерархии приоритетов и выполняются раньше любых других операторов. Например, если задано объявление

struct {

int len;

char *str;

} *p;

то

++p->len

увеличит на 1 значение элемента структуры len, а не указатель p, поскольку в этом выражении как бы неявно присутствуют скобки: ++(p->len). Чтобы изменить порядок выполнения операций, нужны явные скобки. Так, в (++р)->len, прежде чем взять значение len, программа прирастит указатель p. В (р++)->len указатель p увеличится после того, как будет взято значение len (в последнем случае скобки не обязательны).

По тем же правилам *p->str обозначает содержимое объекта, на который указывает str; *p->str++ прирастит указатель str после получения значения объекта, на который он указывал (как и в выражении *s++), (*p->str)++ увеличит значение объекта, на который указывает str; *p++->str увеличит p после получения того, на что указывает str.