[C 언어] - Phone Book V3

RuiN·2022년 8월 8일
0

Practice

목록 보기
3/4
post-thumbnail

Phone Book V2 는 파일을 읽어오고 조회하고 삭제하는 기능을 추가시켰습니다.
이번 V3 에서는 사용자가 명령어를 잘못입력했을때 하는 처리와 최대한 간결화 시킨상태의 로직을 구성해볼것입니다.


Main ( )

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

#define INIT_CAPACITY 3
#define BUFFER_SIZE 50

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 load(char * fileName);              // 파일 로드
void add(char *name, char *numbers);   // 추가
void delete(char *name);         //삭제
void save(char *fileName);    // 저장
int search(char *name);      // 검색 -1 return
void find();               // 찾기
void status();            // 현 정보 조회
void reallocate();        // 재할당


int main() {

   init_directory();     // 배열 크기 할당
   process_command();    // 명령어 입력 함수

   return 0;
}

char** 이중포인터 배열을 사용합니다.

int * name[10] ; 
int **name ; 
위와 같은 의미
우리는 배열을 할당하여 사용할 것이기에 이중포인터배열을 사용합니다.

Init Directory( )

void init_directory() {
    names = (char **) malloc(INIT_CAPACITY *sizeof(char *));
    numbers = (char **) malloc(INIT_CAPACITY*sizeof(char *));
}
  • V2 와 동일하게 malloc 함수로 배열을 동적으로 할당합니다.

Read_Line ( )

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;
}
  • getchar ( ) 의 경우 리턴값은 int 이다 ( 나중에 다룰 예정 )
  • 엔터를 치기 전까지 글자수 제한 전의 글자를 모두 읽어 str 배열에 저장한다.
  • 그다음 i 의 값을 return

Process_Command ( )

void process_command() {
    char command_line[BUFFER_SIZE];
    char *command, *arg1, *arg2;

    while (1) {
        printf("$ ");

        if (read_line(command_line, BUFFER_SIZE) <= 0)       //명령줄을 통째로 읽는다.
            continue;

        command = strtok(command_line, delim);
        if (command == NULL)
            continue;

        if (strcmp(command, "read") == 0) {

            arg1 = strtok(NULL, delim);
            if (arg1 == NULL) {
                printf("File name required\n");
                continue;
            }

            load(arg1);
        } else if (strcmp(command, "add") == 0) {
            arg1 = strtok(NULL, delim);
            arg2 = strtok(NULL, delim);

            if (arg1 == NULL || arg2 == NULL) {
                printf("Invalid Arguments\n");
                continue;
            }
            add(arg1, arg2);

            printf("%s was added successfully\n", arg1);
        } else if (strcmp(command, "find") == 0) {
            arg1 = strtok(NULL, delim);
            if (arg1 == NULL) {
                printf("Invalid Arguments\n");
                continue;
            }
            find(arg1);
        } else if (strcmp(command, "status") == 0) {
            status();
        } else if (strcmp(command, "delete") == 0) {
            arg1 = strtok(NULL, delim);
            if (arg1 == NULL) {
                printf("Invalid Arguments\n");
                continue;
            }
            delete(arg1);
        } else if (strcmp(command,"save")==0) {
            arg1 = strtok(NULL, delim);
            arg2 = strtok(NULL, delim);

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

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

    }
}

strcmp 함수를 이용하여 두개의 단어가 동일하면 0을 return 하여 그안의 함수 실행


Load ( )

void load(char * fileName)
{
    char buf1[BUFFER_SIZE];
    char buf2[BUFFER_SIZE];

    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);
    }
    fclose(fp);
}

Add ( )

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++;
}

reallocate ( )

	void reallocate()
	{	
    int i ;
    capacity *= 2;
    char **tmp1 = (char **) malloc(capacity * sizeof(char *));
    char **tmp2 = (char **) malloc(capacity * sizeof(char *));
    for (int i = 0; i < n; ++i) {
        tmp1[i] = names[i];
        tmp2[i] = numbers[i];
    }
    free(names);
    free(numbers);
    names = tmp1;
    numbers = tmp2;
	}

용량을 2배로 늘리고,. tmp1 과 tmp2 의 동적할당 후 ,
tmp1과 tmp2 에 names와 numbers의 데이터를 넣고,
free 함수로 필요없는 공간을 버리고,
다시 names와 numbers 에 tmp1 과 tmp2 를 넣는다.


Find ( )

void find()
{
    char namesTmp[BUFFER_SIZE];
    scanf("%s", namesTmp);
    int index = search(namesTmp);
    if (index == -1) {
        printf("No person named '%s' exists.  \n", namesTmp);
    } else
        printf("%s\n", numbers[index]);
}

Search ( )

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

V2 와 동일합니다.


Status ( )

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

Delete ( )

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 - 1; ++j) {
        names[j] = names[j + 1];
        numbers[j] = numbers[j + 1];
    }
    n--;
    printf("'%s' was deleted successfully\n",name);
}

Save ( )

void save(char *fileName)
{
    int i;
    FILE *fp = fopen(fileName, "w");
    if (fp == NULL) {
        printf("Open Failed\n");
        return;
    }

    for (int i = 0; i < n; ++i) {
        fprintf(fp, "%s %s\n", names[i], numbers[i]);
    }
    fclose(fp);
}

V2 와 동일한 내용들은 설명을 생략했습니다~!

profile
어디까지 올라갈지 궁금한 하루

0개의 댓글