끄적끄적

반응형

1. 포인터


1.1      포인터의 선언

포인터는 프로그램 메모리 주소를 가질 수 있는 변수 타입입니다.  C언어에서 포인터를 선언할 때에는 원소 타입을 명시하고 포인터 변수를 지시하는 *를 명시하게 됩니다.

 

포맷:

[type] *[변수명];

int *p_exam; /* 정수형 포인터형 번수 p_exam을 선언하였다.  */

 

 여기서 p_exam은 메모리 주소를 갖을 수 있는 포인터 타입으로 해당 메모리 주소에 있는 원소를 int형으로판단하고 사용하겠다는 의미입니다. 실제 p_exam이 가지고 있는 메모리 주소에는 실제 정수형 변수가 있을 수도 있지만 다른 타입의 변수가 있거나 아무런 의미가 없는 주소일 수도 있습니다.  p_exam을 적절한 주소를 대입하고 이를 관리하는 것은 모두 개발자의 책임으로 되어있고 이에 개발자는 신중하게 사용하여야 합니다.

 

int arr[10]={1,2,3,4,5,6,7,8,9,10};

char arr2[10]="123456789";

int count;

int *p_exam; /* 정수형 포인터형 번수 p_exam을 선언하였다.  */

p_exam = arr;

for(count=0;count<10;count++)

{

    printf("[%d] ",*p_exam);

    p_exam++;

}

p_exam = arr2;

while(*p_exam != '\0')

{

    printf("[%c] ",*p_exam);

    p_exam++;

}

 

먼저 선언하는 부분을 살펴보면 크기가 10인 int형 배열과 크기가 10인 char형 배열을 선언 및 초기화를 하였고 테스트를 위해 int 포인터형 변수와 int형 변수 count를 선언하였습니다.

 

int arr[10]={1,2,3,4,5,6,7,8,9,10};

char arr2[10]="123456789";

int count;

int *p_exam; /* 정수형 포인터형 번수 p_exam을 선언하였다.  */

 

p_exam = arr;

for(count=0;count<10;count++)

{

    printf("[%d] ",*p_exam);

    p_exam++;

}

 

 첫번째 루틴에서는 int형 배열의 요소들을 제어하기 위해 p_exam에 arr의 값을 대입하는 구문이 있습니다.  물론 arr은 int형을 원소로 하는 배열명이기 때문에 int형 포인터 상수로 취급을 할 것입니다.  즉, p_exam=arr;이라는 구문은 적절한 표현이 된다는 것입니다.  해당 for문에서는 각 원소에 있는 내용을 출력하는 구문으로 되어 있고 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]이 출력되는 것을 이해할 수 있을 것입니다.

 

p_exam = arr2;

while(*p_exam != '\0')

{

    printf("[%c] ",*p_exam);

    p_exam++;

}

 

그렇다면 두 번째 루틴은 어떠한 실행 결과를 얻게 될까요?  여기에서도 앞에서와 같이  char형 배열의 요소들을 제어하기 위해 p_exam에 arr2의 값을 대입하였습니다.  문제는 arr2가 문자형 배열명으로 char형 포인터 상수로 취급이 된다는 것이지요.  하지만 이를 p_exam이라는 int형 포인터 변수에 대입을 하였고 여기서부터 문제가 발생을 하는 것입니다.  실제 개발자는 arr2의 각 원소의 내용을 출력하고자 하였을 것입니다.  하지만 p_exam이라는 int형 포인터 변수를 통해 처리를 하고자 하는 잘못된 판단때문에 [1] [2] [3] [4] [5] [6] [7] [8] [9]라고 출력하지 않고 [1] [5] [9] ...과 같은 결과를 야기하게 됩니다.  이는 앞서 얘기했던 것처럼 p_exam++이 주소를 1씩 증가하지 않고 4씩 증가하는 데에서 야기된 것입니다.  즉, 포인터 형 변수의 가감 연산에서는 언제나 포인터 형 변수의 타입이 가감의 기준이 됩니다.  이에 우리는 포인터 변수를 선언하고 사용을 할 때에는 어떠한 원소를 접근하기 위한 것인지에 대한 고민은 반드시 선행되어야 할 것입니다.



1.2       포인터 형 변수의 사용

포인터형 변수는 프로그램에서 여러가지 경우에 사용이 됩니다.  이 책에서는 크게 네가지의 경우에 대해서 설명을 하도록 하겠습니다. 첫번째는 지역변수에서 호출하는 함수에게 접근을 하기 위해서 지역 변수의 주소를 매개변수로 넘기고 포인터 변수로 사용하는 방법입니다.  그리고, 두번째는 배열로 선언된 변수의 각 원소에 접근하기 위해 포인터를 상요하는 경우, 세번째는 동적으로 할당받은 메모리를 관리하는 경우입니다.  그리고, 마지막으로 함수명이 갖는 code memory주소를 받아 사용하는 방법입니다.  세번째의 경우는 동적 메모리 할당에 관련된 내용에서 다루기로 하고 네번째 방법에 대해서는 이번장에서 간략히 설명하고 프로그래밍 과정을 설명하면서 다루기로 하겠습니다. 

 

먼저 지역변수를 호출하는 함수에게 접근을 할 수 있게 하기 위한 방법에 대해서 알아보기로 합시다. 

 

지역변수의 경우는 선언된 블럭 내에서만 가시성이 있다고 하였습니다.  이를 해당 블럭에서만 사용할 수 있다고 생각을 하는 경우가 많은데 실제 가시성이 없어 다른 블럭에서 접근을 못하는 것이지 현재 해당 변수를 위해 메모리가 할당이 되어 있다면 접근을 하는 것이 잘못된 것이 아닙니다.  예를 들어 두 개의 지역변수의 값을 바꾸는 경우를 생각해 봅시다.  이 때 우리는 해당 지역변수의 주소를 입력매개변수로 넘겨 호출받은 함수에서는 간접 연산을 통해 값을 바꾸었습니다.

 

void swap(int *pa,int *pb)

{

   int temp = 0;

   temp = *pa;

   *pa = *pb;

   *pb = temp ;

}

void foo()

{

   int i=2, j = 3;

   swap(&i,&j);

}

 

 그리고, 기본 입력함수 scanf함수를 사용할 경우에도 우리가 선언된 변수의 주소를 넘겨줌으로써 scanf함수에서는 변환하여 우리가 선언한 변수에 적절한 값을 대입할 수가 있었던 것입니다. 

 

 그럼, 두번째 경우인 배열로 선언한 공간을 포인터 변수로 사용하는 경우에 대해 알아보기로 합시다.

 

char name[10];

fnInsertStr(name,10);

 

이의 예문에서 fnInsertStr() 함수를 호출하면서 배열명과 크기를 입력 매개변수로 사용하였는데 그렇다면 fnInsertStr()함수의 입력 매개변수의 타입은 어떻게 될 것인지를 예측해 보도록 합시다.  먼저 두번째 입력 매개변수는 int혹은 unsigned형으로 받을 수 있다는 것을 쉽게 알 수 있을 것입니다.  그렇다면 첫번째 입력 매개변수의 타입은 어떻게 되겠습니까?  배열명이 원소의 메모리 주소를 갖고 있다는 것을 잊지는 않았겠지요.  그렇다면 첫번째 입력매개변수는 char형 포인터로 받으면 된다는 것을 쉽게 유추할 수 있을 것입니다.

 

void fnInsertStr(char *p_in, unsigned int len)

{

    int count=0;

    char temp=’\0’;

    while((temp=getchar())!='\n')&&(count<len-1))

    /* stdin으로 부터 한문자를 얻어오고 그 문자가 '\n'가 아니고 현재 처리한 문자의 개수가 len-1보다 작을 동안 loop을 수행하라. */

    {

        p_in[count]=temp;

        count++;

    }

    p_in[count]='\0';  /* 문자열의 끝임을 처리 */

    fflush(stdin);       /* stdin에 남아있는 문자들을 flush시킴 */

}

 

전체적으로 다시 살펴보자면 배열을 통해 변수를 선언하고 배열명을 입력매개변수로 넘겼고 포인터형 변수로 전달 받아 배열처럼 해당 공간을 사용하고 있습니다.  만약, 이책을 통해 여러분이 "배열과 포인터는 같다"라는 느낌을 받는다면 배열과 포인터의 정의를 이해한 것이고 "그래도 배열과 포인터는 조금은 다르군"이라고 느낀다면 동적 메모리 할당을 통해 적절히 프로그래밍을 하는 방법을 터득한 것이고 "그래도 역시 배열과 포인터는 비슷해"라고 느낀다면 이제 C언어를 통해 프로그래밍하면서 알아야 할 배열과 포인터는 어느정도 갖추어졌다고 할 수 있다고 본인은 생각합니다.  여러분이 이 책을 전체를 학습하고 얼만큼 여러분의 것으로 만들었는지 점검해 보시기 바랍니다.



반응형
Please Enable JavaScript!
Mohon Aktifkan Javascript![ Enable JavaScript ]