본문 바로가기
카테고리 없음

포인터 정리

by 코리늬 2018. 3. 14.

포인터는 반드시 집고 넘어가야 하는 부분이라 생각한다.

프로그램에서 사용한 변수들은 프로그램이 실행되었을 때 고유한 메모리 주소값을 가지게 된다.

따라서 특정 변수를 사용할 때 변수명을 사용하지 않더라도 해당변수의 주소값을 알고 있으면 해당 변수에 접근할 수 있다.


포인터를 사용하는 이유 : 변수의 메모리상 주소는 상수값이기 때문에 일반 변수도 주소값을 저장할 수 있다.

하지만 일반 변수는 주소를 값으로만 다루기 때문에 저장된 주소를 사용해 해당 주소에 존재하는 데이터를 참조하거나 변경할 수 없다.

그래서 c/c++에서 포인터라는 변수를 제공하여 저장된 주소를 참조하거나 변경할 수 있는 기능을 부여한다.

포인터 사용법 

  - 자신이 사용하고자 하는 변수명 앞에 "*" 를 붙여준다.

  - & 주소 연산자

  - &a : a에 대해 시작 주소를 구해라

  - * : 간접 참조 연산자

  - a = *&a


1. 주소 지정방식

주소를 지정하는 2가지 방식이 있는데

  - 직접 주소 지정방식 : 변수명을 이용해 직접 해당 변수를 사용하는 방식.

  - 해당 변수의 주소를 이용해 간접적으로 사용하는 방식.  => 포인터  


2. 포인터 변수의 선언

char data; //일반 변수의 선언

char * data; //포인터 변수의 선언

포인터 변수 선언시 그 앞에 자신이 사용할 메모리의 크기를 명시하도록 되어있다.


char *data; 는 자신이 저장한 위치에서 1바이트 크기를 사용.

int *data;는 자신이 저장한 위치에서 4바이트 크기를 사용한다는 뜻이다.


3-1. 포인터의 사용 - 다른 변수의 주소 사용

포인터를 이용해 간접 주소를 지정하려면 대상이 될 변수의 주소를 알아야하는데,

변수가 프로그램이 실행되어 메모리에 적재되기 전 까지 그 주소를 알 수 없고,

적재 될 때마다 주소가 동일하다고 보장할 수 없기 때문에 특정 변수의 주소를 직접 명시할 수 없다.

그래서 c/c++에서 다른 변수의 주소를 얻고 싶을때는 "&" 연산자를 사용한다.



3-2. 포인터의 사용 - 해당 번지 자체를 사용


 3-3. 포인터의 사용 - 해당 번지에 존재하는 값을 참조하거나 변경


4. 포인터 사용 예


함수를 호출할 때 전달하는 인자는 변수 자체를 전달하는 것이 아니라, 변수에 저장된 값을 전달합니다. 그리고 서브함수 내에서 별도의 변수를 만들어 값을 담아서 사용하게 된다.

즉, main()에서의 value와 call_by_value()의 val, main()에서의 refer와 call_by_refer()에서의 ref 변수는 서로 다른 메모리에 존재하는, 사실상 각각 별개의 변수로서 존재하게 된다.

그렇기 때문에, call_by_value() 에서 val = 20; 을 실행하더라도 main()에서의 value는 변경되지 않습니다. 그리고 함수가 종료되면서 val는 사라지고, main()로 되돌아왔을때의 value는 여전히 10인 상태이다.

그렇다면, call_by_refer() 에서 *ref = 20; 을 실행했을 때는 왜 refer에 20이 저장이 되었을까?

그 이유는 바로, ref 라는 변수에다 저장을 한 것이 아니라, *ref 즉 ref가 가지고 있는 주소값 위치에 20을 저장했기 때문입니다. 왜냐하면 ref는 &refer였으므로 refer의 주소를 가지고 있는데, *ref는 ref가 가지고 있는 주소에 해당하는 메모리의 값을 뜻하기 때문에, refer의 값을 의미한다.

그러므로, call_by_refer(&refer)를 실행함으로써 main()에서의 refer를 전달받은 것이 아니라, refer 변수의 주소값을 전달받은 것이고, 그 주소값에 해당하는 위치에다 20 이란 값을 저장하게 되니, *ref = 20 은 ref 에 저장하는 것이 아닌, refer에 저장하는 것이 된다.

5. 이중 포인터

이중포인터는 포인터를 가르키는 "*"를 "**"와같이 두개를 써서 사용한다.

포인터가 어떤 변수의 주소값을 가리킨다라고 하면, 이중포인터는 포인터 변수의 주소값을 가리킨다고 할 수 있다.

즉, 둘다 변수의 주소값을 가리키는 것이다.


main() 시작시에 두 변수 모두 동일한 local_val의 주소값을 가리키게 했으니, *value, *refer 는 10이 된다.

그리고, 아까전과 동일하게 call_by_value()는 변수를 그대로, call_by_refer()는 변수의 주소값을 인자로 보내고, 

각 함수에서는 global_val 의 주소값을 넣어준다.

결과는


call_by_value()에서의 val은 &global_val을 받긴 하지만 함수를 종료하고 나면 값은 사라진다. 

그러므로, main()에서는 여전히 local_val을 가리키고 있으며, 10이 출력된다.

call_by_refer()에서의 ref는 포인터변수의 주소값이므로, *ref 에 &global_val를 넣게 되면 main()에서의 refer 값이 변경되는 셈이므로,

 local_val이 아니라 global_val을 가리키고 있으며, 30이 출력된다.


중요한 것은 '내가 담고자 하는 변수의 주소값'이 필요한 것인데, 그 변수가 포인터 변수이다.

'내가 담고자 하는 (포인터)변수의 주소값'이 필요한 것이 된다.


main() 에서 전달하는 변수가 포인터변수였고, 그 포인터변수의 주소값을 넘겨야 하므로, &refer가 되어야 하는 게 맞으며, 

그에 맞춰서 call_by_refer(int **ref) 처럼 이중포인터가 되는 것이다.



댓글