ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C언어 전화번호부 v2.0 (인프런)
    CS/C언어 2020. 1. 11. 07:00

    ※ 인프런 무료강좌 C로 배우는 자료구조(권오흠 교수님)를 보고 개인적인 복습을 위해 정리한 내용입니다.


    v2.0 에서는

    전화번호부를 파일로 저장하고 로드하고, 알파벳 순으로 정렬할 것이다.

    자료구조는 전화번호부 v1.0과 동일하다.

     

    전화번호부를 파일로 로드하고 저장하기

     

    load 함수

    void load() {
    	char fileName[BUFFER_SIZE];
    	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);
    		names[n] = strdup(buf1);
    		numbers[n] = strdup(buf2);
    		n++;
    	}
    	fclose(fp);	
    }

    fopen 함수를 이용해 읽기모드("r")로 파일을 열고, 파일타입 포인터 변수 fp에 파일을 저장한다.

    if (fp==NULL) { } : 파일을 여는 것에 실패했을 경우의 예외처리를 해준다.

     

    fscanf 함수는 파일의 끝에 도달하면 EOF(End of File)를 리턴한다.

    fscanf가 EOF를 리턴하기 전까지 while 반복문을 돈다.

     

    볼일이 없는 파일은 fclose 함수로 반드시 닫아줘야 한다.

     

    save 함수

    void save() {
    	char fileName[BUFFER_SIZE];
    	char tmp[2];
    	int i;
    	scanf("%s", tmp);
    	scanf("%s", fileName);
    	
    	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);
    }

    fopen 함수를 이용해 쓰기모드("w")로 파일을 열어 파일타입 포인터 변수 fp에 담는다.

     

    쓰기모드로 파일을 열었을 때는

    같은 이름의 파일이 존재하면, 그 파일 위에 내용을 덮어쓰게 되고

    같은 이름의 파일이 존재하지 않으면 새로운 파일을 만들어 작성하게 된다.

     

    데이터를 정렬된 상태로 유지하기 (알파벳 순서)

     

    1) bubblesort 등의 정렬(sorting) 알고리즘 사용

    새로운 데이터가 계속 추가되는 상황이므로 부적절함

    (새로운 사람을 한 명 추가할 때마다 정렬 알고리즘을 사용해야하기 때문에 비효율적이다)

     

    2) 새로운 데이터가 추가될 때마다 제자리를 찾아서 삽입

    E를 추가하려면, 맨 뒤에서부터 검사해

    E보다 큰 것들을 전부 한 칸씩 뒤로 이동한다.

    E보다 작은 것이 나오거나 배열의 시작을 지나치면, 그 다음 자리에 E를 저장한다.

    (처음으로 E보다 작은 것이 나오면 그 바로 뒤에 E를 삽입한다.)

     

    add 함수

    void add() {
    	char buf1[BUFFER_SIZE];
    	char buf2[BUFFER_SIZE];
    	scanf("%s", buf1);
    	scanf("%s", buf2);
    	
    	int i=n-1;
    	while (i>=0 && strcmp(names[i], buf1) > 0) {
    		names[i+1] = names[i];
    		numbers[i+1] = numbers[i];
    		i--;
    	}
    	names[i+1] = strdup(buf1);
    	numbers[i+1] = strdup(buf2);
    		
    	n++;
    	printf("%s was added successfully.\n", buf1);
    }

    i는 n-1에서 시작한다. 배열의 길이가 n일 때 마지막 자리의 인덱스는 n-1이기 때문이다.

     

    strcmp 함수는 첫번째 인자가 두번째 인자보다 크면 양수를 반환하고,

    첫번째 인자가 두번째 인자보다 작으면 음수를 반환한다.

    이 때 크다는 것은 사전식 순서(알파벳 순서)로 더 뒤에 있다는 것이다.

     

    i가 -1이 되거나(배열의 시작을 지나치거나), 나보다 작은 항목이 나오면

    while문을 종료하고 바로 다음 자리에(n+1) 삽입한다.

     

    remove 함수

    void delete() {
    	char buf[BUFFER_SIZE];
    	scanf("%s", buf);
    	
    	int index = search(buf);
    	if (index == -1) {
    		printf("No person named '%s' exists.\n", buf);
    		return;
    	}
    	
    	int j = index;
    	for (; j<n-1; j++) {
    		names[j] = names[j+1];
    		numbers[j] = numbers[j+1];
    	}
    	
    	n--;
    	printf("'%s' was deleted successfully.\n", buf);
    }

     

     

    search 함수는 일치하는 값을 찾아서

    값이 위치하는 인덱스를 반환하고, 만약 일치하는 값이 없을 경우 -1을 반환하는 함수이다.

    search 함수

    더보기
    void search(char *name) { /*char name[]으로 받아도 된다. */
    	int i;
    	for (i=0; i<n; i++) {
    		if (strcmp(name, names[i])==0) {
    			return i;
    		}
    	}
    	return -1;
    }

     

    index가 -1인 경우 존재하지 않는 이름이라는 메세지를 출력한 후 함수를 종료한다.

    index가 -1이 아닌 경우

    index부터 n-1 전까지 돌면서 배열의 원소들을 앞으로 한칸씩 당겨준다.

    (j<n-1인 이유 : 배열의 마지막 원소의 인덱스가 n-1일 때 그 다음 원소(인덱스 n)를 앞으로 한 칸 당겨오게 되는데, n은 빈칸이므로 n-1이 되기 전에 반복문을 종료한다.)

    이렇게 하면 정렬을 유지하면서 index에 위치하는 원소만 삭제할 수 있다.

     

    find 함수

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

     

    status 함수는 v1.0과 동일하다.

    댓글

Designed by Tistory.