ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [1분코딩] 포인터란 무엇인가?
    코딩 2020. 1. 26. 14:40

    Programming Language에서 빼놓을 수가 없는 개념이 있는데

    그게 바로 '포인터' 이다.

     

    보통 개발자들은 처음 C언어를 공부하면서 포인터를 만나면 제대로 이해하지 못한

    예제 코드 몇번 쳐보고 넘어가버린다.

     

    그도 그럴것이 포인터라는 개념이 우리 인간세상 속에서는 대응될만한 것이 없다

    그래서 그런가 도무지 와닿지가 않는다.

     

    그렇다면 이번 기회에 포인터에 대해서 간략하게 알아보자

     

    [1분코딩] 포인터란 무엇인가?

     

     

    - 포인터란?

    포인터란 주소값을 저장하는 변수이다.

    전혀 와닿지 않는다. 그렇다면 예제코드를 한번보자

    int main() {
    
        int a = 10;
    
        int *p = &a;
    
    
    
        print(p);            // 0x32821     16진수 주소값 출력
    
        print(*p);            // 10            10 출력
    
    }

    먼저 첫번째 : int a 변수를 선언하고 여기에 값으로 10 넣었다.

    두번째 : 포인터 p 선언하고 여기에 a변수 주소값을 넣었다.

     

    위에 포인터가 주소값을 저장하는 변수라고 했으니까, a 변수 주소값을 넣어도 문제없지?

     

    세번째 : 포인터 p 출력했다. 0x32821 같은 16진수 주소값이 출력된다.

    네번째 : 포인터 p 앞에 * 붙이면 주소에 저장되어 있는 실제값을 가져온다. 그러므로 10 출력된다.

     

    여기까지가 보통 일반적인 포인터에 대한 설명이다. 그런데 여기서 끝내버리면

    도무지 그래서 어쩌라고? 그래서 int *p, &p 이런걸 쓰는데? 하는 의문이 남는다.

     

    여기서부터 중요하다. 도대체 포인터를 쓰는지 알아보자

     

     

    - 메모리

    int a = 10;

    int a변수를 선언하고 10 할당했을 , 컴퓨터 내부적으로 어떻게 진행되는지 생각해보자

    컴퓨터 내부 메모리에 int 메모리 공간 4Byte 할당하고 여기에 10 고히 넣어놓을 것이다.

    그래야 나중에 변수 a 쓸때 10 가져올테니까 말이다 간단하지?

    a변수가 저장되어 있는 메모리의 주소가 생긴다. 위에서 말한 16진수 주소값이 바로 주소를 말한다.

     

    정리해보면

     

    변수선언 -> 할당 -> 메모리 저장 -> 메모리 주소값 -> 포인터에 변수의 주소를 등록 -> *p 포인터로 메모리 주소에 있는

    실제 값에 접근가능

     

    여기까지... 이게 포인터의 사용법의 전부이다.

     

     

    - 그래서 포인터를 왜쓰냐구??

    서론이 너무 길었다ㅠ 결국 내가 쓰고 싶은건 부분이다.

    다음 예제 코드를 한번보자

    void change(int a) {
    
        a = 777;
    
    }
    
    
    
    int main() {
    
        int a = 10;
    
        print(a);            // 10 출력
    
    
    
        change(a);
    
        print(a);            // 10이 출력될까? 777이 출력될까?
    
    }

    코드는 main에서 선언된 변수a 10 change() 함수를 통해서 값을 777 바꾸고

    싶어하는 예제이다.

     

    그런데 저렇게 하면 과연 변수a 777 바뀌겠는가? 당연히 안바뀐다.

    그대로 10 출력된다.

     

    실제로 이런 문제때문에 초기 Programming Language 설계한 개발자들이 골머리를 앓았다고 한다. (뇌피셜임..)

     

    그래서!!

    그래서!!

    그래서!!

     

    포인터라는 개념을 만들었다.

    포인터에 변수의 주소값을 저장해놓고 포인터로 실제 변수의 메모리 주소에 접근해서 실제 값을 변경하고 싶어서!

     

    예제를 올바르게 바꿔보겠다.

    void change(int* p) {
    
        *p = 777;
    
    }
    
    
    
    int main() {
    
        int a = 10;
    
        int *p = &a;
    
        print(a);            // 10 출력
    
    
    
        change(p);
    
        print(a);            // 10이 출력될까? 777이 출력될까?
    
    }

     

    꺄악! 바로 777 출력된다.

    왜냐? 지겹게도 반복하고 있지만 변수a 실제 주소값을 가지고 있는 포인터 p 넘겨서

    change 함수 안에서 *p = 777;  메모리 주소에 있는 실제 값을 변경했기 때문에

    main() 함수안에서도 변수 a 값이 바꿔버린것이다.

     

    여기까지가 포인터를 쓰는 이유의 전부이다.

    사실 알고보면 별거없는 간단한 개념이지만 포인터라는 개념의 사용도는 너무나도 광범위하고

    대단해서 포인터 없이는 현대 Programming Language 있을 없고 프로그램 또한 개발될 없다.

     

    여기서 이런 말을 하는 분도 있을 것이다.

     

    Javascript에는 포인터 없어요

    Java 포인터 없이 잘만 쓰는데요?

    swift 포인터 없자나요?

     

    아니다.. 있다.. 명시적인 포인터 연산자(*) 없을 뿐이지 내부적으로 모두 위와같은 포인터와

    메모리주소 개념으로 돌아가고 있다.

     

    우리가 항상쓰는 CallBack Method, 콜백 메소드는 과연 어떻게 구현되겠나?

     

    self.alert("Title", "Message") { () in
    
        print("콜백메소드 호출")
    
    }

     

    위와 같이 알랑창을 띄우고 확인이 눌렸을 print 함수가 호출되어 달라는 콜백메소드도

    결국에는 포인터로 구현되는 것이다.

     

    변수가 선언되면 메모리에 저장된다고 하지 않았던가?

    함수는?

    함수도 선언되면 메모리에 저장되는거다. 함수도 주소값을 가지고 거기에 실제 함수값이 저장된다

    그걸 바로 함수포인터라고 부른다.

     

    콜백메소드는 다른게 아니라 함수 파라미터로 함수포인터를 넘겨서

    액션이 끝나면 *함수포인터() 실행해주세요 라고 하는거다.

     

    Call by Value, Call by Reference 얘기하고 싶지만 TMI 생각되서 여기까지 줄인다.

     

    이상 !

    댓글

Designed by Tistory.