대학교에 다니면서 잠시나마 적었던 C언어 기초 강좌 입니다.

그나마 Pointer는 정성들여 썼길래 이 blog에 옮겨서 적어 놓습니다.

14강 3부 포인터의 활용

지금까지 힘들게 1부(http://scanhand.cafe24.com/226-2), 2부(http://scanhand.cafe24.com/pointer-part-2)를 통해서 포인터란 무엇인지 알아보았다.

그런데 과연 이 포인터가 무슨 쓸모가 있길래 이렇게 힘들게 배워야 하는걸까?

굳이 포인터를 쓰지 말고 그냥 기존에 배웠던대로 int a = 3; 이런식으로 쓰면 될 것을 힘들게 포인터란 것을 만들어서 우리를

시험에 들게(^^;) 하는 이유는 무엇일까? 내가 생각 하는 포인터의 가장 큰 용도는 아래 두가지 이다.

  1. 함수의 전달인자로서의 용도

  2. 변수의 동적할당을 위한 용도

(C Language 기준)

제목만 봐서는 무슨 용도인지 모를것이다. 그럼 하나하나 어떤용도로 쓰이지는 예를 들어가면서 살펴보도록 하겠다.

  • 함수의 전달인자로서의 용도

우리가 지금까지 함수를 배우고 만들면서 함수의 전달인자로 int, long, double과 같은 일반적인 변수형을 이용하였다. 이처럼 포인터도

하나의 변수의 형으로서 다른 형과 마찬가지로 함수의 전달 인자로 사용할 수 있는 것이다. 예를 들어

int main()
{
    int  a = 0;
    test(&a);
    printf("a = %d", a);
    return 1;
}

void test(int  *pA)
{
   *pA = 3;
}

이런식의 함수를 만들 수 있는것이다. 기존의 전달인자인 int a대신 int의 포인터형인 int *pA를 전달인자로 사용하였다. main()함수에서

는 test()함수를 호출할때 변수 a의 주소값을 넘기는 것을 볼수 있다. 즉 int형 포인터 변수 pA는 a변수의 주소를 가지고 있는것이다.

pA = &a;

다음으로 test()함수 내에서 pA에 3이라는 값을 대입하고 있다. pA는 현재 a변수의 메모리 주소를 가리키고 있기에 3이라는 값은 a변수

의 메모리에 저장이 된다. 그래서 printf()로 a의값을 출력하면 0이 아닌 3이라는 값이 출력되는 것이다.

이것을 다른 방식으로 생각하면 기존에 함수에서 결과값을 받고자 할때는 단 하나의 return값만을 받을 수 있었지만 전달인자로 포인터

형 변수를 이용하면 여러개의 값을 받을 수 있다.

int  main()
{
    int a, b, sum, sub;
    a = 10;
    b = 3;
    sum = sub = 0;
    process(a, b, &sum, &sub);
    printf("sum = %d, sub = %d\n", sum, sub);
    return 1;
}

void process(int c, int d, int *pSum, int *pSub)
{
   *pSum = c+d;
   *pSub = c-d;
}

결과화면

c_14_3_1

위예제에서 처럼 process()함수에 4개의 전달인자를 넘겨주고있다. 이 전달인자는 아래와 같은 방식으로 전달 된다고 생각 할 수 있을

것이다.

c = a;
d = b;
pSum = ∑
pSub  = ⊂

우리가 배열을 배울때 배열의 이름은 그배열의 시작주소를 뜻한다고 했다. 그리고 실제로 포인터변수를 이용해서 배열을 다루는 것을 지

난 강좌에서 알아보기도 했었다. 그렇다면 이얘기는 함수의 전달인자로 배열을 넘길 수 있다는 것이다. 실제로 예를 들어보자.

int  main()
{
    int a[10], i;
    for(i=0; i<10; i++)
        a[i] = 0;
    process(a);
    for(i=0; i<10; i++)
        printf("%d\n", a[i]);
    return 1;
}

void process(int *pA)
{
    int i=0;
    for(i=0; i<10; i++)
        pA[i] = i;
}

결과화면

c_14_3_2

역시 예상대로 배열을 전달인자로서 사용 할수 있다.

이처럼 함수의 전달인자 전달 방식은 크게 두가지로 나눌 수 있는것이다. 일반적인 변수형을 사용하여 데이터 값을 전달하는 방식인 값

전달 방식 call by value 과 포인터형 변수를 사용하여 주소를 전달하는 방식인 주소 전달 방식 call by reference 으로 구분 한다.

  • 변수의 동적할당을 위한 용도

우선 변수의 동적 할당이란것은 어떤 변수에 내가 원할때 메모리를 할당하고 또, 내가 원할때 메모리를 삭제 하는 것을 뜻한다.

즉 정해져 있는 대로 메모리를 쓰는게 아니라 내맘대로 메모리를 할당하고 삭제 하겠다는 것이다.

int  main()
{
   int  a, b;
   int  sum;
   a=5;
   b=3;
   sum = a+b;
   printf("sum=%d\n", sum);
   return 1;
}

위 예제에서 int a,b;이라고 선언을 하게 되면, a,b 라는 변수에 자동으로 메모리가 할당 되게 된다. 그리고 main()함수가 끝나는 시점인

return 1; 다음의 } 이곳에서 a,b의 메모리는 자동으로 해제되게 된다. 이것은 우리가 어찌 할수가 없이 정해져 있는 대로 메모리가 할당되

고 해제 되는 것이다.

그런데 여기서 sum=a+b; 이 문장 이후에는 a,b라는 변수는 더이상 필요치가 않다. 즉 쓸데 없는 메모리가 사용되고 있다고 볼수있다.

(너무 억지스럽지만 그냥 대충 그렇다고 하자^^;) 이렇게 변수를 더이상 사용하지 않을때 내가 원하는 곳에서 삭제하고 내가 쓰고 싶을

때 할당을 하려면 아래와 같이 사용하면 된다.

#include <stdio.h>
#include <malloc.h> /*malloc()함수를 쓰기위해서 필요한 Header File*/

int  main()                   
{
   int  *pA, *pB;
   int  sum;
   pA   =(int*) malloc(sizeof(int));
   pB   =(int*) malloc(sizeof(int));
   *pA =5;
   *pB = 3;
   sum = *pA+*pB;
   free(pA);
   free(pB);
   printf("sum=%d\n", sum);
   return 1;
}

붉은색 부분에 보지 못했던 함수들을 사용하였다. 하나씩 알아보도록 하자.

우선 포인터변수에 메모리를 할당하고자 할때는 malloc()이라는 함수를 사용한다.

이 함수의 전달인자로 메모리의 크기를 byte단위로 넘겨주면 해당 크기만큼의 메모리를 할당하고 그주소값을 return해 준다. 여기에

(int*) 를 사용하는것은 할당된 주소를 저장하고자 하는 변수가 int * 형이기에 써주는 걸로 이해하자. 자세한 내용은 기회가 생기면 언급

하도록 하겠다.

sizeof() 함수는 전달인자로 넘긴 변수형의 크기를 return한다. 즉 malloc()함수는 int형의 크기인 4byte만큼의 메모리를 할당하여 그 주

소값을 pA에 저장하는 것이다. 이렇게 할당된 메모리를 해제하고 싶을때는 free()함수에 해당 포인터 변수를 넘겨주면 된다.

동적할당은 위 예제처럼 메모리의 할당 및 삭제를 내가 원하는 순간에 할 수 있는 기능도 있지만, 실제적으로 주 사용처는 동적배열이라

고 할 수있다. 지금 까지 배열이라고 하면 int a[10]; 과 같이 미리 그 크기를 할당하고 사용해 왔다. 하지만 동적배열은 배열의 크기를 시

시때때로 내가 맘대로 조정할수 가 있게 된다. 사용방법은 기존 동적할당과 거의 비슷하다.단지 malloc()함수의 전달인자에 데이터 형

에 배열의 크기 만큼 곱한값을 전달 해 주면 된다.

index = 100;
pA   =(int*) malloc(sizeof(int) * index );
pB   =(int*) malloc(sizeof(int) *  index);
free(pA);
free(pB);

malloc()함수에는 400이라는 값이 전달이 되고 400byte의 메모리가 할당된후 그 시작 주소값을 pA에 저장하게 된다. 이것은 index변수

에 들어가 있는 값에 따라 pA에 할당되는 배열의 크기가 달라지는 것과 같다고 얘기할 수 있다. 즉 내가 원하는 대로 배열을 만들수 있는 것이다.

지금 까지 우리는 포인터에 대해서 대략적으로 알아보고 가장 기초적인 사용방법에 대해서 알아 보았다. 이 포인터 강좌는 실제 포인터에

대한 모든것을 다루고자 작성된것이 아니다. 단지 포인터를 공부하는데 있어서 조금이나마 도움이 되었으면 하는 마음에서 작성된것

이라는 것을 기억해 주기 바란다. 참고로, 처음기획단계에서 포인터를 3부로 설명을 마치려 했지만, 많이 부족한듯 하여 부록으로서

int**pA; 이런형식의 2차 포인터에 대해서 간략하게 설명하도록 하겠다.