본문 바로가기

CS/자료구조

[인프런|11강] C로 배우는 자료구조 | 전화번호부 v5.0 (2)

전화번호부 v5.0 (2)

구조체에 대한 포인터, 동적 메모리 할당

전화번호부 v5.0 (1)(구조체에 대한 포인터) 이어서 동적메모리 할당을 적용한 전화번호 프로그램을 만든다.

위 그림처럼 Person ** directory  포인터 배열에 동적메모리 할당을 한다.

#define INIT_CAPACITY 100

 

typedef struct person {   // person은 생략가능

  char *name;  // 배열로 쓰기 위해 *로 선언

  char *number;

  char *mail;

  char *group;

} Person;

 

Person **dicrectory;

int capacity;

int n;

 

void init() {

  directory = (Person **)malloc(INIT_CAPCITY *sizeof(Person *));

  capacity = INIT_CAPACITY;

  n=0;

}

 

 

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

 

  while (1) {

    if (read_line(fp, buffer, BUFFER_LENGTH)<=0)

    break;

    name = strtok(buffer, "#");

    token = strtok(NULL, "#");

    if (strcmp(token, " ")==0)

      number = NULL;

    else

      number = strdup(token);

    token = strtok(NULL, "#");

    if (strcmp(token, " ")==0)

      email = NULL;

    else

      email = strdup(token);

    token = strtok(NULL, "#");

    if (strcmp(token, " ")==0)

      group = NULL;

    else

      group = strdup(token);

    add(strdup(name), number, email, group);

  }

  fclose(fp);

}

 

name은 필수적으로 입력된다고 가정한다. 필수입력값으로 설정

 

 

  • load()

void load(char *fileName) {

  char buffer[BUFFER_LENGTH];

  char * name, *number, *email, *group; char *token;

  FILE *fp = fopen(fileName, "r");

  if (fp==NULL) {

    printf("Open failed.\n");

  return;

}

 

  • add()

void add(char *name, char *number, char *email, char *group) {

  if (n>=capacity)

    reallocate();

   

  int i=n-1;

  while (i>=0 && strcmp(directory[i]->name, name) > 0) {

    directory[i+1] = directory[i];

    i--;

  }

 

  directory[i+1] = (Person *)malloc(sizeof(Person));   // 새로운 데이터를 입력 받기 전에 동적메모리 할당

  directory[i+1]->name = name;

  directory[i+1]->number = number;

  directory[i+1]->email = email;

  directory[i+1]->group = group;

  n++;

}

 

 

 

  • reallocate()

void reallocate() {

  capacity *= 2;

  Person **tmp = (Person **)malloc(capacity * sizeof(Person *));

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

    tmp[i] = directory[i];

  free(dicrectory); // malloc되어 이전 배열에 있던 값은 더이상 쓰지 않게되므로 메모리들은 할당 해제 해주어야한다.

  directory = tmp;

}

 

 

 

 

  • remove()

void reomove(char *name) {

  int i = search(name);    // return -1 if if not exists

  if (i==-1) {

    printf("No person named '%s' exists. \n", name);

    return; 

  }

 

  Person *p = directory[i];

  for(int j=1; j<n-1; j++)

    directory[j] = directory[j+1];

  n--;

  release_person(p);

  printf("'%s' was deleted suceesfully. \n". name);

}

 

void release_person(Person *p)  {

  free(p->name);

  if (p->number != NULL) free(p->number);

  if (p->email != NULL) free(p->email);

  if (p->group != NULL) free(p->group);

  free(p);

   //strdup으로 묵시적으로 복사를 하였다 그렇기에  더 이상 안쓰게 되는 메모리 할당 해제를 잊을 수 있으므로 주의한다.

}

 

 

나머지는   v4.0이랑 같으며 주요하게 다른 점은 구조체 배열이 아닌 구조체 포인터를 쓴다는 점, 동적할당에 따른 안쓰게되는 메모리들에 대해 메모리 할당 해제를 필수적으로 해주어야 한다.