ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C Language] 38. 문자열과 포인터 - C 언어
    CSE/C Language 2015. 8. 4. 15:47

    1. 문자열이란?

     "In C, strings are arrays of characters."


     C에서의 문자열에 대한 정의를 보면, 문자열 형이 없고 단지 문자들의 집합인 배열로 처리한다는 것을 알 수 있다. 또한, 포인터적인 관점에서 본다면 시스템은 문자열 전체에 전혀 관심이 없다. 시스템은 오로지 문자열 중에서도 가장 첫 번째 문자가 저장된 곳의 위치에만 관심이 있을 뿐이다. 문자열의 끝은 널 문자로 판별하기 때문에 널 문자가 없는 문자열은 C에서 상당히 위험한 존재로 여겨지고 메모리 에러의 대부분을 차지한다.





    2. 문자열 포인터 변수

     int 형 포인터 변수가 int 형 변수를 가리킬 수 있는 것과 마찬가지로 문자열 포인터 변수도 문자열을 가리킬 수 있다. 좀 더 정확히 말하면 문자열 중에서도 가장 첫 번째 문자가 저장된 곳을 주소를 기억한다.


     문자열을 만나는 순간 시스템은 문자열을 메모리 어딘가에 저장하고 그 주소를 리턴한다. 이때의 주소는 문자들 중에서 가장 첫 번째 문자가 저장된 곳의 주소이다. 


     아래 예제로 문자열 단위 출력을 해보도록 하자.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    /*
     * str.c
     *
     *  Created on: 2015. 8. 4.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
     
    int main(void) {
     
        char *char_p = "I am a good boy";
     
        for (; *char_p; char_p++) {
            if (*char_p != ' ')
                putchar(*char_p);
            if (*char_p == ' ')
                putchar('\n');
        }
        puts("");
     
        return 0;
    }
     
    cs











    3. 포인터 배열

     여기서는 문자열을 저장할 때 배열을 사용했을 때와 포인터를 사용했을 때의 차이점을 명확히 설명함으로써 포인터가 얼마나 메모리 공간을 효율적으로 사용하는 지 검증해 보기로 한다.


     배열을 사용하여 문자열을 저장한 경우


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    char name[6][20];
     
    strcpy(name[0], "Kim Dong Guk");
    strcpy(name[1], "Lee Dong Guk");
    strcpy(name[2], "Park Dong Guk");
    strcpy(name[3], "Jung Dong Guk");
    strcpy(name[4], "Han Dong Guk");
    strcpy(name[5], "Moon Dong Guk");
     
     
    cs


     여섯 명의 이름을 저장하기 위해 모두 120바이트를 할당하였다. 한 사람의 이름을 저장하기 위한 공간이 들쑥날쑥하기 때문에 넉넉하게 20바이트를 준비하였다. 그 덕분에 남는 공백은 모두 낭비되고 있다. 배열을 사용하여 이름을 저장하는 방식은 한눈에 보아도 메모리 낭비가 심하다는 것을 알 수 있다.



     포인터 배열을 사용하여 문자열을 저장한 경우


    1
    2
    3
    4
    5
    6
    7
    8
    9
    char *name[6];
     
    name[0= "Kim Dong Guk";
    name[1= "Lee Dong Guk";
    name[2= "Park Dong Guk";
    name[3= "Jung Dong Guk";
    name[4= "Han Dong Guk"
    name[5= "Moon Dong Guk";
     
    cs




     name[0]이라는 포인터 변수는 'Kim Dong Guk'이라는 문자열에서 K가 저장된 주소를 기록한다. name[1]은 'L'의 주소를 기록하고 각각 맨 앞의 문자열의 주소를 저장하는데 이와 같이 처리하면 배열을 사용할 때와는 달리 메모리 낭비가 전혀 없음을 알 수 있다.










    4. a, 'a', "a"

     a와 'a' 그리고 "a"는 C에서 전혀 다른 특성을 가지고 있다. 


    1
    2
    3
    4
    5
    6
    7
    char a;         // 1 byte
    short b;         // 2 bytes
    int c;            // 4 bytes
     
    'a'                // 1 byte
    "a"                // 2 bytes, a \0
     
    cs



     마지막 "a"는 문자열 상수로 C에서의 모든 문자열은 널 문자로 끝나기 때문에 눈에 보이지 않는 널 문자가 자동적으로 추가된다.







    5. 포인터 변수와 배열명의 차이

     - 할당받는 메모리의 크기가 다르다.

      배열명: 배열며 자체로는 메모리를 차지하지 않고 배열첨자와 형(type)에 따라서 크기가 결정된다.

      포인터 변수: 포인터를 저장하는 변수이기 때문에 무조건 4 바이트를 할당받는다.


     - 문자열을 저장하는 형식이 다르다(복사와 할당의 차이가 발생)

      배열명: 문자열 상수가 메모리에 저장되는 것이 아니라 문자 하나 하나가 배열에 복사된다.

      포인터 변수: 문자열 상수가 메모리에 저장되고 이 위치가 포인터 변수에 할당된다.

     

     - 증감연산자으 사용 여부가 다르다.

      배열명: 증감 연산자를 사용할 수 없다.

      포인터 변수: 증감 연산자를 사용할 수 있다.

    댓글

Designed by Tistory.