C++

C++ - pointer

hellowhales 2023. 1. 23. 22:38
728x90

포인터는  C/C++에서 가장 중요한 개념 중 하나이다. 포인터의 개념은 주소를 가리키는 변수이다.

int* pInt; // int *pInt

위의 예는 정수 타입의 값을 가지는 주소를 저장하는 변수 pInt를 선언한 것이 된다. 이때 int 뒤에 오는 별표(*)는 int 바로 뒤에 붙어도 되고 변수명 앞에 붙어도 되며 메모리 공간을 가리킨다는 것을 의미한다. 위와 같이 포인터를 선언만 해놓았을 경우 포인터가 구체적으로 가리키는 대상이 없고 이를 초기화되지 않은 변수라 한다. 이러한 초기화되지 않은 변수를 사용하면 프로그램이 뻗어버리기 때문에 포인터 변수는 항상 선언하자마자 초기화해야 한다. 만일 바로 사용하지 않는다면 널 포인터(nullptr)로 초기화해야 한다.

int* pInt = nullptr;

if(!pInt)
{
	cout << "this is nullptr!" << endl;
}

널 포인터는 정상적인 포인터라면 절대 가지지 않을 특수한 값이며 부울 표현식에는 false로 취급한다.

char cChar = 'x';

char* pChar = &cChar;
int* pInt = new int ;

널 포인터가 아닌 다른 주소를 넣을 때는 위와 같은 방법을 사용한다.

주소 참조 연산자 & 를 사용하는 것은 원레 있는 변수의 메모리 주소를 가져와 대입한다. 따라서 pChar는 'x' 문자를 담고 있는 cChar의 메모리 주소를 가지게 된다. 

new 키워드의 경우 heap 공간에 메모리를 동적할당 하는 것이다. 이는 새로운 컨테이너를 하나 만드는 것으로 사용이 끝난 후에 반드시 할당 해제를 해주어야 한다. 

위 코드의 메모리 현황

포인터는 주소값만을 가지고 있으므로 이 주소가 가지고 있는 값에 접근하려면 포인터를 역참조해야 한다.

*pChar = 'y'; 
*pInt = 10;

변수 앞에 나오는 *은 위에 포인터임을 표현해 주는 *과는 다른 역할로 해당 변수 값을 주소로 보고 그 주소로 가서 주소가 가지고 있는 값을 나타내는 연산자이다. 따라서 코드 수행 시 아래와 같은 형태가 된다.

pInt = 10;

만일 *연산자를 붙이지 않고 포인터 변수에 위 같은 코드가 수행되면 포인터 변수는 10이라는 주솟값을 가르키게 되고 당연히 그곳에는 어떤 값이 들어있을지 알 수 없기 때문에 프로그램을 실행하면 어떤 결과가 일어날지 알 수 없다.

 

delete pInt;
pInt = nullptr;

동적할당된 포인터 변수를 다 사용했을 시 delete문을 이용해서 메모리를 해제해주어야 한다. 그리고 사용했던 포인터 변수에 널 포인터를 할당해 두면 포인터를 사용하는데 실수를 줄일 수 있다.

 

구조체에 대한 포인터를 다룰 때는 축약 표현을 사용할 수 있다.

#include <iostream>

using namespace std;

struct Student
{
	int ID;
    float GPA;
};

int main()
{
	Student* myStudent = new Student;
	(*myStudent).ID = 2023123456;
	myStudent->GPA = 3.14;
}

* 연산자를 통해 구조체에 접근한 뒤에 각 필드에 접근할 수 있는데 사용하는데 불편하기 때문에 ->(화살표) 연산자로 구조체를 역참조해서 필드에 바로 접근할 수 있다.

728x90