Пятница, 29.03.2024, 10:31
Приветствую Вас Гость | RSS

Программирование на ЯВУ

Меню сайта
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа

Лекция 14

Определение структурных переменных

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

struct имя_структуры {
 Описание_элементов
};

Пример:

struct dinner {
 char *place;
 float cost;
 struct dinner *next;
};

Структурная переменная описывается с помощью переменной структурного типа.

Примеры:

struct dinner week_days [7]; /* массив структур */
struct dinner best_one; /* одна структурная переменная */
struct dinner *p; /* указатель на структурную переменную */

Структура, запись в терминологии языка Паскаль и Ада, - это составной объект, в который входят компоненты любых типов, за исключением функций. В отличие от массива, который является однородным объектом, структура может быть неоднородной. Тип структуры указывается записью вида

struct {
 список описаний
} имя;

В структуре должен быть указан хотя бы один компонент. Указатель типа структуры используется для определения структур. Определения структур имеют следующий вид:

тип-данных описатели;

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

struct {
 double x,y;
} a,b,c[9];

переменные a и b определяются как структуры, каждая из которых состоит из двух компонентов - x и y. Переменная c определяется как массив из девяти таких структур.

Из определения

struct {
 int year;
 short int month, day;
} date1,date2;

следует, что каждая из двух переменных date1, date2 состоит из трех компонентов: year, month, day.

С типом структуры может быть ассоциировано имя, которое задается описанием типа в форме

typedef struct {
 список описаний
} имя-типа-структуры;

Спецификатор typedef (определяет класс памяти) позволяет нам создать свое собственное имя типа. Это напоминает директиву #define, но со следующими тремя изменениями:

  1. В отличие от #define спецификатор typedef дает символические имена, но ограничивается только типами данных.
  2. Спецификатор typedef выполняется компилятором, а не препроцессором.
  3. В своих пределах спецификатор typedef более гибок, чем #define.

В дальнейшем эти имена могут использоваться для определения структур. Ниже приведен пример описания типа структуры с именем employee:

typedef struct {
 char name[30];
 int id;
 dept d;
 family f;
} employee;

где слова dept, family указывают типы, а именно типы структур, предварительно определенные пользователем. Тип структуры employee может быть использован для определения переменных. Например, определение

employee chairperson, president, e1, e2;

описывает переменные chairperson, president, e1, e2 как структуры типа employee.

Существует и другой способ ассоциирования имени с типом структуры. Этот способ основан на применении меток структуры. Метки структуры аналогичны меткам перечисляемого типа. Метка структуры описывается следующим образом:

struct метка{
 список описаний
}

где метка является идентификатором. В приведенном ниже примере слово student описывается как метка структуры:

struct student {
 char name[25];
 int id,age;
 char sex;
};

Метки структуры используются для определения структур записью вида

struct метка список-идентификаторов;

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

struct node {
int data;
struct node *next;
};

метка структуры node действительно является рекурсивной, так как она используется в своем собственном описании, т.е. в описании указателя next. Из-за наличия знака * переменная next описана как указатель на объекты типа node. Структуры не могут быть прямо рекурсивными. Структура типа S не может содержать компонент, являющийся структурой типа S. Однако структура типа S может содержать компонент, указывающий на структуру типа S.

Доступ к компонентам структуры

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

s.c

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

date1.year
date1.month
date1.day

Поля битов в структурах

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

Пример:

struct bfeg {
 unsigned int bf_flg1 : 10;
 unsigned int bf_flg2 : 6;
};

Данная структура описывает 10-битовое поле, которое для вычислений преобразуется в значение типа unsigned int, и 6-битовое поле, которое обрабатывается как значение типа unsigned int.

Объединения

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

Определение объединенного типа данных аналогично определению структурного типа данных:

union имя_объединения {
 Описания_элементов
};

Пример:

union bigword {
 long bg_long;
 char *bg_char [4];
};

Данные типа union bigword занимают память, необходимую для размещения наибольшего из своих элементов, и выравниваются в памяти к границе, удовлетворяющей ограничениям по адресации как для типа long, так и для типа char *[4].

Описание переменной объединенного типа:

Пример:

union bigword x;
union bigword *p;
union bigword a[100];

Перечисления

Данные перечислимого типа относятся к некоторому ограниченному множеству данных.

Определение перечислимого типа данных:

enum имя_перечислимого_типа {
 Список_значений
};

Каждое значение данного перечислимого типа задается идентификатором.

Пример:

enum color {
 red, green, yellow
};

Описание переменной перечислимого типа:

enum color chair;
enum color suite [40]; 

Использование переменной перечислимого типа в выражении.

Пример:

chair = red;
suite[5] != yellow;

Переменные структуры

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

struct {
 общие компоненты;
 метка активного компонента;
 union {
 описание компонента 1
 описание компонента 2
 ...
 описание компонента n
 } идентификатор;
}

Ниже приведен пример определения переменной структуры health_record:

struct {
/* общая информация */
 char name[25];
 int age;
 char sex;
 /* метка активного компонента */
 marital_status ms;
 /* переменная часть */
 union {
 /* холост */
 /* нет компонентов */
 /* женат */
 struct {
 char marriage_date[8];
 char spouse_name[25];
 int no_children;
 }
 /* разведен */
 char date_divorced[8];
 } marital_info;
} health_record;

где тип marital_status, т.е. тип метки активного компонента ms, описан как

typedef enum {SINGLE, MARRIED, DIVORCED} 
 marital_status;

Ниже приведены несколько примеров ссылки на компоненты переменной структуры:

health_record.name
health_record.ms
health_record.marital_info.marriage_date

Указатели и структуры

Рассмотрим метку структуры student, описание которой было дано выше как

struct student {
 char name[25]; 
 int id, age;
 char sex;
}

Указатель new_student определен как

struct student *new_student;

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

(*new_student).name
(*new_student).id
(*new_student).age
(*new_student).sex

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

new_student->name
new_student->id
new_student->age
new_student->sex

Массив структур

Процесс описания массива структур совершенно аналогичен описанию любого другого типа массива:

struct book libry[MAXBKS];

Этот оператор объявляет libry массивом, состоящим из MAXBKS-элементов. Каждый элемент массива представляет собой структуру типа book. Таким образом, libry[0] является book-структурой, libry[1] - второй book-структурой и т.д.

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

libry[0].value value - первый элемент массива
libry[4].title title - пятый элемент массива

Переименование типов

Формат

typedef старый_тип новый_тип

Примеры:

typedef long large;
/* определяется тип large, эквивалентный типу long */
typedef char *string;
/* тип string, эквивалентен типу char* */

Переименование типов используется для введения осмысленных или сокращенных имен типов, что повышает понятность программ, и для улучшения переносимости программ (имена одного типа данных могут различаться на разных ЭВМ).

Пример:

/* Реализован алгоритм, который позволяет определить 
строки матриц, состоящие из одинаковых целых, 
расположенных в различных столбцах. Используются 
двумерные массивы и структуры. Сначала выполняется 
сортировка строк по возрастанию. Отсортированные 
строки сравниваются и выводятся на экран номера 
одинаковых строк */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#define n 4 /*количество строк */
#define m 4 /*количество столбцов*/
typedef struct mas{int i,i1;} mas;
int m1[n][m]; /*исходный массив*/
struct mas{int i,i1;}; 
mas a[n*2]; 
/*массив типа mas, где будут лежать одинаковые 
 строки, a[1].i и a[1].i1 - одинаковые строки*/
void main()
{
 clrscr();
 int i,j;
 randomize();
 for(i=0;i<n;i++)
 for(j=0;j<m;j++)
 m1[i][j]=random(2);
 /*случайным образом в массив заносим целые*/
 for(i=0;i<n;i++) {
 printf("\n %d) ",i);
 for(int j=0;j<m;j++)
 printf(" %d",m1[i][j]);
 }
 int min, p;
/* индекс минимального элемента после s-го элемента 
i-ой строки сортировка строк массива по возрастанию */
 for(i=0;i<n;i++) { /* i-сортировка i-ой строки */
 for(int s=0;s<m-1;s++) {
 min=m1[i][s+1];
 for(int j=s;j<m;j++)
 if(m1[i][j]<=min) {
 min=m1[i][j];p=j;
 }
/* запоминаем минимальный элемент в ряду после 
s-го элемента */
 if(m1[i][s]>=min) {
 m1[i][p]=m1[i][s];m1[i][s]=min;
 }
/* меняем местами s-й и p-й элемент,если 
 s-й > p-го(минимального) */
 }
 }
 printf("\n");
 for(i=0;i<n;i++) {
 printf("\n %d) ",i);
 for(int j=0;j<m;j++)
 printf(" %d",m1[i][j]);
/* выводим отсортированный массив */
 }
 int s,k=0; 
/*сколько элементов в i-й строке совпадают с элементами i1 строки*/
/*сколько строк совпали*/
 int i1;
 for(i=0;i<n-1;i++) /* верхняя строка i */
 for(i1=i+1;i1<n;i1++) { /* нижняя строка i1 */
 s=0;
 for(int j=0;j<m;j++) 
/* сравнение идет по j-му столбцу */
 if(m1[i][j]==m1[i1][j]) s++;
/* если соответствующие элементы в i-й и i1-й строки совпадают то кол-во совпавших увеличивается на 1 */
 if(s==m) {a[k].i=i;a[k].i1=i1;k++;}
/* если все элементы i-й и i1-й строки совпали, то они одинаковые */
 }
 printf("\n Совпадающие строки :");
 for(i=0;i<k;i++)
 printf("\n %d и %d",a[i].i,a[i].i1);
/* распечатываем a[i].i-ю и a[i].i1-ю совпадающую 
 строку */
 getch();
}
Поиск

Яндекс.Метрика