Skip to Content
💻 코리아IT아카데미 신촌 - 프로그래밍 학습 자료
C++ 프로그래밍Unit 7: 포인터Topic 2: 동적 메모리 할당

Topic 2: 동적 메모리 할당 🧠

🎯 학습 목표

  • 동적 메모리 할당의 개념과 필요성을 이해할 수 있다
  • newdelete 연산자를 올바르게 사용할 수 있다
  • 메모리 누수를 방지하는 방법을 익힐 수 있다
  • 배열과 객체의 동적 할당을 구현할 수 있다

📖 동적 메모리 할당이란?

동적 메모리 할당은 프로그램 실행 중에 필요한 만큼의 메모리를 할당하고 해제하는 기능입니다.

아날로지: 호텔 예약과 같습니다.

  • 정적 할당: 미리 방을 예약해두는 것 (배열 크기 고정)
  • 동적 할당: 필요할 때 방을 예약하고, 떠날 때 반납하는 것

🔍 정적 vs 동적 메모리

#include <iostream> using namespace std; int main() { // 정적 메모리 할당 (스택) int staticArray[100]; // 컴파일 시 크기 결정 // 동적 메모리 할당 (힙) int size; cout << "배열 크기를 입력하세요: "; cin >> size; int* dynamicArray = new int[size]; // 실행 시 크기 결정 // 메모리 해제 delete[] dynamicArray; return 0; }

🔧 new와 delete 연산자

기본 사용법

#include <iostream> #include <string> using namespace std; int main() { // 1. 단일 변수 동적 할당 int* ptr = new int(42); // 초기값 42로 할당 cout << "값: " << *ptr << endl; // 출력: 42 delete ptr; // 메모리 해제 // 2. 배열 동적 할당 int size = 5; int* arr = new int[size]; // 배열 초기화 for(int i = 0; i < size; i++) { arr[i] = i * 10; } // 배열 출력 for(int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; delete[] arr; // 배열 메모리 해제 (주의: delete[]) return 0; }

클래스 객체 동적 할당

#include <iostream> #include <string> using namespace std; class Student { private: string name; int age; public: Student(string n = "Unknown", int a = 0) : name(n), age(a) { cout << "생성자 호출: " << name << endl; } ~Student() { cout << "소멸자 호출: " << name << endl; } void display() { cout << "이름: " << name << ", 나이: " << age << endl; } }; int main() { // 단일 객체 동적 할당 Student* student1 = new Student("김철수", 20); student1->display(); delete student1; // 소멸자 자동 호출 cout << "---" << endl; // 객체 배열 동적 할당 int count = 3; Student* students = new Student[count]{ Student("이영희", 21), Student("박민수", 22), Student("최지원", 19) }; for(int i = 0; i < count; i++) { students[i].display(); } delete[] students; // 모든 객체의 소멸자 호출 return 0; }

⚠️ 메모리 누수와 예방

메모리 누수 예시

#include <iostream> using namespace std; void memoryLeak() { int* ptr = new int[1000]; // 메모리 할당 // ... 작업 수행 if(true) { // 조건부 return return; // delete[] ptr 호출 안 됨 → 메모리 누수! } delete[] ptr; // 실행되지 않음 } void properMemoryManagement() { int* ptr = new int[1000]; try { // ... 작업 수행 (예외 발생 가능) // 예외가 발생해도 메모리 해제를 보장 delete[] ptr; } catch(...) { delete[] ptr; // 예외 발생 시에도 메모리 해제 throw; // 예외 재발생 } }

RAII 패턴 (Resource Acquisition Is Initialization)

#include <iostream> #include <memory> // 스마트 포인터 using namespace std; class SafeArray { private: int* data; int size; public: SafeArray(int s) : size(s) { data = new int[size]; cout << "배열 할당: " << size << "개 요소" << endl; } ~SafeArray() { delete[] data; cout << "배열 해제" << endl; } int& operator[](int index) { return data[index]; } int getSize() const { return size; } }; int main() { { // 스코프 시작 SafeArray arr(5); for(int i = 0; i < arr.getSize(); i++) { arr[i] = i * 2; cout << arr[i] << " "; } cout << endl; } // 스코프 종료 시 자동으로 소멸자 호출 cout << "메인 함수 종료" << endl; return 0; }

🎯 실습: 간단한 동적 배열

#include <iostream> using namespace std; // 동적 배열 생성과 사용 void demonstrateDynamicArray() { int size; cout << "배열 크기를 입력하세요: "; cin >> size; // 동적 메모리 할당 int* dynamicArray = new int[size]; // 배열 초기화 cout << "배열에 값을 입력하세요:" << endl; for(int i = 0; i < size; i++) { cout << "[" << i << "]: "; cin >> dynamicArray[i]; } // 배열 출력 cout << "\n입력된 배열: "; for(int i = 0; i < size; i++) { cout << dynamicArray[i] << " "; } cout << endl; // 메모리 해제 (중요!) delete[] dynamicArray; cout << "메모리가 안전하게 해제되었습니다." << endl; } int main() { demonstrateDynamicArray(); return 0; }

🎯 실습: 메모리 누수 방지하기

#include <iostream> using namespace std; // 안전한 메모리 관리 함수 int* createAndInitArray(int size, int initValue) { cout << "메모리 할당: " << size << "개 정수를 위한 공간" << endl; int* arr = new int[size]; // 배열 초기화 for(int i = 0; i < size; i++) { arr[i] = initValue + i; } return arr; } // 배열 처리 함수 void processArray(int* arr, int size) { cout << "배열 처리 중..." << endl; for(int i = 0; i < size; i++) { arr[i] *= 2; // 각 값을 2배로 } } // 배열 출력 함수 void printArray(int* arr, int size) { cout << "배열: "; for(int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; } int main() { cout << "=== 안전한 동적 메모리 관리 ===" << endl; const int SIZE = 5; // 1. 메모리 할당 int* myArray = createAndInitArray(SIZE, 10); // 2. 초기 상태 출력 cout << "초기 상태: "; printArray(myArray, SIZE); // 3. 배열 처리 processArray(myArray, SIZE); // 4. 처리 후 상태 출력 cout << "처리 후: "; printArray(myArray, SIZE); // 5. 메모리 해제 (중요!) delete[] myArray; cout << "\n메모리가 안전하게 해제되었습니다." << endl; return 0; }

🎮 실습: 성적 관리 시스템

#include <iostream> #include <string> using namespace std; // 간단한 학생 구조체 struct Student { string name; double* scores; // 성적 배열을 가리키는 포인터 int scoreCount; }; // 학생 생성 함수 Student* createStudent(string name, int maxScores) { Student* student = new Student; student->name = name; student->scores = new double[maxScores]; // 성적 배열 동적 할당 student->scoreCount = 0; cout << "학생 '" << name << "' 생성 (최대 " << maxScores << "과목)" << endl; return student; } // 성적 추가 함수 void addScore(Student* student, double score) { // scoreCount는 현재 성적 개수를 의미 student->scores[student->scoreCount] = score; student->scoreCount++; cout << "성적 " << score << "점이 추가되었습니다." << endl; } // 평균 계산 함수 double calculateAverage(Student* student) { if(student->scoreCount == 0) return 0.0; double total = 0.0; for(int i = 0; i < student->scoreCount; i++) { total += student->scores[i]; } return total / student->scoreCount; } // 학생 정보 출력 void printStudentInfo(Student* student) { cout << "\n=== " << student->name << "의 성적표 ===" << endl; cout << "성적: "; for(int i = 0; i < student->scoreCount; i++) { cout << student->scores[i]; if(i < student->scoreCount - 1) cout << ", "; } cout << endl; cout << "평균: " << calculateAverage(student) << "점" << endl; } // 메모리 해제 함수 void deleteStudent(Student* student) { delete[] student->scores; // 성적 배열 해제 delete student; // 학생 객체 해제 cout << "학생 데이터가 안전하게 삭제되었습니다." << endl; } int main() { cout << "=== 동적 메모리 성적 관리 ===" << endl; // 학생 생성 Student* student = createStudent("김철수", 5); // 성적 추가 addScore(student, 85.5); addScore(student, 92.0); addScore(student, 78.5); addScore(student, 88.0); // 정보 출력 printStudentInfo(student); // 메모리 해제 deleteStudent(student); return 0; }

💡 모범 사례와 주의사항

✅ 좋은 습관

  1. 항상 짝을 맞춰라

    • newdelete
    • new[]delete[]
  2. 포인터를 nullptr로 초기화

    int* ptr = nullptr; if(condition) { ptr = new int(10); } // ... 사용 if(ptr != nullptr) { delete ptr; ptr = nullptr; // 중복 해제 방지 }
  3. RAII 패턴 활용

    • 생성자에서 자원 할당
    • 소멸자에서 자원 해제

❌ 피해야 할 실수

  1. 메모리 누수

    // 잘못된 예 int* ptr = new int(10); return; // delete 없음!
  2. 이중 해제

    int* ptr = new int(10); delete ptr; delete ptr; // 오류!
  3. 해제된 메모리 접근

    int* ptr = new int(10); delete ptr; *ptr = 20; // 위험한 접근!

🔍 디버깅 팁

#include <iostream> using namespace std; // 메모리 할당 추적을 위한 간단한 클래스 class MemoryTracker { private: static int allocations; static int deallocations; public: static void* allocate(size_t size) { allocations++; cout << "[할당] " << size << " 바이트, 총 할당: " << allocations << endl; return malloc(size); } static void deallocate(void* ptr) { deallocations++; cout << "[해제] 총 해제: " << deallocations << endl; free(ptr); } static void report() { cout << "\n=== 메모리 사용 보고서 ===" << endl; cout << "할당: " << allocations << endl; cout << "해제: " << deallocations << endl; cout << "누수: " << (allocations - deallocations) << endl; } }; int MemoryTracker::allocations = 0; int MemoryTracker::deallocations = 0;
Last updated on