|
Программирование >> Динамические структуры данных
Семинар 6. Структуры Задача 6.4. Структуры в динамической памяти int birth year: float pay: } man: FILE *fout: if ((fout - fopen( dbase.bin , r+b )) - NULL ){ puts( Ошибка открытия файлаХп ): return 1: } fseek(fout. 0. SEEKJND): int n record = ftell(fout) / sizeof(man): int num; while (true) { puts( Введите номер записи или -1: ): scanf( Xi . &num): if (num < 0 II num >- n record) break: fseek(fout. num * sizeof(man). SEEK SET): fread(&man. sizeof(man). 1. fout): printf( Xs*5i*10.2f\n . man.name, man.birthjear. man.pay): puts( Введите новый оклад: ): scanf( If . &man.pay): fseek(fout. num * sizeof(man). SEEK SET): fwrite(&man. sizeof(man). 1. fout): printf( 3;s3;5i3;i0.2f\n . man.name. man.birthjear. man.pay): fclose(fout): printf( Корректировка завершена.\n ): return 0: В операторе 1 открывается сформированный в предыдущей задаче бинарный файл. Обратите внимание на режим открытия: г+ обозначает возможность чтения и записи, b - двоичный режим (мы говорили о нем на пятом семинаре, см. с. 106). Чтобы проконтролировать введенный номер записи, в переменную nrecord заносится длина файла в записях (оператор 2). До этого указатель текущей позиции файла устанавливается на его конец с помощью функции f seek, следовательно, в результате вызова f tel 1 будет получен ра1змер файла в байтах. В цикле корректировки оклада (оператор 3) текущая позиция в файле устанавливается дважды, поскольку после первого чтения она смещается на размер считанной записи. Выход из цикла выполняется, если будет задан неверный номер записи: меньше нуля или больше, чем их количество (при написании программы мы приняли, что первая запись в файле имеет номер 0). Задача 6.4. Структуры в динамической памяти Вывести на экран содержимое бинарного файла, сформированного в предыдущей задаче, упорядочив фамилии сотрудников по алфавиту. Не тратя времени на предварительное обсуждение, сразу приведем текст программы. #include <stdio.h> #include <string.h> #include <stdlib.h> const int l name = 30: struct Man { char nameCl name + 1]: int birth ear: float pay: int compare(const void *manl. const void *nian2): 1 int main(){ FILE *fbin: if ((fbin - fopen( dbase.bin , rb )) - NULL ) { puts( Ошибка открытия файла\п ): return 1: } fseek(fbin. 0. SEEKJND): int n record - ftell(fbin) / sizeof(Man): 3 4 Man *шп = new Man [n record]: fseek(fbin. 0. SEEK SET): fread(man. sizeof(Man). n record. fbin): fclose(fbin): qsort(man. n record. sizeof(Man), compare): for (int i =0: i < n record: i++) printf( 3;s %Ъл 3;i0.2f\n . man[i].name. man[i].birth ear. man[i].pay): return 0: int compare(const void *nianl. const void *nian2) { return strcmp(((Man *) manl)->name. ((Man *) man2)->name): Рассмотрим моменты, которые отличают эту программу от предыдущих. Во-первых, это чтение из бинарного ()>айла. После открытия файла мы, как и в предыдущей программе, заносим в переменную nrecord его размер в записях, а затем выделяем в динамической памяти место под весь массив структур (оператор 2). Функция f read позволяет считать весь файл за одно обращение (оператор 4), после чего файл уже больше не требуется, поэтому лучше его сразу же закрыть. Ведь вы все равно его пропустите, правда? Для сортировки мы в образовательных целях и для разнообразия использовали стандартную функцию qsort (оператор 5). Ее прототип находится в заголовочном файле <stdl i b. h>. Функция может выполнять сортировку массивов любых размеров и типов. У нее четыре параметра: 1) указатель на начало области, в которой размещается упорядочиваемая информация; 2) количество сортируемых элементов; 3) размер каждого элемента в байтах; 4) имя функции, которая выполняет сравнение двух элементов. На следующем семинаре мы подробно рассмотрим правила оформления функций и передачи имен функций в качестве параметров, а сейчас необходимо уяснить следующее: раз функция qsort универсальна, мы должны дать ей информацию, как сравнивать сортируемые элементы и какие выводы делать из сравнения. Значит, мы должны сами написать функцию, которая сравнивает два любых элемента, и передать ее в qsort. Имя функции может быть любым. Мы назвали ее compare. Оператор 1 представляет собой заголовок (прототип) функции, он необходим компилятору для проверки правильности ее вызова. Для правильной работы qsort требуется, чтобы наща функция имела два параметра - указатели на сравниваемые элементы. Они должны иметь тип void. Функция должна возвращать значение, меньшее нуля, если первый элемент меньше второго, равное нулю, если они равны, и большее нуля, если первый элемент больше. При этом массив будет упорядочен по возрастанию. Если мы хотим упорядочить массив по убыванию, нужно изменить возвращаемые значения так: если первый элемент меньше второго, возвращать значение, большее нуля, а если больше - меньшее. Внутри функции надо привести указатели на void к типу указателя на структуру Man. Для этого мы использовали операцию приведения типа в стиле С (Man *). Более грамотно применять для этого операцию reinterpret cast, введенную в стандарт С++ относительно недавно. Старые компиляторы могут ее не поддерживать. Функция compare с использованием reirterpret cast выглядит вот таким устрашающим образом: int compare(const void *manl. const void *man2) { return strcmp((reinterpret cast <const Man *> (manl))->name. (reinterpret cast <const Man *> (man2))->nanie): Чтобы описание структуры было известно в функции compare, мы перенесли описание структуры, а вместе с ней и описание необходимой ей константы l name в глобальную область. Для упорядочивания массива по другому полю надо изменить функцию сравнения. Вот, например, как она выглядит при сортировке по возрастанию года рождения: int compare(const void *manl. const void *man2) { int p: if(((Man *) manl)->birthjear < ((Man *) man2)->birth year) p = -1: else if(((Man *) manl)->birth year == ((Man *) man2)->birth year) p-0: else p - 1: return p: Можно записать то же самое более компактно с помощью тернарной условной операции, которую мы рассматривали на втором семинаре (см. с. 36). Для разнообразия приведем функцию для сортировки по убыванию оклада: int compare(const void *manl. const void *man2) { return ((Man *) manl)->pay > ((Man *) man2)->pay ? -1: ((Man *) manl)->pay - ((Man *) man2)->pay ? 0 : 1: Как видите, использование стандартных функций сокращает объем про1раммы, но требует некоторых усилий по изучению их интерфейса и правильному оформлению вызова. В качестве небольшого заключительного упражнения измените эти функции так, чтобы они использовали операцию reinterpret cast. Давайте повторим основные моменты этого семинара. 1. Структуры применяются для логического объединения связанных между собой данных различных типов. 2. После описания структурного типа ставится точка с запятой. 3. Элементы структуры называются полями. Поля могут быть любого основного типа, массивом, указателем, объединением или структурой. 4. Для обращения к полю используется операция выбора; точка при обращении через имя структуры и -> при обращении через указатель. 5. Структуры одного типа можно присваивать друг другу. 6. Ввод/вывод структур выполняется поэлементно. 7. Структуры, память под которые выделяет компилятор, можно инициализировать перечислением значений их элементов. Задания Вариант 1 Описать структуру с именем STUDENT, содержащую следующие поля: □ фамилия и инициалы; □ номер группы; □ успеваемость (массив из пяти элементов). Написать программу, выполняющую следующие действия: □ ввод с клавиатуры данных в массив, состоящий из десяти структур типа STUDENT; записи должны быть упорядочены по возрастанию номера 1руппы; □ вывод на дисплей фамилий и номеров групп для всех студентов, включенных в массив, если средний балл студента больше 4.0; □ если таких студентов нет, вывести соответствующее сообщение. Вариант 2 Описать структуру с именем STUDENT, содержащую следующие поля: □ фамилия и инициалы; □ номер группы; □ успеваемость (массив из пяти элементов). Написать программу, выполняющую следующие действия: □ ввод с клавиатуры данных в массив, состоящий из десяти структур типа STUDENT; записи должны быть упорядочены по возрастанию среднего балла; □ вывод на дисплей фамилий и номеров ipynn для всех студентов, имеющих оценки 4 и 5; □ если таких студентов нет, вывести соответствующее сообщение. Вариант 3 Описать структуру с именем STUDENT, содержащую следующие поля: □ фамилия и инициалы; □ номер группы; □ успеваемость (массив из пяти элементов). Написать программу, выполняющую следующие действия: □ ввод с клавиатуры данных в массив, состоящий из десяти структур типа STUDENT; записи должны быть упорядочены по алфавиту; □ вывод на дисплей фамилий и номеров групп для всех студентов, имеющих хотя бы одну оценку 2; □ если таких студентов нет, вывести соответствующее сообщение. Вариант 4 Описать структуру с именем AEROFLOT, содержащую следующие поля: □ название пункта назначения рейса; □ номер рейса; □ тип самолета. Написать программу, выполняющую следующие действия: □ ввод с клавиатуры данных в массив, состоящий из семи элементов типа AEROFLOT; записи должныбыть упорядочены по возрастанию номера рейс □ вывод на экран номеров рейсов и типов самолетов, вылетающих в пункт назначения, название которого совпало с названием, введенным с клавиатуры; □ если таких рейсов нет, выдать на дисплей соответствующее сообщение Вариант 5 Описать структуру с именем AEROFLOT, содержащую следующие поля: □ название пункта назначения рейса; □ номер рейса; □ тип самолета. Написать программу, выполняющую следующие действия: □ ввод с клавиатуры данных в массив, состоящий из семи элементов типа AEROFLOT; записи должны быть размещены в алфавитном порядке по названиям пунктов назначения; □ вывод на экран пунктов назначения и номеров рейсов, обслуживаемых самолетом, тип которого введен с клавиатуры; □ если таких рейсов нет, выдать на дисплей соответствующее сообщение. Вариант 6 Описать структуру с именем WORKER, содержащую следующие поля: □ фамилия и инициалы работника; □ название занимаемой должности; □ год поступления на работу. Написать программу, выполняющую следующие действия: □ ввод с клавиатуры данных в массив, состоящий из десяти структур типа WORKER; записи должны быть размещены по алфавиту; □ вывод на дисплей фамилий работников, чей стаж работы в организации превышает значение, введенное с клавиатуры; □ если таких работников нет, вывести на дисплей соответствующее сообщение. Вариант 7 Описать структуру с именем TRAIN, содержащую следующие поля: □ название пункта назначения; □ номер поезда; □ время отправления. Написать программу, выполняющую следующие действия: □ ввод с клавиатуры данных в массив, состоящий из восьми элементов типа TRAIN; записи должны быть размещены в алфавитном порядке по названиям пунктов назначения; □ вывод на экран информадии о поездах, отправляющихся после введенного с клавиатуры времени; □ если таких поездов нет, выдать на дисплей соответствующее сообщение. Вариант 8 Описать структуру с именем TRAIN, содержащую следующие поля: □ название пункта назначения; □ номер поезда;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |