Language/자료구조

[6] C review < 전화번호부 알고리즘 version3.0 >

Return 2021. 11. 22. 17:13

동작 방식 : 앞서 했던 알고리즘은 배열의 크기를 미리 할당한 후 사용하였습니다. 만약 배열의 크기가 더 커질 필요가 있을때 이 알고리즘은 제대로 동작하지 못합니다. 즉, 배열을 미리 선언할때 동적할당을 하여 선언합니다. 

 

또한 명령어,이름,번호 3가지 모두 한줄에 입력하여 사용할 수 있게 수정합니다. 

 

 

생각해야될 점 2가지 ! 

 

1. 어떻게 동적할당 할 것인가 ? 

 > malloc을 사용합니다. 

 

2. 명령어 이름 번호를 어떻게 한줄에 입력하여 사용할 것인가 즉, 어떻게 구분 할 것인가 ? 

 > 명령어 (공백) 이름 (공백) 번호 식으로 공백으로 각 명령어와 입력 인자를 구분합니다. 

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CAPACITY 100
#define BUFFER_SIZE 20
#define INIT_CAPACITY 3

char **names;
char **numbers;

int capacity = INIT_CAPACITY;
int n = 0;
char *delim = " ";

void init_directory();
void process_command();

int read_line(char *str, int limit);
void add(char *name, char *number);
void find(char *name);
void delete (char *name);
void status();
void load(char *fileName);
void save(char *fileName);
int search(char *name);
void reallocate();

int main()
{
    init_directory();
    process_command();
    return 0;
}

void init_directory()
{
    names = (char **)malloc(INIT_CAPACITY * sizeof(char *));
    numbers = (char **)malloc(INIT_CAPACITY * sizeof(char *));
}

void process_command()
{
    char command_line[BUFFER_SIZE];
    char *command, *argument1, *argument2;

    while (1)
    {
        printf("$ ");
        if (read_line(command_line, BUFFER_SIZE) <= 0)
        {
            continue;
        }

        command = strtok(command_line, delim);

        if (strcmp(command, "read") == 0)
        {
            argument1 = strtok(NULL, delim);
            if (argument1 == NULL)
            {
                printf("File name required.\n");
                continue;
            }
            load(argument1);
        }

        else if (strcmp(command, "add") == 0)
        {
            argument1 = strtok(NULL, delim);
            argument2 = strtok(NULL, delim);

            if (argument1 == NULL || argument2 == NULL)
            {
                printf("Invalid argeuments\n");
                continue;
            }

            add(argument1, argument2);
            printf("%s was added successfully\n", argument1);
        }

        else if (strcmp(command, "find") == 0)
        {
            argument1 = strtok(NULL, delim);
            if (argument1 == NULL)
            {
                printf("Invalied arguments.\n");
                continue;
            }
            find(argument1);
        }

        else if (strcmp(command, "status") == 0)
        {
            status();
        }

        else if (strcmp(command, "delete") == 0)
        {
            argument1 = strtok(NULL, delim);
            if (argument1 == NULL)
            {
                printf("Invalid arguments.\n");
                continue;
            }
            delete (argument1);
        }

        else if (strcmp(command, "save") == 0)
        {
            argument1 = strtok(NULL, delim);
            argument2 = strtok(NULL, delim);

            if (argument1 == NULL || strcmp("as", argument1) != 0)
            {
                printf("Invalid command format\n");
                continue;
            }
            save(argument1);
        }

        else if (strcmp(command, "exit") == 0)
            break;
    }
}

int read_line(char *str, int limit)
{
    int ch, i = 0;
    while ((ch = getchar()) != '\n')
    {
        if (i < limit - 1)
        {
            str[i++] = ch;
        }
    }
    str[i] = '\0';
    return i;
}

int search(char *name)
{
    int i;
    for (i = 0; i < n; i++)
    {
        if (strcmp(names[i], name) == 0)
        {
            return i;
        }
    }
    return -1;
}

void reallocate()
{
    int i;
    capacity *= 2;
    char **tmp1 = (char **)malloc(capacity * sizeof(char *));
    char **tmp2 = (char **)malloc(capacity * sizeof(char *));

    for (i = 0; i < n; i++)
    {
        tmp1[i] = names[i];
        tmp2[i] = numbers[i];
    }

    free(names);
    free(numbers);

    names = tmp1;
    numbers = tmp2;
}

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

    if (n >= capacity)
    {
        reallocate(); // 배열 꽉찬 경우 재할당.
    }

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

void find(char *name)
{
    int index = search(name);
    if (index == -1)
    {
        printf("찾는 사람이 없습니다.");
    }
    else
        printf("%s\n", numbers[index]);
}

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

    printf("Total person : %d\n", n);
}

void delete (char *name)
{

    int index = search(name);
    if (index == -1)
    {
        printf("찾는 사람이 없습니다.");
        return;
    }
    int j = index;
    for (; j < n - 1; j++)
    {
        names[j] = names[j + 1];
        numbers[j] = numbers[j + 1];
    }
    n--;
    printf("%s가 정상적으로 삭제 되었습니다.", name);
}

void load(char *fileName)
{
    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);
        add(buf1, buf2);
        n++;
    }
    fclose(fp);
}

void save(char *fileName)
{
    int i;
    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);
}