ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 31.03.2021

Просмотров: 233

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.


  cin >> invtry[i].lead_time;


}




// Модификация существующего элемента.


void update()


{


 int i;


 char name[80];




 cout << "Введите наименование товара: ";


  cin >> name;




 for(i=0; i<SIZE; i++)


  if(!strcmp(name, invtry[i].item)) break;




 if(i==SIZE) {


  cout << "Товар не найден.\n";


  return;


 }


 cout << "Введите новую информацию.\n";


 input (i);


}




// Отображение на экране инвентарной ведомости.


void display()


{


 int t;


 for(t=0; t<SIZE; t++) {


  if(*invtry[t].item) {


   cout << invtry[t].item << '\n';


   cout << "Стоимость: $" << invtry[t].cost;


   cout << "\nB розницу: $";


   cout << invtry[t].retail << '\n';


   cout << "В наличии: " << invtry[t].on_hand;


   cout << "\nДо пополнения осталось: ";


   cout << invtry[t].lead_time << " дней\n\n";


  }


 }


}


Передача структур функциям


При передаче функции структуры в качестве аргумента используется механизм передачи параметров по значению. Это означает, что любые изменения, внесенные в содержимое структуры в теле функции, которой она передана, не влияют на структуру, используемую в качестве аргумента. Однако следует иметь в виду, что передача больших структур требует значительных затрат системных ресурсов. (Как правило, чем больше данных передается функции, тем больше расходуется системных ресурсов.)

Используя структуру в качестве параметра, помните, что тип аргумента должен соответствовать типу параметра. Например, в следующей программе сначала объявляется структура sample, а затем функция f1() принимает параметр типа sample.


// Передача функции структуры в качестве аргумента.


#include <iostream>

using namespace std;

// Определяем тип структуры.

struct sample {

 int a;

 char ch;

};

void f1(sample parm);

int main()

{

 struct sample arg; // Объявляем переменную arg типа sample.

 arg.a = 1000;

 arg.ch = 'x';

 f1(arg);

 return 0;

}


void f1(sample parm)

{

 cout << parm.a << " " << parm.ch << "\n";

}


Здесь как аргумент arg в функции main(), так и параметр parm в функции f1() имеют одинаковый тип. Поэтому аргумент arg можно передать функции f1(). Если бы типы этих структур были различны, при компиляции программы было бы выдано сообщение об ошибке.


Присваивание структур


Содержимое одной структуры можно присвоить другой, если обе эти структуры имеют одинаковый тип. Например, следующая программа присваивает значение структурной переменной svar1 переменной svar2.


// Демонстрация присваивания значений структур.

#include <iostream>

using namespace std;

struct stype {

 int a, b;

};

int main()

{

 stype svar1, svar2;

 svar1.a = svar1.b = 10;

 svar2.a = svar2.b = 20;

 cout << "Структуры до присваивания.\n";

 cout << "svar1: " << svar1.a << ' ' << svar1.b;

 cout <<'\n';

 cout << "svar2: " << svar2.a << ' ' << svar2.b;

 cout <<"\n\n";

 svar2 = svar1; // присваивание структур

 cout << "Структуры после присваивания.\n";

 cout << "svar1: " << svar1.a << ' ' << svar1.b;

 cout << '\n';

 cout << "svar2: " << svar2.a << ' ' << svar2.b;

 return 0;

}


Эта программа генерирует следующие результаты.


Структуры до присваивания.


svar1: 10 10


svar2: 20 20


Структуры после присваивания,


svar1: 10 10


svar2: 10 10


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



struct stype1 {

 int a, b;

};

struct stype2 {

 int a, b;

};

stype1 svar1;

stype2 svar2;

svar2 = svar1; // Ошибка из-за несоответствия типов.


Несмотря на то что структуры stype1 и stype2 физически одинаковы, с точки зрения компилятора они являются отдельными типами.

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



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

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

Указатель на структуру объявляется так же, как указатель на любую другую переменную, т.е. с помощью символа "*", поставленного перед именем структурной переменной. Например, используя определенную выше структуру inv_type, можно записать следующую инструкцию, которая объявляет переменную inv_pointer указателем на данные типа inv_type:


inv_type *inv_pointer;

Чтобы найти адрес структурной переменной, необходимо перед ее именем разместить оператор "&". Например, предположим, с помощью следующего кода мы определяем структуру, объявляем структурную переменную и указатель на структуру определенного нами типа.


struct bal {

 float balance;

 char name[80];

} person;

bal *p; // Объявляем указатель на структуру.

Тогда при выполнении инструкции


р = &person;

в указатель р будет помещен адрес структурной переменной person.


К членам структуры можно получить доступ с помощью указателя на эту структуру. Но в этом случае используется не оператор "точка", а оператор "->". Например, при выполнении этой инструкции мы получаем доступ к полю balance через указатель р:


p->balance

Оператор "->" называется оператором "стрелка". Он образуется с использованием знаков "минус" и "больше".

Оператор "стрелка" (->) позволяет получить доступ к членам структуры с помощью указателя.

Указатель на структуру можно использовать в качестве параметра функции. Важно помнить о таком способе передачи параметров, поскольку он работает гораздо быстрее, чем в случае, когда функции "собственной персоной" передается объемная структура. (Передача указателя всегда происходит быстрее, чем передача самой структуры.)


Пример использования указателей на структуры


В качестве интересного примера использования указателей на структуры можно рассмотреть С++-функции времени и даты. Эти функции считывают значения текущего системного времени и даты. Для их использования в программу необходимо включить заголовок <ctime>. Этот заголовок поддерживает два типа даты, требуемые упомянутыми функциями. Один из этих типов, time_t, предназначен для представления системного времени и даты в виде длинного целочисленного значения, которое используется в качестве календарного времени. Второй тип представляет собой структуру tm, которая содержит отдельные элементы даты и времени. Такое представление времени называют поэлементным. Структура tm имеет следующий формат.



struct tm {

 int tm_sec; /* секунды, 0-59 */

 int tm_min; /* минуты, 0-59 */

 int tm_hour; /* часы, 0-23 */

 int tm_mday; /* день месяца, 1-31 */

 int tm_mon; /* месяц, начиная с января, 0-11 */

 int tm_year; /* год после 1900 */

 int tm_wday; /* день, начиная с воскресенья, 0-6 */

 int tm_yday; /* день, начиная с 1-го января, 0-365 */

 int tm_isdst /* индикатор летнего времени */

}


Значение tm_isdst положительно, если действует режим летнего времени (Daylight Saving Time), равно нулю, если не действует, и отрицательно, если информация об этом недоступна.

Основным средством определения времени и даты в C++ является функция time(), которая имеет такой прототип:


time_t time(time_t *curtime);


Функция time() возвращает текущее календарное время системы. Если в системе отсчет времени не производится, возвращается значение -1. Функцию time() можно вызывать либо с нулевым указателем, либо с указателем на переменную curtime типа time_t. В последнем случае этой переменной будет присвоено значение текущего календарного времени.

Чтобы преобразовать календарное время в поэлементное, используйте функцию localtime(), которая имеет такой прототип:


struct tm *localtime(const time_t *curtime);


Функция localtime() возвращает указатель на поэлементную форму параметра curtime, представленного в виде структуры tm. Значение curtime представляет локальное время. Его обычно получают с помощью функции time().


Следующая программа демонстрирует использование функций time() и localtime(), отображая на экране текущее системное время.


// Эта программа отображает текущее системное время.

#include <iostream>

#include <ctime>

using namespace std;

int main()

{

 struct tm *ptr;

 time_t lt;

 lt = time('\0');

 ptr = localtime(<);

 cout << ptr->tm_hour << ':' << ptr->tm_min;

 cout << ':' << ptr->tm_sec;

 return 0;

}


Вот один из возможных результатов выполнения этой программы:


14:52:30



Ссылки на структуры


Для доступа к структуре можно использовать ссылку. Ссылка на структуру часто используется в качестве параметра функции или значения, возвращаемого функцией. При получении доступа к членам структуры с помощью ссылки используйте оператор "точка". (Оператор "стрелка" зарезервирован для доступа к членам структуры с помощью указателя.)

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


// Демонстрируем использование ссылки на структуру.

#include <iostream>

using namespace std;

struct mystruct {

 int a; int b;

};

mystruct &f(mystruct &var);

int main()

{

 mystruct x, y;

 x.a = 10; x.b = 20;

 cout << "Исходные значения полей x.a and x.b: ";

 cout << x.a << ' ' << x.b << '\n';

 y = f (x);

 cout << "Модифицированные значения полей x.a и x.b: ";

 cout << x.a << ' ' << x.b << '\n';

 cout << "Модифицированные значения полей y.a и y.b: ";

 cout << y.a << ' ' << y.b << '\n';

 return 0;

}




// Функция, которая получает и возвращает ссылку на структуру.


mystruct &f(mystruct &var)

{

 var.a = var.a * var.a;

 var.b = var.b / var.b;

 return var;

}


Вот результаты выполнения этой программы.


Исходные значения полей x.a and x.b: 10 20


Модифицированные значения полей х.а и x.b: 100 1


Модифицированные значения полей у.а и y.b: 100 1


Ввиду существенных затрат системных ресурсов на передачу структуры функции (или при возвращении ее функцией) многие С++-программисты для выполнения таких задач используют ссылки на структуры.



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


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

Массив, используемый в качестве члена структуры, обрабатывается вполне ожидаемым способом. Рассмотрим такую структуру.


struct stype {


 int nums[10][10]; // Целочисленный массив размерностью 10 х 10.


 float b;


} var;

Чтобы обратиться к элементу массива nums с "координатами" 3,7 в структуре var типа stype, следует записать такой код:


var.nums[3][7]

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

Если некоторая структура является членом другой структуры, она называется вложенной структурой. В следующем примере структура addr вложена в структуру emp.


struct addr {


 char name[40];


 char street[40];


 char city[40];


 char zip[10];


}


struct emp {


 addr address;


 float wage;


} worker;

Здесь структура emp имеет два члена. Первым членом является структура типа addr, которая будет содержать адрес служащего. Вторым членом является переменная wage, которая хранит его оклад. При выполнении следующего фрагмента кода полю zip структуры address, которая является членом структуры worker, будет присвоен почтовый индекс 98765:


worker.address.zip = 98765;

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

Структура также может содержать в качестве своего члена указатель на эту же структуру. И в самом деле для структуры вполне допустимо содержать член, который является указателем на нее саму. Например, в следующей структуре переменная sptr объявляется как указатель на структуру типа mystruct, т.е. на объявляемую здесь структуру.


struct mystruct {


 int а;


 char str[80];


 mystruct *sptr; // указатель на объекты типа mystruct


};

Структуры, содержащие указатели на самих себя, часто используются при создании таких структур данных, как связные списки. По мере изучения языка C++ вы встретите приложения, в которых применяются подобные вещи.

Сравнение С- и С++-структур

С++-структуры — потомки С-структур. Следовательно, любая С-структура также является действительной С++-структурой. Между ними, однако, существуют важные различия. Во-первых, как будет показано в следующей главе, С++-структуры имеют некоторые уникальные атрибуты, которые позволяют им поддерживать объектно-ориентированное программирование. Во-вторых, в языке С структура не определяет в действительности новый тип данных. Этим может "похвалиться" лишь С++-структура. Как вы уже знаете, определяя структуру в C++, вы определяете новый тип, который называется по имени этой структуры. Этот новый тип можно использовать для объявления переменных, определения значений, возвращаемых функциями, и т.п. Однако в С имя структуры называется ее тегом (или дескриптором). А тег сам по себе не является именем типа.


Чтобы понять это различие, рассмотрим следующий фрагмент С-кода.


struct C_struct {


 int а; int b;


}


// объявление переменной C_struct


struct C_struct svar;

Обратите внимание на то, что приведенное выше определение структуры в точности такое же, как в языке C++. Теперь внимательно рассмотрите объявление структурной переменной svar. Оно также начинается с ключевого слова struct. В языке С после определения структуры для полного задания типа данных все равно нужно использовать ключевое слово struct совместно с тегом этой структуры (в данном случае с идентификатором C_struct).

Если вам придется преобразовывать старые С-программы в код C++, не беспокойтесь о различиях между С- и С++-структурами, поскольку C++ по-прежнему принимает С-ориентированные объявления. Например, предыдущий фрагмент С-кода корректно скомпилируется как часть любой С++-программы. С точки зрения компилятора C++ в объявлении переменной svar всего лишь избыточно использовано ключевое слово struct, без которого в C++ можно обойтись.

Битовые поля структур

Битовое полеэто бит-ориентированный член структуры.

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

Метод, который использован в языке C++ для доступа к битам, основан на применении структур. Битовое поле — это в действительности специальный тип члена структуры, который определяет свой размер в битах. Общий формат определения битовых полей таков.


struct имя_типа_структуры {


 тип имя1 : длина;


 тип имя2 : длина;


 .


 .


 .


 тип имяN : длина;


};

Здесь элемент тип означает тип битового поля, а элемент длина — количество битов в этом поле. Битовое поле должно быть объявлено как значение целочисленного типа или перечисления. Битовые поля длиной 1 бит объявляются как значения типа без знака (unsigned), поскольку единственный бит не может иметь знакового разряда.

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