C++에서 포인터와 참조자는 매우 중요한 개념으로, 메모리와 데이터를 직접적으로 관리하고 접근할 수 있게 합니다. 여기서는 포인터의 기본 개념, 포인터 연산, 참조자, 동적 메모리 할당 등을 자세히 설명하겠습니다.
포인터
포인터의 기본 개념
포인터는 다른 변수의 메모리 주소를 저장하는 변수입니다. 포인터는 특정 타입의 데이터를 가리킬 수 있도록 선언됩니다.
#include <iostream> int main() { int var = 42; // 정수 변수 선언 int* ptr = &var; // var의 주소를 저장하는 포인터 선언 std::cout << "var의 값: " << var << std::endl; std::cout << "ptr이 가리키는 값: " << *ptr << std::endl; return 0; }
위 예제에서 ptr
은 var
의 메모리 주소를 저장하는 포인터입니다. *ptr
은 ptr
이 가리키는 값을 참조합니다.
포인터 연산
포인터 연산은 포인터를 조작하는 방법을 제공합니다. 주요 연산은 다음과 같습니다:
&
연산자: 변수의 주소를 구합니다.*
연산자: 포인터가 가리키는 주소의 값을 참조합니다.- 포인터 산술 연산: 포인터에 정수를 더하거나 빼서 메모리의 다른 위치를 가리키게 할 수 있습니다.
#include <iostream> int main() { int arr[5] = {10, 20, 30, 40, 50}; int* ptr = arr; // 배열의 첫 번째 요소를 가리키는 포인터 for (int i = 0; i < 5; ++i) { std::cout << "arr[" << i << "] = " << *(ptr + i) << std::endl; } return 0; }
위 예제에서 ptr + i
는 arr[i]
와 동일합니다.
참조자
참조자는 다른 변수를 가리키는 별칭입니다. 참조자는 선언 시에 초기화되어야 하며, 이후 다른 변수를 참조할 수 없습니다.
#include <iostream> int main() { int var = 42; int& ref = var; // var의 참조자 선언 std::cout << "var의 값: " << var << std::endl; std::cout << "ref의 값: " << ref << std::endl; ref = 100; // 참조자를 통해 var의 값을 변경 std::cout << "변경된 var의 값: " << var << std::endl; return 0; }
위 예제에서 ref
는 var
의 참조자로, ref
를 통해 var
의 값을 변경할 수 있습니다.
동적 메모리 할당
동적 메모리 할당은 런타임에 메모리를 할당하는 방법입니다. C++에서는 new
와 delete
연산자를 사용하여 동적 메모리를 할당하고 해제할 수 있습니다.
#include <iostream> int main() { // 정수형 메모리 동적 할당 int* ptr = new int; *ptr = 42; std::cout << "동적으로 할당된 메모리의 값: " << *ptr << std::endl; // 메모리 해제 delete ptr; // 정수 배열 메모리 동적 할당 int* arr = new int[5]; for (int i = 0; i < 5; ++i) { arr[i] = i * 10; } std::cout << "동적으로 할당된 배열의 값: "; for (int i = 0; i < 5; ++i) { std::cout << arr[i] << " "; } std::cout << std::endl; // 배열 메모리 해제 delete[] arr; return 0; }
위 예제에서는 정수형 변수와 정수 배열을 동적으로 할당하고, 할당된 메모리를 delete
연산자를 사용하여 해제합니다.
포인터와 참조자를 사용한 함수
포인터와 참조자를 함수의 매개변수로 사용하면 함수가 호출된 곳에서 변수의 값을 변경할 수 있습니다.
포인터를 사용한 함수
#include <iostream> void increment(int* ptr) { (*ptr)++; } int main() { int num = 10; increment(&num); std::cout << "포인터를 사용한 함수 호출 후 num의 값: " << num << std::endl; return 0; }
참조자를 사용한 함수
#include <iostream> void increment(int& ref) { ref++; } int main() { int num = 10; increment(num); std::cout << "참조자를 사용한 함수 호출 후 num의 값: " << num << std::endl; return 0; }
위 두 예제에서 increment
함수는 포인터와 참조자를 사용하여 num
의 값을 증가시킵니다.
예제 프로그램
아래는 포인터, 참조자, 동적 메모리 할당을 모두 사용하는 예제 프로그램입니다:
#include <iostream> // 포인터를 사용한 함수 void incrementPtr(int* ptr) { (*ptr)++; } // 참조자를 사용한 함수 void incrementRef(int& ref) { ref++; } int main() { int num = 10; std::cout << "초기 num의 값: " << num << std::endl; // 포인터를 사용하여 num의 값을 증가 incrementPtr(&num); std::cout << "포인터를 사용한 함수 호출 후 num의 값: " << num << std::endl; // 참조자를 사용하여 num의 값을 증가 incrementRef(num); std::cout << "참조자를 사용한 함수 호출 후 num의 값: " << num << std::endl; // 동적 메모리 할당 int* dynamicNum = new int(20); std::cout << "동적으로 할당된 메모리의 초기 값: " << *dynamicNum << std::endl; // 동적 메모리 해제 delete dynamicNum; return 0; }
이 프로그램은 포인터와 참조자를 사용한 함수 호출 및 동적 메모리 할당의 예를 보여줍니다. 포인터와 참조자의 개념을 이해하고, 동적 메모리 관리를 통해 효율적인 프로그램을 작성하는 데 도움이 될 것입니다.