💡 자료구조

전화번호부 v1.0

ji-hyun 2021. 6. 19. 20:41

오늘은 권오흠 교수님께서 전화번호부를 만드는 예제를 가르쳐주셨다.

여태까지 배웠던 C언어의 기초를 응용해서 전화번호부 예제를 만들 수 있었다. 

 

 

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

	names[n] = strdup(buf1);   // strdup 와 strcpy 차이는?
	numbers[n] = strdup(buf2);
	n++;

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

 

buf1 과 buf2 는 지역변수이기 때문에 lifetime 은 짧다. 그러므로 이 함수를 벗어나게 되면 두 변수 모두 소멸하게 된다. 그래서 strdup 를 써주어야 하는 이유는 strdup 함수는 buf1 에 있는 문자열을 복사한 새로운 복제본의 주소를 리턴하게 되기 때문이다. strdup 의 실행원리는 지난 시간에 알아보았었다.

 

그리고 strcpy 가 사용될 수 없는 까닭은 마찬가지로 지난 시간에 배웠지만, n 이라는 변수는 현재 문자열이 아닌 포인터 변수이기 때문에 strcpy 함수가 사용될 수 없었다.

 

 

 

 

 

 

 

 


< C 언어에서 메모리 레이아웃 >

 

c언어 메모리 레이아웃

 

전역변수는 함수의 외부에 선언된 변수들이며, 지역 변수는 함수의 내부에 선언된 변수들을 말한다.

특징을 알아두는게 좋을 것 같아서 밑에 정리해보았다.

 

 

 

전역변수

  • 프로그램이 시작될 때 메모리가 할당되며 프로그램이 종료될 때까지 유지된다
  • Data section 이라고 부르는 메모리 영역에 위치한다

 

지역변수

  • 자신이 속한 함수가 호출될 때 메모리가 할당되며 함수가 retrun될 때 소멸된다
  • 스택(stack)이라고 부르는 영역에 위치한다.

 

 

 

그리고 동적 메모리 할당의 특징이다. 

정리해보면 malloc 함수를 함수 내부에 할당받았더라도 그렇게 할당된 메모리는 그 함수에 국한되지 않는다. 함수가 return 되고 종료되더라도 사라지지 않고 내가 malloc 함수로 할당한 메모리의 주소만 기억할 수 있다면 계속 사용이 가능하다.

이 메모리가 더이상 필요 없다고 생각될 때는 메모리를 해제할 수 있으며, 메모리를 해제시키기 위해서는 명시적으로 free() 함수를 선언해야 한다.

 

 

 

 

따라서 위 그림의 C언어 메모리 레이아웃은 프로그램이 실행될 때 각 변수들이 저장되는 공간을 그림으로 나타낸 것이며, code 라는 부분은 우리가 프로그램한 코드가 컴파일된 기계어로 차지하고 있는 부분이다. 그리고 data sectioncode 부분은 메모리에서 크기가 변하지 않는다. (= 일정하다 ) 그러나 stack 부분은 보통 메모리의 윗부분에 자리하고 있으며, 생기거나 없어질때마다 윗부분이 늘어나거나 줄어들거나 한다. ( = 일정하지 않은 편이다) 그리고 heap 이라는 부분은 메모리의 아랫부분에 자리하고 있으며 이 역시도 늘어나거나(malloc) 줄어들었다(free())가 하기 때문에 일정하지 않다.

 

 

 

 


< Remove 함수 >

void remove() {
	char buf[BUFFER_SIZE];
	scanf("%s", buf);  // 배열이니까 & 쓰지 않는 것을 주의한다. 

	int i;
	for (i = 0; i < n; i++) {
		if (strcmp(buf, names[i]) == 0) {
			names[i] = names[n - 1];
			n--;  // 사람 수 감소된다.
			printf("'%s' was deleted successfully. \n", buf);
			return;
		}
	}
	printf("No person named '%s' exists.\n", buf);  // return 되지 않으면 실행된다.
}

 

위 코드문은 전화번호부에서 사람을 삭제하는 코드문이다. 참고로 strcmp 함수는 2개의 문자열이 같은지 검사하는 함수로, 2개의 문자열이 같으면 1이 아닌 0을 반환하는 함수이다. (생각보다 실수하므로 주의하자) names[ i ] 는 i번째 사람의 이름을 말하며 만약 buf 에 입력한 문자열이 i번째 사람의 이름 문자열과 같다면 삭제를 해야한다.

 

 

이때 i번째 사람의 이름을 그냥 삭제할 수 이유는 배열은 삭제하고 그 부분이 빈공간으로 남아있으면 다른 코드문에서 for문 반복을 하면서 에러가 발생한다. 그러면 해결 방법을 생각해보자.

 

 

이 배열은 사실 순서가 정렬되어 있지 않는 배열이다. 따라서 i번째의 사람이름을 삭제하고 나서 마지막 n-1번째의 사람이름을 i번째에 할당되어도 크게 상관없다. 즉, 맨 마지막 사람을 삭제된 공간으로 옮긴다.

 

names[i] = names[n - 1];

 

 

 

 

실습결과물

 

 

 

 

코드를 다 리뷰하면 좋겠지만 내가 다시 짚어봤으면 하는 부분들만 간단히 정리해서 보는게 나중에 다시 볼때 더 편할 것 같아서 간추렸다.

 

 

 

 

 

 

 

실습 코드

 

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

#define CAPACITY 100
#define BUFFER_SIZE 20


char * names[CAPACITY]; /* names */
char * numbers[CAPACITY]; /* phone numbers */

int n = 0; /* number of people in phone directory */




void add();
void find();
void status();
void remover();






int main() {
	char command[BUFFER_SIZE];
	while (1) {
		printf("$ ");
		scanf("%s", command);
		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)
			remover();
		else if (strcmp(command, "exit") == 0)
			break;
	}
	return 0;
}

void add() {
	char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE];
	scanf("%s", buf1);
	scanf("%s", buf2);
	names[n] = strdup(buf1);
	numbers[n] = strdup(buf2);
	n++;
	printf("%s was added successfully.\n", buf1);
}


char *strdup(char *s)
{
	char *p;
	p = (char *)malloc(strlen(s) + 1);
	if (p != NULL)
		strcpy(p, s);
	return p;
}


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 remover() {
	char buf[BUFFER_SIZE];
	scanf("%s", buf);
	int i;
	for (i = 0; i < n; i++) {
		if (strcmp(buf, names[i]) == 0) {
			names[i] = names[n - 1];
			numbers[i] = numbers[n - 1];
			n--;
			printf("'%s' was deleted successfully. \n", buf);
			return;
		}
	}
	printf("No person named '%s' exists.\n", buf);
}