КАТЕГОРИИ:
АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника
|
Листинг 1.1
#include <fstream.h> #include <string.h> #include <stdlib.h> //#include <windows.h> //0 int main() const int l name = 30, l year = 5, l pay = 10, l buf = l name + l pay; //1
struct Man //2 { int birth year; char name[l name + 1]; float pay; }; const int l dbase = 100; Man dbase [l dbase]; //3
char buf[l buf + 1]; //4 char name[l name + 1]; //5
ifstream fin("dbase.txt", //6 ios::in|ios::nocreate); if (!fin) { cout << "Ошибка открытия файла"; return 1; }
int i = 0; while(fin.getline(buf.l buf)) //7 { if (i >= 1 dbase) { cout << "Слишком длинный файл"; return 1; } strncpy(dbase[i].name.buf.l name); dbase[i].name[l name] = '\0'; dbase[i].birth year = atoi(&buf[l name]); dbase[i].pay = atof(&buf[l name + l year]); i++; } int n record = i.n man = 0; //8 float mean pay = 0;
while(true) //9 { cout <<"Введите фамилию или слово end":cin >> name; //DemToChar(name, name); //10 if(strcmp(name. "end") == 0)break; //11 bool not found = true; //12 for (i = 0; i < n record; i++) //13 {
if (strstr(dbase[i]. name. name)) //14 if (dbase[i]. name[strlen(name)] == '')//15 { strcpy(name. dbase[i]. name); // CharToOem(name.name); //16 cout << name << dbase[i].birth year << '' << dbase[i].pay << endl; n man++; mean_pay += dbase[i].pay; not found = false; } } if (not found) cout<<"Такого сотрудника нет"<<endl; } if (n man > 0) cout << "Средний оклад:" << mean pay/ n man << endl; //17
return 0; }
В операторе 1 заданы именованные константы, в которых хранится формат входного файла, то есть длина каждого из полей записи (строки файла). Такой подход позволяет при необходимости легко вносить в программу изменения. Длина буфера, в который будет считываться каждая строка файла, вычисляется как сумма длин указанных полей. В операторе 2 определяется структура Man для хранения сведений об одном сотруднике. Длина поля, в котором будет находиться фамилия, задана с учетом завершающего нуль-символа. В операторе 3 определяется массив структур dbase для хранения всей базы. Его размерность также задается именованной константой. В операторах 4 и 5 задаются промежуточные переменные: буфер buf для ввода строки из файла и строка name для фамилии запрашиваемого сотрудника. В операторе 6 выполняется открытие файла dbase. txt для чтения. Предполагается, что этот файл находится в том же каталоге, что и текст программы, иначе следует указать полный путь. Входной файл следует создать в любом текстовом редакторе до первого запуска программы в соответствии с форматом, заданным в условии задачи. Файл для целей тестирования должен состоять из нескольких строк, причем необходимо предусмотреть случай, когда одна фамилия является частью другой (например, Иванов и Ивановский). Не забудьте проверить, выдается ли диагностическое сообщение, если файл не найден. Цикл 7 выполняет построчное считывание из файла в строку buf и заполнение очередного элемента массива dbase. Счетчик 1 хранит индекс первого свободного элемента массива. Для формирования полей структуры используются функции копирования строк strncpy, преобразования из строки в целое число atoi и преобразования из строки в вещественное число atof. Обратите внимание на то, что завершающий нуль-символ в поле фамилии заносится «вручную», поскольку функция strncpy делает это только в случае, если строка-источник короче строки-приемника. В функцию atoi передается адрес начала подстроки, в которой находится год рождения. При каждом проходе цикла выполняется проверка, не превышает ли считанное количество строк размерность массива. При тестировании программы в этот цикл следует добавить контрольный вывод на экран считанной строки, а также сформированных полей структуры. Для проверки выдачи диагностического сообщения следует временно задать константу ljjbase равной, а затем меньшей фактического количества строк в файле. При заполнении массива из файла обязательно контролируйте выход за границы массива и при необходимости выдавайте предупреждающее сообщение. Кстати, можно записать эту проверку и так:
while(fin.getline(buf.l buf)&& i < l dbase) { - i++; } if (i >= l dbase) { cout << "Слишком длинный файл"; return 1; }
В операторе 8 определяются две переменные: n_record для хранения фактического количества записей о сотрудниках и njnan - для подсчета сотрудников, о которых будут выдаваться сведения. Следует также не забыть обнулить переменную mean pay, в которой в следующем цикле будет накапливаться сумма окладов. Цикл поиска сотрудников по фамилии организован как бесконечный (оператор 9) с принудительным выходом (оператор 11). Некоторые специалисты считают, что такой способ является плохим стилем, и для выхода из цикла следует определить переменную-флаг, но нам кажется иначе. В операторе 12 определяется переменная-флаг not_found для того, чтобы после окончания цикла поиска было известно, завершился ли он успешно. Имя переменной следует выбирать таким образом, чтобы по нему было ясно, какое значение является истинным:
if (not found) cout «"Такого сотрудника нет" «endl;
В операторе 13 организуется цикл просмотра массива структур (просматриваются только заполненные при вводе элементы). Проверка совпадения фамилии сотрудника производится в два этапа. В операторе 14 с помощью функции strstr поиска подстроки определяется, содержится ли в поле базы name искомая последовательность букв, а в операторе 15 проверяется, есть ли непосредственно после фамилии пробел (если пробела нет, то искомая фамилия является частью другой, и эта строка нам не подходит). Такая простая проверка возможна из-за условия задачи, по которому фамилия должна начинаться с первой позиции каждой строки. Для подобных программ в инструкции для пользователя должно быть четко указано, при помощи каких текстовых редакторов можно произвести первоначальное заполнение файла базы данных. Алгоритм программы составлен в предположении, что фамилия начинается с первой позиции записи в базе данных. Измените программу так, чтобы это ограничение можно было снять. Для этого придется проверить, стоит ли перед фамилией пробел в том случае, если она не начинается с первой позиции. Проверка переменной n man в операторе 17 необходима для того, чтобы в случае, если пользователь не введет ни одной фамилии, совпадающей с фамилией в базе, не выполнялось деление на 0. Крупным недостатком нашей программы является то, что вводить фамилию сотрудника требуется именно в том регистре, в котором она присутствует в базе. Для преодоления этого недостатка необходимо перед сравнением фамилий переводить все символы в один регистр. Для символов латинского алфавита в библиотеке есть функции to!ower (с) и toupper (с), переводящие переданный им символ с в нижний и верхний регистр соответственно, аналогичные функции для символов русского алфавита придется написать самостоятельно. Если в базе есть несколько сотрудников с одной и той же фамилией, программа выдаст сведения обо всех. Теперь рассмотрим вариант записи этой же программы с помощью библиотечных функций ввода-вывода:
|