C++ 배열과 포인터 심화: 동적 메모리 할당과 레퍼런스
함수에 배열 전달 -> 포인터 취급
C++에서 함수에 배열을 전달하면, 배열은 포인터로 처리된다. 즉, 함수는 배열의 복사본을 받는 것이 아니라, 원본 배열의 시작 주소를 가리키는 포인터를 받게 된다. 따라서 함수가 배열에 직접 접근하므로 함수 내부에서 배열을 수정하면 원본 배열에도 영향을 미친다.
void modifyArray(int arr[], int size) {
for (int i = 0; i < size; ++i) {
arr[i] *= 2; // 원본 배열의 값이 변경된다
}
}
동적 메모리 할당: 실행 중 메모리 확보
C++는 프로그램 실행 중에 메모리를 동적으로 할당하고 해제할 수 있는 기능을 제공한다. 이는 컴파일 시점에 메모리 크기를 미리 알 수 없는 경우에 유용하다.
지난 시간에 잠시 언급했던 스택과 힙 개념이 여기에서 사용된다.
복습해보자.
![]() |
stack vs heap |
- 스택(Stack): 컴파일 시점에 크기가 결정되는 메모리 영역으로, 지역 변수와 함수 호출 정보 등을 저장한다.
- 힙(Heap): 프로그램 실행 중에 동적으로 할당되는 메모리 영역으로,
new
연산자를 사용하여 메모리를 할당하고delete
연산자를 사용하여 해제한다.
int* ptr = new int; // 힙에 int 크기의 메모리 할당
*ptr = 10; // 할당된 메모리에 값 저장
delete ptr; // 메모리 해제
메모리 누수와 Dangling Pointer: 동적 메모리 할당의 위험성
프로그램 실행 중 유동적으로 메모리를 할당할 수 있다는 점에서 많은 이점이 있지만, Dynamic memory allocation 시 주의해야 할 점이 있다. 바로 메모리 누수(Memory Leak)와 Dangling Pointer이다.
- 메모리 누수: 할당된 메모리를 해제하지 않으면, 프로그램이 종료될 때까지 해당 메모리 영역을 사용할 수 없게 된다. 이를 메모리 누수라고 하며, 심각한 경우 시스템 성능 저하를 야기할 수 있다.
- Dangling Pointer: 이미 해제된 메모리 영역을 가리키는 포인터를 Dangling Pointer라고 한다. Dangling Pointer를 사용하면 예측 불가능한 오류가 발생할 수 있다.
![]() |
Caution |
레퍼런스: 변수의 또 다른 이름
레퍼런스는 이미 존재하는 변수에 대한 별칭(alias)이다. 레퍼런스를 선언할 때는 type 뒤에 &를 붙여 선언한다. 레퍼런스를 사용하면 변수를 함수에 전달하거나 반환할 때 데이터 복사를 방지하여 효율성을 높일 수 있다.
![]() |
reference |
int num = 10;
int& ref = num; // ref는 num의 별칭
ref = 20; // num의 값이 20으로 변경된다
const
키워드: 변경 불가능한 상수 표현
const
키워드는 변수의 값을 변경할 수 없도록 선언하는 데 사용된다. const
키워드는 포인터와 함께 사용될 때 다양한 의미를 갖는다.
const int* ptr
: 포인터가 가리키는 값을 변경할 수 없다.int* const ptr
: 포인터 자체의 값(즉, 주소)을 변경할 수 없다.const int* const ptr
: 포인터가 가리키는 값과 포인터 자체의 값 모두 변경할 수 없다.
![]() |
Constant |
결론
배열과 포인터는 C++ 프로그래밍에서 핵심 도구임과 동시에 메모리 관리에 대한 책임을 요구한다. 동적 메모리 할당, 레퍼런스, const
키워드 등을 적절히 활용하면 효율적이고 안전한 코드를 작성할 수 있다.
[C++][OOP] Array & Pointer
(https://hyeondev.blogspot.com/2024/09/coop-array-pointer.html)
[C++][OOP] Flow Control - 조건문, 반복문
(https://hyeondev.blogspot.com/2024/09/coop-flow-control.html)