Создание структурных переменных
Как уже отмечалось само описание структуры не приводит к выделению под нее места в ОП. Теперь необходимо создать нужное количество переменных с приведенной структурой и сделать это можно двумя способами.
Способ 1. В любом месте программы для декларации структурных переменных, массивов, функций и т.д., используется объявленный в шаблоне структурный тип, например:
struct Stud_type student; - структурная переменная;
Stud_type Stud[100]; - массив структур
Stud_type *p_stud; - указатель на структуру
Stud_type* Fun(Stud_type); - прототип функции с параметром структурного типа, возвращающей указатель на объект структурного типа.
Способ 2: в шаблоне структуры между закрывающейся фигурной скобкой и символом «;» указывают через запятые идентификаторы структурных данных.
Для нашего примера, используя, можно записать:
struct Stud_type {
char Number[10], Fio[40];
double S_b;
} student, Stud[100], *p_stud;
Если дальше в программе не понадобится вводить новые данные объявленного структурного типа, «Stud_type» можно не указывать.
При декларации структурных переменных возможна их одновременная инициализация
Например:
struct Stud_type {
char Number[10], Fio[40];
double S_b;
} student = {“123456”, “Иванов И.И.”, 6.53 };
или:
Stud_Type stud1 = {“123456”, “Иванов И.И.” };
Отметим, что если список инициализации будет короче, то оставшиеся поля структурной переменной будут заполнены нулями.
Некоторые особенности:
1) поля структуры, как правило, имеют разный тип кроме функций, файлов и самой этой структуры;
2) поля не могут иметь атрибут, указывающий «класс памяти», данный атрибут можно определить только для всей структуры;
3) идентификаторы (ID), как самой структуры, так и ее полей могут совпадать с ID других объектов программы, т.к. шаблон структуры обладает собственным пространством имен;
4) при наличии в программе функций пользователя шаблон структуры рекомендуется поместить глобально перед определениями всех функций и в этом случае он будет доступен всем функциям.
Элементы структур в общем случае размещаются в памяти последовательно с учетом выравнивания начальных адресов.
Выравнивание - установка значения адреса, кратного некоторой величине, определяемой особенностями адресации данных на аппаратном уровне. Часто выравнивание не обязательно, но при этом скорость обращению к объекту может снижаться.
Обращение к полям структур производится при помощи составных имен, которые образуются двумя способами:
а) использованием операции принадлежности (.) в виде:
ID_структуры .ID_поля
или
(*указатель_структуры).ID_поля
б) при помощи операции косвенной адресации (->) в виде:
указатель_структуры -> ID_поля
или
(&ID_структуры) ->ID_поля
Примеры обращения для объявленного ранее шаблона:
1). Stud_Type s1, s2;
Обратиться к полям элемента объявленной структуры s1:
s1. Number, s1. Fio, s1. S_b; 2). Stud_Type *s1, *s2;
Обратиться к полям элемента объявленной структуры s1:
s1 -> Number, s1 -> Fio, s1 -> S_b;
Так как структурная переменная является сложным объектом, операции, например, присваивания для таких переменных необходимо производить при помощи стандартных функций.
Пусть необходимо содержимое структурной переменной s2 присвоить s1:
Stud_Type s1, s2;
Идентификатор структурной переменной является константным указателем на начало размещения данного объекта в ОП, поэтому, в выражении s1 = s2; допущена ошибка, т.к. в левой части - константа. Правильное присваивание:
memcpy(&s1,&s2,sizeof(Stud_Type));
или
Stud_Type *s1, s2;
s1 = s2;
Участок программы, иллюстрирующий передачу структурных данных в функцию:
struct Spisok {
char Fio[20];
float S_Bal;
};
// Описание прототипов
void Out(Spisok );
void Vvod(int, Spisok *);
void main(void) {
Spisok Stud[50], *sved;
. . .
for(i=0;i<N;i++)
Vvod(i, &Stud[i]);
puts("\n Spisok Students");
for(i=0;i<N;i++)
Out(Stud[i]);
. . .
}
void Out(Spisok dan) {
printf("\n %20s %4.2f",dan.Fio, dan.S_Bal);
}
void Vvod(int nom, Spisok *sved) {
printf("\n Введи сведения %d : ",nom+1);
fflush(stdin);
puts("\n ФИО - ");
gets(sved->Fio);
puts("\n Средний балл - ");
scanf(“%f”, &sved->S_Bal);
}
Вложенные структуры
Структуры могут быть вложенными, т.е. поле структуры может связующим полем с внутренней структурой, описание которой должно предшествовать по отношению к основному шаблону.
Например, в структуре person, содержащей сведения - Ф.И.О., дата рождения, сделать дату рождения внутренней структурой date по отношению к структуре person. Тогда шаблон такой конструкции будет выглядеть так:
struct date {
int day, month, year;
};
struct person {
char fio[40];
struct date f1;
} ;
Объявляем переменную и указатель на переменные такой структуры:
struct person a, *p;
Инициализируем указатель p адресом переменной а:
p = &a;
Тогда, обращение к полям структурной переменной a будет выглядеть следующим образом:
a .fio a.f1.day a.f1.month a.f1.year
или
p->fio p->f1.day p->f1.month p->f1.year
Можно в качестве связи с вложенной структурой использовать указатель на нее:
struct date {
int day, month, year;
};
struct person {
char fio[40];
struct date *f1;
} ;
Тогда обращение к полям будет следующим:
a .fio a.f1->day a.f1->month a.f1->year
или
p->fio p->f1->day p->f1->month p->f1->year
Использование средства typedefупрощает определение структурных переменных, так как отпадает необходимость при их декларации указывать ключевое слово stuct. Например:
typedef struct person {
char fio[40];
int day, month, year;
} W ;
здесь W - созданный пользователем тип данных - «структура с указанными полями» и для нашего примера:
W t1, t2; - декларация двух переменных типа W, а это значит, что можно на такие переменные устанавливать указатели и использовать косвенную адресацию.
Массивы структур
Структурный тип "struct ID_структуры" как правило используют для декларации массивов, элементами которых являются структурные переменные. Это позволяет создавать программы, оперирующие с "примитивными базами данных". Например:
struct person spisok[100]; // spisok - массив структур
Или можно записать так:
struct person {
char fio[40];
int day, month, year;
} spisok[100];
В данном случае обращение к полю, например, day i-той записи может быть выполнено одним из следующих способов:
spisok[i].day=22; *(spisok+i).day=22; (spisok+i)->day=22;