Language/자료구조

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

Return 2021. 11. 23. 21:36

동장방식 : 이름과 번호 뿐아니라 email과 소속그룹까지 추가해보자 >> 구조체 이용 , 만약 번호,email,group이 없다면 빈칸으로 둔다. 또한 이름이 하나 이상의 단어로 구성될 수 있으며 단어사이에 여러 개의 공백이 있을 경우 한칸의 공백으로 저장한다. 

 

생각해야할 점 2가지 !

 

1. 구조체를 어떻게 사용할 것인가 ? 

typedef struct person
{
    char *name;
    char *number;
    char *email;
    char *group;
} Person;

Person directory[CAPACITY]; // Person type의 배열 directory를 선언.

person struct를 Person으로 재선언.

 

2. 빈칸을 어떻게 처리 할 것인가?

int compose_name(char *str, int limit)
{
    char *ptr;
    int length = 0;

    ptr = strtok(NULL, " ");
    if (ptr == NULL)
    {
        return 0;
    }
    strcpy(str, ptr);
    length += strlen(ptr);

    while ((ptr = strtok(NULL, " ")) != NULL)
    {
        if (length + strlen(ptr) + 1 < limit)
        {
            str[length++] = ' '; // 이름과 이름사이의 공백
            str[length] = '\0';
            strcat(str, ptr); // strcat는 모두 NULL로 끝나야 정상작동
            length += strlen(ptr);
        }
    }

    return length;
}

배열 하나를 새롭게 만들어서 추가한다. 

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CAPACITY 100
#define BUFFER_LENGTH 100

typedef struct person
{
    char *name;
    char *number;
    char *email;
    char *group;
} Person;

Person directory[CAPACITY]; // Person type의 배열 directory를 선언.

int n = 0;
int read_line(FILE *fp, char *str, int n);
void load(char *fileName);
int compose_name(char *str, int limit);
void handle_add(char *name);
void find(char *name);
void status();
void delete (char *name);
void save(char *fileName);
void add(char *name, char *number, char *email, char *group);
int search(char *name);
void print_person(Person p);

int main(void)
{

    char command_line[BUFFER_LENGTH];
    char *command, *argument;
    char name_str[BUFFER_LENGTH];

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

        command = strtok(command_line, " ");

        if (strcmp(command, "read") == 0)
        {
            argument = strtok(NULL, " ");
            if (argument == NULL)
            {
                printf("Invalid argeuments.\n");
                continue;
            }
            load(argument);
        }

        else if (strcmp(command, "add") == 0)
        {
            if (compose_name(name_str, BUFFER_LENGTH) <= 0)
            {
                printf("Name required.\n");
                continue;
            }
            handle_add(name_str);
        }

        else if (strcmp(command, "find") == 0)
        {
            if (compose_name(name_str, BUFFER_LENGTH) <= 0)
            {
                printf("Name required.\n");
                continue;
            }
            find(name_str);
        }

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

        else if (strcmp(command, "delete") == 0)
        {
            if (compose_name(name_str, BUFFER_LENGTH) <= 0)
            {
                printf("Name required.\n");
                continue;
            }
            delete (name_str);
        }

        else if (strcmp(command, "save") == 0)
        {
            argument = strtok(NULL, " ");
            if (strcmp(argument, "as") != 0)
            {
                printf("Invalid arguments.\n");
                continue;
            }

            argument = strtok(NULL, " ");
            if (argument == NULL)
            {
                printf("Invalid argeuments.\n");
                continue;
            }
            save(argument);
        }

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

    return 0;
}

int read_line(FILE *fp, char *str, int n)
{

    int ch, i = 0;
    while ((ch = fgetc(fp)) != '\n' && ch != EOF)
    {
        if (i < n)
        {
            str[i++] = ch;
        }
    }
    str[i] = '\0';
    return i;
}

void load(char *fileName)
{
    char buffer[BUFFER_LENGTH];
    char *name, *number, *email, *group;

    FILE *fp = fopen(fileName, "r");
    if (fp == NULL)
    {
        printf("Open failed.\n");
        return;
    }

    while (1)
    {
        if (read_line(fp, buffer, BUFFER_LENGTH) <= 0)
        {
            break;
        }
        name = strtok(buffer, "#");
        number = strtok(NULL, "#");
        email = strtok(NULL, "#");
        group = strtok(NULL, "#");

        add(name, number, email, group);
    }
    fclose(fp);
}

void add(char *name, char *number, char *email, char *group)
{
    int i = n - 1;
    while (i >= 0 && strcmp(directory[i].name, name) > 0)
    {
        directory[i + 1] = directory[i];
        i--;
    }

    directory[i + 1].name = strdup(name);
    directory[i + 1].number = strdup(number);
    directory[i + 1].email = strdup(email);
    directory[i + 1].group = strdup(group);

    n++;
}
// 'a'는 단일 문자 리터럴이고 "a"는 'a'와 null을 포함하는 문자열 리터럴이다.

int compose_name(char *str, int limit)
{
    char *ptr;
    int length = 0;

    ptr = strtok(NULL, " ");
    if (ptr == NULL)
    {
        return 0;
    }
    strcpy(str, ptr);
    length += strlen(ptr);

    while ((ptr = strtok(NULL, " ")) != NULL)
    {
        if (length + strlen(ptr) + 1 < limit)
        {
            str[length++] = ' '; // 이름과 이름사이의 공백
            str[length] = '\0';
            strcat(str, ptr); // strcat는 모두 NULL로 끝나야 정상작동
            length += strlen(ptr);
        }
    }

    return length;
}

void handle_add(char *name)
{
    char number[BUFFER_LENGTH], email[BUFFER_LENGTH], group[BUFFER_LENGTH];
    char empty[] = " ";

    printf("  Phone: ");
    read_line(stdin, number, BUFFER_LENGTH);

    printf("  Email: ");
    read_line(stdin, email, BUFFER_LENGTH);

    printf("  Group: ");
    read_line(stdin, group, BUFFER_LENGTH);

    add(name, (char *)(strlen(number) > 0 ? number : empty), (char *)(strlen(email) > 0 ? email : empty), (char *)(strlen(group) > 0 ? group : empty));
}

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#", directory[i].name);
        fprintf(fp, "%s#", directory[i].number);
        fprintf(fp, "%s#", directory[i].email);
        fprintf(fp, "%s#", directory[i].group);
    }
    fclose(fp);
}

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

void delete (char *name)
{
    int i = search(name);
    if (i == -1)
    {
        printf("No person named %s exists.\n", name);
        return;
    }
    int j = i;
    for (; j < n; j++)
    {
        directory[j] = directory[j + 1];
    }
    n--;
    printf("%s was deleted successfully.\n");
}

void find(char *name)
{
    int index = search(name);
    if (index == -1)
    {
        printf("No person named %s exists.\n", name);
    }
    else
        print_person(directory[index]);
}

void print_person(Person p)
{
    printf("%s:\n", p.name);
    printf("     Phone:%s\n", p.number);
    printf("     Email:%s\n", p.email);
    printf("     Group:%s\n", p.group);
}

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