본문 바로가기
프로그래밍/C언어

[C언어] C언어 미니 프로젝트 : 도서 대여 관리 시스템

by HI_Ai 2023. 9. 11.
반응형

미니 프로젝트: 도서 대여 관리 시스템

당신은 도서 대여점에서 일하고 있습니다. 다양한 도서의 정보와 대여 상태를 관리할 수 있는 간단한 프로그램을 작성하려고 합니다.

요구 사항:
각 도서는 제목, 저자, ISBN, 대여 상태(대여 중 또는 재고 있음)와 같은 정보를 가지고 있어야 합니다.
사용자는 다음과 같은 기능을 수행할 수 있어야 합니다:
1. 도서 검색 (제목 또는 저자로 검색)
2. 도서 대여
3. 도서 반납
4. 재고에 새로운 도서 추가
5. 도서 정보 수정 (예: 잘못된 정보 수정)
6. 도서 삭제
7. 모든 도서 목록 보기
도서는 동적 배열을 사용하여 관리되어야 합니다.


먼저 전체 코드를 작성하겠습니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

struct book{
    char title[50];
    char author[50];
    int ISBN;
    bool rend;
};

void search_book(struct book *p, int count)
{
    int book_num;
    bool found = false;

    printf("Enter the book ISBN : ");
    scanf("%d", &book_num);
    
    for (int i = 0; i < count; i++)
    {
        if (book_num == p[i].ISBN)
        {
            found = true;
            printf("this book' information : \n title : %s  author : %s  ISBN : %d  rent : %s \n", p[i].title, p[i].author, p[i].ISBN, p[i].rend ? "true" : "false");
            break;
        }
    }

    if (!found)  // Moved outside the loop and removed the semicolon
    {
        printf("there isn't a correct ISBN number. \n");
    } 
}


void booking_book(struct book *p, int count)
{
    int book_num;
    bool book_found = false;

    printf("What are you booking? please give me a ISPN number. : ");
    scanf("%d", &book_num);

    for(int i=0; i < count; i++)
    {
        if (book_num == p[i].ISBN)
        {
            book_found = true;
            if(p[i].rend == true)
            {
                printf("this book is already booked \n");
            }
            else
            {
            printf("%s is booked successfully \n",p[i].title);
            p[i].rend = true;
            }
            break;
        }
    }
    if (!book_found)
    {
        printf("There is no book with the given ISBN. \n");
    }
}

void returning_book(struct book *p,int count)
{
    int book_num;
    bool book_found=false;

    printf("please give me a returning book's ISPN number. : ");
    scanf("%d", &book_num);

    for(int i=0; i<count; i++)
    {
        if (book_num == p[i].ISBN)
        {
            book_found = true;
            if(p[i].rend == false)
            {
                printf("there are a error \n");
            }
            else
            {
            printf("%s is returned successfully \n",p[i].title);
            p[i].rend = false;
            }
        }
    }
    if(!book_found)
        {
            printf("there are no book. \n");
        }
}

void input_book(struct book *p,int *count)
{
    printf("Enter the title of the book : ");
    scanf(" %9s",p[*count].title);

    printf("Enter the author of the book : ");
    scanf(" %9s",p[*count].author);

    printf("Enter the ISBN of the book : ");
    scanf("%d",&p[*count].ISBN);

    p[*count].rend = false;

    (*count)++;
}

void modify_book(struct book *p, int *count) {
    int book_num;
    int temp_rend;
    
    printf("Enter the ISBN you want to modify : \n");
    scanf("%d", &book_num);

    for(int i=0; i<*count; i++) {
        if(book_num == p[i].ISBN) {
            printf("Modify this book \n");
            
            printf("title : ");
            scanf("%s", p[i].title);
            
            printf("author : ");
            scanf("%s", p[i].author);
            
            printf("ISBN : ");
            scanf("%d", &p[i].ISBN);
            
            printf("rend (0 for false, 1 for true): ");
            scanf("%d", &temp_rend);
            if(temp_rend == 1) {
                p[i].rend = true;
            } else {
                p[i].rend = false;
            }
            
            printf("it is modified successfully. \n");          
            return; // 적절한 ISBN을 찾은 경우, 반복문 종료
        }
    }
    printf("it isn't a correct ISBN \n");
}

void delete_book(struct book *p, int *count)
{
    int book_num;
    bool found = false;  // Initialize to false
    printf("Enter the ISBN number to delete ");
    scanf("%d", &book_num);

    for (int i = 0; i < *count; i++)  // Changed comma to semicolon
    {
        if(book_num == p[i].ISBN)
        {
            found = true;
            printf("this book is deleted \n");
            
            // Shift all subsequent books backward by one position
            for (int j = i; j < *count - 1; j++)
            {
                p[j] = p[j + 1];
            }

            (*count)--;

            break;
        }
    }

    if (!found)  // Corrected the condition and removed the semicolon
    {
        printf("there isn't a book with your ISBN number. \n");
    }
}



void see_all_book(struct book *p, int count)
{
    for(int i = 0; i < count; i++)
    {
        printf("%d : title(%s) author(%s) ISBN(%d) rend(%s) \n", 
               i+1, 
               p[i].title, 
               p[i].author, 
               p[i].ISBN, 
               p[i].rend ? "true" : "false");
    }
}


int main(void)
{
    int choice;
    int count = 0;  // 초기값 설정

    struct book *p = (struct book *) malloc(count * sizeof(struct book));
    if (p == NULL)
    {
        printf("Memory allocation failed! \n");
        exit(1);
    }

    // 메뉴를 출력하고 사용자로부터 선택을 입력받는 부분
    do {
        printf("\n1. search book : (search for title or author) \n");
        printf("2. booking book \n");
        printf("3. returning book \n");
        printf("4. input book \n");
        printf("5. modify book information \n");
        printf("6. delete book \n");
        printf("7. watch all book list \n");
        printf("8. exit \n");
        printf("Enter the number : ");
        scanf("%d", &choice);

        switch(choice)
        {
            case 1:
                search_book(p, count);
                break;
            case 2:
                booking_book(p, count);
                break;
            case 3:
                returning_book(p, count);
                break;
            case 4:
                input_book(p, &count);
                break;
            case 5:
                modify_book(p, &count);
                break;
            case 6:
                delete_book(p, &count);
                break;
            case 7:
                see_all_book(p, count);
                break;
            case 8:
                printf("Good Bye\n");
                break;
            default:
                printf("Invalid choice, please try again.\n");
        }
    } while (choice != 8);

    free(p);  // 메모리를 해제합니다.
    return 0;
}

 

밑의 코드를 보면서 미니 프로젝트를 풀어보도록 하겠습니다.

1. 라이브러리 호출

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

먼저 필요한 라이브러리들을 호출합니다.

 

2. struct book 구조체 생성

struct book {
    char title[50];
    char author[50];
    int ISBN;
    bool rend;
};

book 구조체를 생성합니다. 이때 문자형(title, author)은 char를 사용, 정수형(ISBN)은 int, 그리고 대여 여부를 확인하는 rend는 boolean을 사용합니다. C언어에서는 boolean을 기본적으로 제공하지 않기 때문에 위의 라이브러리에서 <stdbool.h>를 호출하여 사용합니다.

 

3. 사용자 함수 search_book 생성

void search_book(struct book *p, int count)
{
    int book_num;
    bool found = false;

    printf("Enter the book ISBN : ");
    scanf("%d", &book_num);
    
    for (int i = 0; i < count; i++)
    {
        if (book_num == p[i].ISBN)
        {
            found = true;
            printf("this book' information : \n title : %s  author : %s  ISBN : %d  rent : %s \n", p[i].title, p[i].author, p[i].ISBN, p[i].rend ? "true" : "false");
            break;
        }
    }

    if (!found)  // Moved outside the loop and removed the semicolon
    {
        printf("there isn't a correct ISBN number. \n");
    } 
}

int는 book_num, bool 변수를 사용하고 만약 book_num이 p[i].ISBN과 같을 경우에는 이에 대한 내용을 출력하도록 코드 제작하였습니다.

 

4. 사용자 함수 booking_book 생성

void booking_book(struct book *p, int count)
{
    int book_num;
    bool book_found = false;

    printf("What are you booking? please give me a ISPN number. : ");
    scanf("%d", &book_num);

    for(int i=0; i < count; i++)
    {
        if (book_num == p[i].ISBN)
        {
            book_found = true;
            if(p[i].rend == true)
            {
                printf("this book is already booked \n");
            }
            else
            {
            printf("%s is booked successfully \n",p[i].title);
            p[i].rend = true;
            }
            break;
        }
    }
    if (!book_found)
    {
        printf("There is no book with the given ISBN. \n");
    }
}

booking_book 함수를 위해 매개변수는 struct book *p를 사용하여 매개변수의 p를 가져오고 count는 수정 필요가 없어 포인터 함수를 사용하지 않습니다.

bool book_found함수를 통해 대여 여부를 확인하는 변수를 생성합니다.

 

만약 book_num가 p[i].ISBN 중 하나와 동일 할 경우 book_found는 true로 변환시키고 p[i].rend ==true(이미 빌린 상태)일 경우 this book is already booked를 출력, 아닐경우  대여가 가능하다고 출력하고 rend상태는 true로 변경합니다.

 

만약 book_num과 p[i].ISBN이 맞는게 하나도 없다면 아래 if(!book_found)의 함수가 실행되면서맞는 ISBN이 아니라고 출력합니다.

 

5. 사용자 함수 returning_book 생성

void returning_book(struct book *p,int count)
{
    int book_num;
    bool book_found=false;

    printf("please give me a returning book's ISPN number. : ");
    scanf("%d", &book_num);

    for(int i=0; i<count; i++)
    {
        if (book_num == p[i].ISBN)
        {
            book_found = true;
            if(p[i].rend == false)
            {
                printf("there are a error \n");
            }
            else
            {
            printf("%s is returned successfully \n",p[i].title);
            p[i].rend = false;
            }
        }
    }
    if(!book_found)
        {
            printf("there are no book. \n");
        }
}

returning함수는 booking과 비슷하지만 대여했을 때의 rend 상태의 변화가 가장 큰 차이점입니다. 위의 booking 함수를 참고하기 바랍니다.

 

6. 사용자 함수 input_book 생성

void input_book(struct book *p,int *count)
{
    printf("Enter the title of the book : ");
    scanf(" %9s",p[*count].title);

    printf("Enter the author of the book : ");
    scanf(" %9s",p[*count].author);

    printf("Enter the ISBN of the book : ");
    scanf("%d",&p[*count].ISBN);

    p[*count].rend = false;

    (*count)++;
}

input_book 함수는 새로운 책 정보를 입력바당서 구조체 배열에 추가하는 작업을 합니다. count는 추가된 책의 수를 추적, 즉 추가해야함으로 int의 포인터로 전달합니다.(int *count), 책이 추가될때마다 변수가 증가합니다.

p[*count]는 새로운 책에 대한 포인터 count에 대한 정보를 입력하고 마지막에 (*count)++를 사용하여 count의 값을 1 올립니다. 

scanf에서 문자열을 읽을 때 %9s와 같이 숫자를 사용하여 문자열의 길이를 제한하는 것이 좋습니다. 이렇게 하면 버퍼 오버플로우를 방지할 수 있습니다.

 

7. 사용자 함수 modify_book 생성

void modify_book(struct book *p, int *count) {
    int book_num;
    int temp_rend;
    
    printf("Enter the ISBN you want to modify : \n");
    scanf("%d", &book_num);

    for(int i=0; i<*count; i++) {
        if(book_num == p[i].ISBN) {
            printf("Modify this book \n");
            
            printf("title : ");
            scanf("%s", p[i].title);
            
            printf("author : ");
            scanf("%s", p[i].author);
            
            printf("ISBN : ");
            scanf("%d", &p[i].ISBN);
            
            printf("rend (0 for false, 1 for true): ");
            scanf("%d", &temp_rend);
            if(temp_rend == 1) {
                p[i].rend = true;
            } else {
                p[i].rend = false;
            }
            
            printf("it is modified successfully. \n");          
            return; // 적절한 ISBN을 찾은 경우, 반복문 종료
        }
    }
    printf("it isn't a correct ISBN \n");
}

modify_book을 생성하기 위해 매개변수는 *count를 사용합니다.(main함수의 값을 수정해야하기 때문에), 만약 book_num==p[i].ISBN일 경우 title, author, ISBN은 다시 작성하여 수정합니다.

 

8. 사용자 함수 delete_book 생성

void delete_book(struct book *p, int *count)
{
    int book_num;
    bool found = false;  // Initialize to false
    printf("Enter the ISBN number to delete ");
    scanf("%d", &book_num);

    for (int i = 0; i < *count; i++)  // Changed comma to semicolon
    {
        if(book_num == p[i].ISBN)
        {
            found = true;
            printf("this book is deleted \n");
            
            // Shift all subsequent books backward by one position
            for (int j = i; j < *count - 1; j++)
            {
                p[j] = p[j + 1];
            }

            (*count)--;

            break;
        }
    }

    if (!found)  // Corrected the condition and removed the semicolon
    {
        printf("there isn't a book with your ISBN number. \n");
    }
}

먼저 found 변수를 통해 false 경우 해당되는 책이 없음을 출력, 있을 경우 found=true로 수정하게 코드를 만듦니다. book_num == p[i].ISBN일 경우 위의 for구문과 j를 사용하여 해당 위치의 값을 덮어 씌웁니다.(ex i=3일 경우 p[j] = p[j+1]함수를 통해 p[3]은 p[4]의 값이 들어가고 p[4]는 p[5]의 값이 들어가서 p[3]은 없어지게 됌.) 이후 마지막 count 값은 (*count)--를 통해 삭제하게 됩니다.

 

9. 사용자 함수 see_all_book 생성

void see_all_book(struct book *p, int count)
{
    for(int i = 0; i < count; i++)
    {
        printf("%d : title(%s) author(%s) ISBN(%d) rend(%s) \n", 
               i+1, 
               p[i].title, 
               p[i].author, 
               p[i].ISBN, 
               p[i].rend ? "true" : "false");
    }
}

모든 책을 보기 위해서 for함수를 통해 count개수만큼 printf를 하게 됩니다. 그리고 rend변수는 0 or 1이기 때문에 이를 true나 false로 수정하여 보일 수 있게 하였습니다.

 

여기서 ? : (ternary conditional operator)는 C 언어에서의 조건 연산자입니다. condition ? value_if_true : value_if_false와 같은 형식으로 사용됩니다. 주어진 조건이 참이면 value_if_true 값을 반환하고, 그렇지 않으면 value_if_false 값을 반환합니다.

int x = 5;
int y = (x > 3) ? 10 : 20; // y will be 10 because x > 3 is true

 // 위 아래는 같은 코드
 
 if (y = (x>3))
{y = 10;}
else
{y = 20;}

 

10. main 함수 작성

int main(void)
{
    int choice;
    int count = 0;  // 초기값 설정

    struct book *p = (struct book *) malloc(count * sizeof(struct book));
    if (p == NULL)
    {
        printf("Memory allocation failed! \n");
        exit(1);
    }

    // 메뉴를 출력하고 사용자로부터 선택을 입력받는 부분
    do {
        printf("\n1. search book : (search for title or author) \n");
        printf("2. booking book \n");
        printf("3. returning book \n");
        printf("4. input book \n");
        printf("5. modify book information \n");
        printf("6. delete book \n");
        printf("7. watch all book list \n");
        printf("8. exit \n");
        printf("Enter the number : ");
        scanf("%d", &choice);

        switch(choice)
        {
            case 1:
                search_book(p, count);
                break;
            case 2:
                booking_book(p, count);
                break;
            case 3:
                returning_book(p, count);
                break;
            case 4:
                input_book(p, &count);
                break;
            case 5:
                modify_book(p, &count);
                break;
            case 6:
                delete_book(p, &count);
                break;
            case 7:
                see_all_book(p, count);
                break;
            case 8:
                printf("Good Bye\n");
                break;
            default:
                printf("Invalid choice, please try again.\n");
        }
    } while (choice != 8);

    free(p);  // 메모리를 해제합니다.
    return 0;
}

메인 함수에는 choice, count를 먼저 변수로 지정합니다. 그리고 동적 메모리를 활용하기 위하여 struct book *p를 이용하여 동적 메모리를 활성화시킵니다.

do-while 루프는 조건을 테스트하기 전에 블록 내의 문장을 한 번 실행한 다음, 지정된 조건이 참인 동안 계속해서 블록 내의 문장을 반복하여 실행합니다. 주요한 점은, do-while 루프는 최소한 한 번은 실행된다는 것입니다. 왜냐하면 조건 테스트가 루프의 바닥에서 수행되기 때문입니다.

 

switch-case는 여러 조건 중에서 하나를 선택하여 실행하는 데 사용되는 제어 구조입니다.

각각의 조건은 case 라벨로 표시되며, 선택할 조건의 값을 switch 표현식에 전달합니다. switch 내의 표현식은 평가된 후, 결과 값과 각 case 라벨의 값과 일치하는지 확인됩니다.

일치하는 case가 있으면, 해당 case 라벨 다음의 코드가 실행됩니다. break 문은 현재의 switch-case 블록을 종료하게 합니다. 만약 break 문이 없다면, 일치하는 case 라벨 아래의 모든 문장들이 실행될 때까지 계속 실행됩니다.

default 라벨은 선택적입니다. 주어진 switch 표현식의 값이 어떤 case 라벨과도 일치하지 않을 경우에만 실행됩니다.

 

이 코드를 실행하여 필요한 메뉴를 출력하고 choice 값에 따라 메뉴로 들어가서 작업을 실행할 수 있습니다.

 

반응형