Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТП лекции Раздел 4.doc
Скачиваний:
16
Добавлен:
28.09.2019
Размер:
2.56 Mб
Скачать

4.3.3. Составные типы данных. Структуры

Массив, как известно, объединяет под одним именем переменные (элементы) одинакового типа. Структуры служат для объединения в одной переменной эле­ментов разных типов. Например, нижеследующая структура Man объединяет эле­менты типов int и char*:

struct Man // Структура как тип данных для учета людей

{

int Age; // Возраст

char *Name; //Имя

}

Идентификатор Man именует только тип структуры (structure tag), то есть опре­деляет новый тип данных, используемый в программе. Чтобы иметь возможность работы с реальной структурой, надо создать представитель типа (instance of a struct), то есть определить переменную типа Man. В языке C++ для этого доста­точно сделать объявление Man m;. Теперь можно работать с переменной m как со структурой. Добраться до элемента структуры можно с помощью операции <точка>. Например, оператор m.Age=49: присваивает элементу Age струк­туры m типа Man значение 49.

Следующий фрагмент иллюстрирует достаточно надежный способ ввода с консоли значения текстовой строки (в данном случае элемента Name структуры т):

unsigned n; //Длина имени

char buf[80], *p; //Буфер ввода и указатель на начало строки

buf[0] = 60; // Ограничение на длину строки

р = cgets(buf); //Ввод в буфер

n = buf[l]; // Количество фактически введенных символов

if (n) // Если что-нибудь введено

{

m.Name = new char[n+l]; // Захват памяти

strcpy(m.Name.p); // Копирование строки

}

Непосредственный ввод в буфер (обычно многократно используемый для ввода различных строк текста) осуществляет функция cgets. Все остальные операторы обеспечивают надежность. Правила игры задает функция cgets. Она требует, чтобы предварительно в buf [0] было задано максимально допустимое количество сим­волов в строке. Она помещает в buf[l] количество фактически введенных сим­волов и возвращает указатель на начало строки. Сама строка размещается, начи­ная с buf[2], поэтому cgets присваивает переменной р адрес buf[2]. Далее в фрагменте выполняются следующие действия. Если количество введенных сим­волов строки не равно нулю, то она копируется из буфера в предварительно от­веденную для нее область памяти. Надежность ввода обеспечивается тем, что пользователь может нажимать любое количество любых клавиш (по одной), и при этом программа не будет вести себя непредсказуемым образом.

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

Элементами струк­туры могут также быть структуры другого типа или указатели на структуру того же типа.

Частным, особым случаем структуры являются union-структуры. union — это структура, все элементы которой имеют нуле­вое смещение. Они требуют столько памяти, сколько занимает самый большой ее элемент. Указанный тип структур выравнивается так, чтобы можно было ра­ботать с любым элементом. В языке C++ появляется возможность декларации анонимной union-структуры, то есть структуры без имени, например:

struct Captain // Тип объемлющей структуры

{

char *name, *ship; //Два ее элемента

int river; // Третий элемент, задающий способ

// интерпретации четвертого элемента

union

{ // четвертый элемент: union-структура

long on_sea_hours; // Различные интерпретации

short years_of_service; // одной и той же области памяти

}

В каждый момент времени union хранит в отведенной для него компилятором области памяти только один из двух типов значений (long или short):

• если long, тогда его надо интерпретировать как on_sea_hours;

• если short, тогда это значение переменной years_of service.

Получить доступ к элементу анонимной union-структуры можно следующим образом:

Captain cap; // Объявление структуры типа Captain

// Инициализация полей структуры и другие действия

if (cap.river) // Анализ способа интерпретации

printf ("River service: %d years",cap.years_of_service): // Одна интерпретация union

else

printf ("Hours on sea: %1 hrs", cap. on_sea_hours): // Другая интерпретация

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

struct А; //Незавершенная декларация или упреждающее объявление

struct В { struct A *pa };

struct А { struct В *pb };

Объявление struct А; является неполным (incomplete), так как структура А не определена в точке объявления. Ниже появляется полная декларация струк­туры А, которая содержит указатель на уже определенную структуру В. Непол­ная декларация struct А допустима потому, что определение struct В не требует знания размера struct A.