- •Структура как пользовательский тип и совокупность данных
- •Определение шаблона структуры и структурной переменной
- •Расположение структурных переменных в памяти
- •Инициализация структурных переменных
- •Вложенные структуры
- •Операции над структурными переменными
- •Массив структур
- •Структура в качестве аргумента функции
- •Примеры работы со структурами
- •person_list
- •Объединение как пользовательский тип и совокупность данных
- •Определение объединения и переменной объединяющего типа
- •Использование перечисляемого типа для обращения к полям объединения
- •Битовые поля структур и объединений
- •Определение битовых полей
- •Формирование кода символа с помощью битовых полей объединения
- •Формирование байта и вывод на экран его двоичного представления
char adres[60] //адрес владельца
};
Auto mers, volvo, alfa_r [5], *mazda, person_list [20]; //определение структурных переменных
mers.marka |
– доступ к полю «марка» автомобиля mers |
mers |
– вся информация о владельце автомобиля mers |
volvo.fio[0] |
– первая буква фамилии владельца автомобиля volvo |
alfa_r [1].adres[0] – первый символ адреса второго элемента массива владельцев alfa_r
person_list – информация о всех владельцах автомобилей (массив из двадцати наборов данных); person_list[i] – информация о владельце (i+1) –го автомобиля (i –ый элемент в наборе данных);
person_list[i].fio – фамилия владельца (i+1) –го автомобиля; person_list[i].fio[j] – j-ая буква в фамилии владельца (i+1) –го автомобиля
Расположение массива структур в памяти:
person_list
1-ый владелец: |
|
2-ой владелец: |
… |
i-ый владелец: |
... |
|
20-ый владелец: |
||||
person_ list [0] |
|
person_list [1] |
|
person_list [i-1] |
|
|
person_list [19] |
||||
|
|
|
|
|
|
|
|
|
|||
nomer(4 байта) |
|
nomer |
… |
nomer |
… |
|
ОООООООО |
|
|||
marka(20 байт) |
|
marka |
|
marka |
|
|
ОООООООО |
|
|||
fio(40 байт) |
|
|
|
|
fio |
|
|
|
|
ОOОООООО |
|
Adres Adre s |
|
О |
|
|
|||||||
adres(60 байт) |
|
adres |
|
|
adres |
|
|
|
|
ОООООООО |
|
(всего 124 байтa) |
|
|
|
|
|
|
|
|
|
ОООООООО |
|
|
|
|
|
|
|
|
|
||||
person_list [1]. fio |
|
|
|
person_list [i-1].fio[j] |
Массив структурных переменных можно описать и следующим образом: struct {char name[20];
char title[44]; int year; float price;
} books[25];
Тогда к полю year в i-ом элементе массива структур books можно обратиться следующим образом:
books[i].year=2007;
(*(books+i)).year=2007; (books+i)->year=2007;
Структура в качестве аргумента функции
Переменная структурного типа и указатель на структуру может быть формальным параметром и возвращаемым значением функции. В С++ поддерживается вызов функции с передачей (по значению) копии всей структурной переменной (или ее отдельных
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
11
полей). Это приводит к дополнительным потерям времени на запись копии структурной переменной в стек, зато манипуляции с копией не влияют на исходную переменную. По той же причине возврат функцией структурной переменной возможен (return имя_структурной_переменной), но требует затрат на размещение в стеке возвращаемого значения и последующее его копирование из стека в переменную lvalue того же типа, что и возвращаемое значение функции.
Передать структуру в функцию можно также по ссылке и по указателю. Вернуть из функции можно структуру, указатель на структуру и ссылку на структуру.
Проанализируйте примеры:
void f3 |
(Book); //функция, получающая аргумент «структура типа Book» |
|
void f4 |
(Book*); //функция, получающая аргумент |
|
|
|
//«указатель на структуру типа Book» |
void f5 |
(Book&); //функция, получающая аргумент |
|
|
|
//«ссылка на структуру типа Book» |
Book f(); |
//функция, возвращающая структуру типа Book |
|
Book* f1(); |
//функция, возвращающая указатель на структуру типа Book |
Book& f2(); //функция, возвращающая ссылку на структуру типа Book
При наличии спецификатора const функция не может изменять значения полей структуры.
Примеры работы со структурами
1. Определение структурного типа complex, представляющего комплексные числа, заданные в алгебраической форме, и определение структурных переменных x, y этого типа:
struct complex { float re; |
//действительная часть числа |
float im; |
//мнимая часть числа |
} x, y; |
|
При этом x.re – доступ к полю действительной части комплексного числа x, y.im – доступ к полю мнимой части комплексного числа y,
Тогда функции для ввода, вывода, сложения комплексных чисел могут выглядеть
так:
struct complex { float re, im;}; |
//определение структурного типа |
||||
complex read (); |
|
|
|
//прототип функции ввода комплексного числа |
|
void |
print (complex ); |
|
|
|
//прототип функции вывода комплексного числа на экран |
void |
add (complex, complex, complex*); //прототип функции сложения комплексных чисел |
||||
void |
add1 (complex&, complex&, complex&); |
||||
int main() |
|
|
|
|
|
{ |
|
|
|
|
//определение комплексных чисел |
complex c1, c2, c3,c4; |
|
|
|
||
c1 = |
read(); |
|
|
|
//вызов функции ввода числа |
c2 = |
read(); |
|
|
|
|
add (c1, c2, &c3); |
+ |
\t" |
|
<< endl; |
|
print(c1); cout << "\t |
|
||||
print (c2); cout << " |
= |
" |
<< endl; |
||
print (c3); |
|
|
|
|
|
cout |
<< endl; |
|
|
|
|
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
12
add1 (c1, c3, c4); |
+ |
\t" |
<< endl; |
|
print(c1); cout << "\t |
||||
print (c3); cout << " |
= |
" |
<< endl; |
|
print (c4); |
|
|
|
|
_getch(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
complex read() |
|
|
|
|
{ |
|
|
|
|
complex c; |
im:"<< endl; |
|
|
|
cout << "re, |
|
|
||
cin >> c.re |
>> c.im; |
|
|
|
return c; |
|
|
|
|
} |
|
|
|
|
void print (complex c)
{
cout << c.re << " + i*" << c.im << endl; return;
}
void add (complex c1, complex c2, complex *c3)
{
c3->re = c1.re +c2.re; //или (*c3).re = c1.re + c2.re; c3->im= c1.im +c2.im;
return;
}
void add1 (complex &c1, complex &c2, complex &c3)
{
c3.re = c1.re +c2.re; c3.im= c1.im +c2.im; return;
}
2. Определение структурного типа racion, представляющего понятие «рациональное число» и набор функций для сокращения, печати, деления рациональных чисел:
struct racion {int chis, znam;}; //определение структуры
void put (racion); //прототипы функций racion sokr (racion A);
void div (racion A, racion B, racion *C);
int main()
{
racion A, B, C;
puts ("racion1, racion2 : ?");
scanf ("%d%d%d%d", &A.chis, &A.znam, &B.chis, &B.znam); //ввод чисел div(A, B, &C); //вызов функции деления чисел printf (":"); put(A);
printf ("\tna\t"); put(B);
printf ("\n="); put(C); |
//вывод результата |
_getch(); |
|
return 0; |
|
} |
|
void put (racion A) |
//функция выводит на экран «рациональное число» |
{if (A.chis * A.znam <0) printf ("-");
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
13
A.chis = abs(A.chis); A.znam = abs(A.znam);
printf( "%d / %d", A.chis, A.znam);
}
void div (racion A, racion B, racion *C) //функция делит 2 рациональных числа
{
A=sokr(A); B= sokr (B);
C->chis = A.chis*B.znam;
C->znam = A.znam*B.chis; *C= sokr (*C);
}
racion sokr (racion A)
{
int i, min;
if (abs(A.chis) > abs(A.znam)) else min = abs(A.chis);
for (i=min; i>1; i--)
if(A.chis % i ==0 && A.znam % i ==0) break; A.chis /=i;
A.znam /=i; return A;
}
3. Рассмотрим программу, позволяющую по паре чисел (год, порядковый номер дня) получить название и число месяца.
struct date {
int d, m, y; //день, месяц, год char *mname; //название месяца
} md;
//двумерный массив с количеством дней в месяце для високосного и невисокосного года static int dofm[2][12]={{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
//массив строк с названием месяца
static char *name[ ]={"janvar", "fevral", "mart", "aprel", "maj", "ijun", "ijul", "avgust", "sentjabr", "oktjabr", "nojabr", "decabr"};
void monthd(date *, int); //прототип функции пересчета
int main() |
//порядковый номер дня года |
|
{int yd; |
"god, den ?"; |
|
cout << |
//заполнение поля структуры «год» и ввод переменной yd |
|
cin >> md.y >> yd; |
||
monthd (&md, yd); |
//вызов функции и передача ей адреса структуры |
|
md.mname = name[md.m]; |
//присваивание названия месяцу |
|
cout << |
md.d <<" " << md.mname<< endl; |
|
_getch(); |
|
|
return |
0; |
|
} |
|
|
void monthd(date *md, int yd) {int i, v;
v= |
(!(md->y%4) && (md->y%100) || !(md->y%400)); //проверка года на високосность |
||
if |
(yd > 365+v) |
"neverno nomer"; exit(1);} |
//проверка значения дня года |
|
{cout << |
||
md->d = yd; |
//подготовка начального значения для поля md->d |
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
14