포인터의 이해

마블현·2024년 7월 3일

C언어

목록 보기
17/17

포인터란?

포인터는 C언어가 Low레벨 언어의 특성을 지닌다고 할 수 있게 해준 기능이다. 왜냐하면 포인터로 메모리에 직접 접근이 가능하기 때문이다.

메모리에 변수를 선언하면 그 변수가 저장된 메모리 주소 역시 정수이다. 따라서 메모리 주소도 저장이 가능한 값이며, 이의 저장을 위해 마련된 변수가 포인터 변수이다. 메모리 주소 값을 저장하기 위한 변수인 것이다.

포인터 변수 선언

포인터 변수는 기리키고자 하는 변수의 자료형에 따라서 선언하는 방법이 달라진다. 물론 주소 값은 동일한 시스템에서 그 크기가 동일하며 모두 정수의 형태를 갖는다.
포인터 변수를 선언할 때는 *연산자를 사용한다.

int * pnum1; >> int *는 int형 변수를 가리키는 pnum1의 선언을 의미
double * punm2;
type * ptr; >> type형 변수의 주소 값을 저장하는 포인터 변수 ptr

참고로 *의 위치는 상관이 없다. 자료형의 이름에 붙여도 되고 변수의 이름에 붙여도 된다.


포인터 연산자

포인터의 *연산자는 곱셉 연산자가 아니다. 차이점이 있다면, 곱셈 연산자는 이항 연산자지만, 포인터의 *연산자는 단항연산자다.

&연산자

&연산자는 피연산자의 주소 값을 반환하는 연산자이다.

int main(void)
{
	int num = 5;
    int * pnum = #	//num의 주소값을 반환해서 포인터 변수 pnum을 초기화
}

&연산자의 피연산자는 변수여야하며, 상수는 피연산자가 될 수 없다.
변수의 주소 값을 변수와 다른 타입의 포인터에 저장하는 것은 컴파일 에러가 발생하지는 않지만, * 연산 시 문제가 발생하기 때문에 잘못된 것이다.

*연산자

*연산자는 포인터가 가리키는 메모리 공간에 접근할 때 사용하는 연산자이다.

int main(void)
{
	int num = 10;
    int *pnum = #
    *pnum = 20;	//pnum이 가리키는 변수에 20을 저장
}

위의 코드를 실행하면 변수 num의 값은 20으로 저장되는 것이다. 이렇듯 사실상 *pnum은 포인터 변수 pnum이 가리키는 변수 num을 의미하는 것이다.

포인터 형

포인터의 형은 메모리 공간을 참조하는 기준이 된다. 이게 무슨 말이냐면, 포인터 변수에 저장된 주소를 시작으로 몇 바이트를 읽어들여야 하는지에 대한 가이드가 된다는 것이다.
pnum이 int형 포인터 변수이면 pnum에 저장된 주소를 시작으로 4바이트를 읽어 들여 정수로 해석하는 것이다.

포인터에 형이 존재하지 않는다면 * 연산을 통한 메모리의 접근은 불가능하다.

포인터의 잘못된 사용과 널 포인터

포인터 변수에는 메모리의 주소 값이 저장되고, 이를 이용해서 해당 메모리 공간에 접근도 가능하기 때문에 상당히 주의해야한다.

int main(void)
{
	int *ptr;	// 포인터 변수 ptr은 쓰레기 값으로 초기화 됨
    *ptr = 200;
    ...
}

위와 같이 포인터 변수를 선언만하고 초기화하지 않으면, 포인터 변수는 쓰레기 값으로 초기화 된다. 이 상태에서 200을 저장한다면, 메모리의 어느 부분에 200이 저장되는 지 모르게 된다.

int main(void)
{
	int *ptr = 125;	//125는 어디에 저장되는가?
    *ptr = 10;
    ...
}

위의 경우는 포인터 변수 ptr의 초기화로 125를 저장하였다. 이 경우 역시 메모리의 125번지가 어딘지 모르는 상태로 10을 저장하게 되는 것이다.

포인터 변수를 우선 선언만 해놓고, 이후에 유효한 주소 값을 채워 넣을거라면 NULL을 사용하면 된다. 이는 널 포인터이며, 0을 사용해도 좋다.
아무데도 가리키지 않는다는 뜻이며, 메모리 공간에 어떠한 영향도 미치지 않는다.

profile
고수로 나아가는 중

0개의 댓글