연결리스트 응용 라인 에디터
이 블로그의 코드들은 모두 'C언어로 쉽게 풀어쓴 자료구조'라는 책에서 가져왔다. 혼자 공부하기 위해서 써 놓는 혼자말과 코드들이니 자세한 것을 알고 싶다면 책을 사시길 바란다...
연결리스트를 응용한 라인 에디터다. 핵심적인 메서드의 경우에는 이미 앞서 모두 구현된 것을 가져왔다.
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #define MAX_CHAR_PER_LINE 1000 #define MAX_NAME 256 void warning(char*); void error(char*); #define FALSE 0 #define TRUE 1 typedef struct { char a[MAX_CHAR_PER_LINE]; }element; typedef struct { element data; struct ListNode* link; }ListNode; typedef struct { ListNode* head; int length; }LinkedListType; void insert_node(ListNode **phead, ListNode *p, ListNode *new_node){ if (*phead==NULL) { *phead = new_node; (*phead)->link = NULL; } else if (p == NULL) { new_node->link = (*phead)->link; (*phead)->link = new_node; } else { new_node->link = p->link; p->link = new_node; } } void remove_node(ListNode **phead, ListNode *p, ListNode *removed){ if (*phead == NULL) return; else if (p==NULL){ (*phead) = (ListNode*) (*phead)->link; }else{ p->link = removed->link; } free(removed); } void init(LinkedListType *list){ if (list == NULL) return; list->length = 0; list->head = NULL; } ListNode* get_node_at(LinkedListType *list, int pos){ if (pos < 0 || pos > list->length) return NULL; int i; ListNode *p = list->head; for (i=0; i<pos; i++) p = p->link; return p; } int get_length(LinkedListType *list){ return list->length; } void add(LinkedListType *list, int pos, element data){ if (pos < 0 || pos > list->length) return; ListNode *p = get_node_at(list, pos); ListNode *new_node = (ListNode*) malloc(sizeof(ListNode)); new_node->data = data; new_node->link = NULL; insert_node(&(list->head), p, new_node); list->length++; } void add_last(LinkedListType *list, element data){ add(list, get_length(list), data); } void add_first(LinkedListType *list, element data){ add(list, 0, data); } int is_empty(LinkedListType *list){ return list->length == 0; } void delete(LinkedListType *list, int pos){ //LinkedListType은 여기서 검사한다 if (is_empty(list) || pos > list->length) return; //ListNode는 다음 메서드에서 검사한다 ListNode *p = get_node_at(list, pos-1); remove_node(&(list->head), p, p != NULL ? (ListNode*) p->link : NULL); list->length--; } element get_entry(LinkedListType *list, int pos){ // if (is_empty(list) || pos > list->length) // return NULL; ListNode *p = get_node_at(list, pos); return p->data; } void clear(LinkedListType *list){ int i; for (i=0; i<list->length; i++) delete(list, i); } void display(LinkedListType *list){ int i; ListNode *p = list->head; printf("**********\n"); for (i=0; i<list->length; i++) { printf("%s",p->data.a); p = (ListNode*) p->link; } printf("**********\n"); } void warning(char *message){ fprintf(stderr, message); } void error(char *message){ fprintf(stderr, message); exit(1); } void help(){ printf("**********\n"); printf("i: 입력\n"); printf("d: 삭제\n"); printf("r: 파일읽기\n"); printf("w: 파일쓰기\n"); printf("q: 종료\n"); printf("**********\n"); } void read_file(LinkedListType *buffer){ char fname[MAX_NAME]; FILE *fd; element p; if (!is_empty(buffer)) { clear(buffer); } init(buffer); printf("파일 이름 : "); scanf("%s",fname); if ((fd=fopen(fname, "r"))==NULL) { warning("error"); return; } while (fgets(p.a, MAX_CHAR_PER_LINE, fd)) { add_last(buffer, p); } fclose(fd); display(buffer); } void write_file(LinkedListType *buffer){ char fname[MAX_NAME]; FILE *fd; element p; int i; printf("파일 이름 : "); scanf("%s",fname); if ((fd=fopen(fname, "w"))==NULL) { warning("error"); return; } for (i=0; i<get_length(buffer); i++) { p = get_entry(buffer, i); fputs(p.a, fd); } fclose(fd); display(buffer); } void delete_line(LinkedListType *buffer){ int position; if (is_empty(buffer)) { printf("못지움\n"); }else{ printf("지우고 싶은 라인번호를 입력 : \n"); scanf("%d",&position); delete(buffer, position); } display(buffer); } void insert_line(LinkedListType *buffer){ int position; char line[MAX_CHAR_PER_LINE]; element p; printf("입력행 번호 입력 : \n"); scanf("%d\n",&position); printf("내용을 입력 : "); fflush(stdin); // 남아있는 standard input을 비워줌 fgets(line, MAX_CHAR_PER_LINE, stdin); strcpy(p.a, line); // line에 있는 것을 p.a로 copy add(buffer, position, p); display(buffer); } void do_command(LinkedListType *buffer, char command){ switch (command) { case 'd': delete_line(buffer); break; case 'i': insert_line(buffer); break; case 'r': read_file(buffer); break; case 'w': write_file(buffer); break; case 'q': exit(1); break; } } int main(){ char command; LinkedListType buffer; init(&buffer); do{ help(); command = getchar(); do_command(&buffer, command); fflush(stdin); }while (command != 'q'); return 0; }
코드를 실행시키면 잘 돌아갈 것... 이라고 생각했으나. stdin 이 mac 환경에서 먹히질 않는다. 예를 들어 다음의 코드를 보자..
fgets(line, MAX_CHAR_PER_LINE, stdin);
..
이 때 fgets 는 stdin을 \n으로 먹어버린다. 왜냐하면 stdin에 무언가 남아있기 때문이다. 무엇이 남아있을까. 그것은 바로 \n이다. fflush(stdin)이 \n까지 비우질 못하고 있다. 이것은 다음의 코드로 확인할 수있다.
if ((c = getchar()) == '\n') printf("bingo!\n");
위의 코드를 fflush(stdin) 아래에 두고 돌려보면 걸리는 것(bingo!가 출력)을 알 수 있다. 즉, stdin이 flush가 되질 않고 \n이 남아있어서 input값이 존재하는 것으로 이해되어 코드가 실행된다. 참고로 맥환경에서만 그런 듯하니 윈도우계열이신분들은 그냥 넘어가시면 됩니다.
위의 코드를 집어넣으면 fflush가 되질 않던 \n이 getchar()로 먹어들어가서 잘 돌아간다. 한방에 해결하는 방법은 없는건지 ..
댓글 없음:
댓글 쓰기