[자료구조 - C언어] 자료구조 제14강: Music Library Program(10)

2022. 11. 8. 17:01CS/자료구조

728x90

//공부 기록용 포스팅입니다. 틀린 부분이 있을 경우 댓글로 알려주시면 감사합니다! 😎

 

 

0. 실행 예

  • Data file name? - 프로그램을 실행하면 어떤 데이터 파일을 load 할지 물어본다.
    • 입력 없이 Enter를 치면 데이터 파일로부터 데이터를 읽지 않고 프로그램을 실행
  • status - 저장된 모든 노래의 번호, 가수, 제목, 파일의 경로명을 출력
    • 노래의 번호는 입력 순서대로 번호 할당
    • 출력 시 가수 이름 알파벳 순으로 출력
      • 동일한 가수 이름이면 노래 제목으로 알파벳 순으로 출력
  • add - 가수 이름, 제목, 파일명으로 추가
    • 파일명은 지정하지 않아도 된다.
  • search - 가수 이름과 노래 제목으로 검색
    • 제목 없이 가수 이름만 검색해도 된다.
  • play 4 - 4번 노래를 play
  • remove 6 - 6번 노래를 목록에서 삭제
  • save as my_collection.txt - 목록을 파일에 저장
  • exit - 종료
  • 파일 형식
    가수#노래제목#경로#
    LESSERAFIM#Sour Grapes# #
    • 가수#노래제목#경로# 순서
    • #문자를 필드 간의 구분자
    • 존재하지 않는 항목의 경우 하나의 공백 문자로 표시
      • 모든 라인은 반드시 구분자로 끝난다.

 

1. 노래 삭제하기

1-1. void process_command() 수정하기

//main.c

void process_command(){
    ...

    else if(strcmp(command, "remove")==0)
        handle_remove();
    ...
}

//삭제할 노래의 번호가 필요 -> handle_play()와 유사
void handle_remove(){
    char *id_str = strtok(NULL, " ");
    int index = atoi(id_str);
    remove(index);
}

1-2. SNode의 기본 구조

  • Song을 삭제하려면
    • index_directory 아래의 단뱡향 연결 리스트 SNode를 삭제할 뿐만 아니라
    • artist_directory 아래의 양방향 연결리스트 SNode 또한 삭제해야 한다.
  • 그래서 Song을 삭제하려면
    • index_directory 아래의 단뱡향 연결 리스트 SNode를 삭제할 뿐만 아니라
      • SNode는 단방향 연결리스트
        • 단방향 연결 리스트에서 노드를 삭제하려면 이전 노드의 주소가 필요하다.
        • 단방향 연결 리스트에서는
            • remove first
          //삭제하고자 하는 노드 p
          //삭제하고자 하는 노드의 이전 노드 q
          if(q==NULL){
             헤드노드 = p->next;
          }
            • remove after q
          else{
              q->next = p->next;
          }
    • artist_directory 아래의 양방향 연결 리스트 SNode 또한 삭제해야 한다.
      • SNode는 양방향 연결 리스트
        • 양방향 연결 리스트에서 노드를 삭제하려면 이전 노드의 주소는 필요 없다.
        • 양방향 연결 리스트에서는
          • unique node(하나의 노드만 존재)
            //양방향 리스트의 첫번째 노드 first = p->head;
            //양방향 리스트의 마지막 노드 last = p->tail;
            
            if(first == p && last == p){
                first = NULL;
                last = NULL;
                free(p);
            }
          • remove first
            else if(first == p){
                p->next->prev = NULL;
                first = p->next;
                free(p);
            }
          • remove last
            else if(last == p){
                p->prev->next = NULL;
                last = p->prev;
                free(p);
            }
          • in the middle
            else{
                p->prev->next = p->next;
                p->next->prev = p->prev;
            }
    • 그런 다음에 Song을 삭제한다.

1-3. void remove(int index)

//library.h

void remove(int index);
//library.c

void remove_(int index){
    //find the song
    //SNode는 단방향 연결리스트
    //~ 단방향 연결리스트에서는 삭제하려는 이전 노드의 주소가 필요
    SNode *q = NULL;                                                                                    //previous to p
    SNode *p = index_directory[index % SIZE_INDEX_TABLE];    //head node
    while(p != NULL && p->song->index != index){
        q = p;
        p = p->next;
    }


    //단방향 연결리스트
    //either empty list or not exist
    if(p==NULL){
        printf("No such song exists.\n");
        return;
    }

    //find the song
    Song *ptr_song = p->song;

    if(q==NULL){     // remove first
        index_directory[index % SIZE_INDEX_TABLE] = p ->next;
        //p = p->next 금지
        //p와 index_directory[index % SIZE_INDEX_TABLE]은 동일한 값을 가르는 별개의 변수
    }
    else{            // - remove after q
        q->next = p->next;
    }
    free(p);


    //Song 객체를 통해 Artist의 주소는 알아도, SNode의 주소는 바로 알 수 없다.
    //Artist의 SNode를 검색해서 알아야 한다.
    //find the snode in the double linked list of ptr_artist
    Artist *ptr_artist = ptr_song->artist;
    SNode *ptr_snode = find_snode(ptr_artist, ptr_song->title);
    if(ptr_snode == NULL){
        printf("Not found snode - something wrong.\n");
        return;
    }

    //양방향 연결리스트
    remove_snode(ptr_artist, ptr_snode);
    destory_song(ptr_song);
}

void remove_snode(Artist *ptr_artist, SNode *ptr_snode){

    SNode *first = ptr_artist->head;
    SNode *last = ptr_artist->tail;

    //unique node
    if(first == ptr_snode && last == ptr_snode){
        first=NULL;
        last=NULL;
    }
    //remove first
    else if(first == ptr_snode){
        ptr_snode->next->prev = NULL;
//        first = ptr_snode->next;  - 유의
        ptr_artist->head = ptr_snode->next;
    }
    //remove last
    else if(last == ptr_snode){
        ptr_snode->prev->next = NULL;
//        last = ptr_snode->prev;    - 유의
        ptr_artist->tail = ptr_snode->prev;
    }
    //in the middle
    else{
        ptr_snode->next->prev = ptr_snode->prev;
        ptr_snode->prev->next = ptr_snode->next;
    }
    free(ptr_snode);
}

void destory_song(Song *ptr_song){
    if(ptr_song->title != NULL)
        free(ptr_song->title);
    if(ptr_song->path != NULL)
        free(ptr_song->path);
    free(ptr_song);
}

1-3. 결과

 

2. 전체 코드

  • main.c
더보기
//
//  main.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "string_tools.h"
#include "library.h"

#define BUFFER_LENGTH 200


void process_command();
void handle_add();
void handle_load();
void handle_search();
void handle_play();
void handle_save();
void handle_remove();


int main(){
    initialize();
    handle_load();
    process_command();
}

void handle_load(){
    char buffer[BUFFER_LENGTH];
    
    printf("Data file name ?  ");
    
    //data 파일을 로드하지 않겠다
    if(read_line(stdin, buffer, BUFFER_LENGTH) <=0)
        return;
    
    char filePath[BUFFER_LENGTH] = "/~파일주소~/";
    
    char *file = NULL;
    file = strcat(filePath, buffer);

    FILE *fp = fopen(filePath, "r");
//    File *fp = fopen(buffer, "r");
    //사용자가 입력한 파일이 존재하지 않는다면
    if (fp==NULL){
        printf("No such file exists. \n");
        return;
    }
    
    load(fp);
    fclose(fp);
    
    
}

void process_command(){
    
    char command_line[BUFFER_LENGTH];    //한 라인의 데이터를 읽어올 데이터 배열
    char *command;
    while(1){       //무한 루프
        printf("$ ");    //prompt 출력
        
        //사용자의 입력을 라인단위로 받음 - 실제로 읽은 길이를 리턴
        //stdin - 표준 입력 파일로 부터
        //리턴값이 0이하라면 사용자가 입력을 하지 않고 Enter
        if(read_line(stdin, command_line, BUFFER_LENGTH) <=0)
            continue;
        
        command = strtok(command_line, " ");
        if(strcmp(command, "add")==0)
            handle_add();
        else if(strcmp(command, "search")==0)
            handle_search();
        else if(strcmp(command, "remove")==0)
            handle_remove();
        else if(strcmp(command, "status")==0)
            status();
        else if(strcmp(command, "play")==0)
            handle_play();
        else if(strcmp(command, "save")==0){
            char *tmp = strtok(NULL, " ");
            if(strcmp(tmp, "as")!=0)
                continue;
            handle_save();
        }
        else if(strcmp(command, "exit")==0)
            break;
    }
}

void handle_save(){
    char *file_name = strtok(NULL, " ");
    FILE *fp = fopen(file_name, "w");
    save(fp);
    fclose(fp);
}


void handle_add(){
    
    char buffer[BUFFER_LENGTH];
    char *artist = NULL, *title = NULL, *path = NULL;
    
    printf("    Artist: ");
    if(read_line(stdin, buffer, BUFFER_LENGTH)>0)
        artist = strdup(buffer);        //buffer에 저장한 값을 복사해서 대입
    
    printf("    Title: ");
    if(read_line(stdin, buffer, BUFFER_LENGTH)>0)
        title = strdup(buffer);
    
    printf("    Path: ");
    if(read_line(stdin, buffer, BUFFER_LENGTH)>0)
        path = strdup(buffer);
    
    
    //테스트 삼아 컴파일 에러 점검
//    printf("%s  %s  %s\n", artist, title, path);
    
    //add to the music library
    add_song(artist, title, path);
}

void handle_search(){
    char name[BUFFER_LENGTH], title[BUFFER_LENGTH];
    printf("    Artist: ");
    if(read_line(stdin, name, BUFFER_LENGTH) <= 0){
        printf("    Artist name required.\n");
        return;
    }

    //제목을 입력하면 해당 노래만 출력
    //제목을 입력하지 않으면 가수이름으로 검색 ~ 가수의 모든 노래 출력
    printf("    Title: ");
    int title_len = read_line(stdin, title, BUFFER_LENGTH);

    if(title_len <= 0)
        //이름으로만 검색
        search_song_artist(name);
    else
        search_song(name, title);
}

void handle_play(){
    //tokenizing을 계속하는 상황
    char *id_str = strtok(NULL, " ");
    int index = atoi(id_str);
    play(index);
}

//삭제할 노래의 번호가 필요 -> handle_play()와 유사
void handle_remove(){
    char *id_str = strtok(NULL, " ");
    int index = atoi(id_str);
    remove_(index);
}
  • library.h
더보기
//
//  library.h


#ifndef LIBRARY_H
#define LIBRARY_H

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


//타입정의는 일반적으로 헤더파일에 정의
//순환적인 순서 -> 구조체를 정의하기 전에 typedef를 먼저
typedef struct song Song;
typedef struct snode SNode;
typedef struct artist Artist;


struct song{
    Artist *artist;
    char *title;
    char *path;
    int index;
};

struct snode{
    struct snode *next, *prev;
    Song *song;    //SNode는 하나의 Song을 거느리고 있다
};

struct artist {
    char *name;
    struct Artist *next;
    SNode *head, *tail;
};

void initialize();
void add_song(char *artist, char *title, char *path);
void status();
void load(FILE *fp);
void search_song(char *artist, char *title);
void search_song_artist(char *artist);
void play(int index);
void save(FILE *fp);
void remove_(int index);

#endif /* LIBRARY_H */
  • library.c
더보기
//
//  library.c


#include "library.h"
#include "string_tools.h"
//#include <windows.h>


#define NUM_CHARS 256    //한 바이트가 가질 수 있는 모든 값(2^8)
#define SIZE_INDEX_TABLE 100
#define BUFFER_LENGTH 200


//공유하지 않는 다면 소스코드 파일에 정의
//영어 뿐만 아니라 한글까지 표현 && 한 글자로 이니셜 => 256
Artist *artist_directory[NUM_CHARS];
int num_index = 0;

SNode *index_directory[SIZE_INDEX_TABLE];

//add하기 전 초기화 -> main에서 호출
void initialize(){
    for(int i=0; i<NUM_CHARS; i++)
        artist_directory[i] = NULL;

    for(int i=0; i<SIZE_INDEX_TABLE; i++)
        index_directory[i] = NULL;
}

void load(FILE *fp) {
    char buffer[BUFFER_LENGTH];    //한 라인의 데이터를 읽어올 데이터 배열
    char *name, *title, *path;
    while(1){       //무한 루프
        //끝에 도달 - 종료
        if(read_line(fp, buffer, BUFFER_LENGTH) <=0)
            break;

        name = strtok(buffer, "#");
        if(strcmp(name, " ")==0)
            name = NULL;
        else
            name = strdup(name);

        title = strtok(NULL, "#");
        if(strcmp(title, " ")==0)
            title = NULL;
        else
            title = strdup(title);

        path = strtok(NULL, "#");
        if(strcmp(path, " ")==0)
            path = NULL;
        else
            path = strdup(path);

//        printf("%s %s % s\n", name, title, path);
        add_song(name, title, path);
    }
}



Artist *find_artist(char *name){
    //이름의 첫 글자를 배열 인덱스로
    Artist *p = artist_directory[(unsigned char)name[0]];     //인덱스의 첫 번째 artist
    //name[0]: 00000000 ~ 11111111 사이의 값 -> 배열의 인덱스
    //(unsigned char): 8비트의 첫 번째 자리가 1로 시작하는 경우 -> 음수 를 방지하기 위해

    //이름은 알파벳순 정렬이기 때문에 strcmp 값이 적을 때까지만 루프를 순환
    // strcmp(p->name, name) != 0 : 조건은 같은 이름을 찾을 때 까지 루프를 순환
    while(p!=NULL && strcmp(p->name, name) < 0)
        p = p->next;

    if(p!=NULL && strcmp(p->name, name) == 0)
        return p;
    else
        return NULL;
}

Artist *create_artist_instance(char *name){
    Artist *ptr_artist = (Artist *)malloc(sizeof(Artist));
    ptr_artist->name = name;
    ptr_artist->head = NULL;
    ptr_artist->tail = NULL;
    ptr_artist->next = NULL;
    return ptr_artist;
}

Artist *add_artist(char *name){
    Artist * ptr_artist = create_artist_instance(name);
    //p는 head 노드의 주소를 가지게 됨
    Artist *p = artist_directory[(unsigned char)name[0]];    //first node
    Artist *q = NULL;

    //ordered_list
    while(p!=NULL && strcmp(p->name, name) <0 ){
        q = p;
        p = p->next;
    }

    //empty list
    if(p==NULL && q==NULL){
        artist_directory[(unsigned char)name[0]] = ptr_artist;    //유일한 노드
    }
    //add at the front: 새로운 노드를 제일 앞에
    else if(q==NULL){
        ptr_artist->next = artist_directory[(unsigned char)name[0]];
        artist_directory[(unsigned char)name[0]] = ptr_artist;
    }
    else{
        //add_after
        ptr_artist->next = p;
        q->next = ptr_artist;

    }

    return ptr_artist;

    /* if add_first
    ptr_artist -> next = artist_directory[(unsigned char)name[0]];
    artist_directory[(unsigned char)name[0]]; = ptr_artist;
  */
}

Song * create_song_instance(Artist *ptr_artist, char *title, char *path){
    Song *ptr_song = (Song*)malloc(sizeof(Song));
    ptr_song->artist = ptr_artist;
    ptr_song->title = title;
    ptr_song->path = path;
    ptr_song->index = num_index;    //모든 노래들이 서로 다른 index값을 가져야 한다
    num_index++;

    return ptr_song;
}
void print_artist(Artist *ptr_artist);
void insert_node(Artist *ptr_artist, SNode *ptr_snode){
    //ordered by title
    SNode *p = ptr_artist->head;
    while(p!=NULL && strcmp(p->song->title, ptr_snode->song->title)<0)
        p=p->next;

    //add ptr_snode before p
    //case 1. empty
    if(ptr_artist->head == NULL){
        ptr_artist->head = ptr_snode;
        ptr_artist->tail = ptr_snode;
    }
    //case 2. at the front
    else if(p==ptr_artist->head){
        ptr_snode->next = ptr_artist->head;
        ptr_artist->head->prev = ptr_snode;
        ptr_artist->head = ptr_snode;
    }
    //case 3. at the end
    else if(p==NULL){
        ptr_snode->prev = ptr_artist->tail;
        ptr_artist->tail->next = ptr_snode;
        ptr_artist->tail =ptr_snode;
    }
    //case 4. in the middle
    else{
        ptr_snode->next = p;
        ptr_snode->prev = p->prev;
        p->prev->next = ptr_snode;
        p->prev = ptr_snode;
    }
}

void insert_to_index_directory(Song *ptr_song){
    SNode *ptr_snode = (SNode *)malloc(sizeof(SNode));
    ptr_snode->song = ptr_song;
    ptr_snode->next = NULL;
    ptr_snode->prev = NULL;    //unused

    int index = ptr_song->index % SIZE_INDEX_TABLE;

    //insert the snode into the single linked list at index_directory[index]
    //인덱스 디렉토리에 인덱스 칸에 메달려 있는 단방향 연결리스트 안에 ptr_snode가 가리키고 있는 노드를 insert
    //ex. 계산한 나머지가 2였다면 index_directory의 2번째 칸에 삽입

    SNode *p = index_directory[index];
    SNode *q = NULL;    //단방향 정렬된 연결리스트
    while(p!=NULL && strcmp(p->song->title, ptr_song->title) < 0){
        q = p;
        p = p->next;
    }

    //add_first
    if(q==NULL){
        ptr_snode->next = p;
        index_directory[index] = ptr_snode;
    }
    //add_after q
    else{
        ptr_snode->next = p;
        q->next = ptr_snode;
    }
}


void add_song(char *artist, char *title, char *path){
    //case 1. artist가 artist_directory에 이미 존재 -> song을 추가
    //case 2. 존재하지 않는 경우 -> artist를 추가 -> song 추가

    //artist가 존재하는지 부터 검색 - 존재하지 않으면 NULL 리턴
    Artist *ptr_artist = find_artist(artist);

    if(ptr_artist == NULL){
        //artist_directory에 artist 등록하고 주소 리턴하기
        ptr_artist = add_artist(artist);
    }

    //add the song to the artist pointed by ptr_artist
    //prt_artist는 값을 가지고, song을 add할 수 있다
    Song *ptr_song = create_song_instance(ptr_artist, title, path);
    //각각의 Song은 자신을 거느리고 있는 SNode를 가지고 있다, SNode는 이중연결리스트
    SNode *ptr_snode = (SNode *)malloc(sizeof(SNode));
    ptr_snode->song = ptr_song;
    ptr_snode->next = NULL;
    ptr_snode->prev = NULL;


    //ptr_artist에 ptr_snode 넣기
    insert_node(ptr_artist, ptr_snode);

    //index_directory에도 추가
    insert_to_index_directory(ptr_song);
}


void print_song(Song *ptr_song){
    printf("    %d: %s, %s\n", ptr_song->index, ptr_song->title, ptr_song->path);
}

//p가 가리키는 artist를 출력
void print_artist(Artist *p){
    printf("%s\n", p->name);
    SNode *ptr_snode = p->head;
    while(ptr_snode !=NULL){
        print_song(ptr_snode->song);
        ptr_snode=ptr_snode->next;
    }
}


void status(){
    for (int i=0; i<NUM_CHARS;i++){
            Artist *p = artist_directory[i];
        while(p!=NULL){
            print_artist(p);
            p=p->next;
        }
    }
}

//artist 이름과 노래 제목으로 snode를 찾는 함수 분리하기
SNode *find_snode(Artist *ptr_artist, char *title){
    SNode *ptr_snode = ptr_artist->head;
    //노래제목은 알파벳 순 정렬
    while(ptr_snode != NULL && strcmp(ptr_snode->song->title, title) < 0)
        ptr_snode = ptr_snode->next;

    if(ptr_snode != NULL && strcmp(ptr_snode->song->title, title) == 0)
        return ptr_snode;
    else
        return NULL;
}


void search_song(char *artist, char *title){
    Artist *ptr_artist = find_artist(artist);

    if(ptr_artist == NULL){
        printf("No such artist exists.\n");
        return;
    }

    SNode *ptr_snode = find_snode(ptr_artist, title);

    if(ptr_snode != NULL){
        printf("Found:\n");
        print_song(ptr_snode->song);
    }
    else{
        printf("No such song exists.\n");
        return;
    }
}

void search_song_artist(char *artist){
    Artist *ptr_artist = find_artist(artist);

    if(ptr_artist == NULL){
        printf("No such artist exists.\n");
        return;
    }

    printf("Found:\n");
    print_artist(ptr_artist);
}

//노래 번호로 노래 찾기
SNode *find_song(int index){
    SNode *ptr_snode = index_directory[index % SIZE_INDEX_TABLE];
    while(ptr_snode != NULL && ptr_snode->song->index != index)
        ptr_snode = ptr_snode->next;

    return ptr_snode;
}

void play(int index){
    SNode *ptr_snode = find_song(index);
    if(ptr_snode == NULL){
        printf("No such song exists.\n");
    }
    printf("Found the song: %s\n", ptr_snode->song->title);

//    ShellExecute(GetDesktopWindow(), "open", ptr_snode->song->path, NULL, NULL, SW_SHOW);
}

void save_song(Song *ptr_song, FILE *fp){

    if(ptr_song->artist != NULL)
        fprintf(fp, "%s#", ptr_song->artist->name);
    else
        fprintf(fp, " #");

    if(ptr_song->title != NULL)
        fprintf(fp, "%s#", ptr_song->title);
    else
        fprintf(fp, " #");

    if(ptr_song->path != NULL)
        fprintf(fp, "%s#\n", ptr_song->path);
    else
        fprintf(fp, " #\n");
}

void save_artist(Artist *p, FILE *fp){
    SNode *ptr_snode = p->head;
    while(ptr_snode !=NULL){
        save_song(ptr_snode->song, fp);
        ptr_snode=ptr_snode->next;
    }
}


void save(FILE *fp){
    //status는 모든 노래들에 대한 정보를 화면으로 출력
    //save는 그것을 파일로 출력

    for (int i=0; i<NUM_CHARS;i++){
            Artist *p = artist_directory[i];
        while(p!=NULL){
            save_artist(p, fp);
            p=p->next;
        }
    }
}


void remove_snode(Artist *ptr_artist, SNode *ptr_snode){

    SNode *first = ptr_artist->head;
    SNode *last = ptr_artist->tail;

    //unique node
    if(first == ptr_snode && last == ptr_snode){
        first=NULL;
        last=NULL;
    }
    //remove first
    else if(first == ptr_snode){
        ptr_snode->next->prev = NULL;
        first = ptr_snode->next;
    }
    //remove last
    else if(last == ptr_snode){
        ptr_snode->prev->next = NULL;
        last = ptr_snode->prev;
    }
    //in the middle
    else{
        ptr_snode->next->prev = ptr_snode->prev;
        ptr_snode->prev->next = ptr_snode->next;
    }
    free(ptr_snode);
}

void destory_song(Song *ptr_song){
    if(ptr_song->title != NULL)
        free(ptr_song->title);
    if(ptr_song->path != NULL)
        free(ptr_song->path);
    free(ptr_song);
}

void remove_(int index){
    //find the song
    //SNode는 단방향 연결리스트
    //~ 단방향 연결리스트에서는 삭제하려는 이전 노드의 주소가 필요
    SNode *q = NULL;                                                                                    //previous to p
    SNode *p = index_directory[index % SIZE_INDEX_TABLE];    //head node
    while(p != NULL && p->song->index != index){
        q = p;
        p = p->next;
    }


    //단방향 연결리스트
    //either empty list or not exist
    if(p==NULL){
        printf("No such song exists.\n");
        return;
    }

    //find the song
    Song *ptr_song = p->song;

    if(q==NULL){     // remove first
        index_directory[index % SIZE_INDEX_TABLE] = p ->next;
        //p = p->next 금지
        //p와 index_directory[index % SIZE_INDEX_TABLE]은 동일한 값을 가르는 별개의 변수
    }
    else{                   // - remove after q
        q->next = p->next;
    }
    free(p);


    //Song 객체를 통해 Artist의 주소는 알아도, SNode의 주소는 바로 알 수 없다.
    //Artist의 SNode를 검색해서 알아야 한다.
    //find the snode in the double linked list of ptr_artist
    Artist *ptr_artist = ptr_song->artist;
    SNode *ptr_snode = find_snode(ptr_artist, ptr_song->title);
    if(ptr_snode == NULL){
        printf("Not found snode - something wrong.\n");
        return;
    }

    //양방향 연결리스트
    remove_snode(ptr_artist, ptr_snode);
    destory_song(ptr_song);
}
  • string_tools.h
더보기
//
//  string_tools.h


//#pragma once    //헤더 파일이 중복 include 되는 것을 방지
#ifndef STRING_TOOLS_H    //중복 include 방지 정석적 방법
#define STRING_TOOLS_H

#include <stdio.h>

int read_line(FILE *fp, char str[], int n);

#endif /* STRING_TOOLS_H */
  • string_tools.c
더보기
//
//  string_tools.c


#include "string_tools.h"    //소스파일은 자신의 헤더파일을 include 


//매개변수: 파일 포인터, 읽어올 char 배열, 배열의 크기
int read_line(FILE *fp, char str[], int n){
    int ch, i = 0;
    //파일 포인터가 가리키고 있는 파일로 부터 한 char을 읽어서 ch에 저장
    //한 라인의 끝에 도달하거나 파일의 끝에 도달할 때 까지
    while((ch=fgetc(fp)) != '\n' && ch != EOF)
        if(i<n-1)
            str[i++] = ch;
    str[i] = '\0';
    //실제로 읽은 글자수 리턴
    return i;
}

2-1. 전체 결과

Data file name ?  tmpdata.txt
$ status
iu
    0: twenty-three, C://music/twenty-three.mp4
nct127
    1: Cherry Bomb, C://music/Cherry Bomb.mp4
txt
    3: Our Summer, C://music/Our Summer.mp4
    2: crown, C://music/crwon.mp4
$ add
    Artist: txt
    Title: ghosting
    Path: C://music/ghosting.mp4
$ search
    Artist: txt
    Title: 
Found:
txt
    3: Our Summer, C://music/Our Summer.mp4
    2: crown, C://music/crwon.mp4
    4: ghosting, \343\205\343\205C://music/ghosting.mp4
$ search
    Artist: nct127
    Title: Cherry Bomb
No such song exists.
$ search
    Artist: nct127
    Title: Cherry Bomb
Found:
    1: Cherry Bomb, C://music/Cherry Bomb.mp4
$ play 0
Found the song: twenty-three
$ remove 3
$ search
    Artist: txt
    Title: 
Found:
txt
    2: crown, C://music/crwon.mp4
    4: ghosting, \343\205\343\205C://music/ghosting.mp4
$ add
    Artist: txt
    Title: magic
    Path: 
$ status
iu
    0: twenty-three, C://music/twenty-three.mp4
nct127
    1: Cherry Bomb, C://music/Cherry Bomb.mp4
txt
    2: crown, C://music/crwon.mp4
    4: ghosting, \343\205\343\205C://music/ghosting.mp4
    5: magic, (null)
$ save as tmpdata2.txt
$ exit
Program ended with exit code: 0

 

 

 

 


부경대학교 권오흠 교수님의 [c로 배우는 자료구조 및 여러 가지 예제 실습] 강의 정리입니다. 감사합니다.

https://www.youtube.com/watch?time_continue=2302&v=yJs5N_dlfSg&feature=emb_title 

 

728x90