함수를 호출할 때, 파이썬에서는 값만 넘겨줬지만, C++에서는 포인터를 사용해서 변수의 주소를 넘겨줄 수 있다. 이렇게 하면 함수가 변수를 직접 수정할 수 있다.
#include <iostream>
void changeValue(int* ptr) {
*ptr = 20; // 포인터를 이용해 변수의 값을 수정
}
int main() {
int a = 10;
std::cout << "Before: " << a << std::endl;
changeValue(&a); // a의 주소를 함수에 넘김
std::cout << "After: " << a << std::endl;
return 0;
}
changeValue(&a): 변수 a의 주소를 함수에 넘겨줌.
*ptr = 20;: 함수 안에서 포인터를 통해 변수 a의 값을 변경.
파이썬에서는
a=10
a=20
이렇게 덮어쓸 수 있었는데 c++은 상당히 복잡하다.
C++에서는 동적 메모리 할당을 통해 런타임에 메모리를 할당하고 사용해야 한다.
동적 메모리는 프로그램 실행 중에 메모리가 필요할 때 할당하고, 다 사용하면 해제하는 방식으로 사용한다.
이를 통해 배열의 크기를 실행 중에 동적으로 정할 수 있다.
동적 메모리 할당의 문법:
new: 메모리를 동적으로 할당.
delete: 동적으로 할당한 메모리를 해제.
#include <iostream>
int main() {
// 동적 메모리 할당
int* ptr = new int; // 정수형 변수를 위한 메모리 할당
*ptr = 10; // 동적 메모리 공간에 값 할당
std::cout << "Value: " << *ptr << std::endl;
// 메모리 해제
delete ptr; // 동적으로 할당된 메모리 해제
return 0;
}
동적 배열 할당 예시
#include <iostream>
int main() {
int size;
std::cout << "Enter the size of the array: ";
std::cin >> size;
// 동적으로 배열 할당
int* arr = new int[size];
// 배열에 값 입력 및 출력
for (int i = 0; i < size; i++) {
arr[i] = i * 2;
std::cout << arr[i] << " ";
}
std::cout << std::endl;
// 배열 메모리 해제
delete[] arr; // 동적으로 할당된 배열 메모리 해제
return 0;
}
함수에서 포인터를 사용해 두 변수의 값을 서로 바꾸는 프로그램을 만들어보자.
#include <iostream>
void swap(int* ptr1, int* ptr2) {
int temp = *ptr1; //*ptr1: ptr1가 가리키는 값
*ptr1 = *ptr2;
*ptr2 = temp;
}
int main() {
int a = 10;
int b = 20;
std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;
// swap 함수 호출해서 x와 y의 값 교환
swap(&a, &b);
std::cout << "After swap: a = " << a << ", b = " << b << std::endl;
return 0;
}
new를 굳이 사용하는 이유: 동적 메모리 할당
C++에서는
new없이도 변수를 선언하고 사용할 수 있지만,new를 사용하는 이유는 메모리를 다루는 방식에 큰 차이가 있기 때문.
new는 동적 메모리를 할당할 때 사용된다. 동적 메모리를 사용하면, 변수의 크기와 수명을 프로그래머가 마음대로 조절할 수 있다.
프로그램이 실행 중일 때 필요한 만큼 메모리를 만들고, 필요 없어지면 해제할 수 있다.예시: 동적 메모리 할당
#include <iostream> int main() { int* ptr = new int; // 동적 메모리 할당 (정수형 변수 1개) *ptr = 20; // 동적으로 할당된 메모리 공간에 값 저장 std::cout << *ptr << std::endl; // 값 출력 delete ptr; // 동적 메모리 해제 return 0; }여기서
int* ptr = new int;는 실행 중에(런타임) 메모리를 직접 만들어서 사용할 수 있게 한다. 그리고delete ptr;을 사용해서 수동으로 메모리를 해제해줘야 한다.3. 정적 메모리와 동적 메모리의 차이
정적 메모리(스택 메모리) 동적 메모리(힙 메모리) new없이 선언한 변수 (int a;등)new를 사용해 메모리를 할당 (int* p = new int;)크기와 수명이 고정되어 있음 크기와 수명을 실행 중에 동적으로 결정할 수 있음 함수가 끝나면 자동으로 메모리 해제 직접 delete로 메모리를 해제해야 함프로그램 시작 시 자동 할당 실행 도중에 필요할 때 메모리 할당 4. 그럼 언제
new를 써야 할까?
- 프로그램이 실행될 때 얼마나 많은 메모리가 필요한지 모를 때!
- 배열의 크기나 객체의 수가 실행 중에 결정되어야 할 때.
- 동적으로 할당된 메모리를 다른 함수나 클래스와 공유해야 할 때.
예시: 동적 배열의 크기를 런타임에 결정하기
아래 코드에서
new를 사용한 이유가 바로 배열의 크기를 런타임에 결정할 때다:#include <iostream> int main() { int size; std::cout << "Enter the size of the array: "; std::cin >> size; // 크기가 사용자가 입력한 값인 동적 배열 할당 int* arr = new int[size]; for (int i = 0; i < size; i++) { arr[i] = i * 2; // 배열 초기화 } delete[] arr; // 메모리 해제 return 0; }
- 이 코드에서는
size라는 값이 프로그램이 실행되는 도중에 결정된다. 만약new를 사용하지 않고, 그냥int arr[size];처럼 쓰면 컴파일 오류가 발생한다, 왜냐하면 정적 배열의 크기는 컴파일 타임에 고정되어야 하기 때문.- 이처럼,
new를 사용하면 프로그램이 실행 중일 때 배열의 크기를 동적으로 결정할 수 있다!5.
new없이 사용할 수 없는 경우: 동적 메모리의 필요성다음은
new를 사용해야만 원하는 동작을 할 수 있는 몇 가지 예시다:예시 1: 런타임에 배열의 크기를 결정하기
#include <iostream> int main() { int size; std::cout << "Enter the size of the array: "; std::cin >> size; // 사용자가 입력한 크기의 배열을 동적으로 할당 int* arr = new int[size]; // 크기 미리 모를 때 동적 할당 for (int i = 0; i < size; i++) { arr[i] = i + 1; } // 동적으로 할당한 배열을 해제 delete[] arr; return 0; }예시 2: 함수 내부에서 메모리를 할당하여 반환하기
#include <iostream> int* createArray(int size) { int* arr = new int[size]; // 함수 내부에서 배열 동적 할당 for (int i = 0; i < size; i++) { arr[i] = i + 1; } return arr; // 동적 배열을 반환 } int main() { int size = 5; int* myArray = createArray(size); for (int i = 0; i < size; i++) { std::cout << myArray[i] << " "; // 동적 배열의 요소 출력 } delete[] myArray; // 동적 배열 해제 return 0; }
- 이 예시에서
int* arr은 함수 내부에서 동적 배열을 할당하고, 이 배열을 함수 밖으로 반환한다. 이렇게 동적 메모리를 사용하면, 함수가 끝난 후에도 메모리가 유지되기 때문에 반환 후에도 메모리를 사용할 수 있다.- 만약
new를 사용하지 않고 함수 안에서int arr[10];처럼 선언하면, 함수가 끝날 때 배열이 사라져버려서 제대로 값을 사용할 수 없게 된다.