C & C++/디딤돌 C언어

Part 31. 도서 관리 프로그램 III - 도서 추가, 도서 목록, 도서 검색, 장르 삭제 기능 구현

언휴 2024. 1. 23. 11:55

Part 31. 도서 관리 프로그램 III 

107. 도서 관리 프로그램 – 도서 추가

C언어 도서 관리 프로그램 - 도서 추가 기능 구현

이번에는 도서 추가 시퀀스 다이어그램을 작성하기로 해요.
도서 추가에서는 먼저 모든 장르 정보를 보여주게 하세요.
장르를 선택하고 도서 제목과 작가 이름을 입력받아 도서를 생성한 후에 선택한 장르에 도서를 추가해야겠죠.
장르에서는 새로운 장르를 생성하여 장르에 도서를 보관하게 하세요.

C언어 도서 관리 프로그램 - 도서 추가 시퀀스 다이어그램
도서 추가 시퀀스 다이어그램

먼저 Book 헤더에 동적으로 도서를 생성하는 함수와 소멸하는 함수를 선언하고 소스에 구현하세요.
동적으로 Book 개체를 생성하는 함수에서는 동적으로 Book 형식 크기의 메모리를 할당받으세요.
할당받은 메모리를 초기화하고 반환하세요.

void BookBook(Book *book,int bnum,const char *title,const char *author);
Book *NewBook(int bnum,const char *title,const char *author)
{
    Book *book = 0;
    book = (Book *)malloc(sizeof(Book));
    BookBook(book,bnum,title,author);
    return book;
}

Book 개체를 초기화하는 함수에서는 도서 번호와 도서 제목, 저자명을 설정하세요.

void BookBook(Book *book,int bnum,const char *title,const char *author)
{
    book->bnum = bnum;
    memset(book->title,0,sizeof(book->title));
    strncpy(book->title,title,MAX_TNAME_LEN);
    memset(book->author,0,sizeof(book->author));
    strncpy(book->author,author,MAX_ANAME_LEN);
}

Book 개체를 소멸하는 함수에서는 자신만 소멸하면 되겠죠.

void DeleteBook(Book *book)
{
    free(book);
}

장르에도 도서를 생성하여 보관하는 함수를 구현합시다. App에서 사용해야 하는 함수이므로 헤더 파일에 함수 선언문을 작성하고 소스 파일에 함수를 구현하세요.

void GenreAddBook(Genre *genre,const char *title,const char *author)
{
    Book *book = 0;
    genre->last_bnum++;
    book = NewBook(genre->last_bnum,title,author);
    EHArrayPushBack(genre->books,book);
    printf("도서번호:%d 로 추가하였습니다.\n",genre->last_bnum);
}

App에 도서 추가 함수를 작성하기로 해요.
장르 목록을 보여주고 장르를 선택하세요.
장르를 선택하면 도서 정보를 입력받은 후 장르의 도서 추가 함수를 호출하게 하세요.

void AppAddBook(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    char author[MAX_ANAME_LEN+1]="";
    char title[MAX_TNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    AppListGenre(app);
    printf("도서를 추가할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    printf("도서명을 입력하세요.\n");
    gets_s(title,MAX_TNAME_LEN);
    printf("저자명을 입력하세요.\n");
    gets_s(author,MAX_ANAME_LEN);
    genre = (Genre *)(*seek);
    GenreAddBook(genre,title,author);
}

108.도서 관리 프로그램-도서 목록

C언어 도서 관리 프로그램 - 도서 목록 기능 구현

특정 장르 내 도서 목록 보기에서는 먼저 장르 목록을 보여주고 최종 사용자가 장르를 선택하게 하세요.
이 부분은 도서 추가부분을 참고하세요.
그리고 선택한 장르의 모든 도서 정보를 보여주는 함수를 호출하기로 해요.

C언어 도서 관리 프로그램 - 장르 내 도서 목록 기능 시퀀스 다이어그램
장르 내 도서 목록 기능 시퀀스 다이어그램

먼저 Book에 View 함수를 구현하세요.
Genre에서 호출해서 사용하므로 Book 헤더 파일에 선언문을 작성하고 소스 파일에 함수를 구현하세요.

void BookView(Book *book)
{
    printf("제목:%s\n",book->title);
    printf("\t도서번호:%d 저자명:%s\n",book->bnum,book->author);
}

Genre에 ViewAll을 구현하세요.
App에서 호출해서 사용하므로 Genre 헤더 파일에 선언문을 작성하고 소스 파일에 구현하세요.
ViewAll 함수에서는 먼저 자신의 정보를 출력하는 View 함수를 호출하세요.
그리고 배열에 보관하고 있는 모든 도서를 순차적으로 얻어와서 도서 정보를 출력하는 Book의 View 함수를 호출하세요.

void GenreViewAll(Genre *genre)
{
    Iterator seek= EHArrayBegin(genre->books);
    Iterator end= EHArrayEnd(genre->books);
    Book *sbook=0;
    GenreView(genre);
    for(  ;seek != end; ++seek)
    {
        sbook = (Book *)(*seek);
        BookView(sbook);
    }
}

App의 특정 장르 내 도서 보기를 구현하세요.
여기에서는 장르를 선택한 후에 선택한 장르의 ViewAll 함수를 호출하세요.
장르를 선택하는 부분은 도서 추가와 같은 논리예요.

void AppListBookAtGenre(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    AppListGenre(app);
    printf("도서 목록을 확인할 장르명을 입력하세요.\n");
    gets_s (gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    genre = (Genre *)(*seek);
    GenreViewAll(genre);
}

109. 도서 관리 프로그램 – 전체보기

C언어 도서 관리 프로그램 - 전체 보기 기능 구현

전체 보기에서는 App의 배열에 보관한 모든 장르를 순차적으로 접근하여 장르의 전체 도서 보기를 호출하세요.

C언어 도서 관리 프로그램 - 전체 보기 시퀀스 다이어그램
전체 보기 시퀀스 다이어그램

전체 보기 기능은 전체 장르 목록 보기와 논리가 대부분 비슷해요.
차이가 있는 부분은 보관한 장르의 장르 정보 보기(View)가 아닌 장르 내 전체 도서 보기(ViewAll) 함수를 호출하는 것이죠.

void AppListAll(App *app)
{
    Iterator seek= EHArrayBegin(app->genres);
    Iterator end= EHArrayEnd(app->genres);
    Genre *genre=0;
    for(  ;seek != end; ++seek)
    {
        genre = (Genre *)(*seek);
        GenreViewAll(genre);
    }
}

110.도서관리 프로그램 – 도서 번호로 검색

C언어 도서 관리 프로그램 - 도서 번호로 검색 기능 구현

이번에는 도서 번호로 검색 시퀀스 다이어그램을 작성해 보아요.
도서 번호로 검색에서도 장르 목록을 보여주고 장르를 선택하게 하세요.
장르를 선택한 후에 도서 번호를 입력하게 하고 장르의 도서 번호로 검색 기능을 호출하세요.
장르의 도서 번호로 검색 기능에서는 장르 내 배열에 보관한 도서 중에 입력한 도서 번호와 일치하는 도서를 찾아 반환하세요.
App에서는 반환받은 도서의 정보 출력 함수를 호출하세요.

C언어 도서 관리 프로그램 - 도서 번호로 검색 시퀀스 다이어그램
도서 번호로 검색 시퀀스 다이어그램

Book 헤더 파일에 도서 번호를 반환하는 함수를 선언하고 소스 파일에 구현하세요.

int BookGetNum(Book *book)
{
    return book->bnum;
}

Gerne 헤더 파일에 번호로 도서 검색 함수를 선언하고 소스에 구현하세요.
배열에 보관한 도서의 번호가 입력받은 도서 번호와 같은지 확인하여 일치하는 도서가 있으면 반환하세요.

Book *GenreFindBookByNum(Genre *genre,int bnum)
{
    Iterator seek;
    Iterator end;
    Book *book=0;

    seek= EHArrayBegin(genre->books);
    end= EHArrayEnd(genre->books);

    GenreView(genre);

    for(  ;seek != end; ++seek)
    {
        book = (Book *)(*seek);

        if(BookGetNum(book) == bnum)
        {
            return book;
        }
    }

    return 0;
}

App에서 도서 번호로 검색 기능을 구현하기로 해요.
먼저 장르 목록을 보여준 다음 장르를 선택하게 하세요.
그리고 도서 번호를 입력받아 선택한 장르에게 도서를 검색하라고 요청하세요.
반환받은 도서 정보를 출력하세요.

void AppFindBookByNum(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    int bnum=0;
    Iterator seek = 0;
    Genre *genre = 0;
    Book *book = 0;
    AppListGenre(app);
    printf("검색할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    printf("도서 번호를 입력하세요.\n");
    scanf_s("%d", &bnum);
    genre = (Genre *)(*seek);
    book = GenreFindBookByNum(genre,bnum);
    if(book)
    {
         BookView(book);
    }
    else
    {
        printf("도서를 찾지 못했습니다.\n");
    }
}

111. 도서 관리 프로그램 – 제목으로 검색

C언어 도서 관리프로그램 - 제목으로 검색 기능 구현

도서 제목으로 검색 기능은 검색에 사용한 키가 도서 번호 대신 도서 제목으로 변경한 것 말고는 차이가 없어요.

Book 헤더 파일에 도서 제목을 반환하는 함수를 선언하고 소스 파일에 구현하세요.

const char *BookGetTitle(Book *book)
{
    return book->title;
}

Genre 헤더 파일에 도서 제목으로 도서 검색 함수를 선언하고 소스 파일에 구현하세요.

Book *GenreFindBookByTitle(Genre *genre,const char *title)
{
    Iterator seek;
    Iterator end;
    Book *book=0;
    const char *stitle = 0;

    seek= EHArrayBegin(genre->books);
    end= EHArrayEnd(genre->books);

    GenreView(genre);
    for(  ;seek != end; ++seek)
    {
        book = (Book *)(*seek);
        stitle = BookGetTitle(book);
        if(strcmp(stitle,title)==0)
        {
            return book;
        }
    }
    return 0;
}

App에 도서 제목으로 검색 기능도 구현하세요.
도서 번호로 검색과 큰 차이가 없으므로 설명은 생략할게요.

void AppFindBookByTitle(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    char title[MAX_TNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    Book *book = 0;

    AppListGenre(app);
    printf("검색할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    printf("도서 제목을 입력하세요.\n");
    gets_s(title,MAX_TNAME_LEN);
    genre = (Genre *)(*seek);
    book = GenreFindBookByTitle(genre,title);
    if(book)
    {
        BookView(book);
    }
    else
    {
        printf("도서를 찾지 못했습니다.\n");
    }
}

112. 도서 관리 프로그램 – 장르 삭제

C언어 도서 관리 프로그램 - 장르 삭제 기능 구현

장르 삭제 시퀀스 다이어그램을 작성하기로 해요.
여기에서도 장르를 선택하는 부분까지는 같아요.
장르를 선택하였으면 선택한 장르를 소멸하는 함수를 호출하세요.
그리고 장르를 소멸하는 함수에서는 내부에서 생성하여 배열에 보관한 도서도 소멸해야 하는 것을 잊지 마세요.

C언어 도서 관리 프로그램 - 장르 삭제 시퀀스 다이어그램
장르 삭제 시퀀스 다이어그램

Book을 소멸하는 함수는 이미 구현한 것과 차이가 없어요.

Genre를 소멸하는 함수에서는 보관한 모든 도서를 소멸하는 부분을 추가하세요.
Genre에서는 소멸할 때 해제화 작업을 GenreTGenre에서 수행하므로 이 함수를 수정하세요.

void GenreTGenre(Genre *genre)
{
    Book *book=0;
    Iterator seek= EHArrayBegin(genre->books);
    Iterator end= EHArrayEnd(genre->books);
    for(  ;seek != end; ++seek)
    {
        book = (Book *)(*seek);
        DeleteBook(book);
    }
    DeleteEHArray(genre->books);
}

App에서는 장르를 선택하여 Genre를 소멸하는 함수를 호출하세요.
그리고 시퀀스 다이어그램에서는 표시하지 않았지만 장르를 보관하는 배열에서 장르를 삭제하세요.

void AppRemoveGenre(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    AppListGenre(app);
    printf("삭제할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    genre = (Genre *)(*seek);
    DeleteGenre(genre);
    EHArrayErase(app->genres,seek);
}

그리고 AppTApp에서 프로그램 종료 전에 모든 장르를 삭제하는 부분도 작성합시다.

void AppTAppGenre(App *app)
{
    Iterator seek= EHArrayBegin(app->genres);  
    Iterator end= EHArrayEnd(app->genres);
    Genre *genre = 0;
    for(  ;seek != end; ++seek)
    {
        genre = (Genre *)(*seek);
        DeleteGenre(genre);
    }
    DeleteEHArray(app->genres);
}