[C 기초 - 포인터]

Junyeong Fred Kim·2021년 12월 6일
0

C언어

목록 보기
15/21

포인터


포인터는 "주소"를 가리킨다. 이름만 포인터라고 다를 뿐, int, char와 같이 다를 바 없는 변수이다. 그래서 포인터 변수라고 부르기도 한다. 포인터는 변수의 주소값을 저장한다.

#include <stdio.h>

int main()
{
	int *p = NULL;  // int* p == int * p 모두 같음
	int num = 15;

	p = &num;

	printf("int 변수 num의 주소 : %d \n", &num);
	printf("포인터 p의 값 : %d \n", p);
	printf("포인터 p가 가리키는 값 : %d \n", *p);

	return 0;
}

출력

int 변수 num의 주소 : -1841220324
포인터 p의 값 : -1841220324
포인터 p가 가리키는 값 : 15

출력 설명

위와 같이 포인터 변수를 선언할 떄는 담고자 하는 자료형에 *(참조 연산자)를 붙여서 선언한다. int형 변수의 주소를 담고 싶으면, int*을, char형 변수 주소를 담고 싶다면, char*을 사용한다.

*의 위치는 상관 없다.

  • int *p
  • int* p
  • int * p

포인터는 주소값을 담는 변수이기 때문에 어떤 특정한 숫자로 할 수 없다. 따라서 숫자가 아닌 NULL(0)로만 가능하다. 물론 NULL로 초기화하지 않고 그냥 선언만 한 후 주소값을 넣어도 괜찮다. 0은 0번지를 가리키는 것이 아니라, 아무것도 없다는 뜻의 NULL(0)이다.

변수를 초기화하지 않았을 때의 초기값은 쓰레기값이 들어가있다. 포인터 변수도 마찬가지이다. 특히 포인터는 주소값을 다루기 때문에 초기화를 하지 않고 사용하다가 실수로 잘못된 주소를 다루게 되면, 프로그램이 종료되거나 다른 오류를 일으킬 수도 있다. 선언 후 바로 다른 변수의 주소 값을 넣더라도 NULL로 초기화하는 것을 권장

참조 연산자 *


* 연산자는 곱셈을 할 떄 사용하기도 하지만, 포인터를 이용할 때 쓰기도 한다. &연산자 and 연산자와 주소 연산자로 쓰이듯, 두개의 피연산자 (a*b)가 있으면 곱셈 연산자이고 하나의 피연산자만 있으면 참조 연산자이다. 참조 연산자는 포인터의 이름이나 주소 앞에 사용하며, 포인터가 가리키는 주소에 저장된 값을 반환한다.

코드

#include <stdio.h>

int main()
{
	int *p = NULL;  
	int num = 15;

	p = &num;

	printf("int 변수 num의 주소 : %d \n", &num);
	printf("포인터 p의 값 : %d \n", p);
	printf("포인터 p가 가리키는 값 : %d \n", *p);

	return 0;
}

출력

int 변수 num의 주소 : 527571564
포인터 p의 값 : 527571564
포인터 p가 가리키는 값 : 15

출력 설명

num의 주소와 포인터 변수p에 들어있는 값은 동일한 것을 확인할 수 있다. 거기다 참조 연산자 *를 이용하여 p가 가리키는 값을 출력하여 보았는데, *p를 이용하면 p에 들어있는 주소로 가서 그 변수의 값을 가져오게 된다. 따라서 *p가 num에 들어있는 15를 출력하는 것을 확인할 수 있다.

포인터를 이용하면 변수를 이용하듯이 사칙연산이 가능하다. 하지만 한가지 주의할 점은 증감 연산자이다.

코드

#include <stdio.h>

int main()
{
	int *p = NULL; 
	int num = 15;

	p = &num;
	printf("포인터 p가 가리키는 값 : %d\n", *p);
	printf("num의 값 : %d\n\n", num);

	*p += 5;
	printf("포인터 p가 가리키는 값 : %d\n", *p);
	printf("num 값 : %d\n\n", num);

	(*p)++;
	printf("포인터 p가 가리키는 값 : %d\n", *p);
	printf("num 값 : %d\n\n", num);

	*p++;
	printf("포인터 p가 가리키는 값 : %d\n", *p);
	printf("num 값 : %d\n", num);

	return 0;
}

출력

포인터 p가 가리키는 값 : 15
num의 값 : 15
포인터 p가 가리키는 값 : 20
num 값 : 20
포인터 p가 가리키는 값 : 21
num 값 : 21
포인터 p가 가리키는 값 : -540246256
num 값 : 21

출력 설명

주소값이 들어있는 p의 값을 증가시키는게 아니라, 포인터 p에 들어있는 주소로 찾아가 그 값을 5만큼 증가시키는 것이다. * 연산자가 붙으면 주소로 찾아간다고 생각하면 된다.


근데 문제는 (*p)++*p++이다. 둘 다 똑같은 증감 연산자인데, (*p)++는 정상적으로 값이 증가되었꼬, *p++는 이상한 값이 출력된걸까?

간단히 말하면 증감연산자(++,--)가 참조 연산자(*)보다 우선순위가 높다. 따라서 마지막 문단의 *p++의 경우, 주소를 먼저 찾아가지 않고 주소값이 들어있는 변수 p를 먼저 증가시키게된다.

굳이 포인터에 주소를 넣어 간접적으로 사용할 필요없이, 지금까지처럼 변수를 바로 사용하면 되지 않을까?

포인터는 함수를 사용할 때, 진가를 발휘한다. 함수 챕터에서 말한 것과 같이 함수에서는 인자를 전달할 때 복사해서 사용한다. 즉, 전달해주는 원래 변수는 함수에서 수정할 수 없다.

하지만 포인터는 다르다. 포인터로 메모리의 주소를 넘겨주면 함수에서도 메모리에 직접적으로 참조할 수 있기 때문에, 변수의 값을 바로 수정하는 것이 가능하다.

#include <stdio.h>

void pointerPlus(int *num)
{
	*num += 5;
}

void numPlus(int num)
{
	num += 5;	
}

int main()
{
	int num = 15;
	printf("num 값 : %d\n", num);

	numPlus(num);
	printf("numPlus 사용 후 : %d\n", num);

	pointerPlus(&num);
	printf("pointerPlus 사용 후 : %d\n", num);

	return 0;
}

출력

num 값 : 15
numPlus 사용 후 : 15
pointerPlus 사용 후 : 20

출력 설명

numPlus의 경우와는 다르게 pointerPlus 함수를 실행한 후에는 정상적으로 num의 값이 증가되었다. 포인터를 이용해 직접적으로 메모리에 접근하여 값을 변경했기 때문이다.

profile
기억보다 기록

0개의 댓글