일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 유형 변환
- 알고리즘 조건
- c언어 괄호검사
- l-value참조자
- 범위 기반 for문
- auto 키워드
- 네트워크 결합
- LAN의 분류
- 문자형 배열
- r-value참조자
- 괄호 검사 프로그램
- 문제해결 단계
- 운영체제 기능
- 프로그래머스 푸드 파이트 대회
- IPv4 주소체계
- 백준 파이썬
- 논리 연산
- C언어 계산기 프로그램
- 원형 연결 구조 연결된 큐
- C언어 스택 연산
- const l-value참조자
- 주기억장치
- getline()함수
- 회전 및 자리 이동 연산
- 프로그래머스 배열만들기4
- 값/참조/주소에 의한 전달
- const화
- string유형
- 입출력 관리자
- C언어 덱
- Today
- Total
chyam
[간단한 프로젝트]- 도서 관리 프로그램 본문
이번에 멘토링을 하게 되었는데, 처음 과제로 'C언어를 사용한 도서 관리 프로그램' 만들기를 내주셨습니다.
아래의 사진처럼 만드는것을 목표로 잡았습니다.
먼저, 전체 도서 목록을 통해 파일에 저장된 도서 목록들을 출력해줍니다.
이때 도서명과 작가명을 출력해줍니다. 이를 선택하면 도서명을 변경하거나 삭제할수있습니다.
그리고 두번째는 추천 도서목록으로, 일단 5회 이상 검색을 하면 추천을 하게 만들었습니다.
아래는 아직 검색을 하지 않아서 없는것을 볼 수 있습니다.
세번째는 도서를 추가하는것으로 도서명과 작가명을 입력해줍니다.
네번째는 도서를 검색할 수 있는데, 작가명 또는 도서명으로 검색을 할 수 있습니다.
다섯번째는 도서 대출/반납으로, 도서 목록을 불러와 대출 가능여부를 보여주고 대출/반납을 할수있습니다.
여섯번째는 초기화로, 파일의 내용을 모두 삭제합니다.
마지막은 종료 및 저장으로, 파일에 구조체를 저장한뒤 종료해줍니다. 만약에 이걸 안누르고 그냥 끈다면 구조체는 파일에 저장되지않고 날리게됩니다.
먼저 헤더나 미리 정의할것은 아래와 같이 해두었습니다. UP, DOWN, ENTER 옆의 숫자는 방향키를 누르면 나오는 숫자입니다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#define UP 72
#define DOWN 80
#define ENTER 13
그리고 커서 이동을 위해 함수를 작성해줍니다. 이를통해 방향키와 엔터키를 사용하여 목록을 선택할 수 있습니다. GotoXY는 커서를 x,y위치로 옮기는것입니다.
void GotoXY(int x, int y) { //커서이동함수
COORD Cur = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Cur);
}
HideCursor는 깜빡이는 커서를 안보이게해줍니다.
void HideCursor() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(hConsole, &cursorInfo); // 현재 커서 정보를 가져옴
cursorInfo.bVisible = FALSE; // 커서를 숨김
SetConsoleCursorInfo(hConsole, &cursorInfo); // 변경된 커서 정보 설정
}
그다음으로 구조체 선언을 해줍니다. 도서명, 작가명, 검색 횟수, 대출여부, 연결리스트를 위한 prev와 next를 넣어줍니다.
typedef struct Book {
char name[100];
char author[100];
int researchCnt;
int rent;
struct Book* prev;
struct Book* next;
} Book;
cnt는 파일에 저장된 도서의 갯수를 알기위해 static int로 선언해줍니다.
head는 말그대로 연결리스트의 처음, tail은 연결리스트의 마지막이고, book은 연결리스트에 접근하는 변수입니다.
static int cnt = 0;
Book* head = NULL;
Book* tail = NULL, * book = NULL;
아래는 함수의 원형을 선언해준것입니다.
void Menu(); //전체 메뉴
int selectMenu(); //메뉴 선택하기
void AddBook(); //도서 추가
void PrintBooks(); //도서 출력
void SaveFile(FILE* fp); //저장
void FreeBooks(); //메모리 할당 해제
void SearchBooks(); //도서 검색
void SearchAuthor(); //작가명으로 검색
void SearchBookname(); //도서명으로 검색
void ResetFile(FILE* fp); //초기화
void Rent(); //대출 or 반납
void LoadBook(FILE* fp); // 파일에서 책 읽어오기
void RecommendBook(); //추천 도서 목록
메인함수는 아래와 같습니다.
파일을 읽는 형태로 열어주고, LoadBook을 통해 파일에서 읽어와서 연결리스트를 생성합니다.
selectedMenu의 값에 따라 각 함수들을 실행해줍니다.
초기화는 쓰기모드로 열어주는데, 이는 이후에 설명할 예정입니다.
파일을열고나면 마지막엔 항상 fclose로 닫아줘야합니다.
그리고 몇번씩 printf문이 실행이 안되고 바로 메인으로 넘어갔는데 이는 getchar()로 버퍼를 안비워줘서 오류가 났습니다.
종료 전에는 할당된것들을 해제해줘야합니다.
int main() {
FILE* fp = fopen("books.txt", "rb");
LoadBook(fp);
int selectedMenu;
HideCursor();
while (1) {
selectedMenu = selectMenu();
system("cls");
switch (selectedMenu) {
case 1:
PrintBooks();
break;
case 2:
RecommendBook();
break;
case 3:
AddBook();
break;
case 4:
SearchBooks();
break;
case 5:
Rent();
break;
case 6:
fp = fopen("books.txt", "w");
ResetFile(fp);
printf("초기화 완료\n");
break;
case 7:
fp = fopen("books.txt", "wb");
if (fp == NULL) {
fprintf(stderr, "books파일을 찾을 수 없습니다.", "books.txt");
exit(1);
}
SaveFile(fp);
fclose(fp);
return 0;
}
printf("\n 엔터를 눌러 메뉴로 돌아갑니다");
getchar();
system("cls");
}
FreeBooks();
return 0;
}
아래는 메뉴 창입니다.
void Menu() {
printf("********************************************\n");
printf(" 도서 검색 프로그램 \n");
printf("********************************************\n");
printf(" 1 : 전체 도서 목록 \n");
printf("--------------------------------------------\n");
printf(" 2 : 추천 도서 목록 \n");
printf("--------------------------------------------\n");
printf(" 3 : 도서 추가 \n");
printf("--------------------------------------------\n");
printf(" 4 : 도서 검색 \n");
printf("--------------------------------------------\n");
printf(" 5 : 도서 대출/반납 \n");
printf("--------------------------------------------\n");
printf(" 6 : 초기화 \n");
printf("--------------------------------------------\n");
printf(" 7 : 종료 및 저장 \n");
printf("********************************************\n");
}
LoadBook은 파일에서 도서 목록을 읽어와서 연결리스트에 저장해줍니다.
왜냐면 실행할때마다 연결리스트는 초기화되기 때문입니다.
fread를 사용하면 읽어올 데이터가 있으면 값이 1이나오고, 아니면 다른값이 나옵니다. 1이아니면 할당을 해제하고 멈춥니다.
읽어올 데이터가 있을때, head가 NULL이라는것은 처음이라는 뜻입니다.
그리고 cnt를 증가시켜 파일에 몇개의 도서가 있는지를 확인할 수 있게 합니다.
void LoadBook(FILE* fp) {
if (fp == NULL) { // 파일이 없는 경우 초기화
printf("파일이 존재하지 않습니다. 새로운 데이터를 추가하세요.\n");
return;
}
int read = 0;
while (1) {
Book* book = (Book*)malloc(sizeof(Book)); // 새 도서 생성
read = fread(book, sizeof(Book), 1, fp); // 읽기 시도
if (read != 1) { // 더 이상 읽을 데이터가 없으면 종료
free(book);
break;
}
if (head == NULL) { // 연결 리스트가 비어있다면 첫 노드로 설정
head = book;
book->prev = NULL;
}
else { // 기존 연결 리스트에 추가
tail->next = book;
book->prev = tail;
}
book->next = NULL;
tail = book;
cnt++;
}
fclose(fp); // 파일 닫기
}
menuSelect를 통해 메뉴 선택 번호를 결정하게되는데, 1부터 7까지 있고, 1보다 클때는 up이 가능하고, 7보다 작을때는 down이 가능합니다. 세모를 통해 현재 커서의 위치를 알수있습니다.
int selectMenu() {
Menu();
int menuSelect = 1; //메뉴 선택
int getC = 1, mY = 3;
GotoXY(6, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) { //키보드가 입력된 상태인가?
getC = _getch(); //누른거 아스키코드로 받음
switch (getC) {
case UP:
if (menuSelect > 1) {
GotoXY(6, mY);
printf(" ");
mY -= 2;
GotoXY(6, mY);
printf("▶");
menuSelect -= 1;
}
break;
case DOWN:
if (menuSelect < 7) {
GotoXY(6, mY);
printf(" ");
mY += 2;
GotoXY(6, mY);
printf("▶");
menuSelect += 1;
}
break;
}
}
}
return menuSelect;
}
아래는 도서를 추가하는 함수입니다.
book을 동적으로 할당하고, 직접 도서명과 작가명을 입력받고, 초기 검색횟수와 rent를 0으로 만들어줍니다.
void AddBook() {
int cnt = 0;
book = (Book*)malloc(sizeof(Book));
printf("추가할 도서명을 입력해주세요 : ");
scanf_s("%[^\n]s", book->name, sizeof(book->name));
getchar();
printf("작가명을 입력해주세요 : ");
scanf_s("%[^\n]s", book->author, sizeof(book->author));
getchar();
book->researchCnt = 0; //초기 검색 횟수
book->rent = 0;
if (head == NULL) {
head = tail = book;
book->prev = NULL;
book->next = NULL;
}
else {
tail->next = book;
book->prev = tail;
tail = book;
tail->next = NULL;
}
printf("도서가 성공적으로 추가되었습니다.\n");
while (cnt != ENTER) {
if (_kbhit()) {
cnt = _getch();
}
}
}
아래는 전체 도서목록을 출력해주는 함수입니다.
이때 도서를 선택하여 편집또는 삭제를 할수 있도록 커서를 이동해주도록 코드를 짜줍니다.
저는 편하게 도서를 선택하면 숫자를 입력하여 편집/삭제를 할수있도록 해주었습니다.
void PrintBooks() {
Book* tmp = head;
if (tmp == NULL) {
printf("도서 목록이 비어있습니다.\n");
return;
}
printf("========================도서 목록=========================\n");
while (tmp != NULL) {
printf(" 도서명: %s, 작가명: %s\n", tmp->name, tmp->author);
printf("----------------------------------------------------------\n");
tmp = tmp->next;
}
int getC = 1, mY = 1;
int edit = 0;
tmp = head;
GotoXY(1, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) {
getC = _getch();
switch (getC) {
case UP:
if (tmp->prev != NULL) {
GotoXY(1, mY);
printf(" ");
mY -= 2;
GotoXY(1, mY);
printf("▶");
tmp = tmp->prev;
}
break;
case DOWN:
if (tmp->next != NULL) {
GotoXY(1, mY);
printf(" ");
mY += 2;
GotoXY(1, mY);
printf("▶");
tmp = tmp->next;
}
break;
case ENTER: //편집, 삭제
system("cls");
printf("편집을 원하시면 1, 삭제를 원하시면 2, 메뉴로 돌아가기를 원하시면 3을 입력해주세요 :");
scanf("%d", &edit);
getchar();
system("cls");
if (edit == 1) {
printf("수정하시고싶은 책 제목을 입력해주세요 :");
scanf("%s", tmp->name);
getchar();
printf("수정하시고싶은 작가명을 입력해주세요 :");
scanf("%s", tmp->author);
getchar();
}
else if (edit == 2) {
printf("도서를 삭제합니다.\n");
// 첫 번째 노드인지 확인
if (tmp->prev == NULL) {
head = tmp->next; // head를 다음 노드로 변경
if (head != NULL) {
head->prev = NULL; // 새 head의 prev를 NULL로 설정
}
}
else {
tmp->prev->next = tmp->next; // 이전 노드의 next를 현재 노드의 next로 연결
}
if (tmp->next != NULL) {
tmp->next->prev = tmp->prev; // 다음 노드의 prev를 현재 노드의 prev로 연결
}
// 현재 노드의 메모리 해제
free(tmp);
printf("도서가 삭제되었습니다!\n");
}
break;
}
}
}
}
아래는 추천도서 목록입니다. 검색횟수가 5보다 크면 출력해줍니다.
void RecommendBook() {
Book* tmp = head;
if (tmp == NULL) {
printf("도서 목록이 비어있습니다.\n");
return;
}
printf("==================== 추천 도서 목록====================\n");
while (tmp != NULL) {
if (tmp->researchCnt > 5) {
printf(" 도서명: %s, 작가명: %s \n", tmp->name, tmp->author);
printf("--------------------------------------------------\n");
}
tmp = tmp->next;
}
}
아래는 파일을 저장해주는 함수입니다. fwrite를 통해 연결리스트를 파일에 저장해줍니다.
void SaveFile(FILE* fp) {
if (fp == NULL) {
printf("파일 포인터가 NULL입니다. 파일을 열 수 없습니다.\n");
return;
}
book = head;
while (book != NULL) {
// fwrite를 사용하여 책 정보를 파일에 바이너리 형식으로 쓰기
if (fwrite(book, sizeof(Book), 1, fp) != 1) {
printf("파일에 쓰기 오류 발생!\n");
return;
}
book = book->next; // 다음 책으로 이동
}
fclose(fp); // 파일 닫기
}
아래는 도서 대출/반납하는 함수입니다. isRent가 0이면 대출가능한 도서입니다.
strcmp를 통해 문자열을 비교하여 대출/반납을 구현하였습니다.
void Rent() {
book = head;
//char bookName[100];
int isRent = 0;
if (book == NULL) {
printf("대출/반납 가능한 도서가 없습니다.\n");
}
int getC = 1, mY = 2;
int want = 0;
char bookName[100];
printf("도서 대출을 원하시면 1, 반납을 원하시면 2를 입력해주세요 :");
scanf("%d", &want);
if (want == 2) {
int able = 0;
printf("반납하시려는 도서명을 입력해주세요 :");
scanf("%s", &bookName);
getchar();
while (book != NULL) {
if (strcmp(bookName, book->name) == 0 && book->rent==1) {
book->rent = 0;
printf("반납되었습니다! 감사합니다.\n");
able = 1;
break;
}
else if (strcmp(bookName, book->name) == 0 && book->rent == 0) {
printf("이미 반납된 도서입니다. \n");
able = 1;
break;
}
book = book->next;
}
if (!able) {
printf("없는 도서입니다.\n");
}
}
else if(want==1){
Book* tmp = head;
if (tmp == NULL) {
printf("도서 목록이 비어있습니다.\n");
return;
}
printf("=======================도서 목록============================\n");
while (tmp != NULL) {
if (tmp->rent == 0) {
printf(" 도서명: %s, 작가명: %s, 대출 가능\n", tmp->name, tmp->author);
printf("------------------------------------------------------------\n");
}
else if (tmp->rent == 1) {
printf(" 도서명: %s, 작가명: %s, 대출 불가능\n", tmp->name, tmp->author);
printf("------------------------------------------------------------\n");
}
tmp = tmp->next;
}
book = head;
GotoXY(1, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) {
getC = _getch();
switch (getC) {
case UP:
if (book->prev!=NULL) {
GotoXY(1, mY);
printf(" ");
mY -= 2;
GotoXY(1, mY);
printf("▶");
book = book->prev;
}
break;
case DOWN:
if (book->next!=NULL) {
GotoXY(1, mY);
printf(" ");
mY += 2;
GotoXY(1, mY);
printf("▶");
book = book->next;
}
break;
case ENTER: //대출
system("cls");
getchar();
if (book->rent == 0) {
book->rent = 1;
printf("대출되었습니다.\n");
}
else {
printf("이미 대출된 도서입니다.\n");
}
break;
}
}
}
}
else {
printf("유효하지 않은 문자입니다.\n");
}
}
아래는 메모리 해제해주는 함수입니다.
void FreeBooks() {
Book* current = head;
while (current != NULL) {
Book* next = current->next;
free(current);
current = next;
}
}
아래는 도서를 검색해주는 함수입니다. 커서를 이용하여 1번부터 3번에 접근할수있습니다.
void SearchBooks() {
printf(" 1. 작가명으로 찾기 \n");
printf(" 2. 도서명으로 찾기 \n");
printf(" 3. 메뉴로 나가기 \n");
int getC = 1, mY = 0;
int select = 1;
GotoXY(1, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) {
getC = _getch();
switch (getC) {
case UP:
if (select > 1) {
GotoXY(1, mY);
printf(" ");
mY -= 1;
GotoXY(1, mY);
printf("▶");
select -= 1;
}
break;
case DOWN:
if (select < 3) {
GotoXY(1, mY);
printf(" ");
mY += 1;
GotoXY(1, mY);
printf("▶");
select += 1;
}
break;
case ENTER:
switch (select) {
case 1:
SearchAuthor();
break;
case 2:
SearchBookname();
break;
}
}
}
}
}
작가명으로 도서를 찾는 함수입니다. strcmp를 통해 문자열을 비교하여 검색해줍니다. 검색할때마다 researchCnt를 증가시킵니다.
void SearchAuthor() {
system("cls");
// 작가명으로 검색할 수 있는 기능 추가
book = head;
char bookAuthor[100];
int able = 0;
printf("작가명을 입력해주세요 : ");
scanf("%[^\n]s", bookAuthor);
getchar();
while (book != NULL) {
if (strcmp(book->author, bookAuthor) == 0) {
able = 1;
book->researchCnt += 1;
printf("도서명: % s, 작가명 : % s\n", book->name, book->author);
break;
}
book = book->next;
}
if (!able) {
printf("찾으시는 작가님이 없습니다.\n");
}
}
아래는 도서명으로 찾는 함수입니다. strcmp를 이용해 위와같이 찾아줍니다.
void SearchBookname() {
system("cls");
// 도서명으로 검색할 수 있는 기능 추가
book = head;
char bookName[100];
int able = 0;
printf("도서명을 입력해주세요 : ");
scanf("%[^\n]s", bookName);
getchar();
while (book != NULL) {
if (strcmp(book->name, bookName) == 0) {
able = 1;
book->researchCnt += 1;
printf("도서명: % s, 작가명 : % s\n", book->name, book->author);
break;
}
book = book->next;
}
if (!able) {
printf("찾으시는 도서가 없습니다.\n");
}
}
마지막으로 초기화하는 함수입니다. 파일을 덮어쓰는것으로 열어주고 바로 닫아주고 메모리 할당도 해제한뒤 연결리스트도 초기화해줍니다.
void ResetFile(FILE* fp) {
if (fp == NULL) {
printf("파일 열기 실패\n");
return;
}
fclose(fp);
FreeBooks();
head = tail = NULL;
printf("파일 내용이 삭제되었습니다.\n");
}
아래는 전체 코드입니다.
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#define UP 72
#define DOWN 80
#define ENTER 13
void GotoXY(int x, int y) { //커서이동함수
COORD Cur = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Cur);
}
void HideCursor() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(hConsole, &cursorInfo); // 현재 커서 정보를 가져옴
cursorInfo.bVisible = FALSE; // 커서를 숨김
SetConsoleCursorInfo(hConsole, &cursorInfo); // 변경된 커서 정보 설정
}
typedef struct Book {
char name[100];
char author[100];
int researchCnt;
int rent;
struct Book* prev;
struct Book* next;
} Book;
static int cnt = 0;
Book* head = NULL;
Book* tail = NULL, * book = NULL;
void Menu(); //전체 메뉴
int selectMenu(); //메뉴 선택하기
void AddBook(); //도서 추가
void PrintBooks(); //도서 출력
void SaveFile(FILE* fp); //저장
void FreeBooks(); //메모리 할당 해제
void SearchBooks(); //도서 검색
void SearchAuthor(); //작가명으로 검색
void SearchBookname(); //도서명으로 검색
void ResetFile(FILE* fp); //초기화
void Rent(); //대출/반납
void LoadBook(FILE* fp); // 파일에서 책 읽어오기
void RecommendBook(); //추천 도서 목록
int main() {
FILE* fp = fopen("books.txt", "rb");
LoadBook(fp);
int selectedMenu;
HideCursor();
while (1) {
selectedMenu = selectMenu();
system("cls");
switch (selectedMenu) {
case 1:
PrintBooks();
break;
case 2:
RecommendBook();
break;
case 3:
AddBook();
break;
case 4:
SearchBooks();
break;
case 5:
Rent();
break;
case 6:
fp = fopen("books.txt", "w");
ResetFile(fp);
printf("초기화 완료\n");
break;
case 7:
fp = fopen("books.txt", "wb");
if (fp == NULL) {
fprintf(stderr, "books파일을 찾을 수 없습니다.", "books.txt");
exit(1);
}
SaveFile(fp);
fclose(fp);
return 0;
}
printf("\n 엔터를 눌러 메뉴로 돌아갑니다");
getchar();
system("cls");
}
FreeBooks();
return 0;
}
void LoadBook(FILE* fp) {
if (fp == NULL) { // 파일이 없는 경우 초기화
printf("파일이 존재하지 않습니다. 새로운 데이터를 추가하세요.\n");
return;
}
int read = 0;
while (1) {
Book* book = (Book*)malloc(sizeof(Book)); // 새 도서 생성
read = fread(book, sizeof(Book), 1, fp); // 읽기 시도
if (read != 1) { // 더 이상 읽을 데이터가 없으면 종료
free(book);
break;
}
if (head == NULL) { // 연결 리스트가 비어있다면 첫 노드로 설정
head = book;
book->prev = NULL;
}
else { // 기존 연결 리스트에 추가
tail->next = book;
book->prev = tail;
}
book->next = NULL;
tail = book;
cnt++;
}
fclose(fp); // 파일 닫기
}
int selectMenu() {
Menu();
int menuSelect = 1; //메뉴 선택
int getC = 1, mY = 3;
GotoXY(6, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) { //키보드가 입력된 상태인가?
getC = _getch(); //누른거 아스키코드로 받음
switch (getC) {
case UP:
if (menuSelect > 1) {
GotoXY(6, mY);
printf(" ");
mY -= 2;
GotoXY(6, mY);
printf("▶");
menuSelect -= 1;
}
break;
case DOWN:
if (menuSelect < 7) {
GotoXY(6, mY);
printf(" ");
mY += 2;
GotoXY(6, mY);
printf("▶");
menuSelect += 1;
}
break;
}
}
}
return menuSelect;
}
void AddBook() {
int cnt = 0;
book = (Book*)malloc(sizeof(Book));
printf("추가할 도서명을 입력해주세요 : ");
scanf_s("%[^\n]s", book->name, sizeof(book->name));
getchar();
printf("작가명을 입력해주세요 : ");
scanf_s("%[^\n]s", book->author, sizeof(book->author));
getchar();
book->researchCnt = 0; //초기 검색 횟수
book->rent = 0;
if (head == NULL) {
head = tail = book;
book->prev = NULL;
book->next = NULL;
}
else {
tail->next = book;
book->prev = tail;
tail = book;
tail->next = NULL;
}
printf("도서가 성공적으로 추가되었습니다.\n");
while (cnt != ENTER) {
if (_kbhit()) {
cnt = _getch();
}
}
}
void PrintBooks() {
Book* tmp = head;
if (tmp == NULL) {
printf("도서 목록이 비어있습니다.\n");
return;
}
printf("========================도서 목록=========================\n");
while (tmp != NULL) {
printf(" 도서명: %s, 작가명: %s\n", tmp->name, tmp->author);
printf("----------------------------------------------------------\n");
tmp = tmp->next;
}
int getC = 1, mY = 1;
int edit = 0;
tmp = head;
GotoXY(1, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) {
getC = _getch();
switch (getC) {
case UP:
if (tmp->prev != NULL) {
GotoXY(1, mY);
printf(" ");
mY -= 2;
GotoXY(1, mY);
printf("▶");
tmp = tmp->prev;
}
break;
case DOWN:
if (tmp->next != NULL) {
GotoXY(1, mY);
printf(" ");
mY += 2;
GotoXY(1, mY);
printf("▶");
tmp = tmp->next;
}
break;
case ENTER: //편집, 삭제
system("cls");
printf("편집을 원하시면 1, 삭제를 원하시면 2, 메뉴로 돌아가기를 원하시면 3을 입력해주세요 :");
scanf("%d", &edit);
getchar();
system("cls");
if (edit == 1) {
printf("수정하시고싶은 책 제목을 입력해주세요 :");
scanf("%s", tmp->name);
getchar();
printf("수정하시고싶은 작가명을 입력해주세요 :");
scanf("%s", tmp->author);
getchar();
}
else if (edit == 2) {
printf("도서를 삭제합니다.\n");
// 첫 번째 노드인지 확인
if (tmp->prev == NULL) {
head = tmp->next; // head를 다음 노드로 변경
if (head != NULL) {
head->prev = NULL; // 새 head의 prev를 NULL로 설정
}
}
else {
tmp->prev->next = tmp->next; // 이전 노드의 next를 현재 노드의 next로 연결
}
if (tmp->next != NULL) {
tmp->next->prev = tmp->prev; // 다음 노드의 prev를 현재 노드의 prev로 연결
}
// 현재 노드의 메모리 해제
free(tmp);
printf("도서가 삭제되었습니다!\n");
}
break;
}
}
}
}
void RecommendBook() {
Book* tmp = head;
if (tmp == NULL) {
printf("도서 목록이 비어있습니다.\n");
return;
}
printf("==================== 추천 도서 목록====================\n");
while (tmp != NULL) {
if (tmp->researchCnt > 5) {
printf(" 도서명: %s, 작가명: %s \n", tmp->name, tmp->author);
printf("--------------------------------------------------\n");
}
tmp = tmp->next;
}
}
void SaveFile(FILE* fp) {
if (fp == NULL) {
printf("파일 포인터가 NULL입니다. 파일을 열 수 없습니다.\n");
return;
}
book = head;
while (book != NULL) {
// fwrite를 사용하여 책 정보를 파일에 바이너리 형식으로 쓰기
if (fwrite(book, sizeof(Book), 1, fp) != 1) {
printf("파일에 쓰기 오류 발생!\n");
return;
}
book = book->next; // 다음 책으로 이동
}
fclose(fp); // 파일 닫기
}
void Rent() {
book = head;
//char bookName[100];
int isRent = 0;
if (book == NULL) {
printf("대출/반납 가능한 도서가 없습니다.\n");
}
int getC = 1, mY = 2;
int want = 0;
char bookName[100];
printf("도서 대출을 원하시면 1, 반납을 원하시면 2를 입력해주세요 :");
scanf("%d", &want);
if (want == 2) {
int able = 0;
printf("반납하시려는 도서명을 입력해주세요 :");
scanf("%s", &bookName);
getchar();
while (book != NULL) {
if (strcmp(bookName, book->name) == 0 && book->rent==1) {
book->rent = 0;
printf("반납되었습니다! 감사합니다.\n");
able = 1;
break;
}
else if (strcmp(bookName, book->name) == 0 && book->rent == 0) {
printf("이미 반납된 도서입니다. \n");
able = 1;
break;
}
book = book->next;
}
if (!able) {
printf("없는 도서입니다.\n");
}
}
else if(want==1){
Book* tmp = head;
if (tmp == NULL) {
printf("도서 목록이 비어있습니다.\n");
return;
}
printf("=======================도서 목록============================\n");
while (tmp != NULL) {
if (tmp->rent == 0) {
printf(" 도서명: %s, 작가명: %s, 대출 가능\n", tmp->name, tmp->author);
printf("------------------------------------------------------------\n");
}
else if (tmp->rent == 1) {
printf(" 도서명: %s, 작가명: %s, 대출 불가능\n", tmp->name, tmp->author);
printf("------------------------------------------------------------\n");
}
tmp = tmp->next;
}
book = head;
GotoXY(1, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) {
getC = _getch();
switch (getC) {
case UP:
if (book->prev!=NULL) {
GotoXY(1, mY);
printf(" ");
mY -= 2;
GotoXY(1, mY);
printf("▶");
book = book->prev;
}
break;
case DOWN:
if (book->next!=NULL) {
GotoXY(1, mY);
printf(" ");
mY += 2;
GotoXY(1, mY);
printf("▶");
book = book->next;
}
break;
case ENTER: //대출
system("cls");
getchar();
if (book->rent == 0) {
book->rent = 1;
printf("대출되었습니다.\n");
}
else {
printf("이미 대출된 도서입니다.\n");
}
break;
}
}
}
}
else {
printf("유효하지 않은 문자입니다.\n");
}
}
void FreeBooks() {
Book* current = head;
while (current != NULL) {
Book* next = current->next;
free(current);
current = next;
}
}
void SearchBooks() {
printf(" 1. 작가명으로 찾기 \n");
printf(" 2. 도서명으로 찾기 \n");
printf(" 3. 메뉴로 나가기 \n");
int getC = 1, mY = 0;
int select = 1;
GotoXY(1, mY);
printf("▶");
while (getC != ENTER) {
if (_kbhit()) {
getC = _getch();
switch (getC) {
case UP:
if (select > 1) {
GotoXY(1, mY);
printf(" ");
mY -= 1;
GotoXY(1, mY);
printf("▶");
select -= 1;
}
break;
case DOWN:
if (select < 3) {
GotoXY(1, mY);
printf(" ");
mY += 1;
GotoXY(1, mY);
printf("▶");
select += 1;
}
break;
case ENTER:
switch (select) {
case 1:
SearchAuthor();
break;
case 2:
SearchBookname();
break;
}
}
}
}
}
void SearchAuthor() {
system("cls");
// 작가명으로 검색할 수 있는 기능 추가
book = head;
char bookAuthor[100];
int able = 0;
printf("작가명을 입력해주세요 : ");
scanf("%[^\n]s", bookAuthor);
getchar();
while (book != NULL) {
if (strcmp(book->author, bookAuthor) == 0) {
able = 1;
book->researchCnt += 1;
printf("도서명: % s, 작가명 : % s\n", book->name, book->author);
break;
}
book = book->next;
}
if (!able) {
printf("찾으시는 작가님이 없습니다.\n");
}
}
void SearchBookname() {
system("cls");
// 도서명으로 검색할 수 있는 기능 추가
book = head;
char bookName[100];
int able = 0;
printf("도서명을 입력해주세요 : ");
scanf("%[^\n]s", bookName);
getchar();
while (book != NULL) {
if (strcmp(book->name, bookName) == 0) {
able = 1;
book->researchCnt += 1;
printf("도서명: % s, 작가명 : % s\n", book->name, book->author);
break;
}
book = book->next;
}
if (!able) {
printf("찾으시는 도서가 없습니다.\n");
}
}
void ResetFile(FILE* fp) {
if (fp == NULL) {
printf("파일 열기 실패\n");
return;
}
fclose(fp);
FreeBooks();
head = tail = NULL;
printf("파일 내용이 삭제되었습니다.\n");
}
void Menu() {
printf("********************************************\n");
printf(" 도서 검색 프로그램 \n");
printf("********************************************\n");
printf(" 1 : 전체 도서 목록 \n");
printf("--------------------------------------------\n");
printf(" 2 : 추천 도서 목록 \n");
printf("--------------------------------------------\n");
printf(" 3 : 도서 추가 \n");
printf("--------------------------------------------\n");
printf(" 4 : 도서 검색 \n");
printf("--------------------------------------------\n");
printf(" 5 : 도서 대출/반납 \n");
printf("--------------------------------------------\n");
printf(" 6 : 초기화 \n");
printf("--------------------------------------------\n");
printf(" 7 : 종료 및 저장 \n");
printf("********************************************\n");
}
'Project' 카테고리의 다른 글
[WinAPI] - 테트리스 (2) | 2025.02.14 |
---|---|
[JSON을 이용한 도서 관리 프로그램] (1) | 2025.01.20 |