Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lekcija-18.pdf
Скачиваний:
18
Добавлен:
27.03.2016
Размер:
285.74 Кб
Скачать
//определение шаблона структуры PointRecType
//определение шаблона структуры ColorPointRecType

Например:

struct PointRecType

{int x, y;

};

Имена полей в одном шаблоне структуры должны быть уникальными. Однако в разных шаблонах можно использовать совпадающие имена полей. Более того, имя шаблона может совпадать с именами полей и переменных. Поскольку имена полей «скрыты» внутри шаблона, они могут дублировать «внешние» переменные и поля в других описаниях структур.

Например:

struct PointRecType

{ int x, y;

};

struct ColorPointRecType

{int x, y;

unsigned color;

};

 

struct

// определение шаблона структуры без имени

{ PointRecType point;

ColorPointRecType color_point;

} big_struct;

// определение структурной переменной big_struct

int x, y;

//определение простых переменных

PointRecType point;

//определение структурной переменной типа PointRecType

ColorPointRecType color_point ; //определение структурной переменной типа ColorPointRecType

Здесь x, point.x,

color_point.x, big_struct.point.x,

big_struct.color_point.x – разные значения.

Как мы видим из примера, элементом определяемого структурного типа может быть другая структура, тип которой уже определен.

Область видимости шаблона структуры:

локальный шаблон структуры описан внутри блока { } и видим только из пределов данного блока, в частности из пределов конкретной функции;

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

Расположение структурных переменных в памяти

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

порядок их расположения в памяти.

Программирование – лекция 18 (лекции Стрикелевой Л.В.)

5

pack(push,n);

Рассмотрим структуру: struct {

long L; int i1, i2; char c[4];

}STR1;

Впамяти каждый элемент имеет свое место, и размещаются они последовательно:

 

 

 

 

 

 

f0 f1 f2

f3 f4 f5 f6 f7 f8

f9 fa

fb fc fd fe ff

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

long L

 

 

int i1

int i2

 

char c[4]

 

 

 

 

 

 

 

 

Компилятор выделяет под структурную переменную STR1 число байтов памяти,

достаточное для хранения всех ее полей. Однако выделенное количество байт не всегда равно сумме длин отдельных полей из-за влияния дополнительного фактора внутреннего представления структурных переменных, называемого выравниванием.

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

Выравнивание на границе байта устанавливает директива препроцессора #pragma аргумент n задает выравнивание данных в структурах на n байт (

n=(1,2,4,8,16) ). Отмена директивы: #pragma pack(pop). Директива #pragma pack(show)

выводит в качестве warning значение выравнивания по умолчанию, например: value of

pragma pack(show) == 8.

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

отдельная структурная переменная (элемент массива структурных переменных) начинается на границе слова;

любое поле, тип которого не совпадает с типом char, будет начинаться на границе слова;

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

Расположение в памяти структурной переменной STR2 при наличии выравнивания на границе слова:

struct {

long L; char c[3]; int i1, i2;

} STR2;

 

 

 

 

 

 

f0 f1 f2

f3 f4 f5

f6 f7 f8 f9

fa fb fc fd fe ff

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

long L

 

char c[3]

 

 

int i1

 

 

int i2

 

 

 

 

 

 

 

 

Программирование – лекция 18 (лекции Стрикелевой Л.В.)

6

Сумма размеров элементов структуры (4+3+4+4=15) меньше, чем отведено структуре в целом (16) из -за того, что размер массива char c[3]; не кратен длине слова компьютера, и перед элементом int i1 для выравнивания вставлен пустой байт.

Выделенное число байт возвращает операция sizeof .

Инициализация структурных переменных

Разрешается выполнять инициализацию полей структурной переменной при её определении. Например:

struct Book {char name[20]; //определение шаблона структуры char title[44];

int year; float price;

};

 

Book

// инициализация структурных переменных при их определении

 

first_book =

 

{“Mitchel M.”,

 

“Unesennie vetrom”,

 

2007,

 

20000 },

 

child_book =

 

{“Troepolskij G.”,

 

“Belij Bim Chernoe Ucho”,

 

2006,

 

10000},

 

dog_book =

 

{…..};

Инициализирующие значения располагаются в порядке объявления полей в структурном типе. Типы инициализирующих значений должны быть совместимы с типами соответствующих полей в определении структурного типа.

Вложенные структуры

Как мы видели, поле структурной переменной может иметь любой тип, в том числе и быть другой структурой. В качестве членов структуры можно объявлять массивы других структур.

Поле, являющееся структурой, называют вложенной структурой. Естественно, что шаблон вкладываемой структуры должен быть уже известен компилятору. Например:

struct UDC

{char class, subclass; int number;};

struct Book

{ struct UDK udc_class;

 

char name [20];

 

chat title[44];

 

int year;

 

float price;

} first_book, child_book, dog_book;

Программирование – лекция 18 (лекции Стрикелевой Л.В.)

7

Ссылка на поле вложенной структуры формируется из имени структурной переменной, имени структурного поля и имени вложенной структуры. Перечисленные имена разделяются символом «точка». Например:

first_book.udc_class.class = ‘A’; // (first_book.udc_class).class. dog_book.udc_class.number =681;

Теоретически не существует ограничения на величину уровня вложенности структур.

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

Например:

struct Book

{ Book

my_s;

//это ошибка !!!!!

 

char name[20];

 

 

char title[44];

 

 

int year;

 

 

};

float price;

 

 

 

//OK!!!!!

struct Book

{ Book*

my_s;

char name[20]; char title[44]; int year;

float price;

};

Пусть имеем вложенные структуры:

struct Distance //длина в километрах и метрах

{ int km, m;

};

struct Pole //размеры прямоугольного поля

{ Distance length; Distance width,

};

Тогда инициализация структурной переменной типа Pole выглядит так:

Pole pole = { {2, 20}, {1, 5}};

Операции над структурными переменными

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

if (strcmp(first_book.name, “Mitchel M.”) == 0)……. if(first_book.year%4==0)…

first_book.name[0] = lower(first_book.name[0]);

Программирование – лекция 18 (лекции Стрикелевой Л.В.)

8

strcpy (first_book. name, “Mitchel M.”);

//поле-строка получает значение !!!!!

strcpy (first_book. title, “Unesennie vetrom”);

 

cin >> child_book.title;

//полестрока получает значение !!!!!

first_book. year = 2007;

 

cin >> first_book. price;

 

Непосредственно сравнивать две структурные переменные (даже одного типа) нельзя. Сравнивать можно только члены структур. Например:

struct { int a; int b;

} v1, v2;

if ((v1.a == v2.a) && (v1.b == v2.b)) cout << “переменные равны”;

К структурным переменным, определенным с помощью одного и того же

шаблона, применим оператор присваивания.!!! После его выполнения значения полей структурных переменных будут равны. Например:

first_book = child_book;

first_book = child_book = dog_book; RECT r1, r2 = { 2, 6, 4, 2 };

r1.left = 1; r1.top = 5; r1.right = 3; r1.top = 1; r2=r1;

cout<< r2.left << endl; //1

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

НО!!! Поверхностное копирование членов-указателей может стать источником ошибок в дальнейшей работе. Если в структуре есть члены-указатели, то после присваивания будет существовать больше одной структурной переменной, члены которой указывают на одну и ту же область памяти.!!!

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

Если два структурных типа «закольцованы» (поля одного структурного типа объявляются через другой структурный тип и наоборот):

struct A { B *pb;}; struct B { A *pa;};

то допустимо использовать предварительное неполное определение любого из типов:

struct B;

// предварительное неполное определение типа B;

struct A {

B *pb;};

struct B {

A *pa;};

В данном случае предварительное неполное определение структурного типа B допустимо использовать в определении структурного типа A, так как определение указателя pb на структуру типа B не требует сведений о размере структуры типа B.

Программирование – лекция 18 (лекции Стрикелевой Л.В.)

9

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