12 minute read

#1905   손현곤   (sonsea  )
[강좌] C 포인터 선언 이해의 새장 (소개)      01/04 12:53   
25 line

안녕하세요!!

C를 시작하자!의 sonsea입니다.
 제가 이제부터 올려드릴 강좌는 서울대학병원 레지던트인 변성완님
이
개발한 B 구문법이라고 하는 새로운 포인터 선언에 관한 명쾌한 해
석 방법에 관해서 입니다.
 
 뭐, 새로운~이라고 할 것도 없죠. 이것은 91년도에 발표되었으니
깐.

사실, 윈도우즈 프로그래밍으로 환경이 이전하면서 포인터에 대한 복
잡한 사용은 현저히 줄었습니다만, 도스 C로 프로그래밍에 입문하시
고 계시는 여러분들을 위하여 글을 올리겠습니다. 성완님이 사용중지
가 되어연락드릴수 없었으나 이해해주실 것으로 믿고..

 먼저 이 강좌가 요구하는 수준은 C의 완전 초보가 아니라 문법정도 
특히 포인터는 개념이라도 잡고 계신분이라야 합니다.
 예를 들면,
  int x;
  int ax[3];
  int *px;
  int func();
 뭐, 이정도는 알고 계셔야 한다는 것이죠..

 이 강좌는 4회 정도로 올라갈 것입니다. 많이들 기대해 주세요..
 안녕히..


#1906   손현곤   (sonsea  )
[강좌] C 포인터 선언의 명쾌한 새장! (1)      01/08 07:13   
93 line


안녕하세요! C를 시작하자의 SS입니다..
다시 만나게 되어 정말 반갑습니다~

 이 글의 출처는 서울대학병원의 레지던트로 계시는 변성완님이 개발
하신 B구문법에 관한 글입니다. 옮긴이가 나름대로 쉽게 풀어 쓸 것
입니다. 91년엔가 마소지에서도 소개된 적이 있으니, 마소91년게 있
는 분은 보실 필요가 없습니다. 편의를 위해서 경어를 생략하겠습니
다.


==================================
 # 기본적으로 알아야 할 선언 구문
==================================

 이 글에서 기본적으로 알아야 한다는 전제로서의 C언어의선언 구문
을 몇개 살펴 보자. C로 짜여진 소스 프로그램을 보고 그것이 C언어
로 짜여진 프로그램이라는 것을 알 정도의 사람이라면 누구나 아는 내
용일 것이다.

 int x; 정수형 변수 x를 선언
 int ax[3]; int형 배열 ax를 선언
 int *px; int형을 가리키는 포인터 px를 선언
 int f(); int 형을 돌려주는(리턴하는) 함수를 선언

 만일 위의 선언들을 구분하지 못하시는 분이라면 C의 포인터를 입문
서나 SS의 강좌를 통해서 익히고 이 글을 보셔야 할 것이다.


=============================
 # 난해한 C의 선언 구문의 예
=============================

 자신의 수준을 한 번 겸허하게 되돌아보기 바란다.
 우선 여러분들의 기를 꺽어 놓기 위해, 그럴 듯한 선언을 모아 놓
은 표를 제시한다. 이 표는 Turbo C++ 1.0의 메뉴얼중 Getting 
Started편에 나오는 표에서 따온 것이다. C를 공부했다면 (1) - 
(6) 정도는 이해하겠지만 (7) - (9)쯤 되면 어려워 보이고, (10), 
(11)은 고개를 흔들만 하다고 본다.

 만일 이 표의 선언들을 모두 이해하고 있다면, 바로 p를 누르시기 
바란다.

-----------------------------------------------------------------
C의 선언                    의            미
-----------------------------------------------------------------
(1) int f1();               int형을 돌려주는 함수
(2) int *p1;                int형을 가리키는 포인터
(3) int *f2();              int형을 가리키는 포인터를 돌려주
는 함수
(4) int far *p2;            int형을 가리키는 원거리 포인터
(5) int far *f3();          int형을 가리키는 원거리 포인터
를 돌려주는 함수
(6) int *far f4();          int형을 가리키는 근거리 포인터
를 돌려주는 원거리 함수

(7) int (* fp1)(int);       int형을 받아 int형을 돌려주는 함
수를 가리키는 포인터
(8) int (*fp2)(int *ip);    int형을 가리키는 포인터를 받아 
int형을 돌려주는 함수를 가리키는 포인터
(9) int (far *fp3)(int far *ip);
                            int형을 가리키는 원거리 포인터
를 받아 int형을 돌려주는 함수를 가리키는 원거리 포인터
으~ 슬슬 돌이 날라오기 시작하는군..)
(10) int (far *list[5])(int far *ip);
                            int형을 가리키는 원거리 포인터
를 받아 int형을 돌려주는 함수를 가리키는 원거리 포인터의 배열[5]
(11) int (far *gopher(int(far *fp[5](int far ip)))(int 
far *ip);
                            해석은 나중에...

 (으악! 바위가 날라오네!!!)
-----------------------------------------------------------------

 그러나 이 글을 다 읽을 무렵 쯤이면 이 정도의 선언은 모두 여러분
의 손에 있을 것이다. 그렇다고 해서 필자가 거창한 방법을 만들어 
냈다는 것은 아니다. 단지 C언어의 구문을 약간 변형함으로써 포인터
와 관련된 C언어의 선언을 이해하는 데 도움이 될 새로운 구문법을 
구상하였다. 이름하여 B 구문법! 여기서 B란 변의 머리글자임
을 밝혀 둔다.

 B 구문법..이라고 하니 벌써부터 쓸데없는 것 아닌가하고 오해하시
는 분이 계실 것도 같은데, 걱정은 차버리시라고 말씀드리고 싶습니
다. 제가 이 구문법을 접하기 전 암흑속에서 눈물(?)만 흘리고 있었
습니다. 왜냐구요?
고놈의 포인터 땜시.. 하지만 임인건님의 강좌들을 거쳐 이 글을 보
았을 때 다시 광명이 보이기 시작했던 것입니다.

 일반적으로 포인터 선언에 관한 것은 어지간한 실력자라도 시간이 
지
나면 까먹고 다시 책을 뒤적거리게 되지요.. 하지만 이 구문법만 익
혀두면 그럴 일은 절대 없을 것입니다. 오히려 어디가서 도사소리를 
들을 수 있을 것입니다. 보장합니다. 혈서도 쓸 수 있습니다.

 자, 이제 다음회에 지속되는 B 구문법의 실체를 보시면 그 효과
를 깨달으실 수 있을 것입니다..

 2회를 기대하십시요!!
 
 #1907   손현곤   (sonsea  )
[강좌] C 포인터 선언 명쾌한 새장! (2)

안녕하세요! C를 시작하자의 SS입니다..
다시 만나게 되어 정말 반갑습니다~

 이 글의 출처는 서울대학병원의 레지던트로 계시는 변성완님이 개발
하신 B구문법에 관한 글입니다. 옮긴이가 나름대로 쉽게 풀어 쓸 것
입니다.


=====================================
 # B 구문법과 C 구문법간의 변환 규칙
=====================================

-----------------------------------------------------------------
* 규칙 1: 선언에서 *는 괄호에 의해 제한을 받지 않는 한 앞뒤 
어느 쪽에나 자유롭게 붙일 수 있다.
-----------------------------------------------------------------

int *px; < --> int* px;(B구문법)과 같이 상호 변환 가능하다
는 말이다.
이 규칙에 의해 파생되는 B 구문법의 관련 사항을 하나 약속하
자. int*형 이라고 표현하면 이는 int형을 가리키는 포인터
형을 의미하는 것으로 약속한다. 일반적으로 말하면 T*형은 T형
을 가리키는 포인터형이라고 할 수 있겠다. 사실 이것은 C구문법으
로 보아도 위배되는 점이 없고 실제로 많은 C언어 교재에서 사용하
고 있는 약속이므로 별다른 거부감을느낄 수 없으리라 생각한다. 그
러면 B 구문법이 어떻게 이해에 도움이 되는지 알아보자.

 C 구문법 int *px;에서는 *px가 int형이니깐 px는 int형을 가
리키는 포인터 변수이다라고 간접적인 이해를 하는 반면에 B 구문법
에서는 int* px;처럼 하여 px는 int*형 변수이다라고 직접적
인 이해를 한다. int x;가 X는 int형 변수이다를 의미하는 것
과 마찬가지로 int* px;가 px는 int*형 변수이다라는 의미로 
해석하는 것이다.

-----------------------------------------------------------------
* 규칙 2: 선언에서 선언의 대상이 들어 있는 괄호는 구문의 어떤 요
소가 선언의 대상을 앞으로 넘어갈 때 제거하며(C구문법에서 B구문법
으로의 변환) 역으로 뒤로 넘어갈 때 괄호를 씌운다(B 구문법에서 C 
구문법으로의 변환)
-----------------------------------------------------------------

이 규칙이야말로 필자가 만든 구문법의 하이라이트이다. 말이 어려우
니 예를 들기로 한다. int (*x)[3];과 같은 C 구문법 선언에서 
선언하려는 대상은 x이다. 여기서 x가 들어있는 괄호는 (*x)이고 
구문의 요소 [3]이 앞으로 넘어가면서 이를 제거한다.

 -지금 상태-            -이후에 할일-
---------------------------------------------------------
int (*x)[3];         [3]이 앞으로 넘어간다.
int[3] (*x);         그러면 괄호를 제거한다.
int[3] *x;           규칙 1을 적용하여 *를 앞으로 보낸다.
int[3]* x;           완성된 B 구문법 표현이다.
---------------------------------------------------------

그러면 int[3] *x;가 되고다시 규칙 1을 적용하면 int[3]* 
x가 된다. 즉 x는 int[3]*형 변수이다라는 선언이 된다.

여기서 B 구문법의 약속을 하나 더 하기로 한다. B 구문법에서
는 int[3]은 배열 요소가 int형이고 배열요소의 개수가 세 개인 
배열형(array type)인 것으로 약속한다. 그러면 int[3]*형은 
당연히 int[3]을 가리키는 포인터형이 된다.

여기서 필자의 규칙 1, 2를 적용하여 항상 C언어 초보자에게 골치였
던 배열의 포인터(=pointer of array=pointer to array=배열
을 가리키는 포인터와 포인터 배열(array of pointer=포인터가 
요소인 배열)을 명쾌하게 구별해 보기로 한다. 이 문제의 두 선언
은 다음과 같다.

(가) int *x[3]; 포인터 배열(포인터로 이루어진 배열)
(나) int (*x)[3]; 배열의 포인터(배열을 가리키는 포인터)

먼저 (가)를 B 구문법으로 변형하면 규칙 1을 적용하여 int* x
[3]이 된다. 즉 이것은 int*형 배열[3]을 선언한 것이다. int*형
은 int형을 가리키는 포인터이므로 (가)는 포인터 배열을 선언한 
것이다(배열요소 3개*2byte=6byte 소요).
(나)의 경우는 규칙 2를 적용하여 int[3] *x가 되고 다시 규칙 1
을 적용하여 int[3]* x가 된다. 따라서 이는 int[3]*형 변수 x
를 선언한 것이다.
(x가 단지 포인터 변수 하나이므로 2바이트를 소요).
int[3]*형이라는 것은 앞에서도 말한 바와 같이 int형 배열[3]
을 가리키는 포인터형이므로 (나)는 배열을 가리키는 포인터, 즉 
배열의 포인터를 선언한 것이다.

---------------------------------------------------------
(가) int *x[3];
     B구문으로는 int* x[3];
      heap에 동적 변수를 할당받으면
                                    heap
     x[0]+--+--+                  +==+==+
          |  |  | ---------------> |  |  | 대상체는 int형
          +--+--+                  +==+==+
     x[1] +--+--+                  +==+==+
          |  |  | ---------------> |  |  | 대상체는 int형
          +--+--+                  +==+==+
     x[2] +--+--+                  +==+==+
          |  |  | ---------------> |  |  | 대상체는 int형
          +--+--+                  +==+==+
          x 각각은 포인터이다.

      즉 x는 포인터로 이루어진 배열이다.

(나) int (*x)[3];
     B구문으로는 int[3]* x;

      heap에 동적 변수를 할당받으면
                                    heap
     x    +--+--+                  +==+==+
          |  |  | ---------------> |  |  | 대상체는 int[3]형
          +--+--+                  +==+==+
             포인터                   |  |  |
                                   +==+==+
                                   |  |  |
                                   +==+==+
       int형 배열
        즉 int형을 가리키는 포인터 x를 선언한 것이다.
---------------------------------------------------------

여기서 한가지 강조해야 할 점은 여기에 등장하는 포인터의 대상체의 
크기를 명확히 알고 있어야 한다는 것이다. (가) int* x[3];에서
는 x[0], x[1], x[2] 각각이 int형을 가리키는 포인터이므로 포인
터 변수의 크기도 2바이트씩이다.
(나) int[3]* x;에서는 x 자체는 2바이트짜리 포인터 변수이지
만 그 대상체는 int형 배열[3]이므로 대상체의 크기는 6바이트이다.

이번에는 비슷한 주제로 역시 골치거리인 포인터형을 돌려주는 함수
(function returning pointer)와 함수를 가리키는 포인터
(pointer to function)를 구별해 보기로 하자.

(다) int *func(char s);    포인터를 돌려주는 함수
(라) int (*func)(char s);  함수를 가리키는 포인터

(다)를 B구문법으로 변형하면 규칙 1을 적용하여 int* func(char 
s);가 되므로 char s를받아 int *형을 돌려주는 함수의 선언임
을 알 수 있다. 이것이 바로 포인터형을 돌려주는 함수의 선언이
다.

(라)는 규칙 2에 의해 (char s)가 앞으로 넘어갈 때 괄호를 제거하
여 int(char s) *func가 되고 다시 규칙 1에 의해 int(char 
s)* func;가 된다. 즉 func는 int(char s)*형 변수이다. (라)
는 함수의 선언이 아니라 변수의 선언임을 주의해야 한다. int
(char s)*형이라는 것은 int(char s)를 가리키는 포인터형일 것이
다. 다시 여기서 int(char s)를 약속해야 할 필요가 생기는데 그
것은 이미 여러분이 짐작하듯이 char s를 받아 int형을 돌려주는 
함수가 되겠다. 마찬가지로 void(void), int(void), void
(int), int()같은 여러가지 함수의 B구문법적인 표현을 생각할 수 
있을 것이다.

-----------------------------------------------------------------
* 규칙 3: 원거리 포인터(far pointer)를 나타내는 기호$를 약속
하여 far *를 $로 표시하기로 한다. 단 far와 *가 괄호로 분리
되어 있으면 안된다.
-----------------------------------------------------------------

근거리 포인터(near pointer)를 *로 나타냈듯이 (스몰 모델에
서) 원거리 포인터를 $로 나타내기로 한 것이다. 이것은 원거리 
포인터를 돌려주는 근거리 함수와 근거리 포인터를 돌려주는 원거
리 함수를 구별하는 데 유용하다. 다음의 (마), (바)를 생각해
보자.

(마) int far *func(); 원거리 포인터를 돌려주는 근거리 함수
(바) int *far func(); 근거리 포인터를 돌려주는 원거리 함수

(마)에 규칙 3을 적용하면 int $func()이 되고 다시 규칙 1을 적
용하면 int$ func();가 된다. 따라서 이것은 int$형을 돌려주는 
함수(근거리 함수) func를 선언한 것이다.
int*가 int형이 가리키는 포인터(근거리 포인터)였듯이 int$형
(=int far*형)이란 int형을 가리키는 원거리 포인터(farpointer 
to int)이므로 (마)가 원거리 포인터를 돌려주는 근거리 함수의 
선언 예이다.

(바)는 규칙 1을 적용하여 int* far func();가 되므로 
(*far는 $와 다르다) int*형을 돌려주는 원거리 함수 func를 
선언하는 것이다. 즉, (바)는 근거리 포인터를 돌려주는 원거리 함
수의 선언 예이다.

이것으로 B 구문법의 규칙 설명은 끝!

어떻습니까? 혹자는 이거, 누구나 다 알 수 있는 거잖아!!라고 하
실지 모르겠지만 이것도 콜럼부스의 달걀과 같은 것입니다. 저는 이
것을 보고 한마디로 뿅 갔습니다.
이 정도라구요? 이제부터 나오는 앞의 표에 대한 해석을 보시
면 아!하고 맞장구를 치실 것입니다.

그러나, 아직 B 구문법을 완전히 이해하지 못하신 분은 해석 예를 보
면 더욱 쉽게 이해하실 수 있으므로 내 머리는 돌이야...하고 자책
하시는 일이 없기를 당부드립니다.

그럼, 3회를 기대해 주십시요!!

#1908   손현곤   (sonsea  )
[강좌] C 포인터 이해의 명쾌한 새장! (3)      01/08 07:27   
147 line


안녕하세요! C를 시작하자의 SS입니다..
다시 만나게 되어 정말 반갑습니다~

이 글의 출처는 서울대학병원의 레지던트로 계시는 변성완님이 개발하
신 B구문법에 관한 글입니다. 옮긴이가 나름대로 쉽게 풀어 쓸 것입
니다.

자, 그럼 실전예제가 나갑니다!

========================
 < 표>의 해석 - 뿌로이드
========================

자, 그럼 이제 1회에서 나온 악몽의 < 표>에 도전해 보기로 하자.
(1), (2)에 대해선 두말할 필요가 없고,

(3) int *f2();
--------------

규칙 1을 적용 -> int* f2();

int*형(int형을 가리키는 포인터)을 돌려주는 함수 f2를 선언한 것
이다.

(4) int far *p2;
----------------

규칙 3을 적용 -> int $p2;
규칙 1을 적용 -> int$ p2;

int$형(int far *형 = int형을 가리키는 원거리 포인터) 변수 p2
를 선언한 것이다.

(5) int far *f3();
------------------

규칙 3을 적용 -> int $f3();
규칙 1을 적용 -> int$ f3();

int$형(int형을 가리키는 원거리 포인터)을돌려주는 함수 f3을 선언
한 것이다.

(6) int * far f4();
-------------------

규칙 1을 적용 -> int* far f4();

int*형(int형을 가리키는 근거리 포인터형)을 돌려주는 원거리 함
수 f4를 선언한 것이다. 여기서 far가 f4()를 지칭하고 있어 원
래 C의 구문법상 f4가 원거리 함수임을 나타내고 있다. 이 원거리 함
수란 것은 8086/8088 어셈블리어의 호출과 복귀(call & return)
의 모델로 원거리 호출(far call)과 원거리 복귀(far return)를 
사용하고 있다는 것이지 함수의 리턴값과는 무관하다.

(7) int (*fp1)(int);
--------------------

규칙 2를 적용 -> int(int) *fp1;
규칙 1을 적용 -> int(int)* fp1;

int(int)*형 변수 fp1을 선언한것이다. int(int)*형은 int(int)
를 가리키는 포인터이고 int(int)는 int형을 받아 int형을 돌려주
는 함수이므로 fp1은 int형을 받아 int형을 돌려주는 함수를 가리키
는 포인터 변수이다.

(8) int (*fp2)(int *ip);
------------------------

규칙 2를 적용 -> int(int *ip) *fp2;
규칙 1을 적용 -> int(int* ip)* fp2;

int*형을 받아 int형을 돌려주는 함수(int(int* ip))를 가리키는 
포인터 변수 fp2를 선언한 것이다.

(9) int (far *fp3)(int far *ip);
--------------------------------

규칙 3을 적용 -> int ($fp3)(int $ip);
규칙 2를 적용 -> int(int $ip) $fp3;
규칙 1을 적용 -> int(int$ ip)$ fp3;

int(int$ ip)$형 변수 fp3을 선언한 것이다. int(int$ ip)$형이
란 int(int$ ip)를 가리키는 원거리 포인터형이고, int(int$ ip)
는 int$형을 받아 int형을 돌려주는 함수이므로, fp3은 int형을 가
리키는 원거리 포인터를 받아 int형을 돌려주는 함수를 가리키는 원
거리 포인터이다.

(10) int (far *list[5])(int far *ip);
-------------------------------------

규칙 3을 적용 -> int ($list[5])(int $ip);
규칙 2를 적용 -> int(int $ip) $list[5];
규칙 1을 적용 -> int(int$ ip)$ list[5];

앞의 (9)에서 나온 int(int$ ip)$형 변수의 배열을 선언한 것이
다. list[0] - list[4](배열요소가 5개)까지 각 배열요소가 원거
리 포인터형(4바이트)이므로 이 선언은 모두 합쳐 20바이트의 변수 
영역을 잡는다.

(11) int (far *gopher(int (far * fp[5])(int far *ip)))
(int far *ip);
-----------------------------------------------------------------

규칙 3을 적용 -> int ($gopher(int ($fp[5])(int $ip)))(int 
$ip);
규칙 2를 적용 -> int(int $ip) $gopher(int ($fp[5])(int 
$ip));
규칙 1을 적용 -> int(int$ ip)$ gopher(int ($fp[5])(int 
$ip));
                  -------------   |    ---------------------
                  (리턴형)        |           (입력형)
                     |            |              |
                     | 즉, gopher라는 함수선언   |
                     |                           |
        int$을 받아                       |
               int형을 돌려주는                  |
               함수를 가리키는               |
               원거리 포인터                     |
                                   int ($fp[5])(int $ip)
의 해석

                                   int(int$ ip)$ fp[5];이
므로
                                   int(int$ ip)$형 변수의 
배열[5]

 따라서 전체적인 해석은

 근거리 함수 gopher의 선언
 -+-----------------------
  |
  +- (입력형) 어떤 함수를 가리키는 원거리 포인터의 배열[5]
  |           ---------
  |              리턴형: int형
  |              입력형: int형을 가리키는 원거리 포인터
  +- (리턴형)
         같은 포인터형
              ; int$형을 받아 int형을 돌려주는 함수들


 어떻습니까? 특히 (11)번의 경우 아직 헷갈리시는 분들이 대다수 
일 것입니다. 하지만 차근차근히 보고 계시면 입에서 감탄의 신음소
리가 흘러 나오리라고 생각합니다.

4회에서는 문자열을 가리키는 포인터와 해석만 잘하면 뭣해? 작문
을 할줄 알아야지..하고 벌써 투덜거리시는 분들을 위해 B 구문법
의 C 구문법으로의 변환에 대해 알아 볼 것입니다.


#1909   손현곤   (sonsea  )
[강좌] C 포인터의 명쾌한 새장! (4 끝)

안녕하세요! C를 시작하자의 SS입니다..
다시 만나게 되어 정말 반갑습니다~

이 글의 출처는 서울대학병원의 레지던트로 계시는 변성완님이 개발하
신 B구문법에 관한 글입니다. 옮긴이가 나름대로 쉽게 풀어 쓸 것입
니다.

==========================
 문자열을 가리키는 포인터
==========================

 흔히들 쓰는 말에 문자열(string)을 가리키는 포인터라는 것이 
있다. 그러나 이 말은 엄밀하게는 허구이다.
 다음과 같은 프로그램의 일부분이 있다고 하자.

 s = "Hello";
 printf(s);

 char *s는 char* s를 의미하므로 여기서 선언된 s라는 변수는
char*형(char형을 가리키는 포인터) 변수이지 문자열을 가리키는 포
인터가 아니다. 따라서 위의 문장 s = "Hello"에 의해서 s가 가리키
게 되는 것은 문자열(string) "Hello"가 아니라 문자
(char) H인 것이다. 물론 포인터의 주소값으로
는 Hello나 H나 같겠지만, 포인터가 가리키는 대상체의 크기를 
항상 명확하게 인식하고 있는 날카로움이 C 프로그래머에게 필요할 
것이라 생각된다.

======================
 B 구문을  C 구문으로
======================

 이제는 마지막으로 우리가 필요한 C의 선언을 써 보는 연습을 해 보
아야겠다. 즉, 다시 말하면 B 구문을 C 구문으로 바꾸는 연습이다. 
복잡한 것은 별로 쓰이지 않으므로 피하고 간단한 것을 몇 개 예로 들
어 보자.

(1) char를 가리키는 포인터형을 받아 char를 가리키는 포인터형을 
돌려주는 함수 f1  ->  char*형을 받아 char*형을 돌려주는 함수 
f1
-----------------------------------------------------------------
 B 구문으로 -> char* f1(char* s);
 규칙 1을 적용 -> char *f1(char *s);

(2) int형을 가리키는 포인터의 배열(배열요소수는 5)을 가리키는 
원거리 포인터 p
-----------------------------------------------------------------
차근차근히 하나씩 B구문으로 바꾸어 보자.
 int형을 가리키는 포인터 -> int*
 int*의 배열[5] -> int*[5]
 int*[5]를 가리키는 원거리포인터 -> int*[5]$

따라서,
 B 구문으로 -> int*[5]$ p;
 규칙 1을 적용 -> int* [5]$p;
 규칙 2를 적용 -> int* ($p)[5];

[5]가 앞에 나오면 안되므로 원래 있어야 할 자리를 찾아 뒤로 넘어
가면서 괄호()가 생긴다. 앞으로 넘어가면서 괄호를 벗기고, 뒤로 
넘어오면서 괄호를 씌운다는 규칙 2를 상기하기 바란다.

 다시 규칙 1을 적용 -> int *($p)[5];
 규칙 3을 적용  -> int *(far *p)[5];

(3) char*형을 받아 int형을 돌려주는 함수를 가리키는 원거리 포인
터 p
-----------------------------------------------------------------
 B 구문으로 -> int(char* s)$ p;
 규칙 1을 적용 -> int(char *s) $p;
 규칙 2를 적용 -> int($p)(char *s);
 규칙 3을 적용 -> int(far *p)(char *s);

(4) char를 가리키는 포인터를 가리키는 포인터를 돌려주는 함수 f
--------------------------------------------------------------
 B 구문으로 -> char** f();
 규칙 1을 적용 -> char* *f();
 규칙 1을 적용 -> char **f();

 ===============================

 이상입니다. 이제 여러분 앞에는 광명이 서서히 비추고 있을 것입니
다. 이 글을 적어도 3번 정도 정독하면 포인터 선언은 이제 여러분
의 것입니다.

한글프로그래밍 동호회(go hanpro)의 초청강좌란에 가시면 임인건
님의 포인터에 대한 강좌가 올라와 있을 것입니다. 포인터에 관해 그
렇게 명쾌하게 설명된 글은 없었습니다. 포인터에 익숙해지시려면 반
드시 받아보시기를 권합니다.

 수고하셨습니다! 여러분.. SS는 물러갑니다...
 애고, 손가락이야..

Updated: