Основы программирования на языке C

         

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


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

s.c

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

date1.year date1.month date1.day



Объединения


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

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

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];



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


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

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

Пример:

struct dinner { char *plase; 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. Переменная с определяется как массив из девяти таких структур.

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

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

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

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

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

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

В отличие от #define спецификатор typedef дает символические имена, но ограничивается только типами данных.Спецификатор typedef выполняется компилятором, а не препроцессором.В своих пределах спецификатор 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; };

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


Формат

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(); }



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


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

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 {SINGL,MARRIED, DIVORCED} marital_status;

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

health_record.name healts_record.ms health_record.marital_info.marriage_date



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


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

Пример:

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

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



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


Рассмотрим метку структуры 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