Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование / WORD / Лекции по ЯП (часть 3).doc
Скачиваний:
138
Добавлен:
15.04.2015
Размер:
1.34 Mб
Скачать

Сложные структуры

Включение структур в структуры

Проиллюстрируем это следующим примером.

Допустим, нам необходимо работать с прямоугольниками. Прямоугольник можно задать координатами его противоположных (по диагонали) углов.

Структура для хранения координат одной точки имеет следующий вид:

struct coor{

int x;

int y;};

Для задания прямо­угольника необходимы две такие структуры, объединенные в единое целое. Это можно сделать следующим образом:

struct pr {

struct coord nl;

struct coord vp;

}; /*pr – прямоугольник; nl – нижний левый угол; vp – верхний правый*/

Это дает нам только новый тип. Необходимо еще объявить переменную: struct pr mybox;

Инициализация struct pr mybox = {{1,2},{11,22}}

Напишем программу, которая вычисляла бы площадь прямоугольника.

int a,b; /*длина и ширина прямоугольника*/

long s; /* площадь прямоугольника */

main() {/*Ввод кординат*/

printf(“Введите корд Х левого нижнего угла > ”);

scanf(“%d”, &mybox.nl.x);

printf(“Введите корд Y левого нижнего угла > ”);

scanf(“%d”, &mybox.nl.y);

printf(“Введите корд Х правого верхнего угла > ”);

scanf(“%d”, &mybox.vp.x);

printf(“Введите корд Y правого верхнего угла > ”);

scanf(“%d”, &mybox.vp.y);

/* Вычисление длины и ширины прямоугольника*/

a = mybox.vp.x - mybox.nl.x;

b = mybox.vp.y - mybox.nl.y;

/* Вычисление и вывод площади*/

s = a * b;

printf(“ Площадь = %ld”, s);}

Структуры, содержащие массивы

Можно определять структуры, содержащие массивы в качестве своих элементов (полей). Массивы могут быть любых типов (int, char и т.д.). Например, в следующем фрагменте кода определяется структурный тип data, содержащий целочисленный массив х из четырех эле­ментов и символьный массив у из десяти элементов:

struct data {

int x[4];

char y[10]; }

Затем можно объявить переменную record этого структурного типа: struct data record;.

Инициализация struct data record ={{1,2,3,4},'' 0123456789''};

Организация этой структуры показана на рисунке.

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

record.х[2] = 100;

record.у[1] = 'х' ;

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

Чтобы объявить массив структур, надо сначала задать шаб­лон структуры, а затем объявить массив. Пусть, например, программа предназначена для ведения телефонной книги. Можно определить структуру для хранения номера телефона каждого абонента:

struct entry {

char fname[10];

char lname[12];

char phone[8];

}

Затем создаем массив структур типаentry:

struct entry list[100];

Этот оператор объявляет массив с именем list из ста элементов. Каждый элемент представляет собой структуру типа entry и распознается по индексу, как и в любом другом массиве. В каждой из структур содержится три поля, причем эти поля — массивы типа char, Вся получившаяся сложная конструкция данных показана схематически на рисунке.

После объявления массива структур можно использовать его для разнообразных задач об­работки данных.

Например, для присвоения данных из одного элемента массива другому можно записать следующее: list[l] = list[5];

Этот оператор присваивает всем полям структуры list[l] значения соответствующих полей структуры list[5].

Можно также перемещать данные между отдельными полями структур. Например, следующий оператор копирует строку list[5].phone в строку list[l].phone:

strcpy(list[1].phone, list[5].phone);

При желании можно даже обмениваться данными ме­жду отдельными элементами массивов, являющихся полями структур: list[5].phone[l] = list[2].phone[3];

Этот оператор копирует четвертый символ номера телефона из записи list [2] во вторую позицию номера в записи list[5].

Структуры и указатели

Указатели как поля структур

Указатели-поля структур объявляются точно так же, как и любые указатели, не являющиеся членами структур, т.е. с помощью звездочки:

struct data {

int *p_b;

int *p_c;

} a;

В этом примере определяется и создается структура, в которой оба элемента являются указателями на int. Указатели необходимо инициализировать. Это можно сделать, присвоив им подходящие адреса переменных. Если есть две переменные типа int с именами b и c: int b,c;

то можно записать: a.p_b = &b;

a.p_c = &c;

Теперь указатели получили конкретные значения, и для обращения к ним можно использовать операцию ссылки (*). Выражения *a.p_b и b равны и *a.p_с и с тоже равны.

Самым распространенным указателем, используемым в структурах, можно считать указатель на char. То есть речь идет о строках.

В чем разница между использованием массива типа char и указателя того же типа в качестве элементов структуры?

Пример:

struct msg

char p1[30];

char *p2; /* осторожно: не инициализирован! */

} myptrs;

В сущности, оба эти способа предназначены для "помещения" строк в структуры.

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

Пример:

struct msg

{

char p1[10];

char p2[10];

} myptrs;

strcpy(p1, "абвгдежзиклмн"; /* Ошибка! Строка длиннее массива. */

strcpy(p2, "аб"); /* Нет ошибки, но напрасная трата памяти, */

/* поскольку строка короче массива. */

Если же определить структуру, имеющую в своем составе указатель на строку, то это ограничения отпадут. В каждом экземпляре структуры выделяется место лишь для указателя, а сами строки находятся в других местах (где именно — это не ваша забота). Ни напрасной траты памяти, ни ограничения на длину строки не будет, поскольку сами строки не хранятся непосредственно в структуре. Каждый указатель может указывать на строку любой длины, и строка фактически становится частью структуры, хотя и не помещена память в едином блоке с ней.

Внимание: Если не инициализировать указатель, то можно случайно затереть ин­формацию в памяти, предназначенную для чего-то важного. Поэтому, ис­пользуя указатели вместо массивов, выполняйте их корректную инициа­лизацию. Это можно проделать с помощью динамического выделения памяти или ассоциируя указатели с адресами реальных переменных.

Указатели на структуры и передача структур в функции

Возьмем уже рассмотренный ранее пример:

typedef

struct {

int b;

char c;

} t;

/*Объявление переменных*/

t a1,a2;

t *p; /* типизированный указатель на структуру */

p = &а1; /* инициализация указателя на структуру */

Обращение к полям структуры без использования указателей: a1.b=25;

При использовании указателя обращение к полям структуры на языке Си возможно 2-мя путями:

1-ый путь

2-ой путь

(*p).b=25;

Наличие скобок обязательно, т.к. операция обращения к элементу структуры (.) имеет более высокий приоритет, чем операция ссылки по указателю (*).

p->b=25;

(->) – операция косвенного обращения к элементам структуры или операция обращения к структуре по указателю.

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

При передаче по адресу (ссылке) в стек занесется только адрес структуры. При этом копирования структуры не происходит, появляется возможность изменять содержимое элементов структуры, а также сокращается время передачи структур.

Для того чтобы передать структуру в функцию по адресу надо:

  1. в заголовке функции, куда надо передать структуру должен быть объявлен указатель на тип структуры;

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

Пример:

typedef struct {

int a;

char b;

} str;

str x; /* передаваемая переменная-структура х типа str */

void func1(str y) /* процедура, в которую передается структура */

{ y.a = 1; //обращение к элементу структуры

}

void func2(str *ptr) /* процедура, в которую передается указатель на структуру */

{

ptr -> a = 1; //обращение к элементу структуры

или

(*ptr).a = 1; //обращение к элементу структуры

}

main(){

func1(x); //вызов процедуры с передачей структуры по значению

func2(&x1); //вызов процедуры с передачей структуры по адресу

}

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

typedef

struct {

int a;

char b;

} str;

str vs[25]; // массив структур

str *ps; // указатель на массив структур

/*инициализация указателя*/

ps=vs; или ps=&vs[0];

/* обращение к элементу структуры */

vs[5].a =25;

или

(*(ps+5)).a=25;

или

(ps+5)->a=25;