Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <locale.h>
- // файл DATAFILE => загрузка данных в data => обработка данных в data => записывается в файл DATAFILE
- #define DATAFILE "auto.db"
- // данные об автомобилях - одна строка БД
- typedef struct
- {
- char fio[100];
- char address[200];
- char phone[15];
- char mark[25];
- char year[5];
- char number[12];
- char color[25];
- } row_auto;
- // row_auto - это тип, для хранения информации об одной записи о автомобиле
- row_auto *data; // массив данных
- row_auto filter; // условия для выбора данных (фильтрация)
- row_auto sortorder; // правила сортировки
- int cnt; // количество записей в массиве data
- // функция выполняет соединение с БД, т.е. открывает файл
- // возвращает дескриптор файла
- // created - приравнивается 1, если файл был создан
- // default_mode - режим открытия файла по умолчанию
- FILE * connect(const char * path, int * created, const char * default_mode)
- {
- FILE * fp = fopen(path, default_mode);
- if ( fp == 0 ) // если не получилось открыть файл в режиме default_mode
- {
- fp = fopen(path, "w"); // файла нет - попробовать создать новый
- assert(fp != 0); // если fp == 0, то ошибка
- printf("File DB %s not found and was create\n", DATAFILE);
- *created = 1;
- }
- return fp;
- }
- // отключиться от БД
- void disconnect(FILE * fp)
- {
- if ( fp )
- fclose(fp); // закрыть файл, если он был открыт
- }
- // прочитать из файла символы до разделителя (sep)
- void read_until_separate(FILE * f, char * str, char sep)
- {
- char c;
- int i = 0;
- while ( (c = fgetc(f)) != sep )
- {
- str[i] = c;
- ++i;
- }
- }
- // очистка фильтра
- // фильтр - это набор условия для отображаемых полей
- // например, можно отфильтровать данные по адресу, по ФИО, по марке и т.д.
- void filter_reset()
- {
- filter.address[0] = filter.color[0] = filter.fio[0] = filter.mark[0] = filter.number[0] = filter.phone[0] = filter.year[0] = 0;
- }
- // проверка подходит ли по фильтру
- // запись с индексом i => data[i]
- int check_filter(int i)
- {
- // filter.address[0] == 0 тттк фильтр адреса не исползуется
- // filter.fio = "Иванов" - выбрать только людей с фамилией Иванов
- if ( filter.address[0] && strcmp(data[i].address, filter.address) ) return 0;
- if ( filter.color[0] && strcmp(data[i].color, filter.color) ) return 0;
- if ( filter.fio[0] && strcmp(data[i].fio, filter.fio) ) return 0;
- if ( filter.mark[0] && strcmp(data[i].mark, filter.mark) ) return 0;
- if ( filter.number[0] && strcmp(data[i].number, filter.number) ) return 0;
- if ( filter.phone[0] && strcmp(data[i].phone, filter.phone) ) return 0;
- if ( filter.year[0] && strcmp(data[i].year, filter.year) ) return 0;
- return 1; // <= сюда попадем, если имеется фильтр и он не равен данным в соответствующей записи
- }
- // массив данных в виде массива структур передается в качестве параметра
- void load_from_file()
- {
- int created = 0;
- cnt = 0;
- FILE *fp = connect(DATAFILE, &created, "r"); // пробуем открыть файл БД на чтение
- if ( !created )
- { // если получилось открыть файл на чтение -> в нем есть данные
- if ( fscanf(fp, "%d\n", &cnt) ) // если удалось прочитать размер
- {
- data = calloc(cnt, sizeof(row_auto)); // выделение памяти под cnt записей
- for(int i=0; i < cnt; ++i)
- {
- read_until_separate(fp, data[i].fio, ';');
- read_until_separate(fp, data[i].address, ';');
- read_until_separate(fp, data[i].phone, ';');
- read_until_separate(fp, data[i].mark, ';');
- read_until_separate(fp, data[i].year, ';');
- read_until_separate(fp, data[i].number, ';');
- read_until_separate(fp, data[i].color, '\n');
- }
- }
- }
- disconnect(fp);
- printf("Data base was load, count rows = %d\n", cnt);
- }
- // заменяем в строке точку с запятой на запятую
- void fix_semicolon(char * str)
- {
- for( int i = 0; str[i] != 0; ++i)
- if ( str[i] == ';' )
- str[i] = ',';
- }
- // сохранение данных в файл-БД
- void save_data_to_file()
- {
- int created = 0;
- FILE *fp = connect(DATAFILE, &created, "w"); // открываем сразу на запись
- fprintf(fp, "%d\n", cnt);
- for(int i=0; i < cnt; ++i)
- {
- fix_semicolon(data[i].fio);
- fix_semicolon(data[i].address);
- fix_semicolon(data[i].phone);
- fix_semicolon(data[i].mark);
- fix_semicolon(data[i].year);
- fix_semicolon(data[i].number);
- fix_semicolon(data[i].color);
- // записываем запись об автомобиле в файл
- fprintf(fp, "%s;%s;%s;%s;%s;%s;%s\n", data[i].fio, data[i].address, data[i].phone, data[i].mark, data[i].year, data[i].number, data[i].color);
- }
- disconnect(fp);
- }
- // ввод одной записи (строки БД)
- // gets - считать строку (возможно с пробелами)
- void input_row(row_auto * row)
- {
- char empty_str[1];
- fflush(stdin); // очистить поток ввода от символов
- gets( empty_str ); // пропуск первого вызова gets
- printf("ФИО (не более 100 символов): ");
- gets( row->fio );
- printf("Адрес (не более 200 символов): ");
- gets( row->address );
- printf("Телефон (не более 15 символов): ");
- gets( row->phone );
- printf("Марка (не более 25 символов): ");
- gets( row->mark );
- printf("Гос.Номер (не более 12 символов): ");
- gets( row->number );
- printf("Цвет (не более 25 символов): ");
- gets( row->color );
- printf("Год (не более 4 символов): ");
- gets( row->year );
- }
- // добавление строки в БД
- void add_row()
- {
- printf("Ввод данных:\n");
- cnt++; // увеличиваем количество данных
- data = realloc(data, cnt * sizeof(row_auto)); // изменить объем выделенной памяти
- input_row(&data[cnt-1]); // вводим данные в последнюю (новую) строку
- }
- // выбор строки для действия
- int select_row()
- {
- if (cnt > 0)
- {
- int k;
- printf("Введите номер строки [1..%d]:", cnt);
- scanf("%d", &k);
- if (k >= 1 && k <= cnt)
- return k;
- }
- return 0;
- }
- // удаление строки из БД
- void del_row()
- {
- if (cnt > 0)
- {
- printf("Удаление записи\n");
- int k = select_row();
- if (!k)
- printf("Некорректный номер записи\n");
- else
- {
- if (k < cnt)
- { // последнюю запись копируем на место удаляемой
- // strcpy(dst, src) - скопировать из src в dst
- strcpy(data[k-1].address , data[cnt-1].address);
- strcpy(data[k-1].color , data[cnt-1].color);
- strcpy(data[k-1].fio , data[cnt-1].fio);
- strcpy(data[k-1].mark , data[cnt-1].mark);
- strcpy(data[k-1].number , data[cnt-1].number);
- strcpy(data[k-1].phone , data[cnt-1].phone);
- strcpy(data[k-1].year , data[cnt-1].year);
- }
- cnt--;
- }
- }
- else
- printf("Нечего удалять - база пуста\n");
- }
- // отобразить записи в БД
- void show_rows()
- {
- fflush(stdin);
- printf("\n--------------------------------------------------------------------------------\n");
- for(int i=0; i<cnt; ++i)
- {
- if ( !check_filter(i) ) continue;
- printf("\n-Запись # %2d--------------------------------------------------------------------\n", i + 1);
- printf("ФИО: %s\n", data[i].fio);
- printf("Адрес: %s\n", data[i].address);
- printf("Телефон: %s\n", data[i].phone);
- printf("Марка: %s\n", data[i].mark);
- printf("Год: %s\n", data[i].year);
- printf("Гос.Номер: %s\n", data[i].number);
- printf("Цвет: %s\n", data[i].color);
- printf("\n----Нажмите Enter для продолжения-----------------------------------------------\n");
- getchar();
- }
- }
- // поиск строки
- void find_rows()
- {
- printf("Введите параметры поиска:\n!!!Если поле не участвует в поиске - оставьте значение пустым!!!\n");
- input_row(&filter); // ввод фильтра для поиска
- show_rows();
- filter_reset(); // отмена фильтра
- }
- // редактирование строки
- void edit_row()
- {
- if (cnt > 0)
- {
- printf("Редактирование записи\n");
- int k = select_row();
- if (!k)
- printf("Некорректный номер записи\n");
- else
- input_row(&data[k-1]);
- }
- else
- printf("Нечего редактировать - база пуста\n");
- }
- // вернуть 1, если запись a меньше записи b, в противном случае - 0
- // sortorder.fio = '1' - сортировка по возрастанию ФИО
- // sortorder.fio = '2' - сортировка по убыванию ФИО
- int row_less(const row_auto * a, const row_auto * b)
- {
- if ( (sortorder.fio[0] == '1' && strcmp(a->fio, b->fio) < 0) || (sortorder.fio[0] == '2' && strcmp(a->fio, b->fio) > 0) ) return 1;
- if ( (sortorder.address[0] == '1' && strcmp(a->address, b->address) < 0) || (sortorder.address[0] == '2' && strcmp(a->address, b->address) > 0) ) return 1;
- if ( (sortorder.phone[0] == '1' && strcmp(a->phone, b->phone) < 0) || (sortorder.phone[0] == '2' && strcmp(a->phone, b->phone) > 0) ) return 1;
- if ( (sortorder.mark[0] == '1' && strcmp(a->mark, b->mark) < 0) || (sortorder.mark[0] == '2' && strcmp(a->mark, b->mark) > 0) ) return 1;
- if ( (sortorder.year[0] == '1' && strcmp(a->year, b->year) < 0) || (sortorder.year[0] == '2' && strcmp(a->year, b->year) > 0) ) return 1;
- if ( (sortorder.number[0] == '1' && strcmp(a->number, b->number) < 0) || (sortorder.number[0] == '2' && strcmp(a->number, b->number) > 0) ) return 1;
- if ( (sortorder.color[0] == '1' && strcmp(a->color, b->color) < 0) || (sortorder.color[0] == '2' && strcmp(a->color, b->color) > 0) ) return 1;
- return 0;
- }
- // обмен значений
- void swap(row_auto * a, row_auto* b)
- {
- row_auto t = *a;
- *a = *b;
- *b = t;
- }
- // поиск индекса для деления массива - индекса стержневого элемента:
- // слева от этого индекса будут элементы меньше его, справа - больше
- int partition (row_auto * a, int left, int right)
- {
- row_auto * pivot = &a[right - 1]; // стержневой элемент
- int i = left; // индекс минимального элемента
- for (int j = left; j < right - 1; j++)
- {
- if ( row_less(&a[j], pivot) )
- {
- swap(&a[i], &a[j]);
- i++;
- }
- }
- swap(&a[i], &a[right - 1]); // ставим стержневой элемент на верное место
- return i; // возвращаем индекс стержневого элемента
- }
- // сортировка массива a на отрезке [left, right)
- void quick_sort(row_auto * a, int left, int right)
- {
- if (left + 1 < right)
- {
- // находим индекс разделения - элемент a[pi] стоит на своем месте
- int pi = partition(a, left, right);
- // сортируем по частям
- quick_sort(a, left, pi);
- quick_sort(a, pi + 1, right);
- }
- }
- // сортировка строк
- void sort_rows()
- {
- printf("Выберите параметры сортировки:\n");
- printf(" - оставьте поле пустым, если по нему не сортировать\n");
- printf(" - введите 1 для сортировки по возрастанию\n");
- printf(" - введите 2 для сортировки по убыванию\n");
- printf("!! Другие значения будут проигнорированы !!\n");
- input_row(&sortorder); // определяем порядок сортировки
- quick_sort(data, 0, cnt); // сортировка алгоритмом быстрой сортировки
- show_rows();
- }
- // освобождаем выденную память
- void free_memory()
- {
- /* for(int i=0; i<cnt; ++i)
- {
- free(data[i].fio);
- free(data[i].address);
- free(data[i].phone);
- free(data[i].mark);
- free(data[i].number);
- free(data[i].color);
- }*/
- free(data);
- }
- // функция-меню
- void menu()
- {
- filter_reset(); // инициализация пустого фильтра
- load_from_file(); // загрузка из файла БД
- // <тип. возвращаемого зачения> (* <имя функции>[]) (<типы параметров функции>) - массив указателей на функцию
- // массив указателей на функции с соответствующими действиями
- void (*foo[])() = {add_row, del_row, find_rows, edit_row, sort_rows, show_rows};
- while (1)
- {
- int code;
- printf("\n######Выберите команду:######\n");
- printf("# 1. Добавить строку #\n");
- printf("# 2. Удалить строку #\n");
- printf("# 3. Найти строку #\n");
- printf("# 4. Отредактировать строку #\n");
- printf("# 5. Сортировка строк #\n");
- printf("# 6. Вывод строк #\n");
- printf("# 0. Выход из программы #\n");
- printf("Введите номер действия (нажмите клавишу на клавиатуре):");
- code = getchar() - '0';
- printf("\n");
- if (!code) break;
- if (code < 7 && code > 0)
- foo[code-1]();
- else
- printf("Ошибка: неверный код действия!\n");
- }
- save_data_to_file(); // сохранить данные в файл
- free_memory(); // освободить выделенную память
- }
- // точка входа в программу
- int main()
- {
- setlocale(LC_ALL, "Russian");
- menu();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement