Программирование

Главная | Другие дисциплины
анотация модуля | вводная лекция | входной рейтинг контроль
анотация модуля №1 | лекции №1-3 | лабораторные №1-8 | промежуточное тестирование по модулю №1
анотация модуля №2 | лекции №4-7 | лабораторные №9-18 | промежуточное тестирование по модулю №2
анотация модуля №3 | лекции №8-12 | лабораторные №19-25 | промежуточное тестирование по модулю №3
анотация модуля №4 | лекции №13-15 | лабораторные №26-31 | промежуточное тестирование по модулю №4
анотация модуля №5 | лекции №16-17 | лабораторные №32-35 | промежуточное тестирование по модулю №5
анотация модуля №6 | лекции №18-20 | лабораторные №36-41 | промежуточное тестирование по модулю №6
анотация модуля №7 | лекции №21-23 | лабораторные №42-45 | промежуточное тестирование по модулю №7
анотация модуля | список экзаменационных вопросов | часто задаваемые вопросы | итоговое тестирование
small logoБазовый модуль №6

 

ЛЕКЦИЯ №20

В данной лекции будут рассмотрены структуры, массивы структур, объединения.

Структуры

Структуры – это не что иное, как классы, у которых разрешен доступ ко всем их элементам. Пример структуры:

struct Record { int number; char name[20]; };

Так же, как и для классов, операция "." обозначает обращение к элементу структуры.

В отличие от классов, можно определить переменную-структуру без определения отдельного типа:

struct {
     double x;
     double y;
} coord; 
        

Обратиться к атрибутам переменной coord можно coord.x и coord.y.

Битовые поля

В структуре можно определить размеры атрибута с точностью до бита. Традиционно структуры используются в системном программировании для описания регистров аппаратуры. В них каждый бит имеет свое значение. Не менее важной является возможность экономии памяти – ведь минимальный тип атрибута структуры это байт (char), который занимает 8 битов. До сих пор, несмотря на мегабайты и даже гигабайты оперативной памяти, используемые в современных компьютерах, существует немало задач, где каждый бит на счету.

Если после описания атрибута структуры поставить двоеточие и затем целое число, то это число задает количество битов, выделенных под данный атрибут структуры. Такие атрибуты называют битовыми полями. Следующая структура хранит в компактной форме дату и время дня с точностью до секунды.

struct TimeAndDate
{
unsigned hours    :5; // часы от 0 до 24 
unsigned mins     :6; // минуты 
unsigned secs     :6; // секунды от 0 до 60
unsigned weekDay  :3; // день недели
unsigned monthDay :6; // день месяца от 1 до 31
unsigned month    :5; // месяц от 1 до 12
unsigned year     :8; // год от 0 до 100  
};  
        

Одна структура   TimeAndDate требует всего 39 битов, т.е. 5 байтов (один байт — 8 битов). Если бы мы использовали для каждого атрибута этой структуры тип char, нам бы потребовалось 7 байтов.

Использование элементов структуры

Структура позволяет вашим программам группировать информацию, называемую элементами, в одной переменной. Чтобы присвоить значение элементу или обратиться к значению элемента, используйте оператор C++ точку (.). Например, следующие операторы присваивают значения различным элементам переменной с именем worker тута employee;

worker.employee_id = 12345;

worker.salary = 25000.00;

worker.оffice_number = 102;

Для обращения к элементу структуры укажите имя переменной, за которым следует точка и имя элемента. Следующая программа EMPLOYEE.CPP иллюстрирует использование структуры типа employee:

#include <iostream.h>

#include <string.h>

void main(void)

{
struct employee

{
char name [64];
long employee_id;
float salary;
char phone[10];
int office_number;
} worker;

// Копировать имя в строку strcpy(worker.name, "Джон Дой");

worker.employee_id = 12345;
worker.salary = 25000.00;
worker.office_number = 102;

// Копировать номер телефона в строку strcpy(worker.phone, "555-1212") ;

cout << "Служащий: " << worker.name << endl;
cout << "Телефон: " << worker.phone << endl;
cout << "Номер служащего: " << worker.employee_id << endl;
cout << "Оклад: " << worker.salary << endl;
cout << "Офис: " << worker.office_number << endl;
}

Как видите, присваивание целому элементу и элементу с плавающей точкой очень просто. Программа использует оператор присваивания, чтобы присвоить значение соответствующему элементу. Однако обратите внимание на использование функции strcpy для копирования символьной строки в элементы name и phone. Если вы не инициализируете элементы при объявлении переменной типа данной структуры, вы должны копировать символьные строки в символьно-строковые элементы.

Объявление переменных структуры

Структуры C++ позволяют вашим программам группировать в одну переменную связанную информацию различных типов. Структура определяет шаблон для объявлений будущих переменных вашей программы. Каждая структура имеет уникальное имя (иногда называемое тэгом). Используя имя структуры, вы можете объявить переменные типа данной структуры. Биты информации, хранящиеся в структуре, называются элементами. Чтобы использовать или присвоить значение элементу, используйте оператор C++ точку, как показано ниже:

variable.member = some_value;
some_variable = variable.other_member;

СТРУКТУРЫ И ФУНКЦИИ

Если функция не изменяет структуру, вы можете передать структуру в функцию по имени. Например, следующая программа SHOW_EMP.CPP использует функцию show_employee для вывода элементов структуры типа employee:

#include <iostream.h>

#include <string.h>

struct employee

{
char name[64];
long employee_id;
float salary;
char phone[10];
int office_number;
};

void show_employee(employee worker)

{
cout << "Служащий: " << worker.name << endl;
cout << "Телефон: " << worker.phone << endl;
cout << "Номер служащего: " << worker. employee_id << endl;
cout << "Оклад: " << worker.salary << endl;
cout << "Офис: " << worker.office_number << endl;
}

void main(void)

{
employee worker;

// Копировать имя в строку strcpy(worker.name, "Джон Дой");

worker.employee_id = 12345;
worker.salary = 25000.00;
worker.office_number = 102;

// Копировать номер телефона в строку strcpy(worker.phone, "555-1212");

show_employee(worker);
}

Как видите, программа передает переменную типа данной структуры worker в функцию show__employee по имени. Далее функция show_employee выводит элементы структуры. Однако обратите внимание, что программа теперь определяет структуру employee вне main и до функции show_employee. Поскольку функция объявляет переменную worker типа employee, определение структуры employee должно располагаться до функции.
Функции, изменяющие элементы структуры

Как вы знаете, если функция изменяет параметр, вам следует передавать этот параметр в функцию с помощью адреса. Если функция изменяет элемент структуры, вы должны передавать эту структуру в функцию с помощью адреса, Для передачи переменной типа структуры с помощью адреса вы просто предваряете имя переменной оператором адреса C++ (&), как показано ниже:

some_function(&worker);

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

pointer_variable->member = some_value;

Например, следующая программа CHG_MBR.CPP передает структуру типа employee в функцию с именем get_employee_id, которая запрашивает у пользователя идентификационный номер служащего и затем присваивает этот номер элементу структуры employee_id. Чтобы изменить элемент, функция работает с указателем на структуру:

#include <iostream.h>

#include <string.h>

struct employee

{
char name[64];
long employee_id;
float salary;
char phone[10];
int office_number;
};

void get_employee_id(employee *worker)

{
cout << "Введите номер служащего: ";
cin >> worker->employee_id;
}

void main(void)

{
employee worker;

// Копировать имя в строку strcpy(worker.name, "Джон Дой");

get_employee_id(&worker) ;
cout << "Служащий: " << worker, name << endl;
cout << "Номер служащего: " << worker.employee_id << endl;
}

Как видите, внутри main программа передает переменную worker типа структуры в функцию get_employee_id с помощью адреса. Внутри функции gel_employee_id значение, введенное пользователем, присваивается элементу employee_id с помощью следующего оператора:

cin >> worker->employee_id;

Работа с указателями на структуры

Если функция изменяет элемент структуры, вызвавшая программа должна передать структуру в функцию с помощью адреса. Функция, в свою очередь, использует указатель на структуру. Для обращения к элементу структуры функции следует использовать следующий формат:

value = variable->member;
variable->other_member = some_value;

Объединения

Особым видом структур данных является объединение. Определение объединения напоминает определение структуры, только вместо ключевого слова struct используется union:

union number {
     short sx;
     long lx;
     double dx;
}; 
        

В отличие от структуры, все атрибуты объединения располагаются по одному адресу. Под объединение выделяется столько памяти, сколько нужно для хранения наибольшего атрибута объединения. Объединения применяются в тех случаях, когда в один момент времени используется только один атрибут объединения и, прежде всего, для экономии памяти. Предположим, нам нужно определить структуру, которая хранит "универсальное" число, т.е. число одного из предопределенных типов, и признак типа. Это можно сделать следующим образом:

struct Value {
  enum NumberType { ShortType, LongType,
                    DoubleType };
  NumberType type;  
  short sx;      // если type равен ShortType
  long lx;       // если type равен LongType
  double dx;     // если type равен DoubleType
};  
        

Атрибут type содержит тип хранимого числа, а соответствующий атрибут структуры – значение числа.

Value shortVal;
shortVal.type = Value::ShortType;
shortVal.sx = 15; 
        

Хотя память выделяется под все три атрибута sx, lx и dx, реально используется только один из них. Сэкономить память можно, используя объединение:

struct Value {
     enum NumberType { ShortType, LongType, 
                       DoubleType };
     NumberType type;
     union number {  
          short sx;      // если type равен ShortType
          long lx;       // если type равен LongType
          double dx;     // если type равен DoubleType
     } val;
};    
        

Теперь память выделена только для максимального из этих трех атрибутов (в данном случае dx). Однако и обращаться с объединением надо осторожно. Поскольку все три атрибута делят одну и ту же область памяти, изменение одного из них означает изменение всех остальных. На рисунке поясняется выделение памяти под объединение. В обоих случаях мы предполагаем, что структура расположена по адресу 1000. Объединение располагает все три своих атрибута по одному и тому же адресу.

Использование памяти в объединениях.


 

 

 

 

 

 

 

 

 

Рис. 1.  Использование памяти в объединениях.

Замечание. Объединения существовали в языке Си, откуда без изменений и перешли в Си++. Использование наследования классов, описанное в следующей главе, позволяет во многих случаях добиться того же эффекта без использования объединений, причем программа будет более надежной.

ПРЕДСТАВЛЕНИЕ ОБ АНОНИМНЫХ ОБЪЕДИНЕНИЯХ C++

Анонимное объединение представляет собой объединение, у которого нет имени. C++ предоставляет анонимные объединения, чтобы упростить использование элементов объединений, предназначенных для экономии памяти или создания псевдонимов для определенного значения. Например, предположим, что вашей программе требуются две переменные miles и meters. Кроме того, предположим, что программа использует только одну из них каждый данный момент времени. В этом случае программа могла бы использовать элементы объединения, подобного уже обсуждавшемуся объединению distance, а именно name.miles и name.meters. Следующий оператор создает анонимное (безымянное) объединение:

union

{
int miles;
long meters;
};

Как видите, объявление не использует имя объединения и не объявляет переменную объединения. Программа, в свою очередь, может обращаться к элементам с именами miles и meters без помощи точки. Следующая программа ANONYM.CPP создает анонимное объединение, которое содержит элементы miles и meters. Обратите внимание, что программа трактует элементы как обычные переменные. Однако различие между элементами и обычными переменными заключается в том, что, когда вы присваиваете значение любому из этих элементов, значение другого элемента теряется:

#include <iostream.h>

void main(void)

{
union

{
int miles;
long meters;
};

miles = 10000;
cout << "Значение в милях " << miles << endl;
meters = 150000;
cout << "Значение в метрах " << meters << endl;
}

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

Анонимные объединения позволяют вашим программам экономить пространство

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

union

{
char short_name[13];
char long_name[255];
};

О нас | Карта сайта | Наши контакты | ©2007 Красноярский Государственный Педагогический Университет им. В.П.Астафьева
Перепечатка с указанием ссылки.