ВНИМАНИЕ. При заполнении массива из файла обязательно контролируйте выход за границы масси и при необходимости выдавайте предупреждающее сообщение
При заполнении массива из файла обязательно контролируйте выход за границы масси и при необходимости выдавайте предупреждающее сообщение.
Кстати, можно записать эту проверку и так:
В операторе 8 определяются две переменные: n_record для хранения фактического количества записей о сотрудниках и n_man - для подсчета сотрудников, о которых будут выдаваться сведения. Следует также не забыть обнулить переменную mean_pay в которой в следующем цикле будет накапливаться сумма окладов.
Цикл поиска сотрудников по фамилии организован как бесконечный (оператор 9) с принудительным выходом (оператор И). Некоторые специалисты считают, что такой способ является плохим стилем, и для выхода из цикла следует определить переменную-флаг, но нам кажется иначе.
Впрочем, в данном случае выход из цикла действительно организован не лучшим образом, поскольку пользователь вынужден для окончания работы с программой ввести слово end в нижнем регистре. Более удобным был бы выход из цикла по нажатию, например, клавиши Esc. К сожалению, в рамках стандарта это сделать невозможно, однако в большинстве библиотек есть функции типа getch и kbhit, позволяющие анализировать нажатие клавиш. В общем случае, несомненно, следует выбирать интерфейс, наиболее удобный для пользователя, поскольку именно для него и пишутся все без исключения программы.
В операторе 12 определяется переменная-флаг not_found для того, чтобы после окончания цикла поиска было известно, завершился ли он успешно. Обратите внимание на имя переменной: его следует выбирать таким образом, чтобы по нему было ясно, какое значение является истинным. Как видите, в этом случае оператор
хорошо понятен без дополнительных комментариев.
В операторе 13 организуется цикл просмотра массива структур (просматриваются только заполненные при вводе элементы). Проверка совпадения фамилии сотрудника производится в два этапа. В операторе 14 с помощью функции strstr поиска подстроки определяется, содержится ли в поле базы паше искомая последовательность букв, а в операторе 15 проверяется, есть ли непосредственно после фамилии пробел (если пробела нет, то искомая фамилия является частью другой, и эта строка нам не подходит). Такая простая проверка возможна из-за условия задачи, по которому фамилия должна начинаться с первой позиции каждой строки.
Когда вы дойдете до отладки этой части программы, то, вполне возможно, столкнетесь с непонятной на первый взгляд проблемой: программа не может найти запись с заданной фамилией. Впрочем, этот эффект проявляется, только если вы работаете в среде Windows и только на фамилиях, записанных в базе на русском языке; стоит только перейти на латиницу, как все начинает работать нормально. Здесь есть одна тонкость, связанная с разной кодировкой букв русского алфавита (кириллицы) в операционных системах MS DOS и Windows, о чем уже говорилось на первом семинаре.
Напомним, что если вы работаете в интегрированной среде Visual C++ в режиме консольных приложений, то весь ввод-вывод осуществляется в кодировке ASCII. Поэтому поведение данной программы будет различным в зависимости от кодировки текста в файле dbase.txt, а последняя определяется тем, в каком текстовом редакторе вы создавали этот файл.
Допустим, что вы использовали один из редакторов под MS DOS, к примеру Dos Navigator или Far. В этом случае кодировка в файле и в окне вывода одна и та же и программа работает нормально. Но если вы заполнили файл dbase.txt в редакторе NotePad или WordPad (кодировка ANSI), то программа не будет работать с русскоязычными фамилиями.
Если материал первого семинара еще не окончательно улетучился из вашей памяти, то вы знаете, что в таких случаях надо использовать функцию OemToChar(), переводящую символы из кодировки ASCII в кодировку ANSI для введенной с консоли фамилии (переменная name). Для этого достаточно раскомментировать оператор 10 в нашей программе. Аналогично, для нормального вывода текста в консольное окно необходимо обратное преобразование с помощью функции CharToOem() — раскомментируйте оператор 16. Применение указанных функций требует подключения заголовочного файла < windows. h> (раскомментируйте оператор 0).
Для подобных программ в инструкции для пользователя должно быть четко указано, при помощи каких текстовых редакторов можно произвести первоначальное заполнение файла базы данных. Продолжим анализ программы. Мы остановились на том, что алгоритм составлен в предположении, что фамилия начинается с первой позиции записи в базе данных. Измените программу так, чтобы это ограничение можно было снять. Для этого придется проверить, стоит ли перед фамилией пробел в том случае, если она не начинается с первой позиции. Аналогичная проблема рассматривалась на предыдущем семинаре (задача 5.2). Внесите в тестовый пример изменения, необходимые для тестирования этой части программы.
Проверка переменной n_man в операторе 17 необходима для того, чтобы в случае, если пользователь не введет ни одной фамилии, совпадающей с фамилией в базе, не выполнялось деление на 0.
Крупным недостатком нашей программы является то, что вводить фамилию сотрудника требуется именно в том регистре, в котором она присутствует в базе. Для преодоления этого недостатка необходимо перед сравнением фамилий переводить все символы в один регистр. Для символов латинского алфавита в библиотеке есть функции tolower(c) и toupper(c), переводящие переданный им символ с в нижний и верхний регистр соответственно, аналогичные функции для символов русского алфавита придется написать самостоятельно.
Если в базе есть несколько сотрудников с одной и той же фамилией, программа выдаст сведения обо всех.
А теперь давайте рассмотрим вариант записи этой же программы с помощью библиотечных функций ввода-вывода:
Из всех именованных констант осталась одна, задающая длину поля фамилии (l_name, оператор 1). Все остальные константы определять нет смысла, потому что ввод осуществляется не через буферную переменную, а непосредственно в поля структуры с помощью функции чтения строки fgets и форматного ввода fscant (оператор 2). Эта функция сама выполняет действия по преобразованию подстроки в число, которые мы явным образом задавали в предыдущей программе.
Как и в предыдущей версии, программу необходимо «настроить» на ожидаемую кодировку символов. Если вы работаете в среде Visual C++ и готовите текстовый файл dbase.txt с помощью Windows-ориентированного текстового редактора, то раскомментируйте операторы 4 и 5 для преобразования символов из кодировки ASCII в кодировку ANSI и обратно, а также оператор 0 для подключения заголовочного файла < windows.h>.
Мы упростили выход из цикла ввода запросов, теперь для завершения цикла достаточно нажать клавишу Enter (оператор 3). Для вывода сведений о сотруднике мы использовали функцию printf (оператор 6). Как видите, иногда старые добрые функции могут сделать программу более простой и наглядной! Это происходит, когда при вводе и выводе требуется форматирование разнотипных данных.
|