Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <fstream>
- #include <windows.h>
- #include <conio.h>
- #include <string>
- using namespace std; //Пространство имён подключил для Функции FileRead, так как там используется fstream
- struct Date
- {
- int day;
- int month;
- int year;
- };
- struct Music
- {
- char* author;
- char* name;
- Date date;
- int rating;
- };
- Music* DefaultMusic(int &Size) //Данная функция просто возращает заранее подготовленный массив, как стандартный
- {
- Size = 1;
- Music* musics = new Music[Size];
- musics[0].author = (char*)"author";
- musics[0].date.day = 1;
- musics[0].date.month = 1;
- musics[0].date.year = 1;
- musics[0].name = (char*)"name";
- musics[0].rating = 0;
- return musics;
- }
- Music DefaultMusic() //Возвращает один объект как стандартный, используется при редактировании объекта, когда мы отменяем изменения.
- {
- Music music;
- music.author = (char*)"author";
- music.date.day = 1;
- music.date.month = 1;
- music.date.year = 1;
- music.name = (char*)"name";
- music.rating = 0;
- return music;
- }
- void FileWrite(Music* musics, int Size) //Функция для записи в файл.
- {
- FILE* fout = fopen("Musics.txt", "w"); //Создаем указатель на потоковый файл и загружаем его в режиме чтения - "w"
- if(Size <= 0 || fout == NULL) //В случае неудачи, пишем пользователь об ошибке с файлам.
- {
- printf("Ошибка записи в файл.");
- }
- else //В случае удачи, просто заполняем файл в цикле необходимой информацией...
- {
- fprintf(fout, "%d\n", Size);
- for(int i = 0; i < Size; i++)
- {
- fprintf(fout, "%s ", musics[i].author);
- fprintf(fout, "%s ", musics[i].name);
- fprintf(fout, "%d %d %d ", musics[i].date.day, musics[i].date.month, musics[i].date.year);
- fprintf(fout, "%d\n", musics[i].rating);
- }
- }
- fclose(fout); //Файл необходимо закрыть, так как могут быть потери данных...
- }
- //Функция конвертирует C++ строки в C строки, ничего особенного
- char* cstc(string s){
- char *cstr = new char[s.length() + 1];
- strcpy(cstr, s.c_str());
- return cstr;
- }
- Music* FileRead(int &Size){ //Чтение файла с использованием C++ fstream, так как за 2 часа опытов не удалось написать функцию, которая не использовала бы C++ fstream
- Music* musics = NULL; //Создаем массив с объектами и не инициализируем - NULL
- ifstream f;//Создаем указатель на потоковый файл.
- f.open("Musics.txt"); //Читаем файл, в данном случае тип чтения/записи с файлом определяется в ifstream
- if(f.is_open()) //Надо проверить на успешное открытие файла.
- {
- string str; //Строки языка C++, так как обычные строки нельзя использовать в функции getline
- getline(f, str, '\n'); //Функция языка C++, так как взаимодействует со строками C++
- Size = atoi(cstc(str))? atoi(cstc(str)) : 0; //Линейное условие(ленивый if) - определяется как (Условие)? если правда : если ложь;
- if(Size > 0) //Вдруг мы пытаемся прочитать пустой файл, следует исключить...
- {
- musics = new Music[Size]; //Мы теперь знаем, что размер больше 0, так что смело инициализируем массив объектов...
- for(int i = 0; i < Size; i++)
- {
- getline(f, str, ' '); //Схема чтения из файла в данном случае очень простая, мы просто читаем строку с помощью getline и вносим её в массив объектов.
- musics[i].author = cstc(str);
- getline(f, str, ' ');
- musics[i].name = cstc(str);
- getline(f, str, ' ');
- musics[i].date.day = atoi(cstc(str));
- getline(f, str, ' ');
- musics[i].date.month = atoi(cstc(str));
- getline(f, str, ' ');
- musics[i].date.year = atoi(cstc(str));
- getline(f, str, '\n'); //Важно, здесь требуется указать не пробел(' '), а переход на следущую строку, так как мы храним данные именно в таком виде.
- musics[i].rating = atoi(cstc(str));
- }
- }
- }
- f.close(); //куда же без закрытия файла.
- return musics;
- }
- int Write_int(bool zero = false) //Стандартная функция, без комментариев.
- {
- char str[10];
- int value;
- while(true)
- {
- scanf("%s", str);
- value = abs(atoi(str))? abs(atoi(str)) : 0;
- if (zero) break;
- if (!zero && value > 0)
- break;
- else
- printf("Введите значение |n| > 0: ");
- }
- return value;
- }
- Music* Music_Add(Music* musics, int &Size, Music newMusic) //Данная функция расширяет массив объектов и в конец добавляет новый...
- {
- Size++;
- Music* copyMusics = new Music[Size];
- for (int i = 0; i < Size - 1; i++)
- copyMusics[i] = musics[i];
- copyMusics[Size - 1].author = newMusic.author;
- copyMusics[Size - 1].name = newMusic.name;
- copyMusics[Size - 1].date = newMusic.date;
- copyMusics[Size - 1].rating = newMusic.rating;
- delete[] musics;
- return copyMusics;
- }
- Music* Music_Remove(Music* musics, int &Size, int Index) //Функция удаляет объект путём обхода его стороной, например мы хотим удалить 6-ой элемент, сделаем это 0..5 7..10
- {
- Size--;
- Music* copyMusics = new Music[Size];
- for (int i = 0; i < Index; ++i)
- copyMusics[i] = musics[i];
- for (int i = Index; i < Size; ++i)
- copyMusics[i] = musics[i + 1];
- delete[] musics;
- return copyMusics;
- }
- int DateCmp(Date d1, Date d2) //Породия на strcmp, только работает не со строками, а со структурой даты.
- {
- if(d1.year > d2.year)
- return -1;
- else
- if(d1.year < d2.year)
- return 1;
- else
- {
- if(d1.month > d2.month)
- return -1;
- else
- if(d1.month < d2.month)
- return 1;
- else
- {
- if(d1.day > d2.day)
- return -1;
- else
- if(d1.day < d2.day)
- return 1;
- else
- return 0;
- }
- }
- }
- //Редактор строки
- char* strEdit(bool Number = false)
- {
- system("cls");
- HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); //Получаем объект консоли с которой будем работать.
- COORD pos; //Позиция курсора на экране.
- pos.Y = 1;
- pos.X = 0;
- char* cloneStr = NULL;
- char* str = NULL;
- printf("Строка:\n");
- while(true)
- {
- int symbol = _getch();
- //Расширение
- cloneStr = new char[pos.X + 1]; //В данном случае просто расширяем массив символов на 1
- for (int i = 0; i < pos.X; i++)
- if (str[i] != '\0')
- cloneStr[i] = str[i];
- str = new char[pos.X + 1];
- for (int i = 0; i < pos.X; i++)
- str[i] = cloneStr[i];
- delete[] cloneStr; //Кстати, данной команды в прошлых редакторах строк небыло, но она здесь очень важна, так как с каждым редактированием строки наша память засерается на пару байт.
- if (symbol >= 97 && symbol <= 122 && !Number && pos.X < 50) //Проверяем на нажатие англ клавиш.
- {
- str[pos.X] = symbol;
- printf("%c", str[pos.X]);
- pos.X++;
- }
- //Пробел
- if(symbol == 32 && !Number && pos.X < 50)
- {
- str[pos.X] = '_';
- printf("%c", ' ');
- pos.X++;
- }
- if(symbol >= 48 && symbol <= 58 && pos.X < 50 && Number) //Цифры
- {
- str[pos.X] = symbol;
- printf("%c", str[pos.X]);
- pos.X++;
- }
- if (symbol == 8 && pos.X > 0) //Backspace
- {
- str[pos.X] = ' ';
- pos.X--;
- SetConsoleCursorPosition(hConsole, pos); //Функция изменяет позицию курсора в консоли(HANDLE hConsole) на определённую позицию(COORD pos)
- printf("%s", " ");
- }
- SetConsoleCursorPosition(hConsole, pos);
- if (symbol == 13)
- {
- str[pos.X] = '\0';
- break;
- }
- }
- delete[] cloneStr; //Удаляем лишнее..
- return str;
- }
- //Редактор даты, очень похож на редактор строк...
- Date dateEdit()
- {
- system("cls");
- HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
- COORD cursor;
- cursor.X = 0;
- cursor.Y = 1;
- char* cloneStr = NULL;
- char* str = NULL;
- printf("[Дата]:\n / /"); //Данный printf очень важен, так как без его не будут показаны '/' - слешы в дате при редактировании.
- SetConsoleCursorPosition(hConsole, cursor); //Так как мы сместились с изначальной точки, то лучше было бы вернуться на неё обратно.
- while(true)
- {
- int symbol = _getch();
- //Расширение
- cloneStr = new char[cursor.X + 1];
- for (int i = 0; i < cursor.X; i++)
- if (str[i] != '\0')
- cloneStr[i] = str[i];
- str = new char[cursor.X + 1];
- for (int i = 0; i < cursor.X; i++)
- str[i] = cloneStr[i];
- delete[] cloneStr;
- if(symbol >= 48 && symbol <= 58 && cursor.X < 10)
- {
- str[cursor.X] = symbol;
- printf("%c", str[cursor.X]);
- cursor.X++;
- if(cursor.X == 2 || cursor.X == 5)
- cursor.X++;
- }
- if (symbol == 8 && cursor.X > 0)
- {
- str[cursor.X] = ' ';
- cursor.X--;
- if(cursor.X == 2 || cursor.X == 5)
- cursor.X--;
- SetConsoleCursorPosition(hConsole, cursor);
- printf("%s", " ");
- }
- SetConsoleCursorPosition(hConsole, cursor);
- if (symbol == 13 && cursor.X == 10)
- {
- str[cursor.X] = '\0';
- break;
- }
- }
- //Извлечение символ из строки "01/02/2013" и дальнейшее преобразование в число из записть в Date.
- Date date;
- char* temp = new char[3];
- temp[0] = str[0]; temp[1] = str[1]; temp[2] = '\0';
- date.day = atoi(temp);
- temp[0] = str[3]; temp[1] = str[4]; temp[2] = '\0';
- date.month = atoi(temp);
- delete[] temp; temp = new char[5];
- temp[0] = str[6]; temp[1] = str[7]; temp[2] = str[8]; temp[3] = str[9]; temp[4] = '\0';
- date.year = atoi(temp);
- delete[] temp; //Удаляем temp и str, так как мы не используем их в дальнейшем.
- delete[] str;
- return date;
- }
- //Редактор
- Music Music_Edit(Music music, bool isCreated = false)
- {
- Music copyMusic; //Создаем объект, который будем редактировать в дальнейшем
- if(isCreated) //Тут мы копируем данные из Music music, если они были переданы.
- copyMusic = music;
- else
- copyMusic = DefaultMusic(); //загружаем стандартный объект
- bool RUN = true;
- while(RUN)
- {
- system("cls"); //бла.. бла.. бла.. стандартное меню.
- printf("[Редактор книг]\n1.Автор\n2.Название\n3.Дата\n4.Рейтинг\n5.Сохранить\n6.Не сохранять.\nВыбор: ");
- switch(Write_int())
- {
- case 1:
- copyMusic.author = strEdit(); //В случае выбора именно этой строки, мы перейдём в редактор строки, который был описан выше.
- break;
- case 2:
- copyMusic.name = strEdit();
- break;
- case 3:
- copyMusic.date = dateEdit(); //Используем редактор Даты
- break;
- case 4:
- copyMusic.rating = atoi(strEdit(true)); //atoi используем, потому что rating - является не строкой, а int
- break;
- case 5:
- music = copyMusic; //Сохраняем изменённые данные
- RUN = false;
- break;
- case 6:
- if(!isCreated)
- music = DefaultMusic(); //или загружаем стандартные и выходим из редактора объекта.
- RUN = false;
- break;
- default:
- break;
- }
- }
- return music;
- }
- Music* InputMusic(Music* musics, int &Size) //Функция для работы с объектами...
- {
- bool RUN = true;
- while(RUN){
- system("cls");
- printf("[Редактирование списка]\n1.Добавить\n2.Изменить\n3.Удалить\n4.Назад\nВыбор: ");
- switch(Write_int())
- {
- case 1:
- {
- system("cls");
- Music newMusic = DefaultMusic();
- newMusic = Music_Edit(newMusic);
- musics = Music_Add(musics, Size, newMusic);
- printf("Музыка успешно была добавлена в список музыки.\n");
- printf("Для продолжения нажмите любую клавишу...\n");
- _getch();
- break;
- }
- case 2:
- {
- system("cls");
- printf("[Изменить]\nИндекс: ");
- int index = Write_int(true);
- if(index >= Size)
- {
- printf("Вы ввели индекс, который привышает размер списка музыки.\n");
- printf("Для продолжения нажмите любую клавишу...\n");
- _getch();
- break;
- }
- musics[index] = Music_Edit(musics[index], true);
- printf("Музыка успешно была изменена в список музыки.\n");
- printf("Для продолжения нажмите любую клавишу...\n");
- _getch();
- break;
- }
- case 3:
- {
- printf("[Удаление]\nВведите индекс:\n");
- int index = Write_int(true);
- if(index >= Size)
- {
- printf("Вы ввели индекс, который привышает размер списка музыки.\n");
- printf("Для продолжения нажмите любую клавишу...\n");
- _getch();
- break;
- }
- musics = Music_Remove(musics, Size, index);
- printf("Книга удалена.\n");
- printf("Для продолжения нажмите любую клавишу...\n");
- _getch();
- break;
- }
- case 4:
- RUN = false;
- break;
- default:
- break;
- }
- }
- return musics;
- }
- void OutputMusic(Music* musics, int Size){ //Функция сортировки и вывода одновременно...
- int* index = new int[Size]; //Мы сортеруем индексы, дабы не создавать разные типы данных для сортировки...
- for(int i = 0; i < Size; i++)
- index[i] = i; //Индексы не могут повторяться, так что заполняем их индивидуальными значениями.
- int temp = 0;
- bool output = false;
- system("cls");
- printf("[Вывод списка]\n1.По индексу\n2.По Автору\n3.По Названию\n4.По Дате\n5.По Рейтингу\nВыбор: ");
- switch(Write_int())
- {
- case 1:
- output = true;
- break;
- case 2: //Сортировка по Автору
- for (int i = 0; i < Size - 1; i++) //Сортировка по пузырьковому алгоритму, расказать нечего...
- for (int j = 0; j < Size - i - 1; j++)
- if (strcmp(musics[index[j]].author, musics[index[j + 1]].author)> 0)
- {
- temp = index[j]; //замена индексов местами...
- index[j] = index[j + 1];
- index[j + 1] = temp;
- }
- output = true;
- break;
- case 3: //Сортировка по Имени
- for (int i = 0; i < Size - 1; i++)
- for (int j = 0; j < Size - i - 1; j++)
- if (strcmp(musics[index[j]].name, musics[index[j + 1]].name)> 0)
- {
- temp = index[j];
- index[j] = index[j + 1];
- index[j + 1] = temp;
- }
- output = true;
- break;
- case 4: //Сортировка по Дате
- for (int i = 0; i < Size - 1; i++)
- for (int j = 0; j < Size - i - 1; j++)
- if (DateCmp(musics[index[j]].date, musics[index[j + 1]].date) > 0) //Используем вместо strcmp DateCmp, так как нам надо сравнить даты. >(-1) <(1) ==(0)
- {
- temp = index[j];
- index[j] = index[j + 1];
- index[j + 1] = temp;
- }
- output = true;
- break;
- case 5: //Сортировка по Рейтингу
- for (int i = 0; i < Size - 1; i++)
- for (int j = 0; j < Size - i - 1; j++)
- if (musics[index[j]].rating > musics[index[j + 1]].rating)
- {
- temp = index[j];
- index[j] = index[j + 1];
- index[j + 1] = temp;
- }
- output = true;
- break;
- default:
- break;
- }
- if(output) //если мы выбрали один из типов сортировки, то сортировка уже прошла, остаётся только вывести их по сортированным индексам...
- {
- system("cls");
- printf("[Вывод списка/По индексу]\n");
- for (int i = 0; i < Size; i++)
- printf("%d) %s %s %d/%d/%d %d\n", index[i], musics[index[i]].author,
- musics[index[i]].name, musics[index[i]].date.day,
- musics[index[i]].date.month, musics[index[i]].date.year,
- musics[index[i]].rating);
- }
- delete[] index; //Чистим память!
- printf("Для продолжения нажмите любую клавишу...\n");
- _getch();
- }
- int main()
- {
- SetConsoleCP(1251); //Русский язык в консоли. Использовать SetLocale нет смысла, так как он изменяет видимый шрифт, но не вводимые данные...
- SetConsoleOutputCP(1251);
- int Size = 0;
- Music* musics = NULL; //Главный массив объектов, который передается куда либо по цепочке...
- bool firstRun = true; //Для вывода надписи приветствия...
- bool RUN = true;
- while(RUN){
- system("cls");
- if(firstRun)
- {
- printf("Добро пожаловать в меню, Денис Владимирович!\nВыбирайте!\n\n");
- firstRun = false;
- }
- printf("[Меню]\n1.Загрузить список\n2.Сохранить список\n3.Вывод списка\n4.Редактирование списка\n5.Выход\nВыбор: ");
- switch(Write_int()){
- case 1:
- {
- system("cls");
- musics = FileRead(Size); //Загружаем данные из файла.
- }
- case 2:
- {
- system("cls");
- FileWrite(musics, Size); //Записываем данные в файл.
- break;
- }
- case 3:
- {
- OutputMusic(musics, Size); //Выводим данные на экран по определённым полям.
- break;
- }
- case 4:
- {
- musics = InputMusic(musics, Size); //Редактируем объекты.
- break;
- }
- case 5:
- RUN = false; //Выход)))
- break;
- }
- }
- delete[] musics; //Чистим память после работы программы.
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement