КАТЕГОРИИ: Архитектура-(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 отслеживает, значение какого типа содержится в каждом элементе стека.
Дата добавления: 2014-01-06; Просмотров: 704; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |