C언어/디딤돌 C언어 예제

[C언어 소스] 장르별 도서 관리 프로그램

언제나휴일 2016. 12. 4. 19:24
반응형

[C언어 소스] 장르별 도서 관리 프로그램


장르별 도서 관리 프로그램.zip



실습 시나리오

프로젝트 : 장르별 도서 관리 프로그램
 
개요
장르별 도서 관리 프로그램은 콘솔에서 동작하는 응용 프로그램입니다.
 
프로그램 흐름
프로그램을 시작하면 초기 작업으로 파일에 저장한 정보를 로딩합니다.
만약 파일이 없거나 비어있을 때는 초기 작업은 생략합니다.
 
초기 작업을 수행 후에는 최종 사용자에게 메뉴를 선택하게 하여 선택한 기능을 수행하는 것을 반복합니다.
메뉴에는 장르 추가, 장르 삭제, 전체 장르 보기, 특정 장르의 도서 목록 보기, 도서 추가, 도서 일련 번호로 검색, 도서 이름으로 검색, 전체 도서  보기, 프로그램 종료를 선택할 있습니다.
만약 최종 사용자가 프로그램 종료를 선택하면 상호 작용을 끝냅니다.
 
최종 사용자와 상호 작용이 끝나면 모든 장르 정보와 도서 정보를 파일에 저장하고 기존에 파일에 있던 내용에 덮어 씁니다.
 
장르 추가에서는 같은 이름의 장르는 추가하지 않게 합시다.
그리고 장르를 삭제할 장르 도서들도 같이 삭제합니다.
도서 추가에서는 장르를 선택한 후에 도서를 추가합니다.
도서의 일련 번호는 장르에 추가한 도서의 번호로 특정 장르 내에서 도서를 구분하는 키입니다.
도서 일련 번호로 검색 기능은 최종 사용자가 장르를 선택한 후에 도서 일련 번호를 입력하여 검색합니다.
도서 이름으로 검색 기능에서는 같은 이름의 모든 도서 정보를 출력합니다.
전체 도서 보기에서는 모든 장르와 장르 모든 도서 정보를 출력합니다.
 
장르 정보
장르 정보에는 장르 일련 번호와 장르 이름과 장르 내에 보관한 도서 수가 있습니다.
 
도서 정보
도서 정보에는 도서 일련 번호, 도서명, 저자 이름이 있습니다.

그리고 도서 일련 번호는 장르 내에 도서를 추가할 순서대로 부여하는 번호입니다.


소스 코드

// ehcommon.h

#pragma once

typedef enum _key key;

enum _key

{

    NO_DEFINED, F1, F2, F3, F4, F5, F6, F7, F8, F9,F10, ESC

};

void clrscr();

int getkey();


//ehcommon.c

#pragma warning(disable:4996)

#include "ehcommon.h"

#include <conio.h>

#include <stdio.h>

#include <process.h>

void clrscr()

{

    system("cls");

}

 

int getkey()

{

    int key = 0;

    key = getch();

    if(key == 27)

    {

        return ESC;

    }

    if(key == 0)

    {

        key = getch();

        switch(key)

        {

        case 59: return F1;case 60: return F2;case 61: return F3;case 62: return F4;

        case 63: return F5;case 64: return F6;case 65: return F7;case 66: return F8;

        case 67: return F9; case 68: return F10;

        }

    }

    return NO_DEFINED;

}  


// EHArray.h

#pragma once

typedef struct _EHArray EHArray;

typedef void *Element; //요소 형식명을 Element로 정의

typedef Element * Iterator;

struct _EHArray

{

    Element *base; //저장소의 위치 정보

    int capacity;     //현재 저장소의 크기

    int size;           //현재 보관한 요소 개수

};

 

EHArray *NewEHArray(int init_capa,Element init_value); //동적으로 배열 생성

void DeleteEHArray(EHArray *arr); //배열 소멸

int EHArrayGetCapacity(EHArray *arr); //저장소의 크기 가져오기

int EHArrayGetSize(EHArray *arr);       //보관한 요소 개수 가져오기

void EHArrayPushBack(EHArray *arr,Element data); //순차적으로 자료 보관

Element EHArrayGetAt(EHArray *arr,int index); //보관한 요소 가져오기

void EHArraySetAt(EHArray *arr,int index, Element data); //보관한 요소 설정하기

Iterator EHArrayBegin(EHArray *arr); //저장소의 시작 위치

Iterator EHArrayEnd(EHArray *arr); //저장소의 마지막 위치(보관할 위치)

void EHArrayErase(EHArray *arr,Iterator it);//보관한 요소 제거하기


// EHArray.c

#include "EHArray.h"

#include <stdlib.h>

 

void EHArrayEHArray(EHArray *arr,int init_capa,Element init_value);

void EHArrayReserve(EHArray *arr,int capacity);

void EHArrayPushBacks(EHArray *arr,int n,Element value);

void EHArrayTEHArray(EHArray *arr);

 

EHArray *NewEHArray(int init_capa,Element init_value)

{

    EHArray *arr = (EHArray *)malloc(sizeof(EHArray));

    EHArrayEHArray(arr,init_capa,init_value);

    return arr;

 

void EHArrayEHArray(EHArray *arr,int init_capa,Element init_value)

{

    arr->base = 0;

    arr->capacity = 0;

    arr->size = 0;

    if(init_capa>0)

    {

        EHArrayReserve(arr,init_capa);

        EHArrayPushBacks(arr,init_capa,init_value);

    }

}

void EHArrayReserve(EHArray *arr,int capacity)

{

    arr->base = (Element *)realloc(arr->base,sizeof(Element)*capacity);

    arr->capacity = capacity;

}

void EHArrayPushBacks(EHArray *arr,int n,Element value)

{

    int i = 0;

    for(i=0;i<n;i++)

    {

        EHArrayPushBack(arr,value);

    }

}

void DeleteEHArray(EHArray *arr)

{

    EHArrayTEHArray(arr);

    free(arr);

 

void EHArrayTEHArray(EHArray *arr)

{

    if(arr->base)

    {

        free(arr->base);

    }

}

int EHArrayGetCapacity(EHArray *arr)

{

    return arr->capacity;

}

int EHArrayGetSize(EHArray *arr)

{

    return arr->size;

}

 

 

void EHArrayPushBack(EHArray *arr,Element data)

{

    if(arr->capacity == arr->size)

    {

        if(arr->capacity)

        {

            EHArrayReserve(arr,arr->capacity*2);

        }

        else

        {

            EHArrayReserve(arr,1);

        }

    }

    arr->base[arr->size] = data;

    arr->size++;

}

Element EHArrayGetAt(EHArray *arr,int index)

{

    if((index>=0)&&(index<arr->size))

    {

        return arr->base[index];

    }

    return 0;

}

void EHArraySetAt(EHArray *arr,int index, Element data)

{

    if((index>=0)&&(index<arr->size))

    {

        arr->base[index] = data;

    }

}

Iterator EHArrayBegin(EHArray *arr)

{

    return arr->base;  

}

Iterator EHArrayEnd(EHArray *arr)

{

    return arr->base + arr->size;

}

void EHArrayErase(EHArray *arr,Iterator it)

{

    Iterator end;

    arr->size--;

    end = arr->base + arr->size;

    for(  ; it != end; it++)

    {

        (*it) = *(it+1);

    }

}

 


// Book.h

#pragma once

#include <stdio.h>

typedef struct _Book Book;

#define MAX_TNAME_LEN     100

#define MAX_ANAME_LEN 20

struct _Book

{

    char title[MAX_TNAME_LEN+1];

    char author[MAX_ANAME_LEN+1];

    int bnum;

};

Book *NewBook(int bnum,const char *title,const char *author);

Book *NewBook2(FILE *fp);

void DeleteBook(Book *book);

void BookView(Book *book);

int BookGetNum(Book *book);

const char *BookGetTitle(Book *book);

void BookSerialize(Book *book,FILE *fp);


//Book.c

#pragma warning(disable:4996)

#include "Book.h"

#include <stdlib.h>

#include <string.h>

#include <stdio.h>

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;

}

void BookDeserialize(Book *book,FILE *fp);

Book *NewBook2(FILE *fp)

{

    Book *book = 0;

    book = NewBook(0,"","");

    BookDeserialize(book,fp);

    return book;

}

void BookDeserialize(Book *book,FILE *fp)

{

    fread(book,sizeof(Book),1,fp);

}

 

 

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);

}

void DeleteBook(Book *book)

{

    free(book);

}

void BookView(Book *book)

{

    printf("제목:%s\n",book->title);

    printf("\t도서번호:%d 저자명:%s\n",book->bnum,book->author);

}

int BookGetNum(Book *book)

{

    return book->bnum;

}

 

const char *BookGetTitle(Book *book)

{

    return book->title;

}

void BookSerialize(Book *book,FILE *fp)

{

    fwrite(book,sizeof(Book),1,fp);

}


// Gerne.h

#pragma once

#include "Book.h"

#include "EHArray.h"

typedef struct _Genre Genre;

#define MAX_GNAME_LEN 20

struct _Genre

{

    char name[MAX_GNAME_LEN+1];

    int gnum;

    int last_bnum;

    EHArray *books;

};

Genre *NewGenre(int gnum,const char *gname);

Genre *NewGenre2(FILE *fp);

void DeleteGenre(Genre *genre);

const char *GenreGetName(Genre *genre);

void GenreView(Genre *genre);

void GenreAddBook(Genre *genre,const char *title,const char *author);

void GenreViewAll(Genre *genre);

Book *GenreFindBookByNum(Genre *genre,int bnum);

Book *GenreFindBookByTitle(Genre *genre,const char *title);

void GenreSerialize(Genre *genre,FILE *fp);


//Genre.c

#pragma warning(disable:4996)

#include "Genre.h"

#include <stdlib.h>

#include <string.h>

#include <stdio.h>

 

void GenreGenre(Genre *genre,int gnum,const char *gname);

Genre *NewGenre(int gnum,const char *gname)

{

    Genre *genre = 0;

    genre = (Genre *)malloc(sizeof(Genre));

    GenreGenre(genre,gnum,gname);

    return genre;

}

void GenreGenre(Genre *genre,int gnum,const char *gname)

{

    genre->gnum = gnum;

    memset(genre->name,0,sizeof(genre->name));

    strncpy(genre->name,gname,MAX_GNAME_LEN);

    genre->books = NewEHArray(0,0);

    genre->last_bnum = 0;

}

void GenreDeserialize(Genre *genre,FILE *fp);

Genre *NewGenre2(FILE *fp)

{

    Genre *genre = 0;

    genre = NewGenre(0,"");

    GenreDeserialize(genre,fp);

    return genre;

}

void GenreDeserialize(Genre *genre,FILE *fp)

{

    Book *book=0;

    int i = 0;

    int n = 0;

    fread(genre->name,sizeof(genre->name),1,fp);

    fread(&(genre->gnum),sizeof(int),1,fp);

    fread(&(genre->last_bnum),sizeof(int),1,fp);

    fread(&n,sizeof(int),1,fp);

    for(i=0  ;i<n; i++)

    {

        book = NewBook2(fp);

        EHArrayPushBack(genre->books,book);

    }

}

 

void GenreTGenre(Genre *genre);

void DeleteGenre(Genre *genre)

{

    GenreTGenre(genre);

    free(genre);

}

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);

}

 

int GenreGetNum(Genre *genre)

{

    return genre->gnum;

}

 

const char *GenreGetName(Genre *genre)

{

    return genre->name;

}

void GenreView(Genre *genre)

{

    printf("장르 번호:%d 장르 이름:%s\n",genre->gnum,genre->name);

}

 

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);

}

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);

    }

}

 

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;

}

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;

}

void GenreSerialize(Genre *genre,FILE *fp)

{

    Iterator seek;

    Iterator end;

    Book *book=0;

    int n = 0;

 

    fwrite(genre->name,sizeof(genre->name),1,fp);

    fwrite(&(genre->gnum),sizeof(int),1,fp);

    fwrite(&(genre->last_bnum),sizeof(int),1,fp);

 

    n = EHArrayGetSize(genre->books);

    fwrite(&n,sizeof(int),1,fp);

    seek= EHArrayBegin(genre->books);

    end= EHArrayEnd(genre->books);

 

    for(  ;seek != end; ++seek)

    {

        book = (Book *)(*seek);

        BookSerialize(book,fp);

    }

}


//App.h

#pragma once

typedef struct _App    App;

#include "Genre.h"

#include "EHArray.h"

#include <stdio.h>

struct _App

{

    char fname[FILENAME_MAX];

    int last_gnum;

    EHArray *genres;

};

 

App *NewApp(const char *fname);

void AppRun(App *app);

void DeleteApp(App *app);


//App.c

#pragma warning(disable:4996)

#include "App.h"

#include "ehcommon.h"

#include <malloc.h>

#include <stdio.h>

#include <memory.h>

#include <string.h>

 

void AppApp(App *app,const char *fname);

void AppTApp(App *app);

void AppLoad(App *app);

void AppSave(App *app);

 

int AppSelectMenu(App *app);

void AppAddGenre(App *app);

void AppRemoveGenre(App *app);

void AppListGenre(App *app);

void AppListBookAtGenre(App *app);

void AppAddBook(App *app);

void AppFindBookByNum(App *app);

void AppFindBookByTitle(App *app);

void AppListAll(App *app);

 

App *NewApp(const char *fname)

{

    App *app = 0;

    app = (App *)malloc(sizeof(App));

    AppApp(app,fname);

    return app;

}

 

void AppApp(App *app,const char *fname)

{

    memset(app->fname,0,sizeof(app->fname));

    strncpy(app->fname,fname,FILENAME_MAX);

    app->genres = NewEHArray(0,0);

    app->last_gnum = 0;

    AppLoad(app);

    printf("아무 키나 누르세요.\n");

    getkey();

}

 

void AppDeserialize(App *app,FILE *fp);

void AppLoad(App *app)

{

    FILE *fp = 0;

    fp = fopen(app->fname,"r");

    if(fp)

    {

        AppDeserialize(app,fp);

    }

    else

    {

        printf("환영합니다.\n");

    }

}

void AppDeserialize(App *app,FILE *fp)

{

    int n = 0;

    int i = 0;

    Genre *genre=0;

    fread(&(app->last_gnum),sizeof(int),1,fp);

    fread(&n,sizeof(int),1,fp);

    for( i=0 ;i<n;i++)

    {

        genre = NewGenre2(fp);

        EHArrayPushBack(app->genres,genre);

    }

}

 

 

 

 

void AppRun(App *app)

{

    int key = 0;

    while((key = AppSelectMenu(app))!=ESC)

    {

        switch(key)

        {

        case F1: AppAddGenre(app); break;

        case F2: AppRemoveGenre(app); break;

        case F3: AppListGenre(app); break;

        case F4: AppListBookAtGenre(app); break;

        case F5: AppAddBook(app); break;

        case F6: AppFindBookByNum(app); break;

        case F7: AppFindBookByTitle(app); break;

        case F8: AppListAll(app); break;

        default: printf("잘못 선택하였습니다.\n"); break;

        }

        printf("아무 키나 누르세요.\n");

        getkey();

    }

}

int AppSelectMenu(App *app)

{

    clrscr();

    printf("장르별 도서관리 프로그램 \n");

    printf("F1:장르 추가 F2: 장르 삭제 F3: 전체 장르 보기\n");

    printf("F4: 특정 장르의 도서 목록 보기\n");

    printf("F5:도서 추가 F6: 도서 검색(일련번호) F7: 도서검색(제목)\n");

    printf("F8: 전체 도서 보기 ESC: 종료\n");

    return getkey();

}

 

Iterator AppFindGenre(App *app,const char *gname);

void AppAddGenre(App *app)

{

    char gname[MAX_GNAME_LEN+1]="";

    Iterator seek = 0;

    Genre *genre = 0;

 

    printf("%d번째 추가할 장르명을 입력하세요.\n",app->last_gnum+1);

    gets_s(gname,MAX_GNAME_LEN);

 

    seek = AppFindGenre(app,gname);

    if(seek != EHArrayEnd(app->genres))

    {

        printf("이미 존재하는 장르입니다.\n");

        return;

    }

    genre = NewGenre(app->last_gnum+1,gname);

    app->last_gnum++;

    EHArrayPushBack(app->genres,genre);

}

Iterator AppFindGenre(App *app,const char *gname)

{

    Iterator seek;

    Iterator end;

    Genre *sgenre=0;

    const char *sgname=0;

 

    seek = EHArrayBegin(app->genres);

    end = EHArrayEnd(app->genres);

 

    for(  ;seek != end; ++seek)

    {

        sgenre = (Genre *)(*seek);

        sgname = GenreGetName(sgenre);

        if(strcmp(sgname,gname)==0)

        {

            break;

        }

    }

    return seek;

}

 

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);

}

 

void AppListGenre(App *app)

{

    Iterator seek= EHArrayBegin(app->genres);

    Iterator end= EHArrayEnd(app->genres);

    Genre *sgenre=0;

    for(  ;seek != end; ++seek)

    {

        sgenre = (Genre *)(*seek);

        GenreView(sgenre);

    }

}

 

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);

}

 

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);

}

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");

    }

}

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");

    }

}

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);

    }

}

 

void DeleteApp(App *app)

{

    AppSave(app);

    AppTApp(app);

    free(app);

}

void AppTApp(App *app)

{

    DeleteEHArray(app->genres);

}

 

void AppSerialize(App *app,FILE *fp);

void AppSave(App *app)

{

    FILE *fp = 0;

    fopen_s(&fp, app->fname,"w");

    if(fp)

    {

        AppSerialize(app,fp);

    }

    else

    {

       printf("오류!!!데이터 저장 실패\n");

    }

}

 

void AppSerialize(App *app,FILE *fp)

{

    Iterator seek;

    Iterator end;

    int n = 0;

    Genre *genre=0;

    fwrite(&(app->last_gnum),sizeof(int),1,fp);

    n = EHArrayGetSize(app->genres);

    fwrite(&n,sizeof(int),1,fp);

    seek= EHArrayBegin(app->genres);

    end= EHArrayEnd(app->genres);

    for(  ;seek != end; ++seek)

    {

        genre = (Genre *)(*seek);

        GenreSerialize(genre,fp);

    }

}


//Program.c

#include "App.h"

#define DEF_FNAME    "member.ehd"

int main(int argc, char **argv)

{

    App *app = 0;

    if(argc != 2)

    {

        app = NewApp(DEF_FNAME);

    }

    else

    {

        app = NewApp(argv[1]);

    }

    AppRun(app);

    DeleteApp(app);

    return 0;

}


실행 결과

...생략할게요...



본문

[디딤돌 C언어] 101. 도서 관리 프로그램 시나리오

[디딤돌 C언어] 102. 도서 관리 프로그램요구 분석 정의

[디듬돌 C언어] 103. 도서 관리 프로그램 – 분석 결과를 코드로


반응형