ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C 언어 기초 정리 06] 포인터
    개발 이야기/C 2023. 9. 29. 20:48

    포인터란 데이터의 주소정보의 개념이다. 

    앞에 변수에서 이야기했듯이 C의 각 자료형들은 각자 다른 메모리크기를 가진다. 하지만, 이들도 시작주소가 있는데 주소값이란 이런 변수들이 저장되어있는 메모리의 시작주소를 말한다. 

    포인터와 데이터의 주소값

    포인터란?

    포인터란 메모리의 주소값을 저장하는 변수이다(주소를 저장하는 자료형)

    int n = 100;   // 변수의 선언
    int *ptr = &n; // 포인터의 선언

    포인터와 주소값, n의 주소인 0x12를 포인터 변수인 ptr에 저장하는 모습이다

    포인터와 관련된 연산자는 두개로 아래와 같다. 

    - &: 주소연산자로 해당 변수의 주소값을 반환(변수 앞에 사용)

    - *: 참조연산자로 주소에 저장된 값을 반환(포인터 앞에 사용)

    &연산은 해당 변수 -> 주소이고

    *연산은 해당 주소->변수(주소지를 찾아가 그에 해당하는 변수)를 찾아준다

    이는 다중포인터 연산에서도 동일하게 적용된다.

    -WORD란?
    워드(word)란 CPU가 한 번에 처리할 수 있는 데이터의 크기
    1바이트는 8비트이므로 32비트 시스템에서는 32비트 / 8비트 = 4, 즉 4바이트가 1워드(word)로 처리됩니다.
    64비트 시스템에서는 64비트 / 8비트 = 8, 즉 8바이트가 1워드(word)로 처리된다
    포인터변수의 크기는 1워드의 크기와 같다.

    - 포인터의 연산

    int num01 = 10;
    int num02 = 20;
    int *ptr_num01 = &num01;
    int *ptr_num02 = &num02;  
    printf("포인터 ptr_num02 1 증가 후에 가리키고 있는 주소값은 %#x입니다.\n", ++ptr_num02);

    포인터를 1씩 증가시키는 ++연산은 포인터 타입의 자료형이 차지하는 메모리의 크기만큼 포인터를 증가시킨다. 

     

    이중포인터(**)

    이중포인터의 예시

    포인터를 가르키는 포인터, 즉 주소의 주소를 담고있는 포인터가 이중포인터다. 코드 상으로는 아래와 같이 작성한다.

    int num = 10;              // 변수 선언
    int* ptr_num = #       // 포인터 선언
    int** pptr_num = &ptr_num; // 포인터의 포인터 선언  
    
    printf("변수 num가 저장하고 있는 값은 %d입니다.\n", num);
    
    printf("포인터  ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n", *ptr_num);
    printf("포인터의 포인터 pptr_num가 가리키는 주소에 저장된 포인터가 가리키는 주소에 저장된 값은 %d입니다.\n",
        **pptr_num);  
    pintf("포인터  ptr_num의 주소는 %d입니다.\n", *pptr_num);

    void 포인터

    void 포인터는 일반적인 포인트 변수와는 달리 대상이 되는 데이터의 타입을 명시하지 않은 포인터로 어떤 값도 가리키는 것이 가능하지만(변수, 함수, 포인터 등) 메모리 참조와 포인터 연산은 불가능하다, 

    즉, 주소값 저장외에는 아무것도 할 수 없으며, 사용할 때에는 타입 캐스팅이 필요하다.

    int num = 10;         // 변수 선언
    void* ptr_num = # // void 포인터 선언  
    
    printf("변수 num가 저장하고 있는 값은 %d입니다.\n", num);
    printf("void 포인터 ptr_num가 가리키는 주소에 저장된 값은 %d입니다.\n", *(int*)ptr_num);
    //void 포인터이기에 int*을 통해 타입 캐스팅 이후 참조연산(*) 진행

    배열 포인터 ()[]

    배열의 경우 &연산자를 통해 주소를 입력하지 않아도 포인터처럼 사용할 수 있다.

    int arr[3] = {10, 20, 30}; // 배열 선언
    int* ptr_arr = arr;        // 포인터에 배열의 이름을 대입함
    //배열을 포인터로 접근시 아래와 같은 식이 성립
    arr[n] == *(arr + n)

    배열 포인터는 배열을 카르키는 포인터를 의미한다. 배열의 이름은 그 값을 변경할 수 없는 상수라는 점만 제외하면 포인터와 동일하지만, 포인터를 통해 n차원 이상의 배열을 가리킬 수 있기에 배열 포인터를 사용한다.

    주소와 offset을 인자로 받아 주소 + offset에 저장된 값을 반환한다. 

    int arr[2][3] =             // 배열의 선언
    {
        {10, 20, 30},
        {40, 50, 60}
    };
    
    int (*pArr)[3] = arr;       // 배열 포인터의 선언  
    
    printf("%d\n", arr[1][1]);  // 배열 이름으로 참조
    printf("%d\n", pArr[1][1]); // 배열 포인터로 참조

    C Function Pointer(함수를 인자로 받기)

    수치해석에 사용되는 c함수 코드 중 하나인 machar

    프로그램에서 정의된 함수는 실행될 때 모두 메인 메모리에 올라가고, 이때 함수의 이름은 함수의 시작주소를 가리키는 constant pointer가 됩니다. 이렇게 함수를 가리키는 포인터를 함수포인터라고 한다.

    함수 포인터는 returnType (*funcPtr) (arguments)의 형식으로 구성된다. 

    Return Type Name Argument
    float add (float,float)
    float (*funcPth) (float,float)

    이런 함수 포인터를 사용하면 함수를 인자로 받아 처리할 수 있다. 

    float muller(float (*func)(float), float p0, float p2, float xacc)
    {
        void nrerror(char error_text[]);
        int j;
        float p1, f2, p3;
        float f0,f1,dx,swap,xl,rts;
        float a,b,c;
    
        p1 = (p0 + p2) / 2.0;
    
        f0=(*func)(p0);
        f1=(*func)(p1);
        f2=(*func)(p2);
    
        // xl= p0;
        // rts=p2;
        // //swap like secant
        if (fabs(f0) < fabs(f2)) {
            rts=p0;
            xl=p2;
            swap=f0;
            f1=f2;
            f2=swap;
        } else {
            xl= p0;
            rts=p2;
        }
    
        for (j=1;j<=MAXIT;j++){
            c = f2;
            b = (pow((xl-rts),2)*(f1-f2)- (pow((p1-rts),2)*(f0-f2)))/((xl-rts)*(p1-rts)*(xl-p1));
            a = ((p1-rts)*(f0-f2)-((p0-rts)*(f1-f2)))/((xl-rts)*(p1-rts)*(xl-p1));
            dx=2*c/(b+(sgn(b)*sqrt((pow(b,2)-4*a*c))));
    
            p3 = rts - dx;
            //update
            xl=p1;
            p1=rts;
            rts=p3;
    
            f0=f1;
            f1=f2;
            f2 = (*func)(rts);
            if (fabs(dx) < xacc || f2 == 0.0) return rts;
        }
        nrerror("Maximum number of iterations exceeded in muller");
        return 0.0;
    }

    함수포인터를 사용하여 함수를 인자로 받는 예시이다. 

     

Designed by Tistory.