C++

C++ TIL day 11 (포인터 연산 문제)

gbleem 2024. 12. 31. 20:44

1. const 키워드 

  • const 키워드를 언제 쓰고 어떤 역할을 하는지 궁금해서, 해당 키워드에 대한 공부를 해보았다.
  • effective c++ 책의 항목 3 "낌새만 보이면 const를 들이대 보자!" 를 참고했다.

https://gbleem.tistory.com/16

 

const 키워드

블로그 글 TIL day8 에서도 한 번 언급했었는데, 중요하다고 생각이 들어 다시 정리해보려고 한다.effective c++의 항목 3을 많이 참고하여 정리했다.리마인드const 가 함수 앞에 있다면, 반환값을 상수

gbleem.tistory.com

2. 과제 풀이

  • 어제 3번 과제를 마치고 오늘은 4번 과제를 진행하였다.

https://github.com/GBL22M/SCC_CH2-4

 

GitHub - GBL22M/SCC_CH2-4

Contribute to GBL22M/SCC_CH2-4 development by creating an account on GitHub.

github.com

  • 큰 이슈는 없었지만, 주어진 UML과 기능 가이드가 헷갈려서 해석을 하고 수정하는데, 시간이 걸렸다.

UML
도전 기능 가이드

  • 몇 가지 이슈를 정리해보면,
    • BookManager의 find와 get 함수들의 타입이 Book* 인지가 궁금했다.
    • BorrowManager의 stock 의 타입이 unordered_map<string, int> 인지가 궁금했다.
  • 내가 해결한 방식을 설명해 보면
    • 우리가 BorrowManager에서 BorrowBook 함수를 쓸때 title 이라는 string만 받게 된다. (UML에 그렇게 되어있으니까)
    • 그러면, 도전 기능 가이드에 있는 세번째 조건인 책의 작가로 대여 여부를 검색할 때 문제가 생긴다. (author로 빌리는 함수는 없다)
    • 그러므로, 우리는 책의 작가가 들어왔을 때 책의 제목을 찾을 수 있어야 한다.
    • 그 함수가 바로 GetBookByAuthor이 되어야 할 것이다. (FindBookByAuthor은 protected 함수니까)
    • 그러면 왜 이 함수가 Book* 인지 생각해 보았는데, 
      • 만약 우리가 입력한 작가의 이름에 해당하는 책이 없다면, 그때 반환값이 애매해 질 것 같다는 생각이 들었다.
      • 그러나 포인터가 반환값이라면 nullptr을 반환해 버리고, 사용하는 곳에서 if(book == nullptr) 처럼 체크를 할 수 있기 때문이라는 생각이 들었다.
      • 그냥 Book타입이 반환값이라면, title과 author가 비어있는, book 을 반환해야 할지... 이런 것들이 애매할 것 같았다.
      • 아래 코드가 위에서 언급한 내용을 반영하여 구현된 모습의 일부이다.
    • 결과적으로
      • Book* 가 반환 타입인 이유는 못찾은 경우를 위해서라는 생각이 들었고,
      • stock의 타입이 <string,int> 인 이유는 BookManager 타입의 find 함수들을 쓰기 위함이지 않았을까 라는 생각이 들었다.
//BookManager.cpp
Book* BookManager::FindBookByAuthor(string author)
{
	for (const auto& book : books)
	{
		if (book->GetAuthor() == author)
		{
			return book;
		}
	}
	return nullptr;
}

//main.cpp
...
else if (choice == 2)
{
    string author;
    cout << "대여하려고하는 책의 작가를 입력하세요: ";
    cin.ignore();
    getline(cin, author);

    Book* book = bookManager.GetBookByAuthor(author);
    if (book != nullptr)
    {
        borrowManager.BorrowBook(book->GetTitle());
    }
    else
    {
        cout << "존재하지 않는 책입니다\n";
    }
}
  • 추가) 내가 한 방식으로 구현하려면, UML의 BookManager 클래스의 books의 타입이 vector<Book*> 로 바뀌어야 할 것 같았다.

3. 포인터와 레퍼런스

  • 수업을 듣던 도중 포인터와 레퍼런스가 가리키는 값을 바꾸는 함수에 대한 문제가 있었다.
  • 관련 문제를 예전에도 풀었던 기억이 있어서 문제를 정리해보고 그림을 통해 풀이를 해 보았다.
  • 간략하게 정리해 보자면,
    • 해당 값이 주소값인지, 실제 값인지만 헷갈리지 않는다면, 쉽게 해결할 수 있다.
    • x와 y가 주소값이라면, 가리키는 곳(주소) 값을 바꿔준다고 생각하면 된다.
      • x = y; 의 결과는 x가 가리키는 주소값이 y가 가리키는 주소값으로 바뀐다고 생각하면 된다.
      • 그럼 x가 원래 가리키던 곳은 아무도 가리키지 않게 된다.
    • * 통한 연산은 화살표를 따라 간 곳의 값을 바꾼다고 생각하면 된다.
      • *x = 5; 의 의미는 x가 지금 주소값이고, 그 주소값을 따라가서 있는 값을 바꿔주는 것이다.
void foo1(int* x, int* y)
{
    x = y;
    *x = 5;
}

void foo2(int* x, int* y)
{
    int* temp = x;
    x = y;
    *x = 5;   

    *temp = 100;
}

void foo3(int& x, int* y)
{
    x = *y;
    *y = 30;
    y = &x;
    *y = 40;
}

void foo4(int** x, int** y)
{
    int* temp = *x;
    *x = *y;
    *y = temp;
    **x = 5;
}

int main() 
 {    
    int a1 = 10;
    int b1 = 20;
    foo1(&a1, &b1);
    cout << a1 << " " << b1 << "\n";

    int a2 = 10;
    int b2 = 20;
    foo2(&a2, &b2);
    cout << a2 << " " << b2 << "\n";

    int a3 = 10;
    int b3 = 20;
    foo3(a3, &b3);
    cout << a3 << " " << b3 << "\n";

    int a4 = 10;
    int b4 = 20;

    int* pa = &a4;
    int* pb = &b4;
    foo4(&pa, &pb);
    cout << *pa << " " << *pb;    
}
  • 위 코드의 실행 결과

  • 그림을 통한 해설