Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Объединения разнотипных данных

В файле ch_stac1.cpp

Разбор функции ch_stack

Объявление struct создаёт новый тип – ch_stack. В нём два элемента: элемент-массив s и целый элемент top.

Функция reset используется для инициализации. Члену top присваивается значение empty. Конкретный ch_stack, с которым работает эта функция, является аргументом, передаваемым как адрес.

Операция помещения в стек (push) реализована как функция двух аргументов. Член top увеличивается на единицу. Значение c помещается вершину ch_stack. Эта функция полагает, что ch_stack не заполнен. Операция извлечения из стека (pop) реализована таким же образом; в ней предполагается, что ch_stack не пуст. Возвращается значение вершины стека, и член top уменьшается на единицу.

Функции empty и full возвращают значение типа bool. Каждая из них проверяет член top на соответствующее условие. Например, перед вызовом push() программист может проверить, что ch_stack не полон, для того чтобы функция push() работала корректно. Эти функции не изменяют ch_stack, на который они направлен. Поэтому мы можем объявить аргументы-указатели как const. Во всех функциях аргумент ch_stack передаётся как адрес, а для доступа к членам используется оператор указателя структуры ->.

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

#include “ch_stac1.h”

#include <iostream.h>

int main()

{

ch_stack s;

char str[40] = {“Всем привет!”};

int i = 0;

cout << str << endl; //печать строки

reset (&s);

while (str[i] &&!full(&s)) //помещение в стек

push(&s, str[i++]);

while (!empty(&s)) //печать обращённой строки

cout << pop(&s);

cout << endl;

}

Вывод этой программы выглядит так:

Всем привет!

!тевирп месВ

Отметим, что одним из фактических аргументов в каждой из функций является &s, то есть адрес переменной типа ch_stack, объявленной в main(). Мы задаём этот аргумент, поскольку функции ожидают адрес переменной типа ch_stack.

 

 

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

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

Union имя_объединяющего_типа { элементы_объединения };

Пример объединяющего типа:

Union mixture { double d;

Long e[2];

Int k[4]; };

Введя тип объединения, можно определять конкретные объединения, их массивы, а также указатели и ссылки на объединения:

Mixture mA, mB[4]; //объединение и массив объединений

Mixture *pmix; // указатель на объединение

Mixture& rmix = mA; // ссылка на объединение

Для обращения к элементу объединения можно использовать либо уточнённое имя:

Имя_объединения.имя_элемента

либо конструкцию, включающую указатель:

указатель_на_объединение -> имя_элемента

(*указатель_на_объединение). имя_элемента

либо конструкцию, включающую ссылку:

ссылка_на_объединение.имя_элемента

Примеры:

mA.d = 64.8;

mB[2].E[1] = 10L;

pmix = &mB[0];

pmix->E[0] = 66;

cin >> (*pnix).K[1];

cin >> rmix.E[0];

 

Заносить значения в участок памяти, выделенный для объединения, можно с помощью любого из его элементов. То же самое справедливо и относительно доступа к содержимому участка памяти, выделенного для объединения. Если бы элементы объединения имели одинаковую длину и одинаковый тип, а отличались только именами, то использование объединения было бы подобно применению ссылок. Просто один участок памяти в этом случае имел бы несколько различных имён:

Union { int ii, int jj } unij;

Unij.ii = 15; //изменение содержимого;

Cout << unij.jj; //вывод содержимого

 

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

Union { char hh[2];

Int ii;} cc;

Здесь символьный массив char hh[2] и целая переменная int ii – элементы объединения – соответствуют одному участку памяти:

 

Участок памяти,

выделенный

объединению сс

 

Используем введённое объединение с именем сс для решения небольшой конкретной задачи, связанной с доступом к буферу клавиатуры ПЭВМ типа IBM PC. В MS-DOS принято, нажатие на любую клавишу клавиатуры ПЭВМ приводит к занесению в буфер клавиатуры (буфер клавиатуры – это специально зарезервированный участок памяти) целого двухбайтового числа. Каждый байт этого целого числа имеет самостоятельное смысловое значение. Байт с младшим адресом содержит так называемый ASCII-код клавиши, а старший (с большим адресом) содержит дополнительный код, называемый скэн-кодом клавиши. В библиотеке компилятора С++ имеется специальная функция int bioskey(int b); позволяющая получить доступ к буферу клавиатуры. Параметр int b функции bioskey() позволяет выбрать режим её использования. Обращение boiskey(1) проверяет наличие в буфере хотя бы одного кода. Если буфер пуст, то bioskey(1) возвращает ненулевое значение.

Как только в буфере появится код (от нажатия клавиши), функция bioskey(1) возвратит ненулевое значение. Прочитать тот код, который занесён в буфер, и очистить буфер от этого кода позволяет обращение к функции bioskey() с нулевым значением параметра. При обращении bioskey(0) функция выбирает из буфера клавиатуры очередной двухбайтовый код и возвращает его как целое число (двухбайтовое). Выделить из этого числа отдельные байты очень просто с помощью объединения. Следующая программа получает и выводит на экран значения кодов, поступающих в буфер клавиатуры ПЭВМ, работающей под управлением MS-DOS:

 

#include <bios.h> //для функции bioskey()

#include <iostream.h>

void main()

{ union {char hh[2]; int ii; } cc;

unsigned char scn, //скэн-коды

asc; //ASCII-коды

cout << “\nВыход из программы по Ctrl+Z”;

cout << “\n\nSCAN | ASCII”;

do { //цикл до Ctrl+Z

cout << “\n”;

while (bioskey(1) == 0); //До появления кода

cc.ii = bioskey(0);

asc = cc.hh[0];

scn = cc.hh[1];

cout << “ “ << int(scn) << “ | “;

cout << int(asc) << “ “ << asc;

} //выход из цикла по Ctrl+Z, когда asc == 26 и scn == 44:

while (asc!= 26 || scn!= 44);

}

Результат выполнения программы:

SCAN | ASCII

34 | 103 g

35 | 104 h

36 | 106 j

24 | 111 o

44 | 26

 

Для ASCII_кода печатается не только числовое значение, но и соответствующий ему экранный символ.

Обратите внимание на внутренний цикл while с проверкой значение bioskey(1). Он прерывается только при появлении внешнего события – при нажатии на клавишу. Значение bioskey(1) становится при этом отличным от 0, и следует переход ук оператору с обращением bioskey(0).

Возвращаемое целое значение заносится в элемент объединения cc.ii, а потом из объединения выбираются отдельные однобайтовые коды (scn, asc). Внешний цикл будет прерван при появлении кодов asc ==26 и scn == 44 (сочетание клавиш Ctrl+Z). После этого программа прекращает выполнение.

 

Объединение может быть безымянным:

// в файле weekend.cpp

enum week { sun, mon, tues, weds, thurs, fri, sat }; //дни недели

union {

int i;

week w;

};

i = 5;

if (w == sat || w == sun) //суббота или воскресение

cout << “Выходной!”;

Объявление безымянного объединения позволяет использовать идентификаторы отдельных членов как переменные. Имена членов должны быть уникальными в пределах области видимости; кроме того, никакие другие переменные безымянного типа объявлять нельзя. Безымянное объединение, объявленное в области видимости файла, должно быть статическим (static).

Усовершенствуем стек, переделав его в виде объединения различных типов. Суть в том, что стек является структурой данных, полезной для хранения значений любых типов. Такой стек можно использовать для обработки разнородных значений, применяя метод LIFO:

Enum type { int_type, dbl_type, chr_type, str_type };

Union rainbow {

Int i;

Double x;

Char c;

Char* p;

};

struct rbdata {

type t;

rainbow d;

};

struct u_stack {

rbdata s[max_len];

int top;

};

Структура данных u_stack более гибкая, за что приходится расплачиваться дополнительной памятью, которая требуется для хранения переменной t типа type для каждого из элементов. Операции стека кодируются так же, как в ch_stack. Например, push():

Void push(u_stack* stk, str[i++])

{

stk -> s[++stk -> top = c;

}

При использовании u_stack член t отслеживает, значение какого типа содержится в каждом элементе стека.

 

<== предыдущая лекция | следующая лекция ==>
В файле ch_stac1.h | В файле poker.cpp
Поделиться с друзьями:


Дата добавления: 2014-01-06; Просмотров: 704; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.008 сек.