포인터

A Code AM·2020년 3월 1일
0

모르고 썼다

목록 보기
1/7
post-thumbnail

포인터란?

' 메모리의 실제 주소값 '
= 포인터 변수 = 주소값을 저장하는 변수 = '가리키는' 개념
실제로 프로그램이 변수에 있는 값을 가져올 때 값을 가져오는게 아니고 '공간'을 가져온다.

  • 컴퓨터 메모리는 여러 개의 바이트(byte)로 구성되어 있으며 각 바이트마다 0부터 시작하는 주소가 붙여져 있다. 변수는 컴퓨터 메모리에 이름을 붙여서 참조하는 것이다. 프로그래머는 주소에 대해 신경 쓸 필요가 없다. 그냥 변수를 생성해서 사용하면 된다.
  • 하지만 장치 드라이버나 동적 메모리 할당에서는 '메모리를 주소로 참조해야 하는' 경우가 발생한다. 이때 포인터가 사용된다.

값을 가져온다 = 공간을 불러온다

int a= 5;
int *p = &a;

이런식으로 선언하면 a라는 변수가 메모리 상에 자리잡으면서 주소를 갖는다.
그리고 포인터는 이 주소값을 저장한다. (포인터 변수에는 참조연산자 *를 붙여 포인트 변수임을 선언하고 주소값을 저장할 때에는 변수 앞에 주소 연산자 &를 붙여준다)
a라는 변수의 주소값은 가진 포인터 p는 '5'를 가리킨다.

간접 참조(dereferencing, indirection) 연산자* = 역참조

  • 다른 변수, 혹은 그 변수의 메모리 공간 주소를 가리키는 변수. 포인터가 가리키는 값을 가져오는 것을 역참조(dereferencing)라고 한다. *p => a의 주소로 가서 값을 가져와라.

또한, 포인터 변수의 주소를 담는 곳은 따로 저장 되며 (운영체제가 같으면) 그 크기는 모두 동일하다.
64비트에선 8바이트, 32비트에선 4바이트이다.

Q. 자료형에 따라 선언하는 자료형이 달라지는 이유?
A. 가리킬 주소가 어떤 자료형을 갖는지 알려주기 위해 -> int면 4바이트만큼, double이면 8바이트만큼

포인터는 주소값을 담는 변수이기 때문에 어떤 특정한 숫자로 초기화 할 수 없다.
숫자가 아닌 NULL(0)으로만 가능하다. (C++에선 nullptr)

Q. NULL과 nullptr의 차이는?
A. nullptr은 null pointer를 의미. C++에서 함수 오버로딩(함수 이름이 같으나 인자 갯수나 타입에 따라 특징이 다른 여러 함수들을 만드는 것)이라는 기능이 존재하는데 NULL은 0으로 정의되어 있어 int 타입으로 불러와짐 > 컴파일러에서 null포인터인지 정수 0인지 구분이 안되어 문제가 발생할 수 있다. nullptr은 포인터 모든 유형(int, double 등등)으로 변환하고 다른 기능을 차단한다고 함. 그래서 쓸 수 있다면 nullptr을 쓰는게 좋다.


포인터 연산

연산자에는 우선순위가 있어서 증감연산자보다 참조 연산자의 우선순위가 높다
-->> 따라서 (p)++ 와 p++은 다른 결과값을 낸다

p++는 주소 값을 증가시킨거고 ( = 다음 주소값을 가져옴)
(
p)++는 주소가 가리키는 값을 증가 시킨 것.

Q. 왜 굳이 포인터에 주소를 넣어서 사용하나?
A. 함수 때문. 함수에서는 인자를 전달할 때 복사해서 사용함 (call by value). 즉 전달하는 원래의 변수 값은 함수에서 수정할 수 없다. 그러나 포인터는 메모리의 주소로 넘기기 때문에 함수에서도 메모리에 직접적으로 참조할 수 있어서 변수의 값을 바로 수정해버린다 (call by reference).
C언어에서는 주소값 자체를 복사해서 넘겨주는 것이어서 call by address 방식이라고 한다. 근데 call by reference처럼 사용할 수 있다고 함. 일반적으로 C언어에서 함수 전달 방식은 call by value.

길 잃은 포인터(stray pointer)

: 포인터가 가리키고 있던 메모리를 해제(delete) 후 다시 사용하는 것. 포인터는 메모리에서 할당되었던 영역을 가리키고 있을 것이다. 하지만 컴파일러는 그 주소에 다른 데이터를 놓을 수 있다. 따라서 포인터를 사용하게 되면 프로그램이 종료될 것이다.

const 포인터

const int *p1;				// 1
int * const p2;				// 2
const int * const p3;			// 3
  1. p1은 변경되지 않는 정수를 가리키는 포인터. 이 포인터를 통해 참조되는 값은 변경이 불가능
*p1 = 5; // 같은 문장은 불가능
  1. p2는 정수에 대한 상수 포인터. 정수는 변경될 수 있지만 p2는 다른 것을 가리킬 수 없다. 상수 포인터는 재할당 될 수 없다.
p2 = &a // 같은 문장은 불가능.
  1. p3는 상수에 대한 상수 포인터. 포인터가 가리키는 값도 변경이 불가능하고 포인터 p3도 다른 것을 가리키게끔 변경될 수 없다.

( * )기호를 중심으로 const가 왼쪽에 있으면 객체가 변경되지 않는다는 의미. 오른쪽에 있으면 포인터 자체가 변경되지 않는다는 의미

const int *p1;		// 가리키는 정수가 상수
int * const p2;		// p2가 상수가 된다. 따라서 다른 것을 가리킬 수 없음

const 포인터와 const 멤버 함수

멤버 함수를 const로 정의하면 함수 안에서 멤버 변수 변경이 금지됨. const 객체를 가리키는 포인터를 정의하면 이 포인터로 호출할 수 있는 함수는 const 함수 뿐이다.
= 상수 객체에 대한 포인터를 선언하는 것은 이 포인터를 통해 상수 함수만 호출할 수 있다는 의미

profile
배움기록

0개의 댓글