Программирование >>  Динамические структуры данных 

1 ... 15 16 17 [ 18 ] 19 20 21 ... 38


Напомним, что если вы работаете в интегрированной среде Visual С++ в режиме консольных приложений, то весь ввод-вывод осуществляется в кодировке ASCH. Поэтому поведение данной программы будет различным в зависимости от кодировки текста в файле dbase.txt, а последняя определяется тем, в каком текстовом редакторе вы создавали этот файл.

Допустим, что вы использовали один из редакторов под MS DOS, к примеру Dos Navigator или Far. В этом случае кодировка в файле и в окне вывода одна и та же, и программа работает нормально. Но если вы заполнили файл dbase .txt в редакторе NotePad или WordPad (кодировка ANSI), то программа не будет работать с русскоязычными фамилиями.

Если материал первого семинара еще не окончательно улетучился из вашей памяти, то вы знаете, что в таких случаях надо использовать функцию OemToChar (), переводящую символы из кодировки ASCII в кодировку ANSI для введенной с консоли фамилии (переменная паше). Для этого достаточно раскомментировать оператор 10 в нашей программе. Аналогично, для нормального вывода текста в консольное окно необходимо обратное преобразование с помощью функции CharToOemO - раскомментируйте оператор 16. Применение указанных функций требует подключения заголовочного файла <wi ndows. h> (раскомментируйте оператор 0).

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

Продолжим анализ программы. Мы остановились на том, что алгоритм составлен в предположении, что фамилия начинается с первой позиции записи в базе данных. Измените программу так, чтобы это ограничение можно было снять. Для этого придется проверить, стоит ли перед фамилией пробел в том случае, если она не начинается с первой позиции. Аналогичная проблема рассматривалась на предыдущем семинаре (задача 5.2). Внесите в тестовый пример изменения, необходимые для тестирования этой части программы.

Проверка переменной n man в операторе 17 необходима для того, чтобы в случае, если пользователь не введет ни одной фамилии, совпадающей с фамилией в базе, не выполнялось деление на 0.

Крупным недостатком нашей программы является то, что вводить фамилию сотрудника требуется именно в том регистре, в котором она присутствует в базе. Для преодоления этого недостатка необходимо перед сравнением фамилий переводить все символы в один регистр. Для символов латинского алфавита в библиотеке есть функции tolower(c) и toupper(c), переводящие переданный им символ с в нижний и верхний регистр соответственно, аналогичные функции для символов русского алфавита придется написать самостоятельно.

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

А теперь давайте рассмотрим вариант записи этой же программы с помощью библиотечных функций ввода-вывода:

#include <stdio.h> #include <string.h>

#include <windows.h> int mainOI const int l nanie - 30; struct Man { int birth >ear: char name[l name + 1]; float pay:

const int l dbase 100: Man dbase[l dbase]: char named name + 1]:

FILE *fin:

if ((fin - fopen( dbase.txt . r )) = NULL){ puts( Ошибка открытия файлаХп ): return 1: }

int i - 0:

while (!feof(fin)) { fgets(dbase[i].name. l name. fin):

fscanf(fin. %ППг\\ &dbase[i].birthjear. &dbase[i].pay): i++:

if (i > l dbase) { puts( Слишком длинный файл\п ): return 1; }

int n record - i. n man - 0: float mean pay = 0:

while (true) {

puts( Введите фамилию или нажмите Enter для окончания: ); gets(name):

if (strlen(name) = 0)break: OemToChar(name, name):

bool not found - true: for (i - 0: i < n record: i++) { if (strstr(dbase[i].name. name)) if (dbase[i].name[strlen(name)] = ) { strcpy(name. dbase[i].name): CharToOem(name. name):

printf( X30sa;5i 10.2f\n . name. dbase[i].birthjrear, dbase[i].pay):

n man++: mean pay += dbase[i].pay: not found = false;}

if (not found) puts( TaKoro сотрудника нетХп )-

if (n man > 0) printf( Средний оклад: !fel0.2f\n . mean pay / n man) return 0;

0 1

3 4

5 6



Из всех именованных констант осталась одна, задающая длину поля фамилии (Iname, оператор 1). Все остальные константы определять нет смысла, потому что ввод осуществляется не через буферную переменную, а непосредственно в поля структуры с помощью функции чтения строки fgets и форматного ввода fscanf (оператор 2). Эта функция сама выполняет действия по преобразованию подстроки в число, которые мы явным образом задавали в предыдущей программе. Как и в предыдущей версии, программу необходимо настроить на ожидаемую кодировку символов. Если вы работаете в среде Visual С++ и готовите текстовый файл dbase.txt с помощью Windows-ориентированного текстового редактора, то раскомментируйте операторы 4 и 5 для преобразования символов из кодировки ASCII в кодировку ANSI и обратно, а также оператор О для подключения заголовочного файла <wi ndows. h>.

Мы упростили выход из цикла ввода запросов, теперь для заверщения цикла достаточно нажать клавишу Enter (оператор 3). Для вывода сведений о сотруднике мы использовали функцию printf (оператор 6). Как видите, иногда старые добрые функции могут сделать программу более простой и наглядной! Это происходит, когда при вводе и выводе требуется форматирование разнотипных данных.

Задача 6.2. Сортировка массива структур

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

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

Для сортировки применим описанный в Учебнике на с. 59 метод выбора. При всей своей простоте он достаточно эффективен. Надеемся, что вы еще помните основную идею этого метода (мы его использовали в задаче 4.3): из массива выбирается наименьший элемент и меняется местами с первым элементом, затем рассматриваются элементы, начиная со второго, наименьший из них меняется местами со вторым элементом, и так далее. Для упорядочивания требуется количество просмотров, на единицу меньшее, чем количество элементов в массиве (при последнем проходе цикла при необходимости меняются местами предпоследний и последний элементы массива).

#include <fstreani.h> linclude <string.h> finclude <stdlib.h> int main(){

const int l name - 30. 1 jear - 5. l pay = 10. l buf - l name + 1 ear + l pay:

struct Man { int birth year:

char named пап)е + 13: float pay:

const int l dbase = 100: Man dbase[l dbase]: char buf[l buf + 1]:

ifstream fin( dbase.txt . ios::in ios:mocreate);

if (!fin) { cout Ошибка открытия файла endl: return 1: }

int i - 0;

while (fin.getline(buf. l buf)) { strncpy(dbaseCi].name. buf. l name): dbase[i].name[l name] - XO: dbase[i].birth jear = atoi(&buf[l name]): dbase[i].pay - atof(&buf[l name + Ijear]); i++:

if (i > l dbase) { cout Слишком длинный файл endl: return 1: }

int n record fin.closeO:

ofstream fout( dbase.txt ):

if (!fout){ cout Ошибка открытия файла

endl: return 1: }

for (i - 0: i < n record - 1: i++) {

принимаем за наименьший первый из рассматриваемых элементов: int imin - i:

поиск номера минимального элемента из неупорядоченных: for (int j - i + 1: j < n record:

if (dbaseCj].birth ear < dbase[imin}.birth ear) imin - j: обмен двух элементов массива структур: Man а - dbaseCi]: dbaseCi] dbase[imin]: dbase[imin] = a:

for (i - 0: i < n record : i-н-) { fout dbaseCi].name dbase[i].birth year dbaseCi].pay endl:

fout.closeO:

cout Сортировка базы данных завершена endl: return 0:



Семинар 6. Структуры

Задача 6.3. Структуры и бинарные файлы

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

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

СОВЕТ-

Будьте аккуратны при отладке программ, изменяющих входные файлы: следует либо перед запуском программы создать копию исходного файла, либо открывать выходной файл с другим именем, а заменять его на имя, требуемое по заданию, только после того, как удалось убедиться в полной работоспособности программы.

Задача 6.3. Структуры и бинарные файлы

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

Бинарные файлы, то есть файлы, в которых информация хранится во внутренней форме представления, применяются для последующего использования программными средствами. Смотреть на них в текстовом редакторе - занятие, без сомнения, медитативное, но пользы от него немного. Преимущество бинарных файлов состоит в том, что, во-первых, при чтении/записи не тратится время на преобразование данных из символьной формы представления во внутреннюю и обратно, а во-вторых, при этом не происходит потери точности вещественных чисел. Кроме того, при работе с бинарными файлами щироко применяется прямой доступ к информации путем установки текущей позиции указателя. Это дает возможность быстрого получения и изменения отдельных данных файла. Например, в данной задаче мы будем изменять оклад отдельных сотрудников, не затрагивая другие записи базы.

Бинарный файл открывается в двоичном режиме, а чтение/запись в него выполняются с помощью функций библиотеки fread и fwrite.

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

Создание бинарного файла из текстового #include <stdio.h> #include <string.h>

отладочная печать

int main(){ const int l name - 30: struct {

char name[1 name + 1]:

int birth year:

float pay: } man:

FILE *fin:

if ((fin - fopen( dbase.txt . r )) NULL ) {

puts( 0uH6Ka открытия вх. файлаХп ): return 1: } FILE *fout:

if ((fout - fopen( dbase.bin , wb )) NULL ) { puts( 0uH6Ka открытия вых. файлаХп ); return 1: }

while (!feof(fin)) { fgets(man.name. l name. fin): fscanf(fin. *iXf\n . &man.birth >ear. &man.pay): printf( 3;s3;5i3;i0.2f\n . man.name, man.birthear.

man.pay): fwrite(&man. sizeof(man). 1. fout): }

fclose(fout):

printf( Бинарный файл записанХп ): return 0:

Для формирования записей в бинарном файле здесь применяется функция fwrite:

size t fwrite(const void *p. size t size. size t n. FILE *f) Она записывает n элементов длиной size байт из буфера, заданного указателем р, в поток f. Возвращает число записанных элементов.

Для чтения из бинарного файла во второй программе будем применять функцию fread:

size t fread(void *р. size t size. size t n. FILE *f): Она считывает n элементов длиной size байт в буфер, заданный указателем р, из потока f. Возвращает число считанных элементов, которое может быть меньше, чем запрошенное.

Корректировка бинарного файла finclude <stdio.h> #include <string.h> int main(){

const int l name - 30:

struct { char name[l name + 1]:



1 ... 15 16 17 [ 18 ] 19 20 21 ... 38

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика