본문 바로가기

개발

C 언어 도서 관리 프로젝트


C언어의 기초 개념들이 들어 있는 프로젝트, 도서 관리 프로젝트이다. 최종적으로 이러한 것을 만들 것이다. 



 콜솔이라 다소 조잡해 보이지만, 중요한 것은 내용이다!! API는 다 까먹었다!!! (충!성!)


내가 직접 도서관을 만든다고 생각하면서 차근차근 해야 할 것들을 생각해 보자. 우선 도서관에 있는 책들을 전산에 쓸 수 있도록 문서화해야 한다. 이것이 1번, 책을 새로 추가하기이다. 책들의 정보를 하나하나 추가해 주면서 총 몇권이 있는지도 확인해 주어야 할 것이다. 


다음, 도서관에는 책들이 많다. 그래서 검색을 할 수가 있어야 한다. 검색을 하는 옵션으로는 


1. 책 이름으로 검색

2. 저자로 검색

3. 출팔사로 검색


등을 생각해 볼 수 있을 것이다.


 검색을 했다면, 책을 빌리고 반납할 수 있는 기능이 있어야 할 것이다. 이것이 3, 4번 내용이다. 


다음으로, 이건 파일 입출력의 개념을 익히기 위해서 추가된 항목들인데, 책들의 내용을 txt파일로 출력하고, 반대로 이미 출력된 txt파일에서 책 리스트들을 불러올 수 있는 기능들을 추가할 것이다. 이렇게 말이다. 



실컷 책들이름, 저자, 출판사, 대여 가능 여부들을 작성하고 5번을 누르면 아래와 같이 txt파일로 작성이 되게 할 것이다. 



 그리고 이렇게 작성된 파일을 불러와서 다시 사용할 수 있게 하는 것이 목표이다.



 6번으로 리스트를 불러오고 7번으로 출력을 한 상황이다. 우선 가장 기본이 되는 책의 구조를 잡아보자. 


1
2
3
4
5
6
typedef struct BOOK {
    char book_name[30];
    char auth_name[30];
    char publ_name[30];
    int borrowed;
}BOOK;
cs



이렇게 구조체로 구조(?!!)를 잡아주었다. 보통 struct BOOK ㅇㅇㅇ 이렇게 쓰기 싫어서 typedef를 붙여주는 경우가 가 많다. 그런 다음, 이 책들의 배열인 도서관을 선언할 것이다. 


1
2
3
4
5
6
7
8
9
    int user_choice; /* 유저가 선택한 메뉴 */
    int num_total_book = 0/* 현재 책의 수 */
 
    BOOK *book_list;
 
    printf("도서관의 최대 보관 장서 수를 설정해주세요 : ");
    scanf_s("%d"&user_choice);
    
    book_list = (BOOK *)malloc(sizeof(BOOK) * user_choice);
cs


 이는 사용자가 초기에 최대 권수를 설정할 수 있도록 동적 프로그래밍을 사용하였다. 그럼 이제, 각 기능들에 해당하는 함수들을 선언할 것이다. 


1
2
3
4
5
6
7
char search_str(char * dic, char * word);
int register_book(BOOK *book_list, int *nth);
int search_book(BOOK *book_list, int total_num_book);
int borrow_book(BOOK *book_list);
int return_book(BOOK *book_list);
int print_book_list(BOOK *book_list, int total_num_book);
int retrieve_book_info(BOOK **book_list, int *total_num_book);
cs


 각 함수들은, 책을 새로 추가하기, 책을 검색하기, 책을 빌리기/반납하기, 책들의 내용을 출력, 책들의 내용을 불러오는 기능들을 하는 함수들이다. 하나씩 만들어 보자. 그리고 함수들을 만들면서 어떠한 값들을 input으로 받아야 할지 생각을 해야 한다. 기본적으로 BOOK들의 리스트를 받고, 반복을 얼마나 해야 할 지 알기 위해서 전체 책이 몇 권이 있는지를 받기로 하였다. 제일 쉬운 책 추가부터 해보자. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int register_book(BOOK *book_list, int *nth) {
    printf("책의 이름 : ");
    scanf_s("%s", book_list[*nth].book_name, sizeof(book_list[*nth].book_name));
 
    printf("책의 저자 : ");
    scanf_s("%s", book_list[*nth].auth_name, sizeof(book_list[*nth].auth_name));
 
    printf("책의 출판사 : ");
    scanf_s("%s", book_list[*nth].publ_name, sizeof(book_list[*nth].publ_name));
 
    book_list[*nth].borrowed = 0;
    (*nth)++;
 
    return 0;
}
cs


 그냥 scanf로 모두 받은 다음, 전체 권수를 추가만 해 주면 될 것이다. 다음은, 책 검색.


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
31
32
33
34
35
36
37
38
39
40
41
int search_book(BOOK *book_list, int total_num_book) {
    int user_input; /* 사용자의 입력을 받는다. */
    int i;
 
    char user_search[30];
    printf("어느 것으로 검색 할 것인가요? \n");
    printf("1. 책 제목 검색 \n");
    printf("2. 지은이 검색 \n");
    printf("3. 출판사 검색 \n");
    scanf_s("%d"&user_input);
 
    printf("검색할 단어를 입력해주세요 : ");
    scanf_s("%s", user_search, sizeof(user_search));
    printf("검색 결과 \n");
 
    if (user_input == 1) {
        for (i = 0; i < total_num_book; i++) {
            if (search_str(book_list[i].book_name, user_search) >= 0) {
                printf("번호 : %d // 책 이름 : %s // 지은이 : %s // 출판사 : %s \n", i, book_list[i].book_name, book_list[i].auth_name, book_list[i].publ_name);
            }
            else printf("그런 책 없음.\n");
        }
    }
    else if (user_input == 2) {
        for (i = 0; i < total_num_book; i++) {
            if (search_str(book_list[i].auth_name, user_search) >= 0) {
                printf("번호 : %d // 책 이름 : %s // 지은이 : %s // 출판사 : %s \n", i, book_list[i].book_name, book_list[i].auth_name, book_list[i].publ_name);
            }
            else printf("그런 책 없음.\n");
        }
    }
    else if (user_input == 3) {
        for (i = 0; i < total_num_book; i++) {
            if (search_str(book_list[i].publ_name, user_search) >= 0) {
                printf("번호 : %d // 책 이름 : %s // 지은이 : %s // 출판사 : %s \n", i, book_list[i].book_name, book_list[i].auth_name, book_list[i].publ_name);
            }
            else printf("그런 책 없음.\n");
        }
    }
    return 0;
}
cs


 어떤 정보로 검색을 할 지 결정하고, search_str로 실질적인 검색을 한다. search_str은 그냥 문자열을 검색하는 함수이고, 간단하게 그 문자열이 있는지만 보는 함수이다. 아래와 같다. 


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
char search_str(char * dic, char * word) {
    int loc = 0;
    int search_loc = 0;
 
    while (*dic) {
        if (*dic == *word) {
            while (*word) {
                if (*dic != *word) {
                    word -= search_loc;
                    loc += search_loc;
                    search_loc = 0;
                    break;
                }
                dic++;
                word++;
                search_loc++;
                if (*word == 0) {
                    return loc;
                }
            }
        }
        dic++;
        loc++;
    }
    return -1;
}
cs


 책을 빌리고 반납하는 것은 매우 쉽다. borrowed 변수가 0이면 대출 가능한 것, 1이면 이미 대출된 것이라 하였다.


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
31
32
33
34
35
36
int borrow_book(BOOK *book_list) {
    /* 사용자로 부터 책번호를 받을 변수*/
    int book_num;
 
    printf("빌릴 책의 번호를 말해주세요 \n");
    printf("책 번호 : ");
    scanf_s("%d"&book_num);
 
    if (book_list[book_num].borrowed == 1) {
        printf("이미 대출된 책입니다! \n");
    }
    else {
        printf("책이 성공적으로 대출되었습니다. \n");
        book_list[book_num].borrowed = 1;
    }
 
    return 0;
}
int return_book(BOOK *book_list) {
    /* 반납할 책의 번호 */
    int num_book;
 
    printf("반납할 책의 번호를 써주세요 \n");
    printf("책 번호 : ");
    scanf_s("%d"&num_book);
 
    if (book_list[num_book].borrowed == 0) {
        printf("이미 반납되어 있는 상태입니다\n");
    }
    else {
        book_list[num_book].borrowed = 0;
        printf("성공적으로 반납되었습니다\n");
    }
 
    return 0;
}
cs


 이제 책의 리스트를 파일 입출력을 이용해 메모장에 기록하는 함수를 만들 것이다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int print_book_list(BOOK *book_list, int total_num_book) {
    FILE *fp;
    errno_t err = fopen_s(&fp, "book_list.txt""w");
    if (err == 0) {
        printf("success!! ");
    }
    else {
        printf("error");
        return 0;
    }
    fprintf(fp, "%d\n", total_num_book);
 
    for (int i = 0; i < total_num_book; i++) {
        fprintf(fp, "%s\n%s\n%s\n", book_list[i].book_name, book_list[i].auth_name, book_list[i].publ_name);
        if (book_list[i].borrowed == 0) fprintf(fp, "NO\n");
        else fprintf(fp, "YES\n");
    }
 
    fclose(fp);
 
    return 0;
}
cs


 파일 입출력을 위해서 stdlib.h는 미리 include한 상태이다.

 마지막으로 이미 만들어진 메모장 파일을 불러오는 기능을 만들었다. 


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
31
32
int retrieve_book_info(BOOK **book_list, int *total_num_book) {
    FILE *fp;
    errno_t err = fopen_s(&fp, "book_list.txt""r");
    int total_book;
    char borrow[10];
    if (err == 0) {
        printf("success!! ");
    }
    else {
        printf("error");
        return 0;
    }
    fscanf_s(fp, "%d"&total_book);
    *total_num_book = total_book;
 
    free(*book_list);
    (*book_list) = (BOOK *)malloc(sizeof(BOOK) * total_book);
;
    for (int i = 0; i < total_book; i++) {
        fscanf_s(fp, "%s", (*book_list)[i].book_name, sizeof((*book_list)[i].book_name));
        fscanf_s(fp, "%s", (*book_list)[i].auth_name, sizeof((*book_list)[i].auth_name));
        fscanf_s(fp, "%s", (*book_list)[i].publ_name, sizeof((*book_list)[i].publ_name));
        fscanf_s(fp, "%s", borrow, sizeof(borrow));
        //printf("%s %s %s %s\n", (*book_list)[i].book_name, (*book_list)[i].auth_name, (*book_list)[i].publ_name, borrow);
        //printf("%d\n", strcmp(borrow, "NO"));
        if (strcmp(borrow, "NO"== 0) (*book_list)[i].borrowed = 0;
        else if(strcmp(borrow, "YES"== 0) (*book_list)[i].borrowed = 1;
        //printf("%d", (book_list[i])->borrowed);
    }
 
    return 0;
}
cs

 

여기에서 혼동이 올 수가 있는데 아래의 접근 방식이다. 


(*book_list)[i].book_name


book_list는 BOOK들이 들어 있는 구조체 리스트이다. 그래서 아래와 같이 써 주면 book_list는 하나밖에 없는데 다음 book_list에 접근하려고 하기 때문에 작동이 되질 않는다. (참고로 이렇게 실수를 해도 어떠한 오류도 검출되지 않는다.) 아래의 풀이를 보면 이해가 될 것이다 .


(*book_list)[i].book_name == ( *( *book_list + i)).book_name

book_list[i]->book_name == (  *( *(book_list + i))).book_name 


 그럼, 전체 코드는 다음과 같아질 것이다. 아래 글자를 누르면 펼쳐진다.




 


 아주 기초적인 프로그램이었다. 가끔 C를 까먹으면 다시 만들면서 복기할 생각이다.