C++ 입문 2일차: 포인터를 이용한 함수 호출, 동적 메모리 할당

하는·2024년 10월 4일
1

C++ 입문 챌린지

목록 보기
2/5

1. 포인터를 이용한 함수 호출 (Call by Reference)

함수를 호출할 때, 파이썬에서는 값만 넘겨줬지만, 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++은 상당히 복잡하다.

2. 동적 메모리 할당

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];처럼 선언하면, 함수가 끝날 때 배열이 사라져버려서 제대로 값을 사용할 수 없게 된다.
profile
천천히 꾸준히 취미처럼 냐미😋

0개의 댓글