Действий пользователя (запрет ввода недопустимых




Лабораторная работа № 7

Работа со структурами

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

 

Структура - это совокупность элементов р а з л и ч н ы х типов, cгруппированных под одним именем и размещенных в соседних ячейках памяти. Каждое описание структуры фактически вводит новый тип данных, уникальный для конкретной программы.

Приведем пример описания структуры:

 

struct DATE

{

int day; /* День */

int month; /* Месяц */

int year; /* Год */

char day_name[10]; /* Название дня недели */

char mon_name[8]; /* Название месяца */

};

 

Такое описание вводит новый тип данных с именем DATE, которое может использоваться в программе наравне со стандартными типами (char, int, double). Описание структуры следует рассматривать как ш а б л о н размещения компонентов внутри будущих объектов такого типа. Никаких реальных объектов объявленного типа здесь не создается.

Обратите внимание на наличие точки с запятой в конце описания. Отсутствие этого разделителя является распространенной синтаксической ошибкой.

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

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

Элементом шаблона структуры может быть:

 

- простая переменная или указатель на нее;

- массив;

- перечисляемый тип данных;

- объединение;

- другая структура;

- указатель на объект данного структурного типа;

- битовые поля.

 

Чтобы создать сами объекты введенного типа и отвести для их

размещения необходимый объем памяти, нужно написать:

 

struct DATE data;

 

Допустимо опустить ключевое struct, и тогда способ объявления структуры будет абсолютно идентичен способу объявления простой переменной. Сравните:

 

int A; // Объявление переменной A типа int

DATE data; // Объявление структурного объекта data типа DATE

 

Для каждого объекта структурного типа выделяется непрерывная область памяти. Элементы структуры размещаются в ней именно в том порядке, в котором они записаны, начиная с младших адресов. Память под конкретный элемент отводится на границе, соответствующей его типу (так называемое выравнивание по границе слова). Поэтому в выделенной области могут появиться незанятые байты ("дыры") между соседними элементами, вследствие чего размер переменной структурного типа не всегда равен сумме размеров всех ее элементов. Для определения действительного размера объекта структурного типа следует использовать операцию sizeof(type).

Заметим, что термином "структура" в литературе именуют как шаблон структуры, так и сам объект структурного типа.

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

 

DATE data,sm,cont;

 

Допустимо совмещать описание шаблона с объявлением объектов вводимого типа, имена которых в этом случае перечисляются сразу после шаблона:

 

DATE

{

int day;

int month;

int year;

char day_name[10];

char mon_name[8];

} data,sm,cont;

 

Инициализация структуры подобна инициализации одномерного массива и может выполняться одновременно с созданием объекта путем заполнения списка значений полей с учетом их типов:

 

DATE data = {12,4,1944,"Среда","Апрель"};

 

Если же сначала создать объект, а потом заносить в него данные, то это можно сделать для каждого поля отдельным оператором.

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

 

data.year

 

Такое составное имя можно в данном случае рассматривать как имя переменной, хранящей число 1944. Его можно использовать на правах обычного идентификатора, в том числе и в левой части оператора присваивания для изменения текущего численного значения.

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

Итак, вполне возможно начать заполнение объекта так:

 

DATE data; // Создаем объект

data.day = 12;

data.month = 4;

data.year = 1944;

 

Однако для символьных полей присваивание (data.day_name = “Среда”) недопустимо, можно использовать только(!) стандартную функцию копирования строк:

 

strcpy(data.day_name, “Среда”);

strcpy(data.mon_name, “Апрель”);

 

 

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

 

DATE data; // Объявление структурного объекта

DATE *pt; // Создание указателя на структуру

pt = &data; // Занесение в него адреса объекта

 

Указатели на структуру используются в Си столь часто, что имеется специальный символ, позволяющий обращаться к желаемому элементу структуры посредством указателя. Это символ "стрелка вправо" (->), вводимый с клавиатуры как сочетание двух символов: минуса и знака >. Поэтому при наличии указателя на структуру можно получить доступ к элементу структуры еще одним способом:

 

pt->year

 

Эта конструкция рассматривается как значение элемента year того структурного объекта типа DATE, чей адрес хранится в указателе pt. Другими словами, она абсолютно эквивалентна по смыслу составному имени data.year и взаимозаменяема с ним в любой ситуации.

Строго говоря, возможен и третий вариант записи:

 

(*pt).year

 

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

Поскольку элементом массива может быть любой объект известного компилятору типа (кроме функций, естественно), то вполне корректно создавать массивы структур. Это иногда очень удобно.

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

 

struct BOOK

{

char author[MAX_AUT]; // Фамилия автора

char title[MAX_NAME]; // Название книги

int page; // Кол-во страниц

double cost; // Цена (руб)

};

 

Теперь можно объявить массив элементов введенного структурного типа:

 

BOOK book[10];

 

Каждый элемент массива (book[0], book[1],...) является структурой типа BOOK, причем указанным объявлением только выделена память для размещения всех элементов. Никакие значения еще туда не занесены - это нужно делать отдельно. Расположение элементов в памяти - как обычно, по порядку:

 

┌───────────────┬───────────────┬──────────────┬──────────────┐

│ book[0].author│ book[0].title │ book[0].page │ book[0].cost │

└───────────────┴───────────────┴──────────────┴──────────────┘

┌───────────────┬───────────────┬──────────────┬──────────────┐

│ book[1].author│ book[1].title │ book[1].page │ book[1].cost │

└───────────────┴───────────────┴──────────────┴──────────────┘

.............................................................

.............................................................

┌───────────────┬───────────────┬──────────────┬──────────────┐

│ book[9].author│ book[9].title │ book[9].page │ book[9].cost │

└───────────────┴───────────────┴──────────────┴──────────────┘

 

Заметим, что, как и положено для массива, его имя без индексов (book) адекватно адресу начала массива, а элементы book[i] - начальным адресам соответствующих структурных элементов.

Размерности символьных массивов удобно задать символическими именами, которые можно предварительно определить директивами препроцессора, например, так:

 

#define MAX_AUT 15

#define MAX_NAME 30

 

Приведем пример консольной программы работы с подобным массивом структур.

 

#include<stdio.h>

#define MAX_AUT 15

#define MAX_NAME 30

 

// Прототип функции печати

 

void print_book(struct BOOK *pb, int size);

 

struct BOOK // Задаем шаблон структуры

{

char author[MAX_AUT]; // Фамилия автора

char title[MAX_NAME]; // Название книги

int page; // Кол-во страниц

float coust; // Цена (руб)

};

main()

{

// Объявляем и инициализируем массив структур

 

BOOK book[4] =

{

"Толстой","Война и мир",960,10.50,

"Беляев","Человек-невидимка",182,3.60,

"Цвейг","Новеллы",234,5.30,

"Таль","В огонь атаки",156,4.40,

};

// Передадим адрес массива структур

// в функцию распечатки

print_book(book,4);

getch();

}

 

//------------------------------------------

// Функция распечатки массива структур

//------------------------------------------

 

void print_book(struct BOOK *pb, int size)

{

int i;

for(i=0;i<size;i++)

{

printf("\n Автор: %s", (pb+i)->author);

printf("\n Название: %s", (pb+i)->title);

printf("\n Кол-во страниц: %d", (pb+i)->page);

printf("\n Цена: %-5.2f", (pb+i)->cost);

printf("\n\n");

}

return;

}

 

Программа достаточно проста. Следует лишь обратить внимание на запись аргументов функции printf(). Поскольку для любого массива изменение указателя на единицу сдвигает указатель на длину элемента массива, то и для структуры инкремент указателя сдвигает его на размер одного структурного элемента данного типа, что и учтено при изменении указателя:

 

(pb+i)

 

Естественно, функция print_book() должна "знать", что указатель pb - это указатель на конкретную структуру. Поэтому он описан с явным объявлением типа в списке формальных аргументов функции.

 

 

ЗАДАНИЕ НА РАБОТУ

Для указанного варианта:

- разработать шаблон структуры хранения информации;

- выбрать размер статического массива структур;

- разработать графический интерфейс ввода данных

и вывода результата обработки;

- составить алгоритмы и написать функции выполнения

Заданных действий.

- предусмотреть программную защиту от некорректных

действий пользователя (запрет ввода недопустимых



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-04-27 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: