#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
//данные хранятся в виде массива структур из указателя и ключа
//структура элемента таблицы
typedef struct Item
{
int key; //ключ
int offset; //смещение в файле (по отношению к началу файла)
int len; //длина информации
}Item;
//структура - таблица
typedef struct Table
{
int size; //максимальный размер таблицы
int count; //текущий размер таблицы
Item* val; //массив структур item
FILE* fd; //дескриптор файла, чтобы выполнять операции с файлом данных
}Table;
const int SIZE = 10; //максимальный размер таблицы
//меню
int F1_End(Table*); //функция выхода
int F2_Menu(Table*); //меню
int F3_Print(Table*); //вывод элементов
int F4_Input(Table*); //ввод элемента
int F5_DeleteKey(Table*); //удаление элементов
int F6_FindKey(Table*); //поиск и копирование элемента
//функции работы с таблицей
Table* TableCreate(int size); //функция создания пустой таблицы
void TableDelete(Table* T); //удаление таблицы
void TablePrint(Table* T); //вывод таблицы
int TableAdd(Table* T, int key, char* info); //добавление элемента с ключом в таблицу
Table* TableFindKey(Table* T, int key); //поиск и получение копии элемента
int TableFindOurKey(Table* T, int key); //поиск элемнета по ключу в таблице
int TableDeleteKey(Table* T, int key); //удаление
void TableSave(Table* T);
int D_load(Table* T);
int TableLoad(Table* T, char* fname);
int TableCreateFile(Table* T, int size, char* fname);
int dialog(const char *msgs[], int);
int ItemPrint(Item*, FILE* fd); //вывод элемента таблицы
//другие функции
int getInt(int*); //чтение целого числа
int getStr(char**); //функция ввода строк
const char* msgs[] = { NULL, "1.Exit programm", "2.Show menu", "3.Print table",
"4.Input item", "5.Delete key", "6.Find key" }; //строки меню
const int NMsgs = sizeof(msgs) / sizeof(msgs[0]);
int main() {
int rc = 0; //далее до конца - вывод меню
int (*fun[])(Table *) = {NULL, F1_End, F2_Menu, F3_Print,
F4_Input, F5_DeleteKey, F6_FindKey}; //массив функций
Table T = {0, 0, NULL, NULL};
if (D_load(&T) == 0) //если не удалось создать файл
return 1;
while (rc = dialog(msgs, NMsgs))
{
if (!fun[rc](&T)) //вызывается диалоговая функция, соответствующая введенному номеру альтернативы
break;
}
TableSave(&T);
printf("Good bye!");
TableDelete(&T);
return 0;
}
//интерфейсные функции
//завершение программы
int F1_End(Table* T)
{
TableSave(T); //сохранение таблицы
TableDelete(T); //удаление таблицы
return 1;
}
//вывод меню
int F2_Menu(Table* T)
{
int i;
for (i = 1; i < 7; ++i)
printf("%d %s\n", i, msgs[i]);//вывод пунктов меню
return 0;
}
//вывод таблицы
int F3_Print(Table* T)
{
puts("Table:");
TablePrint(T); //вывод
return 0;
}
//добавление ключа
int F4_Input(Table* T)
{
int key = 0;
char* info;
int res;
printf("Enter key: ");
getInt(&key); //читаем ключ
printf("Enter information: ");
res = getStr(&info); //чтение информации
if (res) //проверка на возможность выделить память
{
puts("Memory is out");
TableDelete(T); //удаляем таблицу при нехватке памяти
return 1;
}
if (TableAdd(T, key, info)) //если добавление не успешно
puts("Table is full");
else //если успешно
puts("Item added.");
return 0;
}
//удаление элемента
int F5_DeleteKey(Table* T)
{
int key;
int rc;
printf("Vvod key to delete: \n"); //ввод ключа что нужно удалить
key = getInt(&rc);
TableDeleteKey(T, key);
printf("Deleted 1 items.\n"); //выводим что мы удалили элемент
return 0;
}
//поиск в таблице ключа
int F6_FindKey(Table* T)
{
int key = 0;
Table* NewTable;
printf("Enter key: "); //ввод ключа
getInt(&key);
NewTable = TableFindKey(T, key); //получаем указатель на таблицу с копиями ключа
if (NewTable) //если был элемент с таким ключом
{
puts("Table:");
TablePrint(NewTable); //вывод
TableDelete(NewTable); //и удаление таблицы
}
else
{
puts("Keys not found."); //или выводим сообщение об ошибке
}
return 0;
}
//функци работы с таблицей
//создание таблицы из файла
int D_load(Table* T)
{
int size;
char* fname = NULL;
printf("Enter file name:");
getStr(&fname); //ввод названия файла
if (fname == NULL) //если не введено
return NULL;
if (TableLoad(T, fname) == 0) //если файла нет
{
printf("File not fount. Create file. Enter Size:");
if (getInt(&size) == 0)
return 0;
return TableCreateFile(T, size, fname); //создаем файл
}
return 1;
}
//загрузка таблицы из файла
int TableLoad(Table* T, char* fname)
{
int i;
Item z;
T->fd = fopen(fname, "r+b"); //открываем файл
if (T->fd == 0) //если файла нет
return 0;
fread(&T->size, sizeof(int), 1, T->fd); //чтение размера
T->val = (Item*)calloc(T->size, sizeof(Item)); //создание массива значений
fread(&T->count, sizeof(int), 1, T->fd); //чтение текущего размера
fseek(T->fd, 7, SEEK_SET);
fread(T->val, sizeof(Item), T->size, T->fd); //чтение элемента
for (i = 0; i < (T->size); i++)
{
char* info = (char*)calloc(T->val[i].len, sizeof(char));
fseek(T->fd, T->val[i].offset, SEEK_SET);
fread(info, sizeof(char), T->val[i].len, T->fd);
}
return 1;
}
//создание таблицы в файле
int TableCreateFile(Table* T, int size, char* fname)
{
T->size = size;
T->count = 0;
T->fd = fopen(fname, "w+b"); //открытие файла
if (T->fd == 0)
{
T->val = 0;
return 0;
}
T->val = (Item*)calloc(T->size, sizeof(Item));
fwrite(&T->size, sizeof(int), 1, T->fd); //запись размера
fwrite(&T->count, sizeof(int), 1, T->fd); //запись текущего размера
fwrite(T->val, sizeof(Item), T->size, T->fd); //запись элементов
return 1;
}
//создание таблицы, возвращаем указатель на пустую таблицу
Table* TableCreate(int size)
{
Table* T;
if (size <= 0)
return NULL;
T = (Table*)malloc(sizeof(Table)); //память под структуру таблицы
if (T == NULL)
return NULL;
T->count = 0;
T->size = size;
T->val = (Item*)calloc(size, sizeof(Item)); //память под массив элементов
if (T->val == NULL)
{
free(T);
return NULL;
}
return T;
}
void TableSave(Table* T)
{
fseek(T->fd, sizeof(int), SEEK_SET);
fwrite(&T->count, sizeof(int), 1, T->fd);
fwrite(T->val, sizeof(Item), T->count, T->fd);
fclose(T->fd);
T->fd = NULL;
}
//удаление таблицы
void TableDelete(Table* T)
{
int i;
free(T->val); //чистка остальной памяти
}
//вывод таблицы
void TablePrint(Table* T)
{
int i;
printf("count = %d, size = %d.\n", T->count, T->size);
printf("%2s %7s %s\n", "i", "key", "string");
if (T->count == 0)
puts("Empty table");
else
{
for (i = 0; i < T->count; i++) {
//проходим по массиву
printf("%2d ", i); //выводим очередной элемент
ItemPrint(&T->val[i]);
}
}
}
//добавление ключа в таблицу
int TableAdd(Table* T, int key, char* info)
{
int ind, st;
fseek(T->fd, 0, SEEK_END);
st = ftell(T->fd);
if (T->count == T->size) //проверка на переполнение
return 1;
if (TableFindOurKey(T, key)) {
//пишем новый элемент в конец таблицы
T->val[T->count].key = key;
T->val[T->count].offset = st;
T->val[T->count].len = strlen(info) + 1;
fwrite(info, strlen(info) + 1, 1, T->fd);
++T->count; //увеличиваем текущее количество элементов в таблице
}
return 0;
}
//удаление элементов
int TableDeleteKey(Table* T, int key)
{
int i, j;
if (TableFindOurKey(T, key))
for (i = 0; i < T->count; i++) {
if (T->val[i].key == key) //если элемент сущевстует и ключи совпали
{
j = T->count; //пишем в конец нашей новой таблицы
T->val[j].info = (char *) calloc(strlen(T->val[i].info) + 1,sizeof(char)); //копию найденного элемента
strcpy(T->val[j].info, T->val[i].info);
T->val[j].key = key;
--T->count; //уменьшаем размер таблицы
}
}
}
//поиск элемента в таблице
int TableFindOurKey(Table* T, int key)
{
int i;
for (i = T->count - 1; i >= 0; i--)
if (T->val[i].key == key)
return i;
return -1;
}
//ищем элемент и создаём таблицу с найденными элементами
Table* TableFindKey(Table* T, int key)
{
Table* NewTable = TableCreate(T->size);
NewTable->fd = T->fd;
int i, j;
if (TableFindOurKey(T, key)) {
for (i = 0; i < T->count; i++)
if (T->val[i].key == key) //если элемент сущевстует и ключи совпали
{
j = NewTable->count; //пишем в конец нашей новой таблицы
NewTable->val[j].key = key;
NewTable->val[j].len = T->val[i].len;
NewTable->val[j].offset = T->val[i].offset;
++NewTable->count; //увеличиваем размер таблицы
}
NewTable->size = NewTable->count;
if (NewTable->count)
return NewTable;
else
TableDelete(NewTable);
return NULL;
}
}
//вывод элемента
int ItemPrint(Item* I, FILE* fd)
{
char* info;
info = (char*)malloc(I->len);
fseek(fd, I->offset, SEEK_SET);
fread(info, sizeof(char), I->len, fd);
printf("%7d %s\n", I->key, info);
return 0;
}
//диалог
int dialog(const char *msgs[], int N)
{
char *errmsg = "";
int rc;
int i, n;
do{
puts(errmsg);
errmsg = "You are wrong. Repeate, please!";
//Вывод списка альтернатив
for (i = 0; i < N; ++i)
puts(msgs[i]);
puts("Make your choice: --> ");
n = getInt(&rc); //Ввод номера альтернативы
if( n == 0)//конец файла - конец работы
rc = 0;
} while(rc < 0 || rc >= N);
return rc;
}
//другие функции
//чтение целого числа
int getInt(int* a)
{
int n = 0;
do
{
n = scanf("%d", a); //считаем по адресу а - значение символа. сама функция вернёт -1, если конец файла, 0 если символ не корректный
if (n <= 0) // обнаружен некорректный символ - ошибка
printf("%s\n", "Error! Wrong symbol.");
scanf("%*c");
} while (n <= 0);
return 1;
}
//получаем строку из входного потока
int getStr(char** s)
{
char buf[21]; //считываем из входного потока строку с помощью этого буфера, кусками по 20 сиволов
int n; //сюда будет записываться результат scanf
int len = 0; //сюда длина результирующей строки
*s = (char*)malloc(1); //указатель на результирующую сткроу
**s = '\0'; //ноль байт, пока строка имеет только конец строки
do {
n = scanf("%20[^\n]", buf); //считываем буфер
if (n < 0)
{ //если ввели конец файла (ctrl+Z), то будет -1
free(*s); //очищаем память, возвращаем пустой указатель
return -1;
}
if (n > 0) { //если буфер не пустой
len += strlen(buf); //увеличиваем результирующую длину
*s = (char*)realloc(*s, len + 1); //добавляем память
if (*s) //если память выделилась
strcat(*s, buf); //копируем строку из буфера в конец нашей строки
else
{ //если память не выделилась
free(*s); //очищаем память
return -2;
}
}
else
scanf("%*c"); //если перенос строки, то очищаем входной поток
} while (n > 0); //пока во входном потоке есть хоть один символ
return 0;
}