ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C언어 전화번호부 v1.0 (인프런)
    CS/C언어 2020. 1. 10. 21:01

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


    전화번호부 v1.0

    이름, 전화번호의 리스트 저장 & 검색 기능 제공하는 전화번호부 프로그램 만들기

    add john 01092419488 //새로운 사람 추가
    
    delete john //삭제
    
    find henry //이름으로 전화번호 검색
    
    status //전화번호부에 저장된 모든 사람을 출력
    
    exit //프로그램 종료

     

    프로그램을 만들기 위해서는 가장 먼저 '자료구조'부터 생각해보아야 한다.

    자료구조는 프로그램에서 다룰 데이터를 어디에 어떤 구조로 저장할 것인가를 말한다.

     

    동일한 타입의 데이터가 여러 개 있을 때 사용할 수 있는 가장 기본적인 자료구조는 배열이다.

    v1.0에서는 

    데이터가 두 가지 종류(이름, 전화번호)이므로

    names 배열과 numbers 배열을 만들어 데이터를 저장할 것이다.

    두 배열의 인덱스를 통해 이름과 전화번호가 연결된다.

     

    배열 names, numbers의 데이터 타입은 char * 이다.

    두 배열에는 문자열(이름, 전화번호)을 저장할 것인데, 문자배열의 첫번째 원소의 주소를 저장하는 것이므로 포인터이고 그 주소에 담겨있는 데이터의 타입이 문자이기 때문에 char 타입이다.

    *전화번호는 정수로 저장하지않고 문자열로 저장한다.

     

    #include <stdio.h>
    #include <string.h>
    
    #define CAPACITY 100
    #define BUFFER_SIZE
    
    char * names[CAPACITY];
    char * numbers[CAPACITY];
    int n = 0; /* 전화번호부에 저장된 사람의 수 */
    
    void add();
    void find();
    void status();
    void remove();
    
    int main() {
    	char command[BUFFER_SIZE];
    	while (1) {
    		printf("$ ");
    		scanf("%s", command);
    
    		if (strcmp(command, "add")==0)
    			add();
    		else if (strcmp(command, "find")==0)
    			find();
    		else if (strcmp(command, "status")==0)
    			status();
    		else if (strcmp(command, "delete")==0)
    			remove();
    		else if (strcmp(command, "exit")==0)
    			break;
    	}
    	return 0;
    }

     

    main 함수에서는

    무한루프( while (1) {} )로 프롬프트 문자를 출력하고 사용자의 입력을 받는 것을 반복한다.

     

    루프 안에서는

    strcmp 함수(string.h 라이브러리)로 사용자의 입력값 command를

    add/find/status/delete와 비교해 각각 해당되는 함수를 실행하고

    사용자의 입력값이 exit인 경우 루프를 종료하며 프로그램을 종료시킨다.

     

    사용자가 add명령을 입력하면 실행되는 add 함수이다. 

    void add() {
    	char buf1[BUFFER_SIZE];
    	char buf2[BUFFER_SIZE];
    	scanf("%s", buf1);
    	scanf("%s", buf2);
    	
    	names[n] = strdup(buf1);
    	numbers[n] = strdup(buf2);
    	n++;
    	
    	printf("%s was added successfully.\n", buf1);
    }

     

    names[n] = buf1; 와 같이 전역변수인 names[n]에 지역변수 buf1을 직접 할당할 경우

    함수가 끝났을 때 buf1이 사라지기 때문에 문제가 생길 수 있다. (buf1은 스택에 할당된 메모리(지역변수)이므로 add 함수가 return되고 나면 소멸된다. )

    따라서 strdup 함수를 이용해 buf1에 저장된 문자열을 복제한 후 배열 names[n]에 복제된 배열의 주소를 저장해야 한다.

    복제된 배열은 strdup 함수 내에서 malloc으로 힙(heap)에 할당된 메모리이므로, add 함수가 종료된 후에도 소멸되지 않는다.

     

    이 때 strdup 함수하나의 문자열을 인자로 받아 복제한 다음 메모리에 할당하고, 메모리의 주소를 반환하는 함수이다.

    char * strdup (char *s) {
    	char *p;
    	p = (char *)malloc(strlen(s)+1); /*+1은 null charactor 자리*/
    	if (p != null)
    		strcpy(p, s);
    	return p;
    }
    
    /* strdup 함수 내부를 간단하게 나타낸 코드 */

     

    동적 메모리 할당으로 새로운 char 타입 배열을 만들고, 그 배열의 주소를 char 타입 포인터 변수 p에 담는다.

    strcpy 함수로 배열 s에 있는 문자열과 null charactor를 배열 p로 복사한다. (데이터타입이 같기 때문에 복사 가능)

    배열 p를 리턴한다.

     

    그 외의 함수들이다. 

    find 함수

    void find() {
    	int i = 0;
    	char buf[BUFFER_SIZE];
    	scanf("%s", buf);
    	
    	while (i < n) {
    		if(strcmp(names[i], buf)==0) {
    			printf("%s %s\n", names[i], numbers[i]);
    			return;
    		} 
    		i++;
    	}
    	printf("No person named '%s' exists.\n");
    }

    strcmp는 두 개의 문자열이 일치할 경우 0을 리턴하는 함수이다.

     

    status 함수

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

     

    remove 함수

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

    배열의 중간에 빈 칸이 생기지 않도록

    맨 마지막 사람을 삭제된 자리로 옮기고

    현재 전화번호부에 저장된 사람의 수를 1 감소시킨다(n--)

    그리고 성공적으로 삭제되었다는 메세지를 출력한다.

    만약 없는 이름일 경우 그런 이름을 가진 사람이 없다는 메세지를 출력한다.

     

    C언어에서의 메모리 관리

     

    전역변수 : 함수의 외부에 선언된 변수들

    프로그램이 시작될 때 메모리가 할당되며 프로그램이 종료될 때까지 유지된다.

    Data section이라고 부르는 메모리 영역에 위치한다.

     

    지역변수 : 함수의 내부에 선언된 변수들

    자신이 속한 함수가 호출될 때 메모리가 할당되며 return될 때 소멸된다.

    스택(stack)이라고 부르는 메모리 영역에 위치한다.

     

    동적 메모리 할당(dynamic memory allocation)

    변수를 선언하지 않고, 아무때나 malloc 등의 함수를 호출하여 필요한 크기의 메모리를 할당할 수 있다.

    동적으로 할당된 메모리는 힙(heap)이라고 부르는 영역에 위치한다.

    동적으로 할당된 메모리는 명시적으로 free() 함수를 호출하여 반환하지 않는 한, 프로그램이 종료될 때까지 계속 유지된다.

     

    c언어의 메모리 레이아웃

    stack : 지역변수가 할당되는 영역

    heap : 동적으로 할당된 메모리

    data section : 전역변수가 할당되는 영역

    code section : 코드(기계어)가 저장되는 영역

    코드 섹션과 데이터 섹션의 크기는 프로그램이 실행되는 동안 변하지 않는다.

    스택의 크기는 일정하지 않고 함수 호출과 종료에 따라 변한다.

    힙의 크기도 마찬가지로 고정되어 있지 않다.

     

     

    프로그램 전체 소스코드

    더보기
    #include <stdio.h>
    #include <string.h>
    
    #define BUFFER_SIZE 20
    #define CAPACITY 100
    
    char *names[CAPACITY];
    char *numbers[CAPACITY];
    int n = 0;
    
    void add();
    void find();
    void delete();
    void print_status();
    
    int main() {
    	char command[BUFFER_SIZE];
    	while (1) {
    		printf ("$ ");
    		scanf("%s", command);
    		if(strcmp(command, "add") == 0) 
    			add();
    		else if(strcmp(command, "delete") == 0)
    			delete();
    		else if(strcmp(command, "find") == 0)
    			find();
    		else if(strcmp(command, "status") == 0)
    			print_status();
    		else if(strcmp(command, "exit") == 0)
    			break;
    	}
    	return 0;
    }
    
    
    void add() {
    	char buf1[BUFFER_SIZE];
    	char buf2[BUFFER_SIZE];
    	scanf("%s", buf1);
    	scanf("%s", buf2);
    	
    	names[n] = strdup(buf1);
    	numbers[n] = strdup(buf2);
    	n++;
    	
    	printf("%s was added successfully.\n", buf1);
    }
    
    void delete() {
    	int i = 0;
    	char buf[BUFFER_SIZE];
    	scanf("%s", buf);
    	
    	for(i=0; i<n; i++) {
    		if(strcmp(names[i], buf)==0) {
    			names[i] = names[n-1];
    			numbers[i] = numbers[n-1];
    			n--;
    			printf("'%s' was deleted successfully.\n");
    			return;
    		}
    	}
    	
    	printf("No person named '%s' exists.\n");
    }
    
    void find() {
    	int i = 0;
    	int existence = 0;
    	char buf[BUFFER_SIZE];
    	scanf("%s", buf);
    	
    	while (i < n) {
    		if(strcmp(names[i], buf)==0) {
    			printf("%s %s\n", names[i], numbers[i]);
    			return;
    		} 
    		i++;
    	}
    	printf("No person named '%s' exists.\n");
    }
    
    void print_status() {
    	int i = 0;
    	while (i < n) {
    		printf("%s %s\n", names[i], numbers[i]);
    		i++;
    	}
    	printf("total %d persons\n", n);
    }

     

    댓글

Designed by Tistory.