。공부 。2008.01.27 20:57
혹시 함수도 주소값을 갖고 있다는거 아시나요?
그럼 함수의 자료형만 안다면 함수역시 포인터가 되는거 아닐까요?
그렇습니다 함수역시 주소값을 갖고 있고 자료형또한 갖고 있습니다.
그럼 주소는 어떻게 되고 자료형은 무엇을 갖는지 그 자료형을 어떻게 알아 내는지 를 알아보죠
간단히 함수의 포인터 타입을 알아보자는겁니다.

void show(int a){
    printf("%d \n",a);
}
위와같은 함수가 있습니다 간단히 int형 변수를 매개변수로 받아 출력을 하는 show합수지요
함수의 자료형을 얻기 위해서 우린 함수의 리턴타입과 매개변수타입이 무엇인지를 알아야 합니다.
위의 show 함수의 리턴타입은 void형 이고 매개변수는 int형이되겠지요..
그럼 show의 포인터 를 만들이렇게 됩니다.
void(*show_ptr)(int) = show;
위의 문장을 보면 잘 이해가 안가실겁니다. 위의 포인터타입을 영어해석(?) 하듯 읽어 보지요.
show 함수의 포인터 show_ptr을 선언하는데 리턴타입은void형이고 매개변수는 int형인 포인터 *show_ptr을 선언.

음... 어렵나요? 그럼 이렇게 비교해보죠
void show(int a)         --> show함수        
void(*show_ptr)(int)    --> 포인터 show_ptr
어떻습니까 둘이 많이 닮아있죠? 다 똑같은데 함수에 괄호()와 이름앞에 '*'붙은거 뺴곤 똑같다는것을 알수있습니다.

다른 예를 한번더 들어보죠.
int fct(char *str, int aa)       
void(*show_ftc2)(char*, int)
이제 좀 감이 오시죠? 이렇듯 함수를 포인터로 선언한것을 우리는 함수포인터라 합니다.
하지만 둘이 완전히 같은것은 아닙니다 ..

[ 함수와 함수포인터의 차이 ]
        함수           --> 포인터 상수
        함수 포인터 --> 포인터 변수

[ 함수포인터 간단한 예제]
#include <stdio.h>

void show(int a){
    printf("%d \n",a);
}

int main(void){
    int aa = 10;
    void(*show_ptr)(int) = show;
   
    printf("%d %d \n",show,show_ptr);

    show(aa);
    show_ptr(aa);

    return 0;
}

함수의 정체를 알았기 때문에 우린 이제 show() 함수를 이렇게 이렇게 읽어야 될겁니다. show라는 포인터가 가르키를 함수를 호출하면서 인자값으로 상수 10을 전달하라고 말이죠.


신고
Posted by kyoe
。공부 。2008.01.23 00:22
1차원 배열의 포인터 타입을 결정할때 우리는 포인터의 자료형과 포인터 연산시 증가하는 바이트 크기가 같다 는것을 알고 있다.
그럼 2차원 배열은 어떨까? 1차원 배열과 같을까? 이렇게 같으면 얼마나 좋으련만.. 그렇지가 않다.
포인터의 자료형은 1차원배열과 마찬가지로 포인터가 가르키는 자료형과 일치하지만 포인터 연산시 증가하는 바이트의 크기가 틀리다. 같은 int형 배열이더라도 증가하는 값은 4byte로 동일한것이아니라 그때 그때 틀리다는 것이다.

예를 들어 보자.
int arr[3][2] = {1,2,3,4,5,6};
위와같이 3*2배열이 있다.
자료형은 당연히 int형일테지만 포인터 연산시 증가하는 값은 몇byte일까?
확인하는 간단한 방법은 주소값을 출력하면 되겠죠
printf("arr[0] : %d\n",arr[0]);
printf("arr[1] : %d\n",arr[1]);
printf("arr[2] : %d\n",arr[2]);
2차원 배열에서 arr[0] 이라 함은 배열의특정 위치를 가르키는 포인터가 된다 즉 주소값을 갖게된다.
하지만 arr[0][0] 은 배열의 요소값을 가르키기때문에 출력하면 1값이 출력될것이다.
이렇게 주소를 출력하면 이런값이 뜬다 결과값이 개개인 컴퓨터마다 틀리겠지만 증가값은 같다.
arr[0] : 0x00
arr[1] : 0x08
arr[2] : 0x16

분명 int형 배열인데 왜 4byte씩 증가되지 않고 8byte씩 증가 되었을까?
표현이 잘될런지는 모르지만 그림으로 설명하면 아래와 같이 설명할수있다.

arr[0] -------->   1  ,             2       
                         a[0][0]      a[0][1]
                         0x00           0x04   

arr[1] -------->   3  ,             4      
                        a[1][0]      a[1][1]
                         0x08           0x12  

arr[2] -------->   5  ,             6      
                        a[2][0]      a[2][1]
                         0x16           0x20  

arr[0]이 배열의 첫번째 행을 가르키는 것을 알수 있다 3*2배열이기 때문에 한 행에는 2개의 값이 있고 그행의 첫번째 주소를 가르키게 되는것이다.
arr[1]은 첫번째행의 두번째 요소를 가르키는것이아니라 두번째 행인 a[1][0]을 가르키는 것을 알수있수있다 그럼 위의 결과값이 왜 4byte씩 증가 되지 않고 8byte씩 증가 되었는지 우리는 그 결론은 여기서 찾을수 있다 2차원 배열의 포인터연산시 증가하는 값은 포인터의 자료형의메모리크기*행의 갯수!
행단위증가를 하는것을 알수있다.

[ 다차원 포인터타입 정의 ]
     - 가리키는 대상의 자료형
     - 포인터 연산시 증가하는 바이트의 크기

위에서 정의 내리기를 다차원 배열의 포인터 타입은 가리키는 대상과 포인터연산시 증가하는 바이트의 크기 가 같으면 같은포인터타입이라는것을 알수있다.

int array1[3][2];
int array2[2][3];
위와같이 두개배열의 포인터타입은 서로 일치할까요?
그렇죠.. 아닙니다 서로 가르키는 대상이 int형인건 같지만 포인터 연산시 증가하는 바이트의 크기가 틀리죠.. array1은 8byte , array2는 12byte씩 증가하게 됩니다.

이렇게해야 서로의 포인터타입이 같게 되는것이죠
int array1[3][2]
int array2[4][2]

그럼 위의 이차원 배열을 포인터에 대입해 보겠습니다.
int (*pp)[2] = array1;
어때요? 이해가 가나요? 어떻게 보면 복잡해보이고 헷갈릴수 있습니다.
우리는 int* pp[2]; 이런문장을 배웠기 때문일텐데요 이문장과 위의 문장은 완전히 다른 코드입니다.
int* pp[2] 를 해석하면 int형 포인터를 요소로 2개 갖고있는 배열 pp로 해석되고
int (*pp)[2] 를 해석하기보다는 읽어보는게 나을거 같다. 읽어보면 다음과 같다.
pp라는 포인터를 선언을 하는데 가르키는 자료형은 int형이고 포인터 연산을 했을시
int형메모리크기(4byte)*2byte 만큼 건너뛴다 라고 표현할수 있다.
표현이 좀 어려웠나요 하지만 이렇게 이해하는것이 가장 쉬울거 같네요..
물론 이건 제기준입니다.^^:

[ 2차원배열 포인터타입의 간단한 예 ]
#include <stdio.h>

void show(int (*pp)[4], int a){
    int i,j;
    for(i=0; i<a; i++){
        for(j=0; j<4; j++){
            printf("%d",pp[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

int main(void){
    int array1[2][4] = {{1,2,3,4},{5,6,7,8}};
    int array2[3][4] = {{1},{2},{3}};

    show(array1, 2);
    show(array2, 3);

    return 0;
}

여기저기 굴러다니는 간단한 예제를 따와 봤습니다
테스트를 해보니 잘되더군요 이만한 예제가 없는듯해서.. 그리고 항상 깜밖깜밖잊는 내 머리를 위해서 준비한 예제지요^^:
신고
Posted by kyoe
。공부 。2008.01.18 23:02
배열역시 포인터이기 때문에 포인터변수에 배열이름의 주소값을 대입할수있습니다.
이말은 즉 포인터변수는 배열의 첫번째요소의 주소로 초기화를 시킬수있고 그곳을 가르킬수있다는 겁니다. 또한 포인터는 자료형을 갖고 있기때문에 배열과 마찬가지로 배열의 요소를 포인터연산을 통해 가르키를값을 변경시킬수도 있을 것입니다.
지금부터 그예를 들어 포인터연산을 통해 포인터변수의 값을 변경해보도록하죠.

int array[3] = {1,2,3,};
int형 데이터 3개를 저장할수있는 배열 array를 선언하고 요소를 1,2,3초기화 해줍니다.

int* pp = array;   //배열이름은 배열의 첫번째 요소의 주소를 값으로 갖는다.
int형 포인터변수 pp에 배열 array의 주소값으로 초기화 즉 array의 첫번째 요소의 주소로 초기화합니다.
이렇게 되면 포인터 pp는 array의 첫번째요소를 가르키게 됩니다.

우리가 배열의 요소값을 출력할때 어떻게 했죠? 그렇습니다. array[0],array[1]... 이렇식으로 배열의 값을 출력할수 있었습니다. 포인터역시 배열과 똑같이 사용할수있습니다.
printf("%d, %d, %d \n",pp[0],pp[1],pp[2]);
이렇게 배열과 완전히 같게 쓸수가 있습니다.

하지만 우리는 이렇게 쓰기전에 아래와같이 포인터연산을 통해 포인터 pp가 가르키는 주소값을 변경할수있다는것 부터 안뒤에 써야겠죠?
printf("%d, %d, %d \n",*(pp+0),*(pp+1),*(pp+2));
포인터는 자료형을 갖는다고 위에서도 설명을 드렸고 우리는 int형 배열을 선었했죠 이렇게 되면 배열의 한개한개 요소는 4byte를 갖게 되고 포인터 pp역시 4byte의 공간을 참조하게 됩니다.
예를 들어 배열의 첫번째 요소의 주소값을 0x0010 이라 해둡시다 그럼 두번째 요소의 주소값을 당연히 4byte증가한 0x0014가 되겠죠?
잠깐 여기서 만약 *(pp+1) 이렇게 써주지 않고 *pp+1을 써주면 어떻게 될까요? 이렇하면 포인터pp의 주소값이 증가되지 않고 포인터pp가 가르키는 값이 증가 될겁니다.
우리는 우선순의에 의해서 괄호안의 값이 먼저 연산되는것을 알고 있습니다. 그럼 pp의 값이 증가되고  즉 pp는 array의 주소를 갖고 있기때문에 주소값을 1증가시킨뒤 * 연산을 하게되는겁니다 이렇게되면 결국엔 증가한 주소의 값을 가르키는것이죠.
여기까지 말하면 대충 아~ 하고 감이 오는분들도 계실겁니다. 
첫번째 *(pp+0) 은 포인터 pp의 값을 0만큼증가시켰기때문에 가르키는곳음 처음과 일치합니다. 하지만 *(pp+1)은 포인터 pp의 값을 1만큼증가시키고 그값을 가르키고 있네요 포인터값이 1증가 됬으니까 포인터 pp는 0x00011을 가르킬거라고요? 아니겠죠.. 포인터 pp는 int형 포인터이기때문에 +1을 해주면 4byte가 증가하게 되는겁니다 즉 배열요소 첫번째 주소 값에서 4byte가 증가한 0x0014를 가르키게 되죠.
만약 char형이라면 값을 +1증가시킬때 1byte씩증가가 되고 double형이면 8byte씩 증가 하게 됩니다.
array[i] == *(pp+i) 가 성립하게 되는것이죠.
배열을 *(array+i)  이렇게 쓸수도 있다는겁니다.

아래와같이 사용해도 무방합니다.
printf("%d, ",*(pp));
printf("%d, ",*(++pp));
printf("%d\n",*(++pp));
참! 여기서 알고 넘어가야 할것이 있는데 왜 여기선 위에서 처럼 한줄로 코딩을 하지 않았을까요?

신고
Posted by kyoe
。공부 。2008.01.17 23:07
배열이란 둘이상의 변수를 동시에 선언하거나 많은 양의 데이터를 일괄적으로 처리할때 주로 쓰인다.
하지만 우린 배열이또다른 의미를 갖고 있다는것을 알면서도 대충알고만 넘어가는 경우가 많다.

배열을 또다른 말로 풀이하면 상수포인터라고 말할수있습니다.
그이유를 알아보자.

int array[5] = {0,1,2,3,4};
다음과 같은 배열이 있고 배열 array의 첫번째 요소의 주소값이 0x1000번지에 할당되었다고 가정하자.
그럼 두번째 요소인 array[1]은 int형 배열이기 때문에 4byte를 건너뛴 0x004번에 할당될것이다. 만 double형이였다면 8byte씩 건너뛰어서 할당이 되겠지요..

아래와같이 배열요소의 결과값을 출력하면 결과값은 당연히 0과 1이 나오겠죠?
printf("array[0] : %d, array[1] : %d \n",array[0],array[1]);

그럼 이번엔 배열 요소의 주소값을 출력해 보죠. 결과값은 위에서 가정한 0x1000과 0x004 가 나올겁니다.
printf("%d 번지, %d 번지\n",&array[0],&array[1]);

마지막으로 배열이름의 주소값을 출력해 보도록하죠 이상하게도 위의 array[0]번째요소의 주소값인
0x000이 출력이 됩니다. 이것으로 우리는 배열의 이름은 배열의 첫번째요소 즉 배열의 0번째 인덱스의 주소값을 갖는것을 알수있습니다.
printf("array배열이름의 주소 : %d \n",a);

포인터로 예로 들자면 포인터 역시 주소값을 가르킬수있고 또한 자료형도 갖고 있습니다.
이렇게 우리는 주소값 + 자료형 을 갖고 있는것을 포인터라 하죠
배열역시 주소값과 자료형을 갖고 있기때문에 우리는 배열역시 포인터라고 정의를 내릴수 있습니다.

하지만 배열과 포인터가 완전히 같지는 않습니다. 포인터는 다른주소 의 값을 가질수 있지만 배열은 처음에 할당된 주소값만을 가르킬수있습니다. 만약 배열의 주소값을 변경할수있다면 백개씩이나 되는 배열을 요소를 갖고있는 배열을 실수로 다른 주소로 변경하게 된다면 난감하겠죠.. 뭐 간단한 예를 든겁니다. 꼭 이래서 그런것이 아니라.
실제로
int oop = 10;
array = &oop;
이렇게 array배열에 변수 opp의 주소값을 넣으면 에러가 발생합니다.

간단히 정리하자면 이렇습니다.
배열의 배열이름은 주소값과 자료형을 갖는 포인터이지만 주소값을 변경할수없는 상수포인터이다.

신고
Posted by kyoe
。공부 。2007.12.27 15:18
사용자 삽입 이미지

작년 개인프로젝트로 테트리스란걸 만들어보기로했다 전부터 한번쯤은 만들어 보고 싶었기에..
이때가 기회다싶어 레포트도할겸 공부도할겸 겸사겸사 만들어본 테트리스.
약 40여일이 걸려 완성한듯싶다..
지금도 몇몇 버그가 있을지모르지만.. 굳이 찾으려 애쓰지않으면 게임하는데는 지장이 없는듯하다^^:

신고
Posted by kyoe

티스토리 툴바