프로그래밍을 공부한 내용을 정리하며 기록하고 있습니다 📝
포인터
주소값과 메모리 글에서, 프로그래밍한 코드의 변수와 같은 데이터들이 메모리상에 저장되면서 주소값을 가진다고 설명했었습니다. 포인터는 이러한 데이터의 주소값을 저장해, 데이터를 간접적으로 조작할 수 있게 해주는 형식입니다.
GPT가 설명해준 비유가 적절해 가져와 보았습니다.
변수는 데이터를 저장한 건물, 포인터는 그 건물의 주소를 적은 종이입니다.
변수라는 건물은 메모리라는 큰 도시 안의 특정 주소에 자리 잡고 있습니다.
포인터는 건물 자체가 아니라, 그 건물이 어디에 있는지의 정보만을 가집니다.
포인터에 적힌 주소를 따라가면 해당 건물(변수)에 도달할 수 있습니다. 이를 통해서 건물 안의 데이터에 접근할 수 있습니다.
포인터의 사용
위와 같은 형태가 가장 기본적인 포인터의 형태입니다. 변수명 앞에 * 을 붙이게 되면 포인터 변수가 되고, 해당 포인터 변수에 변수(a)의 주소값을 대입하면 포인터가 변수를 가리키게 됩니다. 이렇게 포인터를 통해 변수(a)의 값을 간접적으로 조작할 수 있습니다.
이 때 사용하는 & 연산자는 해당 변수의 주소값을 반환하는 주소연산자, * 연산자는 주소에 저장되어 있는 값을 반환하는 참조 연산자라고 합니다.
포인터를 사용한 동적 메모리 할당
이러한 포인터는 주로 동적 메모리 할당에 사용됩니다. 기본적으로 코드 상의 변수들은 컴파일되면서 메모리의 데이터 영역이나 스택 영역에 저장되게 되는데, 동적 메모리 할당을 할 경우엔 힙 영역에 저장되게 됩니다. (CS : 소프트웨어 기초 : 메모리 할당과 구조 단락 참고)
아래와 같이 포인터를 사용해 메모리를 동적으로 할당할 수 있습니다.
#include <iostream>
using namespace std;
int main()
{
int* ptr = new int(5); // 힙에 메모리 동적 할당
cout << "동적으로 할당된 값 : " << *ptr << endl; // 5 출력
delete ptr; // 동적 메모리 해제
ptr = nullptr; // 포인터 초기화
cout << "포인터 해제됨 : " << ptr << endl; // null pointer 값 0000000000000000 출력
}
포인터로 클래스 객체를 동적으로 생성
또, 이러한 포인터를 활용해 아래와 같이 클래스 객체를 동적으로 생성하고 접근하는 것도 가능합니다.
#include <iostream>
using namespace std;
class MyClass
{
int value;
public:
MyClass(int v) : value(v) {}
void display() // 클래스 멤버 변수 값 출력용 함수
{
cout << "Value : " << value << endl;
}
};
int main()
{
MyClass* obj = new MyClass(33); // 객체 동적 생성
obj->display();
delete obj; // 메모리 해제
}
포인터로 배열의 요소들 접근
배열 변수는 배열의 첫 번째 요소의 주소값을 가지고 있습니다. 배열의 이러한 특성을 이용해서 포인터로 배열의 요소들에 접근하는 것도 가능합니다.
배열과 포인터의 자료형에 따라 주소값이 증가하는 크기가 달라지는 것을 확인할 수 있습니다. (int형일 경우 4바이트씩 증가, double 형일 경우 8바이트씩 증가)
#include <iostream>
using namespace std;
int main()
{
int arr[] = { 1, 2, 3, 4, 5 };
int* ptr = arr; // arr = 배열의 첫 번째 요소의 주소값이기 때문에 & 필요없음
for (int i = 0; i < 5; ++i)
{
cout << "arr[" << i << "] = " << *(ptr + i) << endl; // 배열의 요소 출력
cout << ptr + i << endl; // 변경되는 주소값 출력
}
}
this 포인터
클래스에서 멤버 함수 등을 사용할 때에 this 포인터라는 상수형 포인터를 사용하기도 합니다. this 포인터에 대한 자세한 설명과 예시는 아래 글을 추천드립니다.
C++ 09.10 - this 포인터
this 포인터 객체 지향 프로그래밍에서 가장 많은 질문 중 하나는 "클래스의 멤버 함수를 호출할 때 C++는 어떻게 호출할 객체(인스턴스)를 찾는가?" 이다. 이 질문에 대한 정답은 this라는 숨겨진
boycoding.tistory.com
이 외에도 포인터에는 구조체의 멤버에 간접적으로 접근하거나, 포인터로 포인터를 가르키는 이중 포인터 등의 사용 방식도 있습니다.
포인터 변수의 크기
포인터 변수는 int*, double* 등의 어떤 자료형을 가리키든 모두 동일한 크기를 가집니다.
하지만 컴파일러의 비트 수에 따라선 포인터의 크기가 달라지게 됩니다. 포인터 변수의 크기는 32비트 컴파일러에선 4바이트, 64비트 컴파일러에서는 8바이트가 됩니다.
출처
포인터 변수의 크기 - [C언어]포인터 변수의 크기는 4바이트? 아니다!