TIL

2024.12.26

iiblueblue 2024. 12. 26. 11:11

Code KATA

오늘치의 알고리즘 코드카타와 어제의 코드카타를 풀이하고 정리하였다.

https://iiblueblue.tistory.com/104

 

[2024.12.25] 서울에서 김서방 찾기

문제 설명String형 배열 seoul의 element중 "Kim"의 위치 x를 찾아, "김서방은 x에 있다"는 String을 반환하는 함수, solution을 완성하세요. seoul에 "Kim"은 오직 한 번만 나타나며 잘못된 값이 입력되는 경우

iiblueblue.tistory.com

https://iiblueblue.tistory.com/105

 

[2024.12.26] 나누어 떨어지는 숫자 배열

문제 설명array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요.divisor로 나누어 떨어지는 element가 하나도 없다면 배열에서 -1을

iiblueblue.tistory.com

풀이에 어려움은 없었지만 사소한 디테일들이 부족해서 작은 오류들이 발생했었다. 하지만 오류 원인도 금방 찾고 해결도 해서 앞으로는 실수가 없더록 주의하면 될 것 같다.

 

 

C++

오랜만에 C++을 다시 보면서 궁금했던 내용들, 잊어버린 내용들을 다시 글로 정리해보면서 공부했다.

https://iiblueblue.tistory.com/99

 

함수 인자 전달 방식

⊙ 값에 의한 전달과 참조에 의한 전달을 이해하고 차이를 안다.⊙ 참조 변수에 대해 안다.⊙ 함수에 전달되는 배열의 특징을 이해한다.⊙ 상수 참조 매개변수를 알고 필요성을 이해한다. 함수

iiblueblue.tistory.com

https://iiblueblue.tistory.com/103

 

동적 메모리 할당과 삭제

⊙ 힙과 스택의 차이와 용도를 알아보자.⊙ 싱글 변수, 배열, 싱글 객체, 객체 배열의 동적 메모리를 할당하는 방법을 알아보자.⊙ 동적 할당된 변수나 객체를 사용하는 방법에 대해 알아보자.⊙

iiblueblue.tistory.com

https://iiblueblue.tistory.com/107

 

포인터의 개념과 사용

⊙ 포인터 변수가 무엇인지 이해하고 선언하고 사용하는 방법을 안다.⊙ 포인터 대입의 의미 차이를 이해한다.⊙ 직접 참조와 간접 참조의 차이를 안다. 메모리는 프로그램이 실행될 때 사용하

iiblueblue.tistory.com

https://iiblueblue.tistory.com/108

 

다중 포함 방지

⊙ 헤더파일에 작성하는 다중 포함 방지문을 이해한다. 헤더 파일에 대해서 다시 배우면서 오랜만에 해더 파일을 작성했는데 모든 예제에 앞부분에 같은 문구가 있는 것을 보고 이것이 무엇인

iiblueblue.tistory.com

 

 

 

Quest

  • 간단한 프로그래밍 구현
  • OOP Summary

OOP Summary를 저번에 1차적으로 구현했는데 구현에 관련해 질문이 생겨 질문방에 질문을 올렸었다. 질문방에서 답변을 받은 후 코드에 수정이 필요한 부분이 생겨 수정하였다. 그리고 오늘 동적 할당과 해제에 대해 더 공부하다가 수정했으면 좋겠는 부분을 발견하여 추가 수정하였다.

 

1. 클래스별 헤더 파일, 구현 파일 생성

이전에 Animal.h 헤더에 Dog, Cat, Cow 클래스도 포함하여 작성하였었다. 구현부도 마찬가지로 Animal.cpp 파일에 몰아 넣어 작성했었다. 근데 헤더파일과 구현부 파일을 나누는 기준에 대해 궁금해져 질문방에 질문을 하나 올렸었다. 질문과 질문에 대한 답은 아래와 같았다.

Q :
혹시 헤더 파일을 나누는 기준이 무엇인가요? 클래스마다 헤더와 구현부 cpp파일이 있어야 하는 것인가요? 아니면 하나의 헤더에 여러 개의 클래스(예를 들어 부모, 자식 클래스가 같이)가 들어가기도 하나요? 어떤 기준으로 헤더파일을 나누는지 궁금합니다!

A :
아닙니다! 보통은 하나의 클래스가 하나의 헤더 파일 + 하나의 구현 파일로 구성되는 것이 좋아요.

다만, 템플릿 클래스나 함수는 헤더 파일에 구현을 포함해야 합니다. 아직은 먼 얘기지만 템플릿 특성상 컴파일 타임에 코드가 생성되어서요!

일단은 기본적으론 클래스 하나에 헤더와 구현부 하나씩 할당하는 걸로 해주세요!

 

답변을 듣고 만들어 두었던 Animal.h 헤더파일을 클래스마다 쪼개서 만들기로 하였다.

결과적으로는 동물 클래스마다 헤더파일을 만들고 구현부도 각각 나누어서 작성하였다. Main에는 Dog, Cat, Cow 각각의 헤더파일을 포함하도록 하였다.

 

2. 동적 메모리 해제 추가

동적 메모리 할당화 해제에 대해 공부하면서 메모리 누수와 동적 메모리 해제의 중요성에 대해서 정리해보게 되었다. 정리하다보니 main 함수에서 동적 객체를 선언하고 해제하지 않았다는 것이 생각나서 일단 해제되지 않은 메모리들을 해제할 수 있도록 코드를 추가하였다.

// 변경 전
int main()
{
	// Animal 타입의 포인터 배열 선언
	Animal* animals[3];
	animals[0] = new Dog();
	animals[1] = new Cat();
	animals[2] = new Cow();

	// 각 동물의 울음소리(반복문)
	for (int i = 0; i < 3; i++)
	{
		animals[i]->makeSound();
	}
    ...
}

// 변경 후
int main()
{
	// Animal 타입의 포인터 배열 선언
	Animal* animals[3];
	animals[0] = new Dog();
	animals[1] = new Cat();
	animals[2] = new Cow();

	// 각 동물의 울음소리(반복문)
	for (int i = 0; i < 3; i++)
	{
		animals[i]->makeSound();
	}

	// 메모리 해제
        for(int i=; i<3; i++)
        {
            delete animals[i];
            animals[i] = nullptr;
        }
	...
}

 

또 createRandomAnimal 함수에서도 createAnimal이라는 이름으로 객체를 동적 할당하고 그 객체를 return 하는 방식으로 함수를 만들었었는데 그러면 return 하고 나서 객체를 해제할 수 없다는 것을 깨달았다. 그래서 해당 객체를 지우고 바로 객체를 return하는 식으로 변경하였다.

// 변경 전
Animal* createRandomAnimal()
{
	Animal* createAnimal = nullptr;
	int randomNum = rand() % 3;
	switch (randomNum)
	{
	case 0:
		createAnimal = new Dog(); break;
	case 1:
		createAnimal = new Cat(); break;
	case 2:
		createAnimal = new Cow(); break;
	default:
		return nullptr; break;
	}
    
    return createAnimal;
}

// 변경 후
Animal* createRandomAnimal()
{
	int randomNum = rand() % 3;
	switch (randomNum)
	{
	case 0:
		return new Dog();
	case 1:
		return new Cat();
	case 2:
		return new Cow();
	default:
		return nullptr; break;
	}
}

 

마지막으로 동적 메모리 해제 이후 포인터도 함께 초기화 해주는게 좋다는 사실을 공부하고 나서 메모리 해제와 함께 포인터 초기화 코드를 추가하였다.

// 수정 전
Zoo::~Zoo()
{
	// 모든 동물 메모리 해제
	for (int i = 0; i < 10; i++)
	{
		delete animals[i];
	}
}

// 수정 후
Zoo::~Zoo()
{
	// 모든 동물 메모리 해제
	for (int i = 0; i < 10; i++)
	{
		delete animals[i];
		animals[i] = nullptr;
	}
}

 

3. 정적 선언과 동적 초기화

동적 메모리 해제 부분을 추가하는 과정에서 delete 대신 delete[]를 사용할 수 있을 거라고 생각했다. 그래서 반복문에 delete로 구현했던 부분들을 모두 delete[]로 수정하였다. 그런데 이 수정이후 계속 오류가 발생하고 프로그램에 중단에 중단되었다. 오류의 원인을 찾아보니 내가 선언한 방식으로는 delete[]을 이용한 메모리 해제가 불가능 하다는 것이었다.

 

배열을 동적 할당한줄 알았는데 알고보니 배열 자체는 정적 배열로 선언한 것이고 안에 요소들만 new를 이용해 동적할당 된 것이라고 한다. 따라서 메모리를 해제할 때는 for문을 이용해 delete로 하나씩 해제해 주어야 한다. delete[]는 배열 자체를 동적으로 선언하지 않았기 때문에 사용이 불가능 하다.

 

자세한 내용은 아래 블로그에 정리하였다.

https://iiblueblue.tistory.com/109

 

배열 자체의 정적 선언과 요소의 개별적 동적 할당

⊙ delete[]과 delete+반복문 사용처의 차이를 이해한다.⊙ 배열 자체의 선언과 요소의 선언의 성질이 다른 상황을 이해한다. 배열 자체의 선언 ≠ 요소의 선언코드 하나만 먼저 보도록 하자.// Animal

iiblueblue.tistory.com

 

결론적으로 수정해야할 부분들은 모두 수정하고 주석까지 달아서 제출만 하면 되는 상태로 완성하였다.

https://github.com/iiblueblue/NBC_OOPSummary.git

 

GitHub - iiblueblue/NBC_OOPSummary: 내일배움캠프 C++ CH2 OOP Summary 2번 과제

내일배움캠프 C++ CH2 OOP Summary 2번 과제. Contribute to iiblueblue/NBC_OOPSummary development by creating an account on GitHub.

github.com

 

'TIL' 카테고리의 다른 글

2024.12.30  (0) 2024.12.30
2024.12.27  (0) 2024.12.27
2024.12.24  (0) 2024.12.24
2024.12.23  (0) 2024.12.23
2024.12.20  (0) 2024.12.20