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;
}
이 프로그램은 포인터와 참조자를 사용한 함수 호출 및 동적 메모리 할당의 예를 보여줍니다. 포인터와 참조자의 개념을 이해하고, 동적 메모리 관리를 통해 효율적인 프로그램을 작성하는 데 도움이 될 것입니다.
