Programming/C C++
다음 Program은 변수를 활용한 간단한 예제입니다.

#include <stdio.h>

main()
{
  int i;
 
  i = 100;
 
  printf("i값 : %d\n", i);
}


이 Program은 결과로 i값을 출력합니다.


이 Program은 변수 i에 3이라는 값을 넣고 다시 i변수를 통해 해당 값을 출력하도록 작성된 예제입니다.

그런데 Computer의 입장에서 보면 단순히 변수 i가 있다는 것에서 끝나지 않습니다. 변수 i가 선언되면 Memory에 integer형의 Data를 담을 수 있는 공간을 확보하고 그 안에 3이라는 정수값을 저장합니다. 이때 저장된 해당 위치를 Memory의 Address라는 주소형태로 구분해야 합니다.

만일 변수라는 개념이 없이 개발자가 직접 Memory주소를 가지고 Data를 다루게 되면 Program구현이 상당히 어려워지고 위험해지게 될 것입니다. 그래서 Memory주소를 직접 다루는 대신 변수라는 Data를 다루기 시작한 것입니다.

일반적으로 변수를 참조하면 해당 변수에 들어있는 값을 다루게 되는데 만일 변수의 값이아닌 변수가 가리키고 있는 Memory주소를 직접 다루고자 한다면 Pointer를 사용해야 합니다.

#include <stdio.h>

main()
{
  int i;
  int *p;
 
  i = 100;
  p = &i;
 
  printf("i값 : %d\n", i);
  printf("i의 memory 주소값 : %d\n", p);
  printf("해당 memory주소에 있는 실제 data : %d\n", *p);
}


Pointer를 쓰기위해 int *p; 로 Pointer를 선언합니다. 이 Pointer는 p = &i;를 통해 i변수의 주소값을 저장하고 마지막 printf()함수를 통해 pointer가 가리키고 있는 Memory주소에서 Data를 가져와 보여주고 있습니다.


이처럼 특정 변수에 값이 아닌 주소를 직접 불러오려고 하면 변수 앞에 & 문자를 붙여 주기만 하면 됩니다. 이때 이렇게 불러들인 주소값을 직접 다루기 위해 Pointer가 사용되는 것입니다.

Pointer는 특정 변수가 가리키고 있는 번지를 기억하는 역활을 하며 Pointer를 통해 해당 Memory번지에 있는 Data를 가져오려면 Pointer앞에 *문자를 추가해야 합니다. 그러면 Pointer는 Memory주소에 있는 값을 직접 나타내게 되는 것입니다.

1. 배열과 Pointer의 활용

배열을 활용하고 있는 다음 Program을 보십시오.

#include <stdio.h>

sprint(char ss[]);

main()
{
  char s[6] = "hello";
 
  sprint(s);
}

sprint(char ss[])
{
  int i;
 
  for (i=0;i<=4;i++){
    printf("%c\n", ss[i]);
  }
 
  return;
}


이 Program은 main함수에서 char형 배열변수에 hello라는 문자열을 대입하고 sprint함수의 for문으로 해당 배열값의 각요소를 출력합니다.


main함수에서 sprint함수를 호출할때 작성한

sprint(s);

이 부분을 주목해 주세요.

배열을 전달할때는 위와 같이 배열변수 이름만이 사용되고 있습니다. 이는 배열전체를 모두 전달하는 것이 아니라 배열이 시작되는 Memory의 첫 주소값을 전달하고 sprint함수에서는 전달받은 주소값을 통해 배열값을 활용하고 있습니다.

즉 배열의 경우 배열변수이름만 쓰게되면 해당 배열이 시작되는 주소값을 얻게 된다는 것이고(일반변수처럼 & 문자를 붙이지 않습니다.) 이 특징 통해 Pointer에서도 배열을 다룰 수 있다는 의미가 됩니다.

#include <stdio.h>

main()
{
  char s[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
  char *p;
 
  p = s;
 
  printf("%s\n", p);
}


char배열 s의 시작주소를 char주소를 기억하는 p Pointer에 대입합니다. 그러면 s와 Pointer p의 주소는 같아지고 Printf함수에서는 배열 s가 아닌 p형 Pointer로 문자열을 출력할 수 있는 것입니다.(s배열로 문자열을 출력할때도 printf("%s\n", s); 로 주소값을 통해 문자열을 출력하였으므로 Pointer로 출력할때도 p를 그대로 사용하여야 합니다. *p로 하면 주소에 있는 값을 받아오므로 제대로된 결과를 얻을 수 없습니다.)


Pointer로 문자열 표현시 위에서 처럼 배열을 사용하는 경우도 있지만 Pointer자체에 직접 문자열을 초기화 하는 것도 가능합니다.

#include <stdio.h>

main()
{
  char *p = "hello";
 
  printf("%s\n", p);
}


Pointer p에 "hello"라는 문자열을 초기화 합니다. 이때 Pointer p는 "hello"문자열을 저장하고 있는 Memory에서 h로 시작하는 주소를 갖게 됩니다.


위 Program에서 p는 "hello"문자열의 시작주소를 가지고 있으므로 첨자로 배열주소를 지정하면 문자배열처럼 다룰 수 있습니다.

#include <stdio.h>

main()
{
  char *p = "hello";
  int i;
 
  for (i = 0; i < 5; i++)
    printf("%c\n", p[i]);
}



참고:
예제에서는 for문을 통해 Pointer p의 첨자를 증가시키면서 주소에 있는 값을 가져오고 있습니다. 이는 언뜻 보면 p Pointer의 주소를 1씩 증가시키는 것처럼 보일 수도 있으나 실제로는 그렇지 않습니다.

현재 Pointer p는 char형이므로 Pointer p에 +1을 한다는 것은 1byte만큼의 주소를 건너뛴다는 의미가 됩니다. 잘 알고계시는 바와 같이 char형은 8bit(1byte)의 Memory공간을 갖고있기 때문입니다.

2. Ponter를 통한 값의 변경

Pointer는 주소값을 가진다고 하였습니다. 이 Pointer에서 직접 값을 조작하면 원래 변수에 있던 값도 같이 바뀌게 됩니다. 왜냐하면 Pointer와 변수는 같은 주소를 유지하고 있기 때문입니다.

#include <stdio.h>

main()
{
  int a = 100;
  int *p;
 
  p = &a;
 
  *p = 200;
 
  printf("a의 값 %d - p의 값 %d\n", a, *p);
}


처음 변수 a에 100의 값을 대입하고 Pointer p에 해당 변수의 주소값을 건네준뒤 *p = 200;에서 Pointer가 가리키는 주소(변수 a의 주소)에 있는 값을 200으로 변경합니다. 이때 변수 a도 Pointer p와 같은 주소값을 가지고 있으므로 200의 값을 갖게 됩니다.


#include <stdio.h>

main()
{
  char s[6] = "hello";
  char *p;
  int i;
 
  p = s;
 
  *(p + 3) = 'p';
  *(p + 4) = '!';
 
  printf("%s\n", s);
  printf("%s\n", p);
 
  for (i = 0; i <= 5; i++){
    printf("%c\n", *(p + i));
  }
}


char형 배열 s에 "hello"라는 문자열을 초기화 한 후 배열의 시작주소값을 Pointer p에 전달합니다. Pointer p는 s배열의 시작주소을 가지므로 Pointer값을 1증가면 Pointer p주소값이 1만큼 늘어나게 되므로 Pointer p는 문자 'e'가 위치한 주소로 바뀌게 됩니다.

주의:
void형의 Pointer는 특정 범위를 주소값을 가지고 있는 상태가 아니므로 +나 -연산이 불가능합니다.

이런 원리를 통해 *(p + 3) = 'p'; 라고 하면 Pointer p의 주소값 3늘어나게 되고 (이때 p는 "hello"에서 4번째 배열을 가리키는 'l'의 주소값을 의미합니다.) 동시에 값을 'p'로 바꾸고 있습니다. 이와 같은 방법으로 마지막 배열의 주소값 Data도 '!'로 바꾼 후 최종적으로 조회하게 되면 다음과 같은 결과를 얻게 되는 것입니다.


3. const와 Pointer

Pointer변수를 const로 하면 값을 변경할 수 없는 Pointer가 됩니다. 이때 const를 어떻게 선언하느냐에 따라 주소값을 const로 할것인가 또는 값을 const로 할것인가가 달라지게 됩니다.

(1) 주소 const

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  char *const p = s;
 
  printf("%s\n", p);
}


*const p 형태로 Pointer를 선언해서 이 Pointer에 지정된 주소값 자체는 바꿀 수 없도록 하고 있습니다.


여기서 주소값을 바꿀 수 없다는 점에 주목해 주십시오. char *const p = s;로 Pointer를 선언함과 동시에 배열 s의 주소값을 대입하고 있는데 이렇게 하는 이유는 *const p로 인해 주소값을 바꿀 수 없기 때문에 선언과 동시에 주소값을 전달해 줘야 하기 때문입니다.

결국 다음과 같이 *const 로 Pointer를 선언한 뒤 새로운 값을 대입하는 것은 불가능한 것입니다.

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  char *const p;
 
  p = s;
 
  p += 1;
 
  printf("%s\n", p);
}


*const p로 Pointer를 선언하고 p에 s의 주소값을 대입하고 있으며 이후 Pointer자신의 값을 다시 1만큼 증가하도록 하고 있습니다.


Compil시 값을 바꿀 수 없다는 Error를 표시하고 있습니다.

(2) 값 const

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  const char *p;
 
  p = s;
 
  printf("%s\n", p);
}


const char *p로 Pointer를 선언하여 Pointer의 주소는 바꿀 수 있으나 값을 바꿀 수는 없도록 하고 있습니다.


예제에서 p = s;를 통해 주소값을 대입하고 있지만 해당 Pointer는 값을 바꿀 수 없는 형태의 Pointer이므로 아무런 문제 없이 Compil되고 실행됩니다.

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  const char *p;
 
  p = s;
 
  *p = 'x';
 
  printf("%s\n", p);
}


const로 선언된 Pointer에 *p = 'x';의 형태로 값을 바꾸도록 하고 있습니다.


p Pointer는 const로 선언되었으므로 값을 바꿀 수 없다는 Error를 내며 Compil에 실패합니다.

4. 범용 Pointer

Pointer의 선언은 원래

char *p;

처럼 해당 Pointer의 Data형을 지정됩니다. 하지만 어떤 Data형으로도 쓰일 수 있는 Pointer가 있는데 그것이 바로 범용 Pointer입니다. 이러한 범용 Pointer는 다음과 같이 선언됩니다.

void *p;

Pointer선언 부분에 Data형 대신 void라고 하면 해당 Pointer는 범용 Pointer가 됩니다. 이렇게 선언된 Pointer는 어떤 Pointer라도 포함할 수 있게 됩니다.

void *p;
char *cp;
int *ip;
 
p = cp;
p = ip;

하지만 범용 Pointer의 주소를 일반 변수에 대입할 때는 그Data형을 지정해 줘야 합니다. 왜냐하면 범용 Pointer는 주소값만 가질뿐이지 어떠한 Data형인지 지정되지 않았기 때문에 얼마만큼의 Memory를 확보해야 하는지에 대해서는 알 수 없기 때문입니다.

#include <stdio.h>

main()
{
  void *p;
  char c;
  int i;
 
  c = 100;
  p = &c;
 
  i = *(int *)p;
     
  printf("%d\n", i);
}


int i에 대입시 범용 Pointer를 int형 Pointer로 cast하여 대입(*(int *)p)하고 있습니다.


만일 위와 같이 하지 않고 그냥 대입하려 한다면

#include <stdio.h>

main()
{
  void *p;
  char c;
  int i;
 
  c = 100;
  p = &c;
 
  i = *p;
     
  printf("%d\n", i);
}


Compiler는 오류를 발생시키게 됩니다.


5. 함수와 Pointer와의 관계

변수를 선언하면 그 변수는 Computer의 Memory에서 해당 Data형에 맞는 크기 만큼의 영역을 확보하게 될 것입니다.

함수도 마찬가지 입니다. 함수자체도 Memory어딘가에 위치하고 있으며 결과적으로 함수가 위치한 이 주소값을 Pointer로 활용할 수 있습니다. 따라서 실제로 이런 동작을 구현하게 되면 직접 함수를 호출하지 않고도 Pointer만으로 함수를 호출한 것과 같은 결과를 얻을 수도 있습니다.

#include <stdio.h>

int plus(int i, int j);

main()
{
  int (*pls) (int i, int j);
  int ir;
  pls = plus;
 
  ir = pls(10, 20);
 
  printf("%d\n", ir);
}

int plus(int i, int j)
{
  return i + j;
}


int (*pls) (int i, int j);을 통해 함수형 Pointer인 pls를 선언합니다. 이때 Pointer를 함수처럼 호출할때의 인수도 int, int j같이 지정해 줘야 합니다.

이 Pointer를 pls = plus;와 같이 대입하면 plus() 함수의 주소값이 해당 pls Pointer에 대입되고 이후 pls(10, 20);를 통해 함수를 호출하듯이 사용할 수 있게 되는 것입니다.

이는 plus함수가 Memory의 1000번지에 있다고 가정한다면 plus(10, 20);라고 하였을 경우 1000번지에 10과 20을 넘겨 처리를 수행한다라는 의미가 되므로(주소값이 목적이 되므로) 주소값을 갖는 Pointer를 함수처럼 활용하는것 또한 가능해 지는 것입니다.


다음은 함수 Pointer를 조금 변형한 것으로 함수의 인수 자체를 함수 Pointer로 구현한 것이며 결과는 이전 예제와 같습니다.

#include <stdio.h>

int plus(int i, int j);

main()
{
  int ir;
 
  ir = callplus(plus, 10, 20);
 
  printf("%d\n", ir);
}

int callplus(int (*pls) (int i, int j), int x, int y)
{
  return pls(x, y);
}

int plus(int i, int j)
{
  return i + j;
}


callplus(plus, 10, 20)에 의해 함수자체를 함수 Pointer의 인수로 건네줍니다. 이때 callplus()함수는 그 내부에서 전달받은 함수 Pointer를 통하여 실질적인 함수호출을 실현합니다.

함수 Pointer에 대해 하나더 언급하자면 함수 Pointer도 배열로 처리하는 것이 가능하다는 것입니다. 이미 변수 Pointer를 언급할때 배열로서 처리할 수 있다라고 하였는데 이것은 함수 Pointer의 경우도 마찬가지 입니다.

#include <stdio.h>

int plus(int i, int j);
int mlus(int i, int j);

main()
{
  int (*pls[2]) (int i, int j);
  int ir;
  int ir2;
 
  pls[0] = plus;
  pls[1] = mlus;
 
  ir = pls[0](10, 20);
  ir2 = pls[1](30, 10);
 
  printf("%d\n", ir);
  printf("%d\n", ir2);
}

int plus(int i, int j)
{
  return i + j;
}

int mlus(int i, int j)
{
  return i - j;
}


int (*pls[2]) (int i, int j);을 통해 pls Pointer함수를 배열로 하여 2개(0~1)를 생성하도록 하였습니다.

이후 일반 배열처럼 pls[0], pls[1]... 과 같이 해당 함수 Pointer를 활용하기만 하면 됩니다.

'Programming > C C++' 카테고리의 다른 글

[C, C++] Microsoft C, C++ Compiler  (0) 2010.01.22
[C, C++] Class 상속  (0) 2010.01.13
[C, C++] 함수작성및 Data전달  (0) 2010.01.07
C언어 함수사용 예제 Souce  (0) 2010.01.06
[C, C++] Pointer  (0) 2010.01.05
[C, C++] 변수통용범위(변수의 기억 Class)  (0) 2010.01.04
0 0