카테고리 없음

C++_10주차_const동적 메모리 할당(new, delete)

두팔이의과제요졍 2024. 11. 5. 11:49

new 연산자를 사용하는 프로그래밍 언어:

C++: 객체를 동적으로 생성할 때 new 키워드를 사용합니다.
Java: 객체를 생성할 때 new 연산자를 사용하며, 메모리를 할당합니다.
C#: 객체 인스턴스를 생성할 때 new 키워드를 사용합니다.
JavaScript: 생성자 함수나 클래스를 통해 객체를 만들 때 new 키워드를 사용합니다.
PHP: 객체를 생성할 때 new 키워드를 사용합니다.

 

 


 

 

동적으로 메모리를 할당한다는 것은 컴퓨터가 필요할 때마다 메모리를 사용할 수 있도록 요청하는 것을 의미함.

예를 들어, 우리가 책을 읽을 때, 필요한 페이지를 한 장씩 넘겨서 읽는 것처럼, 프로그램도 필요할 때마다 메모리를 요청해서 사용하는 것이 필요함

 

이렇게 하는 이유는:

효율성: 프로그램이 필요할 때만 메모리를 사용하니까, 메모리를 낭비하지 않음
유연성: 프로그램이 실행되는 동안 필요한 메모리의 양이 변할 수 있어. 예를 들어, 게임에서 새로운 캐릭터가 추가될 때마다 메모리를 더 요청 가능
자동 관리: 프로그램이 끝나면 사용했던 메모리를 자동으로 반환할 수 있어서, 메모리를 깔끔하게 관리 가능

 


 

비쥬얼 스튜디오에서 한 번에 바꾸기

컨트롤 + f + h

 

 

 


⭐이름을 배열에 저장해서 받는 코드

 

 

이름을 배열에 저장해서 받는 코드

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string> //strcpy에서 오류나면 string.h로 변경
using std::cout;
class Cat {
private: //생략가능
	int age;
	char name[20];
	// const char* name; //A
public:
	Cat(int age, const char* n) {
		this->age = age;
		strcpy(name, n); // name=n; //A
		cout << name << "고양이 객체가 만들어졌어요.\n";
	}
	~Cat() { cout << name << "객체 바이\n"; };
	int getAge();
	const char* getName();
	void setAge(int age);
	void setName(const char* pName);
	void meow();
};
int Cat::getAge() {
	return age;
}
void Cat::setAge(int age) {
	this->age = age;
}
void Cat::setName(const char* pName) {
	strcpy(name, pName);
	//strcpy(대상주소, 원본주소);
	//strcpy_s(대상주소, 대상의길이, 원본주소);
	//name=pName; //A
}
const char* Cat::getName() {
	return name;
}
void Cat::meow() {
	cout << name << "고양이가 울어요\n";
}
int main() {
	Cat nabi(1, "나비"), yaong(1, "야옹"), * pNabi;
	cout << nabi.getName() << " 출생 나이는 " << nabi.getAge() << "살이다.\n";
	cout << yaong.getName() << " 출생 나이는 " << yaong.getAge() << "살이다.\n";
	pNabi = &nabi;
	cout << pNabi->getName() << " 출생 나이는 " << pNabi->getAge() << "살이다.\n";
	nabi.setName("Nabi");
	nabi.setAge(3);
	cout << nabi.getName() << " 나이는 " << nabi.getAge() << "살이다.\n";
	yaong.meow();
	nabi.meow();
	return 0;
}

 

 

배열을 안쓰고 std::string형을 써서 더 편하게

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string> //strcpy에서 오류나면 string.h로 변경
using std::cout;
class Cat {
private: //생략가능
	int age;
	std::string name;
	// std::string name; //A
public:
	Cat(int age, std::string n) {
		this->age = age;
		name, n; // name=n; //A
		cout << name << "고양이 객체가 만들어졌어요.\n";
	}
	~Cat() { cout << name << "객체 바이\n"; };
	int getAge();
	std::string getName();
	void setAge(int age);
	void setName(std::string pName);
	void meow();
};
int Cat::getAge() {
	return age;
}
void Cat::setAge(int age) {
	this->age = age;
}
void Cat::setName(std::string pName) {
	name, pName;
	//strcpy(대상주소, 원본주소);
	//strcpy_s(대상주소, 대상의길이, 원본주소);
	//name=pName; //A
}
std::string Cat::getName() {
	return name;
}
void Cat::meow() {
	cout << name << "고양이가 울어요\n";
}
int main() {
	Cat nabi(1, "나비"), yaong(1, "야옹"), * pNabi;
	cout << nabi.getName() << " 출생 나이는 " << nabi.getAge() << "살이다.\n";
	cout << yaong.getName() << " 출생 나이는 " << yaong.getAge() << "살이다.\n";
	pNabi = &nabi;
	cout << pNabi->getName() << " 출생 나이는 " << pNabi->getAge() << "살이다.\n";
	nabi.setName("Nabi");
	nabi.setAge(3);
	cout << nabi.getName() << " 나이는 " << nabi.getAge() << "살이다.\n";
	yaong.meow();
	nabi.meow();
	return 0;
}

 

 


 

 

 

변수를 상수로 만드는 방법

우선 변수로 만들고

바꾸고 싶지 않으면 const로 만들고 상수화 한다

초기값에서 -> 변경하는 형식

 

 

 

 

오류 수정 코드

#include <iostream>

class Dog {
private:
    int age; // private으로 선언

public:
    int getAge() const; // const 메서드
    void setAge(int a) { age = a; }
    void view() const { // const 메서드로 변경
        std::cout << "나는 view\n";
    }
};

int Dog::getAge() const {
    view(); // 오류 ① 수정
    return age; // 오류 ② 수정: age를 증가시키지 않음
}

int main() {
    Dog happy;
    happy.setAge(5);
    std::cout << happy.getAge(); // 5 출력
    return 0;
}

 

 


 

 

실습 소스

#include <iostream>
class Dog {
	int age;
public:
	Dog(int a) { age = a; }
	int getAge() const;
	void setAge(int a) { age = a; }
	void view() const
	{
		std::cout << "나는 view\n";
	}
};
int Dog::getAge() const
{
	view();
	return (age);
}
int main()
{
	const Dog happy(5); //const 객체
	//happy.setAge(7); // 오류
	std::cout << happy.getAge();
	return 0;
}

 

 


 

 

⭐(중요/어려움) 포인터 개요

 

 

C++에서 변수의 값과 주소를 출력하는 프로그램

결과가 계속 바뀜

 

 

 

포인터 변수 선언

 

 

첫 번째 코드

#include <iostream>

int main() {
    int x = 1;          // 정수형 변수 x를 1로 초기화
    int* px = &x;      // x의 주소를 px 포인터 변수에 저장
    std::cout << x << " " << &x << " " << px; // x의 값, x의 주소, px의 값(주소)을 출력
    return 0;        
}

 

출력 내용:
x: 변수 x의 값 (1)
&x: 변수 x의 메모리 주소
px: 포인터 px가 가리키는 주소 (즉, x의 주소)

 

 

 


두 번째 코드

#include <iostream>

int main() {
    int x = 1;          // 정수형 변수 x를 1로 초기화
    int* px = &x;      // x의 주소를 px 포인터 변수에 저장
    std::cout << x << " " << &x << " " << *px; // x의 값, x의 주소, px가 가리키는 값(즉, x의 값)을 출력
    return 0;        
}


출력 내용:
x: 변수 x의 값 (1)
&x: 변수 x의 메모리 주소
*px: 포인터 px가 가리키는 값 (즉, x의 값인 1)

 

요약
주요 차이점:
첫 번째 코드에서는 px를 출력하여 포인터가 가리키는 메모리 주소를 보여줍니다.
두 번째 코드에서는 *px를 출력하여 포인터가 가리키는 값 (즉, x의 값)을 보여줍니다.

 

 

그림으로 보기 (파이썬 튜텨)

포인터 변수는 지시할 때 사용한다.

포인터는 변수의 주소를 가리키고, 그 주소를 통해 값 저장함

 

 


 

 

동적 메모리 할당

 

⭐⭐⭐(필수/시험 무조건 나옴) 동적 메모리를 사용하는 이유

 

 

 

 

 

C++ 코드는 정적 할당과 동적 할당의 차이를 보여주는 예제

 

 

 

 

주어진 C++ 코드는 정적 할당과 동적 할당을 사용하는 예시

동적 할당에서 new 연산자를 사용하여 초기값을 설정하는 방법

 

 

 

동적 메모리의 팔당과 해제 : new 와 delete

 

동적 할당된 메모리를 사용한 후 올바르게 해제하는 예제 (delete)

 

 

배열로 할당과 삭제 (대괄호 주의)

 

 


(중요/ 시험 예상문) 

#include <iostream>
#include <stdlib.h> // exit(1) 사용을 위한 헤더

int main() {
    int i, n;          // 정수형 변수 i, n 선언
    int *num;         // 정수형 포인터 num 선언

    std::cout << "몇 개의 숫자를 입력하시겠습니까?=";
    std::cin >> i;    // 사용자로부터 입력받은 숫자를 i에 저장

    num = new int[i]; // i개의 정수를 저장할 동적 배열 할당
    if (num == NULL) exit(1); // 메모리 할당 실패 시 종료

    for (n = 0; n < i; n++) { // 0부터 i-1까지 반복
        std::cout << "숫자를 입력하십시요: ";
        std::cin >> num[n]; // 사용자로부터 입력받은 숫자를 배열에 저장
    }

    std::cout << "당신이 입력한 숫자는: ";
    for (n = 0; n < i; n++) { // 0부터 i-1까지 반복
        std::cout << num[n] << " "; // 저장된 숫자를 출력
    }

    delete[] num; // 동적 메모리 해제
    return 0;     // 프로그램 종료
}

⭐⭐(중요 / 시험 확정 문제)배열의 이름은 배열의 시작주소

 


포인터 객체는 *이 아니고, -> 로 접근한다.

 

#include <iostream>

class Dog {
private:
    int age; // 개의 나이를 저장할 private 멤버 변수
public:
    int getAge(); // 나이를 반환하는 메서드
    void setAge(int a); // 나이를 설정하는 메서드
};

int Dog::getAge() {
    return age; // 나이를 반환
}

void Dog::setAge(int a) {
    age = a; // 나이를 설정
}

int main() {
    Dog *dp; // Dog 객체를 가리킬 포인터 선언
    dp = new Dog[10]; // Dog 객체 배열 동적 할당

    // 메모리 할당 실패 시 처리
    if (!dp) {
        std::cout << "메모리 할당이 되지 않았습니다.";
        return 1;
    }

    // 각 Dog 객체의 나이를 설정
    for (int i = 0; i < 10; i++) {
        dp[i].setAge(i); // i번째 객체의 나이를 i로 설정
    }

    // 각 Dog 객체의 나이를 출력
    for (int i = 0; i < 10; i++) {
        std::cout << i << "번째 객체의 나이는 " << dp[i].getAge() << " 입니다." << std::endl;
    }

    delete[] dp; // 동적 할당된 메모리 해제
    return 0; // 프로그램 종료
}

 

 


배열 객체 동적 할당

#include <iostream>

// Dog 클래스 정의
class Dog {
private:
    int age;  // 개의 나이를 저장하는 private 멤버 변수
public:
    int getAge();     // age를 반환하는 public 멤버 함수
    void setAge(int a);  // age를 설정하는 public 멤버 함수
};

// Dog 클래스의 getAge() 멤버 함수 정의
int Dog::getAge()
{
    return age;  // private 멤버 변수 age의 값을 반환
}

// Dog 클래스의 setAge() 멤버 함수 정의
void Dog::setAge(int a)
{
    age = a;  // 매개변수 a의 값을 private 멤버 변수 age에 할당
}

int main()
{
    Dog *dp;  // Dog 객체를 가리키는 포인터 선언

    dp = new Dog[10];  // 10개의 Dog 객체를 동적으로 할당하여 배열 생성
    // 위 문장은 다음과 같이 한 줄로 작성할 수도 있음: Dog *dp = new Dog[10];

    // 메모리 할당 실패 체크
    if(!dp) {
        std::cout << "메모리할당이 되지 않았습니다.";
        return 1;  // 프로그램 비정상 종료
    }

    // 각 Dog 객체의 나이를 설정 (0부터 9까지)
    for(int i = 0; i < 10; i++)  // C++에서는 동적 할당된 객체 배열도 []로 접근 가능
        dp[i].setAge(i);

    // 각 Dog 객체의 나이를 출력
    for(int i = 0; i < 10; i++)
        std::cout << i << "번째 객체의 나이는 " 
                  << dp[i].getAge() << " 입니다. " << std::endl;

    delete[] dp;  // 동적으로 할당된 메모리 해제 (배열 형태로 할당했으므로 delete[]를 사용)

    return 0;  // 프로그램 정상 종료
}

 

 

 

#include <iostream>
class Dog {
private:
	int age;
public:
	int getAge();
	void setAge(int a);
};
int Dog::getAge()
{
	return age;
}
void Dog::setAge(int a)
{
	age = a;
}
int main()
{
	Dog* dp;
	Dog happy;
	dp = new Dog; // Dog *dp=new Dog
	if (!dp) {
		std::cout << "메모리할당 불가!";
		return 1;
	}
	happy.setAge(3);
	std::cout << happy.getAge();
	dp->setAge(5); //dp는 포인터 객체라 ->로 접근
	std::cout << "메모리에 할당된 값은 "
		<< dp->getAge() << "입니다.";
	delete dp;
	return 0;
}

 

 

 

 

고양이 배열 객체 동적 메모리 할당

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using std::cout;
class Cat {
private: //생략가능
int age;
std::string name;
public:
Cat(int age, std::string n) {
this->age = age;
name=n;
cout << name << "고양이 객체가 만들어졌어요.\n";
}
~Cat() { cout << name << "객체 바이\n"; };
int getAge();
std::string getName();
void setAge(int age);
void setName(std::string pName);
void meow();
};
int Cat::getAge() {
return age;
}
void Cat::setAge(int age) {
this->age = age;
}
void Cat::setName(std::string pName) {
name=pName;
}
std::string Cat::getName() {
return name;
}
void Cat::meow() {
cout << name << "고양이가 울어요\n";
}
int main() {
Cat nabi(1, "나비"), yaong(1, "야옹"), * pNabi;
cout << nabi.getName() << " 출생 나이는 " << nabi.getAge() << "살이다.\n";
cout << yaong.getName() << " 출생 나이는 " << yaong.getAge() << "살이다.\n";
pNabi = &nabi;
cout << pNabi->getName() << " 출생 나이는 " << pNabi->getAge() << "살이다.\n";
nabi.setName("Nabi");
nabi.setAge(3);
cout << nabi.getName() << " 나이는 " << nabi.getAge() << "살이다.\n";
yaong.meow();
nabi.meow();
return 0;
}