<< Предыдущая Оглавление Следующая >>


5.3. Пример программирования. Простой словарь

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

#include
#include
#include
#include

Создание любой программы должно начинаться с анализа способа представления данных в программе. В данном случае русское слово и его английский эквивалент целесообразно объеденить в структуру, которая и будет представлять элемент данных программы. Так как количество слов в словаре может быть любым, то следует использовать связный список для их описания. Таким образом, получаем следущий тип структуры для описания слов в словаре (объекта данных):

typedef struct tag_word {
char wd_eng[100]; //русское слово
char wd_rus[100]; //английский эквивалент
tag_word* prev, *next; //указатели для работы связного списка
} WORD_DICT;

Объявим следующие вспомогательные глобальные переменные для работы связного списка:

WORD_DICT* head = NULL, *tail = NULL;

Работа программы должна начинаться с загрузки ранее введенной информации (словаря) в память компьютера. Для этого введем новую функцию LoadDict() и опишем ее следующим образом:

void LoadDict()
{
FILE* fp = fopen("dict.dat","rb");
if(fp != NULL)
{
while(!feof(fp))
{
WORD_DICT* word = (WORD_DICT *)
malloc(sizeof(WORD_DICT));
fread(word,sizeof(WORD_DICT),1,fp);
List_dict_add(word);
}
fclose(fp);
}
}

В данной функции в цикле while сначала создается новый объект WORD_DICT, а затем в него записывается информация из файла dict.dat. После этого новый созданный объект необходимо поместить в связный список. Это осуществляется с помощью функции List_dict_add(), реалзиация которой приведена ниже:

void List_dict_add(WORD_DICT* add_word)
{
if(head == NULL) head = add_word;

add_word->prev = tail;
add_word->next = NULL;

if(tail != NULL) tail->next = add_word;
tail = add_word;
}

Данная функция в качестве аргумента принимает указатель на объект, который должент быть помещен в конец связного списка. Для этого достаточно настроить его указатели prev и next соответственно на предыдущий и последующий объекты, если они существуют. Если объект add_word является первым в списке, то указатель head должен указывать на него. Это выполняется в первом условии данной функции. Во второй строке указателю prev объекта присваивается адрес последнего объекта в списке (указатель tail всегда указывает на последний объект). Учитывая, что объект добавляется в конец списка, то указатель next должен быть равен NULL. Наконец, в последнем условии проверяется, существует ли последний объект в списке, и если существует, то его указатель next должен указывать на вновь добавленный объект, а сам указатель tail указывать на него.

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

int ShowMainMenu()
{
int ret = 2;
printf("\n");
printf("1. Add words to a dictionary\n");
printf("2. Translate\n");
printf("3. Exit from the application\n");
printf("\n");
printf("Choose an menu item: ");scanf("%d",&ret);

return ret;
}

Данная функция выводит на экран строки меню и предлагает пользователю сделать выбор. Номер выбранного пункта возвращается функцией главной программе. Там же осуществляется проверка номера выбранного пункта и выполняются соответствующие действия. Таким образом, функция main() принимает вид:

int main(int argc, char* argv[])
{
LoadDict();
int item = ShowMainMenu();
while(item != 3)
{
switch(item)
{
case 1:Add_words();break;
case 2:Translate();break;
case 3:break;
}
item = ShowMainMenu();
}

SaveDict();
FreeDict();

return 0;
}

Здесь сначала вызывается функция загрузки словаря, а затем выводится главное меню. Для того чтобы меню было доступно в процессе работы программы, реализуется цикл, в котором осуществляется проверка номера выбранного пункта и выполняются соответствующие действия. Можно заметить, что если пользователь выбрал третий пункт меню (выход из программы), то работа цикла while() завершается, и программа переходит к функциям SaveDict() и FreeDict(), которые сохраняют информацию в файл и освобождают память (удаляют связный список).

Рассмотрим работу функции Add_words(), которая добавляет новые слова в словарь:

void Add_words()
{
char rus_word[100], eng_word[100];
char ch;

do
{
printf("\n--------Add words-------------\n");
printf("Input a russian word: ");scanf("%s",rus_word);
printf("Input an english word: ");scanf("%s",eng_word);
printf("Add the word to a dictionary? Y/N: ");
ch = getch();
if(ch == 'Y' || ch == 'y')
{
WORD_DICT* word = (WORD_DICT *)malloc(sizeof(WORD_DICT));
strcpy(word->wd_eng,eng_word);
strcpy(word->wd_rus,rus_word);
List_dict_add(word);
}
printf("\nWould you like input any word? Y/N: ");
ch = getch();
} while(ch != 'N' && ch != 'n');
}

Здесь вводятся русское и английское слова, которые затем, при согласии пользователя, добавляются в связный список. Для этого, сначала создается объект типа WORD_DICT в памяти компьютера, затем инициализируются его поля wd_eng и wd_rus соответственно английским и русским введенными словами и с помощью функции List_dict_add() объект добавляется в конец связного списка. Данная процедура продолжается до тех пор, пока пользователь не выйдет из цикла do while(), т.е. пока на последний вопрос не ответит символом ‘N’.

Реализация функции Translate() подобна функции Add_words() и имеет вид:

void Translate()
{
char rus_word[100];
char ch;

do
{
printf("\n--------Translate english words to russian-------------\n");
printf("Input a russian word: ");scanf("%s",rus_word);

WORD_DICT* current = head;
while(current != NULL)
{
if(strcmp(current->wd_rus,rus_word) == 0)
{
printf("English: %s\n",current->wd_eng);
break;
}
current = current->next;
}
if(current == NULL) printf("The word don't find\n");

printf("\nWould you like input any word? Y/N: ");
ch = getch();

} while(ch != 'N' && ch != 'n');
}

Здесь после ввода русского слова с клавиатуры выполняется цикл while, в котором просматриваются все объекты связного списка и проверяется условие: если введенное русское слово совпадает с русским словом из словаря, то на экран выводится английское слово и цикл досрочно завершается оператором break. После цикла проверяется условие на равенство указателя current зачению NULL. Это возможно только в том случае, если в словаре не было найдено нужного русского слова. Поэтому на экран, в этом случае, будет выведено сообщение «Слово не найдено».

Функция SaveDict() вызывается перед завершением программы и имеет следующую реализацию:

void SaveDict()
{
FILE* fp = fopen("dict.dat","wb");
if(fp != NULL)
{
WORD_DICT* current = head;
while(current != NULL)
{
fwrite(current,sizeof(WORD_DICT),1,fp);
current = current->next;
}
}
fclose(fp);
}

Наконец, последняя функция FreeDict() удаляет выделенную память перед выходом из программы и опредляется как:

void FreeDict() {
while(head != NULL) List_dict_remove(head);
}

где функция List_dict_remove()определена в виде:

WORD_DICT* List_dict_remove(WORD_DICT* crn)
{
if(crn->prev != NULL) crn->prev->next = crn->next;
if(crn->next != NULL) crn->next->prev = crn->prev;

if(crn == head) if(crn->prev != NULL) head = crn->prev;
else head = crn->next;

if(crn == tail) if(crn->next != NULL) tail = crn->next;
else tail = crn->prev;

free(crn);
return tail;
}

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

Таким образом, реализована простая программа с 8 пользовательскими функциями, которые удобно записать в виде прототипов перед функцией main(), а их реализации после нее.


<< Предыдущая Оглавление Следующая >>