К
Первоначальным образом для данных типа структур явились строки таблиц, с которыми знаком любой человек. Характерным для таблиц любого содержания является наличие столбцов, в каждом из которых хранятся однотипные данные. Однако в соседних столбцах типы данных могут отличаться. Если специфической особенностью массивов является использование одного и того же типа для всех элементов массива, то строки таблиц можно представлять как последовательность полей данных разного типа. Для каждого поля строки таблицы известно наименование соответствующего столбца таблицы и тип размещаемого в этом поле значения. Например, поле "Фамилия" заполняется текстовой информацией, поле "Год рождения" хранит целочисленные данные, на поле "Пол" достаточно записывать единственный символ 'М' или 'Ж' и т.д.
То, что принято называть "шапкой" таблицы в языках программирования носит название шаблона структуры. Например, шаблон структуры, описывающей данные о книге, может быть устроен следующим образом:
struct book {
char title[40]; //наименование
char authors[30]; //авторы
char publishing_house[15]; //издательство
int year; //год издания
int pages; //количество страниц
float price; //цена
}
Идентификатор book выполняет функцию имени шаблона или типа
структуры. В дальнейшем им можно пользоваться для объявления
конкретных переменных – структур типа book:
struct book b1,b2,b3; //три переменных типа book
В языке C++ служебное слово struct можно опускать:
book b1,b2,b3;
Обратите внимание на то, что строковые поля в структурах имеют фиксированные размеры. Это существенно упрощает обработку данных, т.к. работа с полями переменной длины могла бы привести к очень медленно работающим программам.
Вообще говоря, объявление шаблона структуры и переменных, связанных с этой структурой, можно совместить:
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
} b1,b2,b3;
Более того, в объявлении шаблона структуры можно опустить имя шаблона:
struct {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
} b1,b2,b3;
Однако если данная структура должна выступить в качестве параметра какой-либо функции, то и в заголовке этой функции и в ее прототипе без имени шаблона не обойтись.
Для доступа к соответствующим полям структур используются составные имена, образованные из имени структуры и имени поля:
strcpy(b1.title,"C++:Экспресс курс"); strcpy(b1.authors,"В.Лаптев"); cout << b1.title; b1.year=2004;
Если мы имеем дело с указателем, который настроен на адрес структуры, то составные имена записываются с использованием двух символов "->":
struct book *p=b1; //указатель на структуру strcpy(p->title,"C++:Экспресс курс"); strcpy(p->authors,"В.Лаптев"); cout << p->title; p->year=2004;
Структуры могут объединяться в массивы:
struct book c[20]; //массив структур
И тогда для доступа к полям соответствующего элемента используются индексированные составные имена:
strcpy(с[2].title,"Язык C++ ") strcpy(c[2].authors,"В.В.Подбельский"); cout << c[2].title; c[2].year=1996; struct book *pс=с; strcpy(pс[2]->title,"C++:Экспресс курс"); strcpy(pс[2]->authors,"В.Лаптев"); cout << pс[2]->title; pс[2]->year=2004;
При объявлении переменных типа структура их поля могут быть проинициализированы довольно естественным способом:
struct book a={"Programming Languages", "Jean E.Sammet",
"Prentice-Hall", 1969,785,49.99};
Для структур, объявленных с использованием одного и того же шаблона, допустима операция присваивания:
b1=a; //все поля структуры a копируются в структуру b1
К сожалению, одноименные поля строкового типа у структур так
копировать нельзя – необходимо прибегать к услугам функций типа :
strcpy(b1.authors,a.authors); //копируем поле "авторы"
Над содержимым числовых полей структур можно выполнять все операции, доступные для соответствующего типа данных.
Некоторые числовые поля структур могут быть объявлены как битовые
шкалы с указанным количеством двоичных разрядов. С одной стороны, это
предоставляет возможность компоновать в рамках машинных слов некоторые
группы данных и располагать их более компактно в оперативной памяти. С
другой стороны, такая возможность избавляет программиста от забот по
выделению и вклеиванию соответствующих групп двоичных разрядов. Однако
на расположение
struct qq{ int a:10; int b:14; } xx, *px;
xx.a=127;
px=xx;
px->b=9;
В зависимости от признака выравнивания границ данных эти значения могут быть расположены в оперативной памяти по-разному:

С целью принудительного расположения
struct { int a:10;
int :6;
int b:14; } yy;
Если функция не изменяет структуру, то такую структуру можно передать по значению.
Пример 9.1. Отображение полей структуры на экране дисплея
#include <iostream.h>
#include <conio.h>
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
};
void show_book(book b)
{ cout << "Title: "<< b.title << endl;
cout << "Authors: "<< b.authors << endl;
cout << "Publishing house: "<< b. publishing_house << endl;
cout << "Year: "<< b.year << endl;
cout << "Pages: " << b.pages << endl;
cout << "Price: " << b.price << endl;
}
void main()
{ book a={"Programming Languages", "Jean E.Sammet",
"Prentice-Hall", 1969,785,49.99};
show_book(a);
getch();
}
//=== Результат работы ===

Если обработка структуры в функции связана с изменением содержимого полей, то такую структуру необходимо передавать по указателю или по ссылке.
Пример 9.2. Параметр функции – указатель на структуру.
#include <iostream.h>
#include <conio.h>
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
};
void input_book(book *b) //структура передается по указателю
{ cout << "Title: ";
cin >> b->title;
cout << "Authors: ";
cin >> b->authors;
cout << "Publishing house: ";
cin >> b->publishing_house;
cout << "Year: ";
cin >> b->year;
cout << "Pages: ";
cin >> b->pages;
cout << "Price: ";
cin >> b->price;
}
void main()
{ book a,*pa=a;
input_book(pa);
getch();
}
Пример 9.3. Параметр функции – ссылка на структуру
#include <iostream.h>
#include <conio.h>
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
};
void input_book(book b) //структура передается по ссылке
{ cout << "Title: ";
cin >> b.title;
cout << "Authors: ";
cin >> b.authors;
cout << "Publishing house: ";
cin >> b.publishing_house;
cout << "Year: ";
cin >> b.year;
cout << "Pages: ";
cin >> b.pages;
cout << "Price: ";
cin >> b.price;
}
void main()
{ book a;
input_book(a);
getch();
}
В некоторых таблицах используются многоэтажные шапки, когда определенное поле заголовка, в свою очередь, распадается на несколько полей. Такая же ситуация может встретиться и в структурах, когда в качестве очередного поля выступает другая структура. И уровень вложения таких полей ничем не ограничен.
Пример 9.4. Вложенные структуры
struct Point {int x; int y;};
struct Line {Point P1; Point P2;}
Line ab;
ab.P1.x=5;
ab.P1.y=5;
ab.P2.x=25;
ab.P2.y=30;
Конечно, приведенная выше запись не являет образец компактности в программе, но она демонстрирует составные имена, обеспечивающие доступ к вложенным полям.
Функции могут не только получать структуры в качестве своих параметров, но и возвращать результаты в виде структур. И это означает, что функция, возвращающая значение может иметь в качестве результата своей работы совокупность значений полей соответствующей структуры.
Пример 9.5. Функции g1, g2 и g3 возвращают структуру
#include <iostream.h>
#include <conio.h>
struct ss {int a; float b; };
ss g1(ss v) //параметр - значение
{ v.a=7; v.b=8; return v; }
ss g2(ss v) //параметр - ссылка
{ v.a=v.b+7; v.b=v.a+8; return v; }
ss g3(const ss v) //параметр - константная ссылка
{ ss q;
q.a=v.b+7; q.b=v.a+8; return q;
}
void main()
{ ss x1,y1={1,2};
ss x2,y2={3,4};
ss x3,y3={5,6};
x1=g1(y1);
cout << "x1=" << x1.a << '; ' << x1.b << endl;
cout << "y1=" << y1.a << '; ' << y1.b << endl;
y1=g1(y1);
cout << "x1=" << x1.a << '; ' << x1.b << endl;
cout << "y1=" << y1.a << '; ' << y1.b << endl;
x2=g2(y2);
cout << "x2=" << x2.a << '; ' << x2.b << endl;
cout << "y2=" << y2.a << '; ' << y2.b << endl;
x3=g3(y3);
cout << "x3=" << x3.a << '; ' << x3.b << endl;
cout << "y3=" << y3.a << '; ' << y3.b << endl;
y3=g3(y3);
cout << "x3=" << x3.a << '; ' << x3.b << endl;
cout << "y3=" << y3.a << '; ' << y3.b << endl;
getch();
}
//=== Результат работы ===
x1=7; 8 //x1 - изменился
y1=1; 2 //y1 - не изменился
x1=7; 8 //x1 - не изменился
y1=7; 8 //y1 - изменился
x2=11; 19 //x2 - изменился
y2=11; 19 //y2 - изменился
x3=13; 13 //x3 - изменился
y3=5; 6 //y3 - не изменился
x3=13; 13 //x3 - не изменился
y3=13; 13 //y3 - изменился
В языке C++ структуры послужили прообразом классов. Их основное отличие от структур языка C в том, что теперь структуры могут объединять разнородные данные с функциями – методами их обработки. Часть компонент структуры может быть доступна всем пользователям, другая часть может быть сокрыта, т.к. предназначена для выполнения внутренних задач. Однако со всеми этими особенностями структур мы будем знакомиться после изучения основ объектно-ориентированного программирования.
Перечисления представляют собой список идентификаторов, введенных пользователем:
enum name_list {name1,name2,...};
За каждым таким именем по умолчанию закрепляются целочисленные константы:
name1 соответствует константа 0;name2 соответствует константа 1;В чем смысл замены целочисленных констант такими символьными
обозначениями? Дело в том, что в конкретных прикладных задачах удобно
иметь дело с мнемоническими обозначениями характеристик некоторых
объектов. Например, имея дело с цветами радуги, было бы удобно ввести
обозначение для палитры радуги ( rainbow ) и перечислить в ней цвета в
том порядке, как они упорядочены в природе (" каждый охотник желает
знать, где сидят фазаны " – красный, оранжевый, желтый, зеленый, голубой, синий,
фиолетовый):
enum rainbow {red, orange, yellow, green, aqua, blue, purple};
Переменная r_col, которая будет в дальнейшем обозначать цвет
радуги, должна быть связана с именем списка, и это позволит
присваивать ей значения, более понятные, чем соответствующие целые
числа:
enum rainbow r_col; r_col=yellow; ............... if(r_col==yellow)...
В языке C++ при объявлении переменных типа перечисление разрешается
опускать служебное слово enum:
rainbow r_col=yellow;
В программах обработки экономической информации очень часто приходится иметь дело с названиями месяцев, дней недели. В таких случаях полезно прибегать к перечислениям типа:
enum week {sunday=1, monday, tuesday, wednesday, thursday,
friday, saturday};
enum month {jan=1, feb, mar, apr, may, jun, jul, aug, sep,
oct, nov, dec };
В приведенных выше примерах две особенности. Во-первых, нумерация
констант по умолчанию с 0 противоречит общепринятым нормам работы с
календарем. Поэтому для первой константы указано нестандартное
значение 1, а все последующие будут пронумерованы в порядке
возрастания номеров. Во-вторых, в перечислении названий месяцев
имеется возможность нарваться на сообщение об ошибке. Дело в том, что
сокращения для " октября " и " декабря " совпадают со служебными словами oct - восьмеричный и dec - десятичный, которые участвуют в управлении
потоковым выводом числовых данных. Можно перейти к другим
обозначениям, где первая буква месяца будет заглавной, тогда конфликта
удастся избежать.
Перечисления очень широко используются многими системными программами, особенно графическими:
enum line_style{SOLID_LINE, //сплошная линия
DOTTED_LINE, //пунктирная линия
CENTER_LINE, //штрих-пунктирная линия
DASHED_LINE, //штриховая линия
USERBIT_LINE}; //линия, определяемая пользователем
enum COLORS {BLACK,BLUE,GREEN,CYAN,RED,MAGENTA,BROWN,...};
Системный набор операций над переменными типа перечислений довольно ограниченный: им можно присваивать значения из объявленного списка, сравнивать значения однотипных переменных, передавать в качестве параметров другим функциям. Попытка вывести их значения приводит к появлению на экране приписанных им числовых номеров. Даже какой-то контроль за выходом из допустимого числового интервала для этих данных не реализован. Об этом свидетельствует следующий пример:
#include <stdio.h>
#include <conio.h>
void main()
{ enum qq {zero, one, two, three};
enum qq a,b;
a=one;
b=a+two;
printf("a=%d b=%d",a,b);
getch();
}
//=== Результат работы ===
a=1 b=3
Правда, при компиляции 7-й строки было выдано предупреждение о
попытке присвоения значения типа int переменной типа qq, но все
обошлось. Однако замена на оператор b=a+three; никаких эмоций у
компилятора не вызвала и был получен результат b=4. Даже попытка
выполнить b=5 ; тоже прошла гладко. Так что с данными типа enum
компилятор работает как с целыми числами и на выход за пределы
заданного диапазона внимания не обращает.
Обратим внимание еще на один нюанс в приписывании числовых номеров константам из перечисления:
enum num12 {one=1,ein=1,two,zwei=2};
Этот пример демонстрирует, что числовые номера в списке констант могут дублироваться, но сами имена должны быть уникальными. Использование одного и того же имени в двух разных перечислениях недопустимо.
Объединения – это такие наборы данных, которые компилятор должен
разместить в оперативной памяти, начиная с одного и того же места.
Впервые такое совмещение разных данных появилось в языке ФОРТРАН, где
для этой цели использовался оператор
В языках C, C++ объединения создаются с помощью оператора union. В
рамках MS-DOS, где нехватка оперативной памяти давала себя знать, с
помощью объединений можно наложить друг на друга массивы, используемые
в разное время. Однако наиболее важная цель объединений – расположить
в одном и том же месте данные разного типа. Это позволяет обращаться к
тем или иным полям, используя переменные разного типа. Наиболее
характерным объектом такого типа является ячейка электронной таблицы,
в которой пользователь может разместить текст или числовое выражение
того или иного типа.
Самым употребительным объединением в рамках MS-DOS было
использование dos.h было
определено объединение REGS:
struct WORDREGS // структура из 16-битных данных
{ unsigned int ax,bx,cx,dx,si,di,cflag,flags; };
struct BYTEREGS // структура из 8-битных данных
{ unsigned char al,ah,bl,bh,cl,ch,dl,dh; }
union REGS {struct WORDREGS x;
struct BYTEREGS h; };
В этих объявлениях содержатся описания двух структур, которые
имитируют распределение в оперативной памяти
MOV AH,2 ; номер функции 2 засылается в регистр AH MOV BH,0 ; номер страницы в текстовом режиме MOV DH,10 ; номер строки, в которую переводится курсор MOV DL,25 ; номер колонки INT 10H ; вызов прерывания с номером 16
Для того чтобы выполнить аналогичные действия (не прибегая к
библиотечной функции gotoxy ) на языке C надо проделать следующие
операции:
union REGS r; //заводим область регистров в памяти ............... r.h.ah=2; //засылаем номер функции в "регистр" AH r.h.bh=0; //засылаем номер страницы в "регистр" BH r.h.dh=y; //засылаем номер строки в "регистр" DH r.h.dl=x; //засылаем номер столбца в "регистр" DL int86(0x10,r,r); //имитация прерывания с номером 10h
Функция int86 перепишет содержимое объединения r в машинные
регистры, предварительно сохранив их содержимое, выполнит команду
прерывания, передающую управление подфункции MS-DOS с номером 2,
которая переместит курсор в заданную позицию. По окончании работы
подфункции содержимое
Может быть, вам покажется, что приведенный фрагмент излишне
усложнен, но реальная работа функции gotoxy(x,y) требует еще большего
числа операций.
В языке C++ также была предпринята попытка использовать объединения для создания классов. Однако о деталях другого использования объединений в разделе "C++ и объектно-ориентированное программирование".
К
Первоначальным образом для данных типа структур явились строки таблиц, с которыми знаком любой человек. Характерным для таблиц любого содержания является наличие столбцов, в каждом из которых хранятся однотипные данные. Однако в соседних столбцах типы данных могут отличаться. Если специфической особенностью массивов является использование одного и того же типа для всех элементов массива, то строки таблиц можно представлять как последовательность полей данных разного типа. Для каждого поля строки таблицы известно наименование соответствующего столбца таблицы и тип размещаемого в этом поле значения. Например, поле "Фамилия" заполняется текстовой информацией, поле "Год рождения" хранит целочисленные данные, на поле "Пол" достаточно записывать единственный символ 'М' или 'Ж' и т.д.
То, что принято называть "шапкой" таблицы в языках программирования носит название шаблона структуры. Например, шаблон структуры, описывающей данные о книге, может быть устроен следующим образом:
struct book {
char title[40]; //наименование
char authors[30]; //авторы
char publishing_house[15]; //издательство
int year; //год издания
int pages; //количество страниц
float price; //цена
}
Идентификатор book выполняет функцию имени шаблона или типа
структуры. В дальнейшем им можно пользоваться для объявления
конкретных переменных – структур типа book:
struct book b1,b2,b3; //три переменных типа book
В языке C++ служебное слово struct можно опускать:
book b1,b2,b3;
Обратите внимание на то, что строковые поля в структурах имеют фиксированные размеры. Это существенно упрощает обработку данных, т.к. работа с полями переменной длины могла бы привести к очень медленно работающим программам.
Вообще говоря, объявление шаблона структуры и переменных, связанных с этой структурой, можно совместить:
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
} b1,b2,b3;
Более того, в объявлении шаблона структуры можно опустить имя шаблона:
struct {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
} b1,b2,b3;
Однако если данная структура должна выступить в качестве параметра какой-либо функции, то и в заголовке этой функции и в ее прототипе без имени шаблона не обойтись.
Для доступа к соответствующим полям структур используются составные имена, образованные из имени структуры и имени поля:
strcpy(b1.title,"C++:Экспресс курс"); strcpy(b1.authors,"В.Лаптев"); cout << b1.title; b1.year=2004;
Если мы имеем дело с указателем, который настроен на адрес структуры, то составные имена записываются с использованием двух символов "->":
struct book *p=b1; //указатель на структуру strcpy(p->title,"C++:Экспресс курс"); strcpy(p->authors,"В.Лаптев"); cout << p->title; p->year=2004;
Структуры могут объединяться в массивы:
struct book c[20]; //массив структур
И тогда для доступа к полям соответствующего элемента используются индексированные составные имена:
strcpy(с[2].title,"Язык C++ ") strcpy(c[2].authors,"В.В.Подбельский"); cout << c[2].title; c[2].year=1996; struct book *pс=с; strcpy(pс[2]->title,"C++:Экспресс курс"); strcpy(pс[2]->authors,"В.Лаптев"); cout << pс[2]->title; pс[2]->year=2004;
При объявлении переменных типа структура их поля могут быть проинициализированы довольно естественным способом:
struct book a={"Programming Languages", "Jean E.Sammet",
"Prentice-Hall", 1969,785,49.99};
Для структур, объявленных с использованием одного и того же шаблона, допустима операция присваивания:
b1=a; //все поля структуры a копируются в структуру b1
К сожалению, одноименные поля строкового типа у структур так
копировать нельзя – необходимо прибегать к услугам функций типа :
strcpy(b1.authors,a.authors); //копируем поле "авторы"
Над содержимым числовых полей структур можно выполнять все операции, доступные для соответствующего типа данных.
Некоторые числовые поля структур могут быть объявлены как битовые
шкалы с указанным количеством двоичных разрядов. С одной стороны, это
предоставляет возможность компоновать в рамках машинных слов некоторые
группы данных и располагать их более компактно в оперативной памяти. С
другой стороны, такая возможность избавляет программиста от забот по
выделению и вклеиванию соответствующих групп двоичных разрядов. Однако
на расположение
struct qq{ int a:10; int b:14; } xx, *px;
xx.a=127;
px=xx;
px->b=9;
В зависимости от признака выравнивания границ данных эти значения могут быть расположены в оперативной памяти по-разному:

С целью принудительного расположения
struct { int a:10;
int :6;
int b:14; } yy;
Если функция не изменяет структуру, то такую структуру можно передать по значению.
Пример 9.1. Отображение полей структуры на экране дисплея
#include <iostream.h>
#include <conio.h>
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
};
void show_book(book b)
{ cout << "Title: "<< b.title << endl;
cout << "Authors: "<< b.authors << endl;
cout << "Publishing house: "<< b. publishing_house << endl;
cout << "Year: "<< b.year << endl;
cout << "Pages: " << b.pages << endl;
cout << "Price: " << b.price << endl;
}
void main()
{ book a={"Programming Languages", "Jean E.Sammet",
"Prentice-Hall", 1969,785,49.99};
show_book(a);
getch();
}
//=== Результат работы ===

Если обработка структуры в функции связана с изменением содержимого полей, то такую структуру необходимо передавать по указателю или по ссылке.
Пример 9.2. Параметр функции – указатель на структуру.
#include <iostream.h>
#include <conio.h>
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
};
void input_book(book *b) //структура передается по указателю
{ cout << "Title: ";
cin >> b->title;
cout << "Authors: ";
cin >> b->authors;
cout << "Publishing house: ";
cin >> b->publishing_house;
cout << "Year: ";
cin >> b->year;
cout << "Pages: ";
cin >> b->pages;
cout << "Price: ";
cin >> b->price;
}
void main()
{ book a,*pa=a;
input_book(pa);
getch();
}
Пример 9.3. Параметр функции – ссылка на структуру
#include <iostream.h>
#include <conio.h>
struct book {
char title[40];
char authors[30];
char publishing_house[15];
int year;
int pages;
float price;
};
void input_book(book b) //структура передается по ссылке
{ cout << "Title: ";
cin >> b.title;
cout << "Authors: ";
cin >> b.authors;
cout << "Publishing house: ";
cin >> b.publishing_house;
cout << "Year: ";
cin >> b.year;
cout << "Pages: ";
cin >> b.pages;
cout << "Price: ";
cin >> b.price;
}
void main()
{ book a;
input_book(a);
getch();
}
В некоторых таблицах используются многоэтажные шапки, когда определенное поле заголовка, в свою очередь, распадается на несколько полей. Такая же ситуация может встретиться и в структурах, когда в качестве очередного поля выступает другая структура. И уровень вложения таких полей ничем не ограничен.
Пример 9.4. Вложенные структуры
struct Point {int x; int y;};
struct Line {Point P1; Point P2;}
Line ab;
ab.P1.x=5;
ab.P1.y=5;
ab.P2.x=25;
ab.P2.y=30;
Конечно, приведенная выше запись не являет образец компактности в программе, но она демонстрирует составные имена, обеспечивающие доступ к вложенным полям.
Функции могут не только получать структуры в качестве своих параметров, но и возвращать результаты в виде структур. И это означает, что функция, возвращающая значение может иметь в качестве результата своей работы совокупность значений полей соответствующей структуры.
Пример 9.5. Функции g1, g2 и g3 возвращают структуру
#include <iostream.h>
#include <conio.h>
struct ss {int a; float b; };
ss g1(ss v) //параметр - значение
{ v.a=7; v.b=8; return v; }
ss g2(ss v) //параметр - ссылка
{ v.a=v.b+7; v.b=v.a+8; return v; }
ss g3(const ss v) //параметр - константная ссылка
{ ss q;
q.a=v.b+7; q.b=v.a+8; return q;
}
void main()
{ ss x1,y1={1,2};
ss x2,y2={3,4};
ss x3,y3={5,6};
x1=g1(y1);
cout << "x1=" << x1.a << '; ' << x1.b << endl;
cout << "y1=" << y1.a << '; ' << y1.b << endl;
y1=g1(y1);
cout << "x1=" << x1.a << '; ' << x1.b << endl;
cout << "y1=" << y1.a << '; ' << y1.b << endl;
x2=g2(y2);
cout << "x2=" << x2.a << '; ' << x2.b << endl;
cout << "y2=" << y2.a << '; ' << y2.b << endl;
x3=g3(y3);
cout << "x3=" << x3.a << '; ' << x3.b << endl;
cout << "y3=" << y3.a << '; ' << y3.b << endl;
y3=g3(y3);
cout << "x3=" << x3.a << '; ' << x3.b << endl;
cout << "y3=" << y3.a << '; ' << y3.b << endl;
getch();
}
//=== Результат работы ===
x1=7; 8 //x1 - изменился
y1=1; 2 //y1 - не изменился
x1=7; 8 //x1 - не изменился
y1=7; 8 //y1 - изменился
x2=11; 19 //x2 - изменился
y2=11; 19 //y2 - изменился
x3=13; 13 //x3 - изменился
y3=5; 6 //y3 - не изменился
x3=13; 13 //x3 - не изменился
y3=13; 13 //y3 - изменился
В языке C++ структуры послужили прообразом классов. Их основное отличие от структур языка C в том, что теперь структуры могут объединять разнородные данные с функциями – методами их обработки. Часть компонент структуры может быть доступна всем пользователям, другая часть может быть сокрыта, т.к. предназначена для выполнения внутренних задач. Однако со всеми этими особенностями структур мы будем знакомиться после изучения основ объектно-ориентированного программирования.
Перечисления представляют собой список идентификаторов, введенных пользователем:
enum name_list {name1,name2,...};
За каждым таким именем по умолчанию закрепляются целочисленные константы:
name1 соответствует константа 0;name2 соответствует константа 1;В чем смысл замены целочисленных констант такими символьными
обозначениями? Дело в том, что в конкретных прикладных задачах удобно
иметь дело с мнемоническими обозначениями характеристик некоторых
объектов. Например, имея дело с цветами радуги, было бы удобно ввести
обозначение для палитры радуги ( rainbow ) и перечислить в ней цвета в
том порядке, как они упорядочены в природе (" каждый охотник желает
знать, где сидят фазаны " – красный, оранжевый, желтый, зеленый, голубой, синий,
фиолетовый):
enum rainbow {red, orange, yellow, green, aqua, blue, purple};
Переменная r_col, которая будет в дальнейшем обозначать цвет
радуги, должна быть связана с именем списка, и это позволит
присваивать ей значения, более понятные, чем соответствующие целые
числа:
enum rainbow r_col; r_col=yellow; ............... if(r_col==yellow)...
В языке C++ при объявлении переменных типа перечисление разрешается
опускать служебное слово enum:
rainbow r_col=yellow;
В программах обработки экономической информации очень часто приходится иметь дело с названиями месяцев, дней недели. В таких случаях полезно прибегать к перечислениям типа:
enum week {sunday=1, monday, tuesday, wednesday, thursday,
friday, saturday};
enum month {jan=1, feb, mar, apr, may, jun, jul, aug, sep,
oct, nov, dec };
В приведенных выше примерах две особенности. Во-первых, нумерация
констант по умолчанию с 0 противоречит общепринятым нормам работы с
календарем. Поэтому для первой константы указано нестандартное
значение 1, а все последующие будут пронумерованы в порядке
возрастания номеров. Во-вторых, в перечислении названий месяцев
имеется возможность нарваться на сообщение об ошибке. Дело в том, что
сокращения для " октября " и " декабря " совпадают со служебными словами oct - восьмеричный и dec - десятичный, которые участвуют в управлении
потоковым выводом числовых данных. Можно перейти к другим
обозначениям, где первая буква месяца будет заглавной, тогда конфликта
удастся избежать.
Перечисления очень широко используются многими системными программами, особенно графическими:
enum line_style{SOLID_LINE, //сплошная линия
DOTTED_LINE, //пунктирная линия
CENTER_LINE, //штрих-пунктирная линия
DASHED_LINE, //штриховая линия
USERBIT_LINE}; //линия, определяемая пользователем
enum COLORS {BLACK,BLUE,GREEN,CYAN,RED,MAGENTA,BROWN,...};
Системный набор операций над переменными типа перечислений довольно ограниченный: им можно присваивать значения из объявленного списка, сравнивать значения однотипных переменных, передавать в качестве параметров другим функциям. Попытка вывести их значения приводит к появлению на экране приписанных им числовых номеров. Даже какой-то контроль за выходом из допустимого числового интервала для этих данных не реализован. Об этом свидетельствует следующий пример:
#include <stdio.h>
#include <conio.h>
void main()
{ enum qq {zero, one, two, three};
enum qq a,b;
a=one;
b=a+two;
printf("a=%d b=%d",a,b);
getch();
}
//=== Результат работы ===
a=1 b=3
Правда, при компиляции 7-й строки было выдано предупреждение о
попытке присвоения значения типа int переменной типа qq, но все
обошлось. Однако замена на оператор b=a+three; никаких эмоций у
компилятора не вызвала и был получен результат b=4. Даже попытка
выполнить b=5 ; тоже прошла гладко. Так что с данными типа enum
компилятор работает как с целыми числами и на выход за пределы
заданного диапазона внимания не обращает.
Обратим внимание еще на один нюанс в приписывании числовых номеров константам из перечисления:
enum num12 {one=1,ein=1,two,zwei=2};
Этот пример демонстрирует, что числовые номера в списке констант могут дублироваться, но сами имена должны быть уникальными. Использование одного и того же имени в двух разных перечислениях недопустимо.
Объединения – это такие наборы данных, которые компилятор должен
разместить в оперативной памяти, начиная с одного и того же места.
Впервые такое совмещение разных данных появилось в языке ФОРТРАН, где
для этой цели использовался оператор
В языках C, C++ объединения создаются с помощью оператора union. В
рамках MS-DOS, где нехватка оперативной памяти давала себя знать, с
помощью объединений можно наложить друг на друга массивы, используемые
в разное время. Однако наиболее важная цель объединений – расположить
в одном и том же месте данные разного типа. Это позволяет обращаться к
тем или иным полям, используя переменные разного типа. Наиболее
характерным объектом такого типа является ячейка электронной таблицы,
в которой пользователь может разместить текст или числовое выражение
того или иного типа.
Самым употребительным объединением в рамках MS-DOS было
использование dos.h было
определено объединение REGS:
struct WORDREGS // структура из 16-битных данных
{ unsigned int ax,bx,cx,dx,si,di,cflag,flags; };
struct BYTEREGS // структура из 8-битных данных
{ unsigned char al,ah,bl,bh,cl,ch,dl,dh; }
union REGS {struct WORDREGS x;
struct BYTEREGS h; };
В этих объявлениях содержатся описания двух структур, которые
имитируют распределение в оперативной памяти
MOV AH,2 ; номер функции 2 засылается в регистр AH MOV BH,0 ; номер страницы в текстовом режиме MOV DH,10 ; номер строки, в которую переводится курсор MOV DL,25 ; номер колонки INT 10H ; вызов прерывания с номером 16
Для того чтобы выполнить аналогичные действия (не прибегая к
библиотечной функции gotoxy ) на языке C надо проделать следующие
операции:
union REGS r; //заводим область регистров в памяти ............... r.h.ah=2; //засылаем номер функции в "регистр" AH r.h.bh=0; //засылаем номер страницы в "регистр" BH r.h.dh=y; //засылаем номер строки в "регистр" DH r.h.dl=x; //засылаем номер столбца в "регистр" DL int86(0x10,r,r); //имитация прерывания с номером 10h
Функция int86 перепишет содержимое объединения r в машинные
регистры, предварительно сохранив их содержимое, выполнит команду
прерывания, передающую управление подфункции MS-DOS с номером 2,
которая переместит курсор в заданную позицию. По окончании работы
подфункции содержимое
Может быть, вам покажется, что приведенный фрагмент излишне
усложнен, но реальная работа функции gotoxy(x,y) требует еще большего
числа операций.
В языке C++ также была предпринята попытка использовать объединения для создания классов. Однако о деталях другого использования объединений в разделе "C++ и объектно-ориентированное программирование".
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.