YUIN

자료구조 5 [전화번호부.v2] 본문

자료구조

자료구조 5 [전화번호부.v2]

유_인 2023. 8. 22. 22:45

Main Idea: 자료구조는 phonebookv1과 동일하게 하되, 여기에 파일로 저장하고 로드하기, 알파벳 순으로 정렬하기 기능을 추가하도록 하자. 

 

1.  실행 예시

 

변경사항:

- 파일로부터 데이터를 읽어오는 부분에 대한 코딩 작업이 필요하다.

- status에 대한 정보를 불러들일 때, 항상 알파벳 순으로 정렬된 상태를 유지하도록 한다. 

- 마지막 부분에 save as "파일명"으로 저장하는데, 같은 파일명일 경우 기존의 내용을 덮어쓰게 되고, 다른 파일명을 입력할 경우 새로운 파일이 생성된다 (이 부분에 대한 별도의 코딩을 필요하지 않다).

- 자료구조는 phonebookv1과 동일하다.

 

 

2. main 함수

int main() {
	char command[BUFFER_SIZE];
	while (1) {
		printf("$ ");
		scanf("%s", command);

		if (strcmp(command, "read") == 0)
			load();
		else if (strcmp(command, "add") == 0)
			add();
		else if (strcmp(command, "find") == 0)
			find();
		else if (strcmp(command, "status") == 0)
			status();
		else if (strcmp(command, "delete") == 0)
			erase();
		else if (strcmp(command, "save") == 0)
			save();
		else if (strcmp(command, "exit") == 0)
			break;
	}
	return 0;
}

phonebookv1과 달라진 점이 있다면 read와 save 명령을 추가했고 각각을 처리하는 함수 load()와 save()를 추가했다는 점이다. 

 

 

3. load 함수 

void load() {
	char fileName[BUFFER_SIZE];
	char buf1[BUFFER_SIZE];
	char buf2[BUFFER_SIZE];

	scanf("%s", fileName);

	FILE* fp = fopen(fileName, "r");
	if (fp == NULL) {
		printf("Open failed.\n");
		return;
	}
	while ((fscanf(fp, "%s", buf1) != EOF)) {
		fscanf(fp, "%s", buf2);
		names[n] = strdup(buf1);
		numbers[n] = strdup(buf2);
		n++;
	}
	fclose(fp);
}

load 함수에서 파일명을 입력받는데, C 프로그램에서 파일에 접근하기 위해서는 먼저 파일을 열어야 하므로 fopen을 사용하여 파일을 열 수 있도록 해준다. fopen은 파일 포인터 fp를 리턴해주는데, 여기서의 fp의 타입은 FILE이다. 그리고 if문을 사용하여 파일을 여는데 실패했을 경에 대한 예외처리를 해준다. 

(while문)- fscanf를 통해 파일을 읽는데, 이때 EOF(end of file)이면 읽기를 멈춘다. 파일의 형식은 이름-전화번호일 것이므로 buf1에는 사용자의 이름이, buf2에는 전화번호가 저장돼 있을 것이다. 즉, 파일의 끝에 도달할 때까지 반복해서 이름과 전화번호를 읽어서 배열에 저장한다. 

fclose를 통해 파일을 닫아주도록 한다. 

 

4.  save 함수

void save() {
	int i;
	char fileName[BUFFER_SIZE];
	char tmp[BUFFER_SIZE];

	scanf("%s", tmp);
	scanf("%s", fileName);

	FILE* fp = fopen(fileName, 'w');
	if (fp == NULL) {
		printf("Open failed.\n");
		return;
	}
	for (i = 0; i < n; i++) {
		fprintf(fp, "%s %s\n", names[i], numbers[i]);
	}
	fclose(fp);
}

실행 예시에서 파일을 저장할 때 save as "파일명"으로 저장하게 했는데, save는 함수 이름이며, 따라서 명령을 읽으면 이 함수를 호출하게 된다. as는 필요없는 문자열이므로 그냥 무시하게 하고, 그 뒤에 오는 문자열인 파일명만 fileName으로 저장하게 된다. 

파일을 저장하기 위해선 파일을 열어야 하므로 fopen을 사용하는데, 파일에 쓸 때는 모드를 "w"로 하고 열어야 한다. 

 

5.  데이터 정렬된 상태로 유지하기

 

- bubblesort 등의 정렬(sorting) 알고리즘 사용하는 방법 -> 새로운 데이터가 계속적으로 추가되는 상황에서는 부적절하다. 

- 새로운 데이터가 추가될 때마다 제자리를 찾아서 삽입하는 방식

 

void add() {
	char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE];
	scanf("%s", buf1);
	scanf("%s", buf2);

	int i = n - 1;
	while (i >= 0 && strcmp(names[i], buf1) > 0) {
		names[i + 1] = names[i];
		numbers[i + 1] = numbers[i];
		i--;
	}
	names[i + 1] = strdup(buf1);
	numbers[i + 1] = strdup(buf2);
	n++;

	printf("%s was added successfully.\n", buf1);
}

add 함수는 과 같이 바뀐다. 

사전식 순서로 나보다 큰 항목들은 모두 한 칸씩 뒤로 이동시키고, 처음으로 나보다 작은 항목이 나오면 그것 바로 뒤에 삽입한다. 

 

6. remove/erase 함수

 

void erase() {
	char buf[BUFFER_SIZE];
	scanf("%s", buf);

	int index = search(buf); //returns -1 if not exists
	if (index == -1) {
		printf("No person named '%s' exists.\n", buf);
		return;
	}
	int j = index;
	for (; j < n - 1; j++) {
		names[j] = names[j + 1];
		numbers[j] = numbers[j + 1];
	}
	n--;
	printf("No person named '%s' exists.\n", buf);
}

 

7. 전체 코드 

 

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

#define CAPACITY 100
#define BUFFER_SIZE 20

char* names[CAPACITY];
char* numbers[CAPACITY];
int n = 0;

void add();
void find();
void status();
void remove();
void load();
void save();

int main() {
	char command[BUFFER_SIZE];
	while (1) {
		printf("$ ");
		scanf("%s", command);

		if (strcmp(command, "read") == 0)
			load();
		else if (strcmp(command, "add") == 0)
			add();
		else if (strcmp(command, "find") == 0)
			find();
		else if (strcmp(command, "status") == 0)
			status();
		else if (strcmp(command, "delete") == 0)
			erase();
		else if (strcmp(command, "save") == 0)
			save();
		else if (strcmp(command, "exit") == 0)
			break;
	}
	return 0;
}

void load() {
	char fileName[BUFFER_SIZE];
	char buf1[BUFFER_SIZE];
	char buf2[BUFFER_SIZE];

	scanf("%s", fileName);

	FILE* fp = fopen(fileName, "r");
	if (fp == NULL) {
		printf("Open failed.\n");
		return;
	}
	while ((fscanf(fp, "%s", buf1) != EOF)) {
		fscanf(fp, "%s", buf2);
		names[n] = strdup(buf1);
		numbers[n] = strdup(buf2);
		n++;
	}
	fclose(fp);
}

void save() {
	int i;
	char fileName[BUFFER_SIZE];
	char tmp[BUFFER_SIZE];

	scanf("%s", tmp); //which is "as", discarded
	scanf("%s", fileName);

	FILE* fp = fopen(fileName, 'w');
	if (fp == NULL) {
		printf("Open failed.\n");
		return;
	}
	for (i = 0; i < n; i++) {
		fprintf(fp, "%s %s\n", names[i], numbers[i]);
	}
	fclose(fp);
}

void add() {
	char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE];
	scanf("%s", buf1);
	scanf("%s", buf2);

	int i = n - 1;
	while (i >= 0 && strcmp(names[i], buf1) > 0) {
		names[i + 1] = names[i];
		numbers[i + 1] = numbers[i];
		i--;
	}
	names[i + 1] = strdup(buf1);
	numbers[i + 1] = strdup(buf2);
	n++;

	printf("%s was added successfully.\n", buf1);
}

void find() {
	char buf[BUFFER_SIZE];
	scanf("%s", buf);

	int i;
	for (i = 0; i < n; i++) {
		if (strcmp(buf, names[i]) == 0) {
			printf("%s\n", numbers[i]);
			return;
		}
	}
	printf("No person named %s exists.\n", buf);
}

void status() {
	int i;
	for (i = 0; i < n; i++)
		printf("%s  %s\n", names[i], numbers[i]);
	printf("Total %d persons.\n", n);
}

void erase() {
	char buf[BUFFER_SIZE];
	scanf("%s", buf);

	int index = search(buf); //returns -1 if not exists
	if (index == -1) {
		printf("No person named '%s' exists.\n", buf);
		return;
	}
	int j = index;
	for (; j < n - 1; j++) {
		names[j] = names[j + 1];
		numbers[j] = numbers[j + 1];
	}
	n--;
	printf("No person named '%s' exists.\n", buf);
}