본문 바로가기

CS/자료구조

[인프런|4강] C로 배우는 자료구조 | 전화번호부 v1.0

 

전화번호부 v1.0

 

위와 같이 동작되도록 전화번호부 프로그램을 만든다.
add, find, status, delete 등의 동작 구현

 

코딩 이전에 어떤 자료구조로 저장할지 프로그램의 자료구조를 먼저 생각해야한다. 

- 어떤 데이터를 다루고 유지해야 하는지 생각

 

전화번호부 v1.0의 경우 

1. 내부적으로 저장해야하는 데이터는 여러사람의 이름, 전화번호

char * 타입의 names[], numbers[]를 선언

전화번호의 경우 '-' 기호를 사용하며 0으로 시작하는 경우 정수형일때 0이 빠지므로 문제가 된다. 그래서 char 타입을 사용한다.

 

#include ..

#define CAPACITY 100
#define BUFFER_SIZE 100

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

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

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, "delete")==0)
      remove;
    else if (strcmp(command, "exit")==0)
      break;
   }
   return 0;
}

 

  • add()
void add() {

  char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE];

  scanf("%s", buf1);
  scanf("%s", buf12;

  names[n] = strdup(buf1);
  numbers[n] = strdup(buf2);
  n++;
  printf("%s was added successfully.\n", buf1);

}

 

문자열은 char 배열, char 포인터로 주로 표현된다.

char arr[] 과 char *arr 은 같은 의미이지만 차이점은 

arr[]의 경우 arr, arr[0]이 가르키는 초기 주소값을 변경할 수 없다. (1강 참조)

*arr의 경우 가르키는 변수 주소값을 변경할 수 있다.

 

strdup는 넘겨받는 문자배열의 길이 +1만큼(문자열 끝이라는 의미 \0 포함하여) 알맞게 문자열을 복사하여 만들어준다.

 

buf1은 스택에 할당된 메모리 = 지역변수

 

  • 전역변수

함수 외부에 정의되며 프로그램이 종료될 때까지 사용된다.

 

메모리의 data section에 저장됨.

ex) 위 main 함수에서 

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

 

  • 지역변수

함수 내부에 선언되어 있으며 함수가 호출된 동안만 사용되는 변수.

스택영역에 있다.

 

  • 동적 메모리 할당

malloc으로 호출하여 필요한 크기만큼 메모리를 할당가능하며 힙 영역에 있다.

동적 할당은 명시적으로 free()함수를 호출하여 반환해야지만 메모리에서 해제된다.

 

code, data section 프로그램이 실행되는 동안 크기가 변하지 않는다. 프로그램 작성시 이미 크기가 고정되므로.

보통 heap과 stack서로 반대방향으로 크기가 늘었다 줄어든다.

stack은 지역변수가 늘어날 때 커지고 호출된 함수가 종료되면 반환되어 작아진다.

heap은 동적 메모리 할당될때 커지고 free로 반환될 때 작아진다.

둘이 가질 수 있는 최대 영역의 합은 같다. 같은 영역 내에서 자원을 나눠쓴다.

 

 

  • find()

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);

  }

}

 

strcmp두 문자열이 동일할때 0을 리턴한다.

찾고자하는 사람을 찾는 함수 없으면 없다고 출력하고 종료.

 

  • status()

void status() {

  int i;

  for (i=0; i<n; i++)

      printf("%s %s\n", names[i], numbers[i]);

  printf("Total %d persons. \n", n);  

}

 

전화번호부에 있는 이름, 전화번호 그리고 총 몇 명이 있는지 반환

 

 

  • 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];

      number[i] = numbers[n-1];

      n--;

      printf("'%s' was deleted successfully. \n", buf);

      return;

    }

  }

  printf("No person named '%s' exists/ \n", buf);

}

배열 중간에 빈칸을 만들지 않는다. 만약 만드는 경우 공간 낭비일 뿐 아니라 다른 함수(find, status 등)의 경우 모든 배열이 꽉 차있는 것을 기준으로 코딩되어있으므로 배열 중간 데이터가 삭제되고 채워지지 않는 경우 에러가 발생하게 될 수 있다.

 

현재 전화번호부에서는 누가 먼저 들어와있는지가 중요하지 않으므로 삭제된 자리(인덱스)에 배열의 마지막 데이터를 끌어와서 저장한다. 전부다 앞으로 끌어당기면 불필요한 연산이 발생하기에 이 방법은 쓰지 않는다.