Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Си++ Занятие 10.doc
Скачиваний:
5
Добавлен:
19.11.2019
Размер:
123.39 Кб
Скачать

2. Оператор typedef

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

Синтаксис typedef-объявления:

typedef тип имя;

Пример 6. Введение нового имени типа для обозначения целого числа

typedef int INTEGER;

После такого объявления можно создавать целые числа, используя новое имя типа:

INTEGER a, b;

Оно будет выполнять то же самое, что и привычное объявление int a, b.

Другими словами, INTEGER можно использовать как синоним ключевого слова int.

При работе со структурами оператор typedef определяет структурный тип и присваивает ему обозначение (имя):

typedef strucr tovar

{char name[20]; //наименование

double prise; //цена

int vol; //количество

date in_date; //дата поступления

} sklad1;

Ниже для одной и той же структуры введены два имени:

tovar стандартным образом,

sklad1 с помощью оператора typedef.

Теперь структурные объекты могут определяться как с помощью типа sklad1, так и с помощью обозначения struct tovar.

Пример 6.

//Три структуры (tea, meat, broad) типа sklad1

sklad1 tea, meat, broad;

//Две структуры (pen, book) типа struct tovar

struct tovar pen, book;

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

9.3 Определение структуры безымянного типа

Следующий вариант определения структур является некоторым упрощением приведенных выше вариантов. Можно определять структуры, вводя «внутреннее строение» (т.е. элементы структуры), но не вводя имени структурного типа. Такой безымянный структурный тип используется для однократного определения структур.

Пример 7. Определить структуру для введения данных о компьютере

struct

{ char processor[10];

int frequency;

int memory;

int disk;

} IBM, DEC, COMPAQ;

После такого определения программист может работать со структурными объектами IBM, DEC, COMPAQ, но не может вводить в программу новые объекты. Если же все же понадобится создание дополнительных объектов, придется полностью повторить приведенное выше определение структурного типа.

9.4 Доступ к элементам структуры

Итак, мы научились определять структуры, создавать и инициализировать переменные структурного типа, осталось научиться работать с ними.

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

Для доступа к полям структуры используются два специальных оператора:

. (точка), когда работают с именем структуры;

-> (минус и знак «больше»), когда работают с указателем на структуру.

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

Кроме участия в выражениях, поля структур могут вводиться с клавиатуры, их можно передавать функциям и т.д.

Пример 8. Обращение к полям структуры с использованием оператора «.» и через указатель.

#include <stdio.h>

#include <string.h>

void main()

{ struct date

{ int day;

char month[15];

int year;

};

//Объявление объектов структуры

struct date s_day={10, “september”, 1988}, e_day, *p1, *p2;

//Использование операции «.»

e_day.day = 22;

memcpy (e_day.month, s_day.month, 15);

e_day.year = s_day.year;

//Использование указателей

p1=&s_day;

p2=&e_day; //установка указателей на переменные s_day и e_day

p2->day = 22;

memcpy (p2->month, p1->month, 15);

p2->year = p1->year;

printf(“\ne_day: day=%d \t month=%s \t year=%d \ n”, /

e_day.day, e_day.month, e_day.year);

}

\t – горизонтальная табуляция

%s – строка символов

Определены следующие объекты структуры:

- переменные s_day и e_day, причем для s_day одновременно с созданием проведена инициализация,

- указатели на структуру с именами р1 и р2.

В примере выполнены одинаковые действия двумя разными способами – с применением имен объектов и с безымянным использованием через указатели. Оператор e_day.day = 22 записывает число 22 в поле day переменной e_day.

Обратим внимание, что перед точкой стоит имя объекта, для которого выделена память (а не имя типа структуры).

В поле e_day.year заносим элемент другой структуры – s_day.year. Третье поле e_day.month представляет собой строку текста. Как известно, в стандарте языка С, С++ нет встроенных средств работы со строками, есть возможность работать только с отдельными символами строки, поэтому для работы с целыми строками приходится использовать библиотечные функции. В нашем примере используется функция memcpy() из библиотеки string.h, которая копирует 15 символов из строки s_day.month в строку е_day.month.

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

- для обращения к полю day структуры e_day:

p2->day = 22;

- для копирования строки month из структуры s_day в структуру e_day

memcpy (p2->month, p1->month, 15);

При работе со структурами можно использовать комбинацию доступа через указатель и операцию «точка».

(*p2).day = 22;

memcpy ((*p2).month, (*p1).month, 15);

(*p2). year = (*p1). year;

Здесь используется операция разыменования указателя (*) для доступа к переменной структурного типа, а затем через операцию «точка» получаем доступ к полю структуры.

Следующий пример демонстрирует доступ к вложенным структурам. В структурном типа tovar поле in_date представляет собой элемент структурного типа date, т.е структурный тип date вложен в структурный тип tovar.

Пример 9.

struct tovar tea, sklad[100], *pt;

tea.in_date.day = e_day.day;

tea.in_date.year = 1985;

//установка указателя на 5 элемент массива

pt=&sklad[5];

pt->vol = 20;

pt->in_date.day = 25;

(*pt).in_date.year = 2000;

Обращение к элементу вложенной (внутренней) структуры типа date проходит в два этапа, сначала выбирается поле структуры tea (в данном случае структура in_date), а затем поле структуры in_date (например, day). Во вложенных структурах также возможна работа с операцией «точка» и указателем. В нашем примере это:

tea.in_date.day = e_day.day;

pt=&sklad[5];

pt->in_date.day = 25;

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

Что еще можно делать со структурой? Разумеется, передавать в функцию в качестве параметра и возвращать в качестве результата. Однако есть здесь одна особенность – нельзя передавать в функцию и возвращать из нее саму структуру, т.е. работать со структурой «по значению», как с переменной. Параметр-структура может быть передана только через указатель, и никаким другим способом, т.е. нужно использовать адрес структурного объекта.

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

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

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

Пример 10.

#include <stdio.h>

//определение структурного типа COMPLEX

typedef struct

{double re; //действительная часть числа

double im; // мнимая часть числа

} COMPLEX;

//запись значений в структуру COMPLEX

void set_complex (COMPLEX *n, double re, double im)

{n->re=re;

n->im=im;

}

//сложение двух переменных COMPLEX

COMPLEX* add_complex (COMPLEX *n1, COMPLEX *n2)

{static COMPLEX result;

result.re = n1->re + n2->re;

result.im = n1->im + n2->im;

return &result;

}

//Печать переменной COMPLEX

void print_complex (COMPLEX *n)

{printf (“deistvitel’naya chast’: %f \t mnimaya chast’: %f \n”, n->re, n->im);

}

//Головная функция программы

void main ()

{ COMPLEX num1, num2, *ptr;

set_complex(&num1, 1.0, 1.0);

set_complex(&num2, 3.0, 0.0);

ptr=add_complex(&num1, &num2);

print_complex (ptr);

}

Новый структурный тип COMPLEX введен с помощью директивы typedef, что позволяет в дальнейшем при обращении к новому типу опускать ключевое слово struct. Определение структурного типа включает два поля – для действительной и для мнимой части комплексного числа.

Функция set_complex() служит для записи данных в комплексное число. Она не возвращает никакого значения и имеет три параметра. Первый – указатель на структуру типа COMPLEX (на комплексное число, в которое будет происходить запись). Второй и третий параметры служат для передачи значений, записываемых соответственно в действительную и мнимую части комплексного числа.

Функция add_complex() складывает два комплексных числа и возвращает их сумму в вызывающую программу. Оба параметра и возвращаемое значение – указатели на структурные объекты типа COMPLEX. Обратим внимание, что возвращаемое значение – это указатель на переменную result, которая определяется в теле функции add_complex(). Для того, чтобы переменная result была доступна из вызывающей программы, она объявляется как статическая переменная и поэтому не уничтожается при выходе из функции. Оператор return возвращает адрес переменной result, при помощи явного обращения к оператору взятия адреса &.

Функция print_complex() выводит на печать комплексное число и комментарий. Функция не возвращает значения, а в качестве параметра ожидает указатель на объект типа COMPLEX.

Обратим внимание, что когда в качестве формального параметра функции объявлен указатель (в нашем примере на структуру), то при вызове функции передается адрес переменной. В первом случае, при вызове функций set_complex() и add_complex(), явно, путем передачи адресов переменных num1 и num2, а во втором случае, при вызове функции print_complex() – неявно, путем передачи указателя (в котором уже записан адрес переменной).

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

Для этого в функции main определяем две переменные для хранения комплексных чисел num1, num2, и указатель *ptr для адресации результата. В дальнейшем для работы со сложным объектом, каковым является комплексное число, будем использовать соответствующую функцию, в этом случае в вызывающей программе «не видны» подробности строения структурного объекта, т.е. нет обращения к отдельным элементам структуры, все эти подробности спрятаны внутри соответствующей функции.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]