15장 라이브러리를 활용한 애플리케이션

JongseokLee·2021년 7월 31일
0

C 프로그래밍 기초

목록 보기
15/15
post-thumbnail

15장 라이브러리를 활용한 애플리케이션

1. 회원관리 프로그램 구현

1) 이중 연결 리스트(doubly linked list) 구조

  • 연결 포인터 2개 사용(prev : 이전 연결 포인터, next : 다음 연결 포인터)
  • HEAD 노드는 next 연결 포인터만 사용하며, 첫 번째 노드를 가리킴
  • 첫 번째 노드는 next 연결 포인터만 사용하며, 두 번째 노드를 가리킴
  • 마지막 노드는 prev 연결 포인터만 사용

2) 사용 라이브러리

헤더파일설명사용함수
<stdio.h>표준 입출력 라이브러리printf(), scanf_s(), getchar()
<stdlib.h>표준 라이브러리(동적 메모리 관리, 난수발생 등calloc(), free()
<string.h>문자열 라이브러리strcmp()

헤더파일설명사용 함수
"DLL.h"사용자 정의 라이브러리(이중 연결 리스트 구현initialize_DLL(), printf_node(), new_node(), append_node(), insert_node(), delete_node(), search_node()

함수설명
initailize_DLL()이중 연결 리스트의 head 노드 생성
print_node()이중 연결 리스트의 모든 노드를 화면에 출력
new_node()새로운 노드 생성
append_node()새로운 노드를 이중 연결 리스트에 추가
insert_node()새로운 노드를 이중 연결 리스트에 삽입
delete_node()이중 연결 리스트에서 노드 삭제
search_node()이중 연결 리스트에서 노드 검색

2. 도서관리 프로그램 구현하기

1) 구현 개요

  • 이중 연결 리스트 활용하여 구현
  • 파일 저장 및 읽어오기 기능 구현
  • 노드의 순차적 검색 기능 구현
  • 노드를 수정하는 기능 구현
소스함수설명
read_book()파일에서 도서자료를 읽어와 이중 연결 리스트 생성
projectBook.cwrite_book()이중 연결 리스트를 파일로 저장
update_book()이중 연결 리스트의 등록, 수정, 삭제, 검색 메뉴 실행
"bookDLL.h"print_one_node()하나의 노드를 화면에 출력

3. 단원 실습

1) 이중 연결 리스트를 이용한 회원관리 프로그램을 활용하여 실행화면처럼 수정하시오.
2) 도서관리 프로그램과 동일한 기능을 하도록 수정하시오.

  • (1) 회원 자료 파일을 읽어오거나 저장하는 기능 추가
  • (2) 회원 자료를 순차적으로 검색하는 기능 추가
  • (3) 회원 정보를 수정하는 기능 추가

enum MAIN_MENU { END, READ, LIST, UPDATE, WRITE };
enum MAIN_MENU main_select;
enum UPDATE_MENU { EXIT, PREV, NEXT, INSERT, MODIFY, DELETE, SEARCH };
enum UPDATE_MENU update_select;

#include "DLLtotal.h"
void read_member();
void update_member();
void write_member();
char member_name[20] ="member.txt";

int main()
{
	NODE_t* data = NULL;
	initialize_DLL();  // 연결 리스트 생성(head 생성)

	while (head != NULL) {   // 연결 리스트가 생성되었으면 반복
		system("cls");   // 화면 지우기

		printf("=======================================================\n");
		printf("\t\t   회원관리 프로그램\n");
		printf("=======================================================\n");
		printf("1 : 회원 자료 읽어 오기\n");
		printf("2 : 회원 현황 보기\n");
		printf("3 : 회원 관리 하기\n");
		printf("4 : 회원 자료 저장 하기\n");
		printf("0 : 종료\n");
		printf(">> ");
		scanf_s("%d", &main_select);  // 메뉴선택
		getchar();
		if (main_select == END)	break;
		switch (main_select) {
		case READ:  // 회원 자료 읽어 오기
			read_member();
			getchar();
			break;
		case LIST:  // 회원 현황 보기
			print_node();
			getchar();
			break;
		case UPDATE: // 회원 관리하기
			update_member();
			break;
		case WRITE: // 회원 자료 저장 하기
			write_member();
			getchar();
			break;
		}
	}
}
void read_member() {
	printf("읽어올 회원 자료 파일 이름을 입력하세요 : ");
	scanf_s("%s", member_name, sizeof(member_name));
	getchar();

	NODE_t* data;
	FILE* file;
	if (fopen_s(&file, member_name, "rt") == 0) {  // 파일을 읽기 모드로 오픈
		int count = 0;
		while (1) {
			data = (NODE_t*)calloc(1, sizeof(NODE_t));
			int result = fscanf_s(file, "%s %d %s", data->name, sizeof(data->name), &data->age, data->phone, sizeof(data->phone));
			if (result != EOF) {  // 읽기 성공시 데이터 개수, 실패시 -1(EOF)
				append_node(data);
				count++;
				printf("%s %d %s\n", data->name, data->age, data->phone);
			}
			else break;
		}
		fclose(file);
		printf("[ %d ]개의 데이터를 읽었습니다.\n", count);
	}
	else {
		printf("%s 파일을 읽어오지 못했습니다.\n", member_name);
	}
}
void write_member() {

	NODE_t* data = head;
	FILE* file;
	if (fopen_s(&file, member_name, "wt") == 0) {  // 파일을 쓰기모드로 오픈
		int count = 0;
		while (data->next != NULL) {
			data = data->next;
			fprintf(file, "%s %d %s\n", data->name, data->age, data->phone);
			count++;
		}
		fclose(file);
		printf("[ %d ]개의 데이터를 저장하였습니다.\n", count);
	}
	else {
		printf("%s 파일을 저장하지 못했습니다.\n", member_name);
	}
}

void update_member() {
	NODE_t* data;
	current = head->next;     // 첫번째 회원을 현재 화면에 보는 회원으로 설정
	while (head != NULL) {   // 연결 리스트가 생성되었으면 반복
		system("cls");   // 화면 지우기
		printf("=======================================================\n");
		printf("\t\t   회원 관리 하기\n");
		printf("=======================================================\n");
		if (current != NULL) print_one_node(current);  // 현재 회원 화면 출력
		printf("1 : 이전 회원\n");
		printf("2 : 다음 회원\n");
		printf("3 : 회원 등록\n");
		printf("4 : 회원 수정\n");
		printf("5 : 회원 삭제\n");
		printf("6 : 회원 검색\n");
		printf("0 : 주 메뉴로 돌아가기\n");
		printf(">> ");
		scanf_s("%d", &update_select);  // 메뉴선택
		if (update_select == EXIT) break;
		if (current == NULL) {                     // 출력할 노드가 없으면 "이전","다음","수정","삭제", "검색" 기능 선택안되게 함.
			switch (update_select) {               //  "등록", "주메뉴로 돌아가기"는 가능
			case PREV:
			case NEXT:
			case MODIFY:
			case DELETE:
			case SEARCH:
				continue;
			}
		}
		switch (update_select) {
		case PREV:  // 이전 회원
			if (current->prev != NULL) current = current->prev;
			break;
		case NEXT:  // 다음 회원
			if (current->next != NULL) current = current->next;
			break;
		case INSERT: // 회원 등록
			data = new_node();    // 새로운 노드 입력받아서 생성
			if (head->next == NULL) append_node(data);  // 첫노드 추가
			else insert_node(data);  // 새로운 노드 삽입
			current = data;
			break;
		case MODIFY: // 회원 수정
			data = new_node();    // 새로운 노드 입력받아서 생성
			current->age = data->age;
			strcpy_s(current->phone, sizeof(current->phone), data->phone);
			free(data);
			break;
		case DELETE: // 회원 삭제
			delete_node();
			break;
		case SEARCH: // 회원 검색
			search_node();
			break;
		}
	}
}

---------------------------------------------------------------------

#pragma once
#includ<stdio.h>
#includ<stdlib.h>
#includ<string.h>

typedef struct MEMBER {
	char name[20];
	int age;
	char phone[20];
	struct MEMBER* prev;   // 이전 노드 연결 포인터
	struct MEMBER* next;   // 다음 노드 연결 포인터
} NODE_t;

NODE_t* head;   // 연결 리스트의 head
NODE_t* current; // 현재 화면에 표시되는 노드

void initialize_DLL() {                  // head 노드 생성
	head = (NODE_t*)calloc(1, sizeof(NODE_t));
	if (head == NULL) {
		printf("이중 연결 리스트를 생성하지 못했습니다!!\n");
		getchar();
	}
}
void print_node() {    // 이중 연결 리스트 전체 출력
	NODE_t* p = head;
	if (p->next != NULL) {
		printf("=======================================================\n");
		printf("이름\t\t나이\t전화번호\n");
		printf("=======================================================\n");
		do {
			p = p->next;
			printf("%-10s\t%4d\t%-s\n", p->name, p->age, p->phone);
		} while (p->next != NULL);
		printf("=======================================================\n");
	}
	else {
		printf("출력할 자료가 없습니다.\n");
	}
}
void print_one_node(NODE_t* data) {    // 하나의 노드만 출력
	if (data != NULL) {
		printf("=======================================================\n");
		printf("%10s [ %s ]\n", "이름", data->name);
		printf("%10s [ %d ]\n", "나이", data->age);
		printf("%10s [ %s ]\n", "전화번호", data->phone);
		printf("=======================================================\n");
	}
}
NODE_t* new_node() {  // 데이터 생성
	NODE_t* data = (NODE_t*)calloc(1, sizeof(NODE_t));
	if (data != NULL) {
		switch (update_select) {
		case INSERT:	// 회원 등록인 경우에만 회원 이름을 입력받음.
			printf("회원 이름을 입력하세요 : ");
			scanf_s("%s", data->name, sizeof(data->name));
		case MODIFY:  // 회원 수정인 경우에는 회원 이름을 입력받지 않음
			printf("나이를 입력하세요 : ");
			scanf_s("%d", &data->age);
			printf("전화번호를 입력하세요 : ");
			scanf_s("%s", data->phone, sizeof(data->phone));
			break;
		}
	}
	else {
		printf("메모리 할당 실패!\n");
		getchar();
	}
	return data;
}
void append_node(NODE_t* data) {   // 데이터 추가
	NODE_t* p = head;
	while (p->next != NULL)
		p = p->next;
	p->next = data;
	if (p != head) data->prev = p;    // 노드가 하나도 없을 경우에는 실행 안됨. 처음 추가되는 노드인 경우에는 NULL
}
void insert_node(NODE_t* data) {    // 데이터 삽입
	NODE_t* p = head;
	while (p->next != NULL) {           // 현재 위치 다음으로 삽입
		p = p->next;
		if (p == current) break;
	}

	if (p == head) {   // 첫노드로 삽입하는 경우
		data->next = p->next;
		data->next->prev = data;
		p->next = data;
	}
	else if (p->next == NULL) {  // 마지막노드로 삽입하는 경우
		data->prev = p;
		p->next = data;
	}
	else {  // 중간 노드로 삽입하는 경우
		data->next = p->next;
		data->next->prev = data;
		p->next = data;
		data->prev = p;
	}
}
void delete_node() {          // 데이터 삭제

	NODE_t* p = current;
	if (current->next != NULL) current = current->next;   // 현재 위치를 다음 노드로 설정
	else {
		if (current->prev != NULL) current = current->prev;  // 현재 위치를 이전 노드로 설정
		else current = NULL;   // 현재 위치를 설정 안함.(연결리스트에 노드가 없는 경우)
	}

	if (p->next == NULL && p->prev == NULL) {  // 노드가 한개인 경우
		head->next = NULL;
	}
	else if (p->next == NULL && p->prev != NULL) {  // 마지막 노드이면
		p->prev->next = NULL;
	}
	else if (p->prev == NULL && p->next != NULL) {  // 처음 노드이면
		p->next->prev = NULL;
		head->next = p->next;
	}
	else {   // 중간 노드이면
		p->next->prev = p->prev;
		p->prev->next = p->next;
	}
	free(p);

}
void search_node() {          // 데이터 검색
	char name[20];
	printf("검색하고자 하는 이름을 입력하세요 : ");
	scanf_s("%s", name, sizeof(name));
	getchar();

	NODE_t* p = head;
	while (p->next != NULL) {
		p = p->next;
		if (!strcmp(p->name, name)) {  // 이름으로 해당 노드 찾기
			current = p;   // 현재 찾은 노드를 현재 노드로 설정
			break;
		}
	}
}

<Result>

profile
DataEngineer Lee.

0개의 댓글