ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C Language] 36. 1차원 배열과 포인터 - C 언어
    CSE/C Language 2015. 7. 20. 15:46

    1. 1차원 배열과 포인터 변수 초기화

     1차원 배열에 대해서는 앞 단원에서 충분히 배웠으므로 여기서는 배열과 포인터의 결합에 대해 알아보도록 하자.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    /*
     * arrp.c
     *
     *  Created on: 2015. 7. 20.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
     
    int main(void) {
        int tmp[3= {157741};
        int *tmp_p;
     
        tmp_p = tmp;
     
        printf("%d\n"*tmp_p);
     
        return 0;
    }
     
    cs




     








     포인터를 많이 사용해 보지 않았다면 이상하고 생각된 결과 일 것이다. 왜냐하면 tmp_p = tmp에서 tmp의 앞에 & 연산자가 없기 때문이다. 


     이를 이해하려면 다음 두 가지를 각인시켜야 할 것이다.


      1. 배열명은 주소 값이다.

      2. 배열명은 첫 번째 배열요소의 주소 값이다.







    2. 1차원 문자배열과 대상체

     앞의 예제는 int 형 배열이었는데, 이번에는 문자배열을 포인터 변수가 가리킬 수 있도록 포인터 변수를 초기화하고 중요한 대상체에 대해 알아보자.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    /*
     * arrp.c
     *
     *  Created on: 2015. 7. 20.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
     
    int main(void) {
     
        char tmp[9= "triumph";
        char *tmp_p = tmp;
     
        printf("*tmp_p = %c\n"*tmp_p);
        printf("tmp_p = %s\n", tmp);
     
        return 0;
    }
     
    cs












     조금씩 어려워지고 있으므로 집중하도록 하자. tmp는 9 개의 문자가 들어갈 방을 마련하였다. ( char tmp[9] = "triumph";)


     마지막 방은 널(NULL) 문자가 들어가야 하므로 문자열 + 널 문자 만큼의 공간을 마련하기 위해 배열 첨자를 9로 두었다.


     문자들을 저장해야 하기 때문에 char 형을 지정했으며 1 차원 문자배열의 주소 값을 저장하기 위해서 tmp_p라는 포인터 변수의 형도 char 로 지정하였다.


     다음 초기화하여 *tmp_p로 접근한 결과 tmp[0]의 문자, 즉 대상체의 개념을 포함하기 때문에 't'라는 값을 포함하고 있다.


     하지만 tmp_p는 대상체에 대한 개념이 없고 tmp_p 라는 포인터 변수에 들어 있는 주소 값만 을 뜻한다.


     포인터 변수에 '*'를 붙이는 순간 대상체에 대한 개념이 포함된다는 것을 반드시 기억해 두어야 한다.


     이것을 모르면 포인터에 대한 개념을 잡았다고 확신할 수 없다. 지금처럼 1차원일 때는 프로그램을 작성할 때 전혀 불편함이 없지만 2 차원부터는 대상체에 대한 개념 없이는 포인터에 대한 진전은 상당히 더디어진다.


     




    3. '포인터 변수 + 정수'의 의미

     포인터 변수에는 주소 값이 저장되어 있다. 이곳에 정수를 더한다는 것은 다음과 같은 의미를 가진다.


     '나는 SK View 아파트 105동 101호에 산다'라고 했을 때, '나의 친구는 SK View 아파트 105동 101호에 산다'라고 하는 것보다는 

     

     '나의 친구는 내 옆집에 산다' 라고 하는 것이 더욱 간결하고 이해하기 쉽다.


     그러한 상황을 포인터를 통해 연출할 수 있게 된다. 아래 예제를 살펴보자.

     

     

    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
    26
    27
    28
     
    /*
     * arrp.c
     *
     *  Created on: 2015. 7. 20.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
     
    int main(void) {
     
        int num_arr[3= {1030100};
        int *num_p = num_arr;
     
        printf("*num_p = %d\n"*num_p);
        printf("*num_p + 1 = %d\n"*num_p + 1);
        printf("*num_p + 2 = %d\n"*num_p + 2);
     
        puts("");
     
        printf("*(num_p) = %d\n"*(num_p));
        printf("*(num_p + 1) = %d\n"*(num_p + 1));
        printf("*(num_p + 2) = %d\n"*(num_p + 2));
     
        return 0;
    }
     
    cs









     위 세개의 출력문에서는 각각 10, 11, 12를 출력한다.


     출력 결과를 통해 포인터 변수 + 정수 연산을 괄호 없이 사용한 경우에는 대상체를 가져와서 더해주는 연산이 된다.


     아래 세개의 출력문에서는 각 num_arr의 요소를 접근하게 된다. 괄호의 사용 용도에 대해 알 수 있을 것이다.







    4. 1차원 문자배열과 포인터

     아래 예제를 충분히 습득하면 배열과 포인터에 대한 개념이 조금씩 명확해질 것이며, 포인터라는 산의 윤곽이 잡히고 어떻게 포인터를 습득해야 하는지 본인 스스로가 느낄 것이다.



    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
    /*
     * arrp.c
     *
     *  Created on: 2015. 7. 20.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
     
    int main(void) {
     
        int i;
        char tmp[] = "triumph";
        char *char_p = tmp;
     
        int tmp_size = strlen(tmp);
     
        puts("(1) 배열, char_p로 tmp[] 출력==================");
        printf("tmp[] = %c", tmp[0]);    // 배열 tmp[] 출력
        printf("%c", tmp[1]);
        printf("%c", tmp[2]);
        printf("%c", tmp[3]);
        printf("%c", tmp[4]);
        printf("%c", tmp[5]);
        printf("%c\n\n", tmp[6]);
     
        printf("*char_p = %c"*char_p);    // char_p를 사용하여 tmp[] 출력
        printf("%c"*(char_p + 1));
        printf("%c"*(char_p + 2));
        printf("%c"*(char_p + 3));
        printf("%c"*(char_p + 4));
        printf("%c"*(char_p + 5));
        printf("%c\n\n"*(char_p + 6));
     
        puts("(2) for문을 이용한 배열 tmp 출력==================");
        printf("tmp[] = ");
        for (i = 0; i < tmp_size; i++)
            printf("%c", tmp[i]);
     
        puts("");
        puts("");
     
        puts("(3) for문을 이용한 char_p 출력==================");
        printf("*(char_p) = ");
        for (i = 0; i < tmp_size; i++)
            printf("%c"*(char_p + i));
     
        puts("");
        puts("");
     
        puts("(4) char_p를 배열처럼 사용해서 출력 ===============");
        printf("char_p = ");
        for (i = 0; i < tmp_size; i++)
            printf("%c", char_p[i]);
     
        puts("");
        puts("");
     
        puts("(5) char_p를 증가연산자와 결합하여 사용해서 출력 ===============");
        for (i = 0; i < tmp_size; i++)
            printf("%c"*char_p++);
     
     
     
        return 0;
    }
     
    cs











    5. 배열명의 숨은 뜻

     '배열명은 주소 값이다'라고 말하면 50점이고 '배열명과 포인터 변수와의 정확한 차이점을 안다'라고 하면 100점이다.


     배열명의 숨은 뜻을 알면 포인터 변수와의 차이점은 자연히 구분되고 이를 자유롭게 사용할 수 있을 것이다. 


     배열명의 숨은 뜻을 알지 못하면 프로그래밍을 하면서 포인터 변수는 잘 처리되는데, 배열명으로는 왜 처리가 안되는지에 대한 명확한 답변을 얻을 수 없고 포인터 변수를 사용할 곳에 배열명을 사용함으로써 문제를 발생시키거나 그 반대의 경우가 생긴다.


     그러다 보면 결국 프로그래머는 이것저것 사용해보고 그 중 작동하는 것을 사용하거나 무조건 포인터 변수를 사용하게 되는 것이다.


     배열명과 포인터 변수에 끌려 다니지 말고 원리를 파악한 후 자유롭게 사용하자.






    1
    2
    3
    4
    int tmp[3= {157};
     
    int *tmp_p;
     
    cs




     tmp_p를 초기화 하는 방식에는 두 가지가 있다.


     1. tmp_p = tmp;

     2. tmp_p = &tmp[0];



     2번은 tmp의 배열 중에서 첫 번째 배열요소가 저장된 주소 값을 tmp_p에 할당한 것이다. 이것은 큰 문제는 발생시키지 않지만 2 차원 배열에서는 문제의 소지가 다분하다.


     

    1
    2
    3
    4
    5
    6
    7
    printf("%d %d %d\n", tmp[0], tmp[1], tmp[2]);
    printf("%d %d %d\n"*tmp, *(tmp + 1), *(tmp + 2));
     
    printf("%d %d %d\n", tmp_p[0], tmp_p[1], tmp_p[2]);
    printf("%d %d %d\n"*tmp_p, *(tmp_p + 1), *(tmp_p + 2));
     
     
    cs



     위의 4 문장은 모두 1, 5, 7 을 출력해 준다. 배열명을 사용하든 포인터 변수를 사용하든 전혀 차이점은 없다. for() 문을 사용하여 다시 작성해 보면 아래와 같다.


    1
    2
    3
    4
    5
    6
    7
    for (i = 0; i < 3; i++)
        printf("%d %d %d\n", tmp[i], *(tmp + i), tmp_p[i], *(tmp_p + i));
     
     
    1 1 1 1
    5 5 5 5
    7 7 7 7
    cs



     

     마지막으로 아래 프로그램을 구동하여 결과를 확인해보자.



    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
    26
    27
    /*
     * arrp.c
     *
     *  Created on: 2015. 7. 20.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
     
    int main(void) {
     
        int i;
        int tmp[3= {157};
        int *tmp_p = tmp;
     
        for (i = 0; i < 3; i++)
            printf("[ %d] = %d\n", i, *tmp_p++);
     
        puts("");
     
        for (i = 0; i < 3; i++)
            printf("[ %d] = %d\n", i, *tmp++);
     
     
        return 0;
    }
     
    cs




     22번 라인에서 에러가 날 것이다. 결국 위 예제들을 통해 알 수 있는 것은 아래와 같다.


      배열명은 주소 값이다.









    6. 종합예제

     문자열을 입력하고 입력된 문자열의 길이를 출력하는 프로그램을 작성해 보자.



    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    /*
     * arrp.c
     *
     *  Created on: 2015. 7. 20.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
    #define SIZE 512
     
    int string_length(char *);
     
    int main(void) {
     
        char buf[SIZE];
        int length;
     
        fgets(buf, sizeof(buf), stdin);
     
        length = string_length(buf);
     
        printf("문자열의 길이는 %d 입니다.\n", length);
     
        return 0;
    }
     
    int string_length(char *buf) {
        int size;
     
        for (size = 0*buf != '\0'; buf++)
            size++;
     
        return size;
    }
     
    cs











    다음은 입력한 문자열 중에서 대문자가 몇 개나 입력되었는지 알아보는 프로그램이다.




    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    /*
     * arrp.c
     *
     *  Created on: 2015. 7. 20.
     *      Author: Yeonsu
     */
     
    #include <stdio.h>
    #define SIZE 1024
     
    int get_count_upper(char *);
     
    int main(void) {
     
        char buf[SIZE];
        int count;
     
        fgets(buf, sizeof(buf), stdin);
     
        count = get_count_upper(buf);
     
        printf("입력한 문자 중에 대문자는 %d 개 입니다\n", count);
     
        return 0;
    }
     
     
    int get_count_upper(char *buf) {
        int count = 0;
     
        while (*buf) {
            if ((*buf >= 'A') && (*buf <= 'Z'))
                count++;
            buf++;
        }
     
        return count;
    }
     
    cs









    댓글

Designed by Tistory.