
Общие сведения
Структуры - это тип данных, состоящий из фиксированного числа компонентов, называемых полями. Очень часто возникает необходимость описать характеристики некоторого объекта, представляемого и обрабатываемого в программе: Таким объектом может быть человек, автомобиль, журнал и т.д. В отличие от массива компоненты (поля) структуры могут быть различного типа. Для описания объекта "автомобиль" могут потребоваться, например, следующие характеристики:
марка и тип кузова автомобиля (символьные строки);
год выпуска автомобиля (целый тип);
объем цилиндра (целый тип).
Чтобы можно было ссылаться на то или иное поле структуры, поля именуются.
Объявление структуры:
struct <имя типа>
{
<cn. nолей>
};
здеcь <имя типа> - правильный идентификатор;
<cn. nолей> - список полей, представляющий собой последовательность разделов, между которыми ставится точка с запятой. Например: struct autom {
char mark[10], type [10];
int date;
float ob;
}
Как элементы массива, так и поля структуры можно использовать в качестве отдельных переменных. К каждому компоненту можно обратиться, если указатель имя переменной типа struct, затем точку и имя поля. Используя, описанный выше тип, напишем фрагмент программы:
a
98
strcpy(machine.mark, "volvo");
machine.date = 1996;
strcpy(machine.type, "car");
machine.ob = 5000;
puts(machine. mark);
printf("%d\n",machine.date);
puts(machine.type);
printf("%7.2f\n",machine.ob);
a1=machine; a2=&a1;
a2>ob=3000;
}
Каждое поле структуры можно рассматривать как обычную переменную, которую можно напечатать или использовать в расчетах. Вместе с тем структуру можно использовать как единое целоe. Предположим, что имеется описание типа autom, тогда можно записать:
autom mach1, mach2;
Это означает, что переменная mach1 содержит поля mark, typе, date, ob, точно такие же поля содержит и переменная mach2. Возможен оператор присваивания:
mach1 =mach2;
Для переменных одного типа можно проверить выполнение отношения равенства или неравенства. Как и в случае массивов, допустимы операции сравнения == и !=.
Так как на тип элементов массива не накладывается ограничений, то можно создавать массив, компонентами которого являются структуры, объявлять указатели на структуры.
Приведем описание такого массива:
autom machine[100]
Принимая во внимание предыдущее описание autom, можно сделать вывод, что описана таблица 6, в которой могут содержаться данные на 100 автомобилей.
Табл.7
Далее можно записать следующие операторы: для обращения к первому элементу массива
99
для чтения первого элемента:
read (machine [1].mark);
Как и в массиве, значения переменных и констант типа struct можно присваивать другим переменным такого же типа:
machine[1] = machine[2];
Поле структуры само может быть структурой. В примере структуры autom введем дату приобретения автомобиля.
struct dat { int den;
char mes[10];
int god;
} ;
struct autom {
char mark[15], type[15];
dat date1;
int date;
float ob;
} ;
autom machine;
При обращении к полю god необходимо продолжать уточнения:
machine.date1.god: = 1949;
Рассмотрим пример программы с использованием массива структур. На основе таблицы, содержащей фамилии студентов, оценки по физике, математике и программированию, определить средний балл каждого студента и фамилию студента с максимальным средним баллом.
// Пример pr31
#include <stdio.h>
#include <string.h>
#define n 25
#define stp ""
struct w { char fam[15];
int os[3];
float sr;
} ;
void main()
{ w wed[n];
int i=0, j, imax;
float max = 0, s;
printf ("Введите фамилию \n");
while(strcmp(gets(wed[i].fam),stp)!=0 && i<n)
{ s=0;
printf("Введите ocenki \n");
for(j=0; j<3; j++)
{ scanf("%d",&wed[i].oc[j]);
100
}
wed[i].sr=s/3.0;
if(max<wed[i].sr)
{max=wed[i].sr;
imax=i;
}
while(getchar()!=’\n’);
if(i<n) printf("Введите следующую фамилию"); printf("\n");
i++;
}
int k=i; // Реальное количество студентов в группе
puts("icxod tabl");
puts(" fam ocenki sred bal ");
for(i=0; i<k; i++)
{printf("%15s",wed[i].fam);
for(j=0; j<3; j++)
printf("%5d",wed[i].oc[j]);
printf("%5.2f\n",wed[i].sr);
}
printf("max=%s\n",wed[imax].fam);
}
Эту же программу составим с использованием указателей на структуру // Пример рr32
#include <stdio.h>
#include<string.h> #include <iostream.h>
struct w {char fam[15];
int oc[3];
float sr;
} ;
void main()
{ w *wed,*ptr,*ptrmax;
int i=0,j,n;
float max=0,s;
cout<<"Введите число студентов\n";
cin>>n;
wed=new w[n];
ptr=wed;
cout<<"Введите фамилию \n";
while(gets(ptr->fam)!=NULL && i<n)
{
s=0;
101
for(j=0; j<3; j++)
{ cin>>ptr->oc[j];
s+=ptr->oc[j];
}
ptr->sr=s/3.0;
if(max<ptr->sr)
{max=ptr->sr
ptrmax=ptr;
}
i++;
if(i<n) cout<<"Введите следующую фамилию \n";
ptr++;
}
int k=i;
puts("icxod tabl");
puts("fam ocenki sred bal");
for(i=0, ptr=wed; i<k; i++,ptr++)
{
printf("%15s",ptr->fam);
for(j=0; j<3; j++)
printf("%5d",ptr->oc[j]);
printf("%9.2f\n",ptr->sr);
}
printf("max=%s\n", ptrmax->fam);
}
Следующий пример демонстрирует использование структуры в качестве параметра функции. В этой задаче требуется на основе таблицы, содержащей данные о группе туристов (фамилию, адрес: город, улицу, номер дома, номер квартиры), вывести фамилии туристов, проживающих в разных городах по одинаковому адресу. Достаточно найти одну такую пару. , #include <stdio.h>
#include <string.h>
#define n5
#define stp""
struct w {char fam[15];
char gor[15];
char ul[15]; ; , int dom,kw;} ;
void main() Tv' '
{ int k; ' '
struct w wed[n]; *'
int proc (int a,struct w wed[], int& , int k);
int i=0,j,f;
p
102
while(strcmp(gets(wed[i].fam),stp)!=0 && i<n)
{printf("введите город \n");
gets(wed[i].gor);
printf("введите улицу \n");
gets(wed[i].ul);
printf("введите номер дома и квартиры \n");
scanf("%d%d", &wed[i].dom, &wed[i].kw);
while(getchar()!=’\n’);
if(i<n) printf("введите следующую фамилию"); printf("\n");
i++;
}
k=i;
for(j=0; j<k; j++)
printf("%s%s%s%d%d
\n",wed[j].fam,wed[j].gor,wed[j].ul,wed[j].dom,wed[j].kw);
for(j=0; j<k-1; j++)
{ f=pros(j,wed,i,k);
if(f)
{
puts("По одинаковому адресу проживают:");
printf("%s",wed[j].fam);
printf(" u %s",wed[i].fam); break;
}
}
if(!f) puts("Таких нет!");
}
int pros (int a,struct w wed[],int &i,int k)
{
for (i=a+1; i<k; i++)
if (strcmp(wed[a].gor,wed[i].gor)!=0)
if (strcmp(wed[a].ul,wed[i].ul)==0)
if (wed[a].dom==wed[i].dom)
if (wed[a].kw==wed[i].kw)
{return 1; break;
}
return 0;
}
Объединения
Со структурами в "близком родстве" находятся объединения, которые описываются с помощью ключевого слова union [8]. Синтаксис описания объединения отличается от описания структур только ключевым словом:
u
103
{
<сп. полей>
} ;
здесь <имя типа> - правильный идентификатор;
<сп. полей> - список полей, представляющий собой последовательность разделов, между которыми ставится точка с запятой. Например:
u {
int digit;
double big;
char letter;
} ;
Как и в случае со структурами, это описание не задает какую-либо переменную, а задает только шаблон объединения. Можно объявить переменную:
union и f1, *ptr, m[10];
В отличие от структуры для переменной типа union места в памяти выделяется ровно столько, сколько надо элементу объединения, имеющему наибольший размер в байтах. В приведенном выше примере под переменную f1 будет выделено 8 байтов памяти. Bсе поля объединения будут иметь один и тот же начальный адрес. Таким образом, объединения позволяют запоминать данные различных типов в одном и том же месте памяти:
f1.digit=43; // 43 записывается в f1; используется 2 байта;
f1.big=7.0; // 43 стирается, 7.0 записывается; используется 8байт;
f1.letter='w'; // 7.0 стирается, 'w' записывается; используется 1 байт;
В каждый момент времени запоминается только одно значение; нельзя записать два значения одновременно, даже если для этого достаточно памяти.
Битовые поля структур и объединений
В отличие от других языков программирования язык Си обеспечивает доступ к одному или нескольким битам в байте или слове. Внутри структур и объединений могут в качестве их компонентов использоваться битовые поля. Каждое битовое поле представляет целое или беззнаковое целое значение, занимающее в памяти фиксированное число битов (от 1 до 16). Битовые поля могут быть только элементами структур, объединений классов, т. е. они не могут быть самостоятельными объектами программ. Битовые поля не имеют адресов, нет указателей и ссылок на битовые поля. Они не могут объединяться в массивы. Назначение битовых полей - обеспечить удобный доступ к отдельным битам данных. Чаще всего битовые поля используют при работе с флажками, которые могут принимать только два значения, что позволяет экономить память.
С
104
struct <имя_структуры>
{
<тип поля> имя поля1: длина в битах;
<тип поля> имя поля2: длина в битах;
……..
<тип поля> имя поляN: длина в битах;
Имя может быть пропущено, тогда соответствующее количество байтов не используется (пропускается). Обычно эта возможность используется для изменения порядка размещения битовых полей, выравнивания их по границам слов:
struct w {
int a:9;
int :7;
int b:9;
} ;
Программа, приведенная ниже, выдает на экран двоичный код ASCII
символа, вводимого с клавиатуры.
#include <stdio.h>
#include <conio.h>
struct byte {
int b1:1;
int b2:1;
int b3:1;
int b4:1;
int b5:1;
int b6:1;
int b7:1;
int b8:1;
} ;
union bits {
char ch;
struct byte b;
} u;
void decode(union bits);
main()
{do
{ u.ch=getche();
printf(":");
decode(u);
}
while (u.ch!= 'q');
return 0;
}
105
{
if (x.b.b8) printf("1");
else printf("0");
if (x.b.b7) printf("1");
else printf("0");
if (x.b.b6) printf("1");
else printf("0");
if (x.b.b5) printf("1");
else printf("0");
if (x.b.b4) printf("1");
else printf("0");
if (x.b.b3) printf("1");
else printf("0");
if (x.b.b2) printf("1");
else printf("0");
if (x.b.b1) printf("1");
else printf("0");
printf("\n");
}
Контрольные вопросы
1. Как описываются структуры?
2. Чем структуры отличаются от объединения?
3. Для чего используются битовые поля?
4. Как обратиться к структуре по указателю?
Варианты заданий
На основе сводной экзаменационной ведомости, включающей фамилии студентов и дисциплины (математика, физика, программирование, история), подсчитать средний балл для каждого студента и вывести на печать
1. Ведомость в порядке возрастания среднего балла.
2. Ведомость, упорядоченную в алфавитном порядке.
3. Напечатать название предмета, по которому получено наибольшее количество "двоек", и фамилии студентов, получивших по этому предмету "двойку".
4
106
На основе записной книжки, содержащей сведения: фамилия, год рождения, адрес (город, улица, номер дома, квартиры), место работы (учебы):
5. Напечатать по алфавиту фамилии лиц, живущих в Хабаровске.
6. Напечатать фамилии и адреса лиц, живущих в Хабаровске по улице Тихоокеанской, и расположить список в алфавитном порядке.
7. Напечатать список лиц, работающих (учащихся) в ХГТУ по алфавиту.
На основе таблицы, содержащей следующую информацию о каждом из 20 студентов некоторого вуза: <фамилия>, <имя>, <отчество>, <пол>, <возраст>, <курс> причем в фамилии, имени и отчестве - не более 12 букв, пол указывается буквами М и Ж, возраст - целое от 16 до 35, курс - целое от 1 до 5. Написать программу, которая вводит эту информацию и печатает следующие данные:
8. Номер курса, на котором наибольший процент мужчин.
9. Список студенток в алфавитном порядке.
10. Самое распространенное женское имя.
11. Список студенток первого курса в алфавитном порядке.
На основе таблицы чемпионата по футболу, содержащей данные о команде: название команды, число выигрышей, поражений, ничьих, количество забитых и пропущенных мячей:
12. Составить итоговую таблицу чемпионата, подсчитав число очков для каждой команды и расположение их в порядке возрастания.
13. Напечатать результаты команды, набравшей наибольшее количество пропущенных мячей.
14. Напечатать таблицу, расположив команды в порядке убывания пропущенных мячей.
15. Напечатать результаты команд, набравших одинаковое количество очков.
16. Вывести таблицу в порядке убывания числа поражений.
На основе таблицы, включающей названия 10 моделей автомобиля, их технические характеристики (мощность, наибольшая скорость, масса, вид кузова, рабочий объем цилиндра), цену:
17. Напечатать таблицу, расположение модели в порядке убывания
мощности.
18. Напечатать таблицу в порядке убывания стоимости моделей.
19. Вывести на печать технические характеристики автомобиля с наибольшей скоростью.
20. Напечатать таблицу, расположив модели в порядке возрастания рабочего объема цилиндра.
Н
107
21. Составить итоговую таблицу, подсчитав общую стоимость для каждой услуги и расположив их в порядке возрастания общей стоимости.
22. Напечатать название самой дорогой услуги;
23. Напечатать таблицу, расположив названия услуг, в порядке убывания их стоимости.
24. Напечатать названия услуг, имеющих одинаковую стоимость.
25. Вывести таблицу в порядке убывания сроков выполнения услуг.
108