C-C++/명품 C++ Programming

[(개정판) 명품 C++ programming] 5장 실습 문제

최옥구 2023. 1. 6. 07:00
반응형

1.두 개의 Circle 객체를 교환하는 swap() 함수를 '참조에 의한 호출'이 되도록 작성하고 호출하는 프로그램을 작성하라.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

class Circle
{
    int radius;
public:
    Circle();
    Circle(int radius) { this->radius = radius; }
    int getRadius() { return radius; }
    void setRadius(int radius) { this->radius = radius; }
    void swap(Circle &a, Circle &b);
};

void Circle::swap(Circle& a, Circle& b)
{
    int swap;
    swap = a.getRadius();
    a.setRadius(b.getRadius());
    b.setRadius(swap);
}

int main()
{
    Circle a(10);
    Circle b(20);
    cout << "a의 반지름 >> " << a.getRadius() << endl;
    cout << "b의 반지름 >> " << b.getRadius() << endl;
    swap(a, b);
    cout << "a의 반지름 >> " << a.getRadius() << endl;
    cout << "b의 반지름 >> " << b.getRadius() << endl;
}

 


 

2. 다음 main() 함수의 실행 결과를 참고하여 half() 함수를 작성하라.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

double half(double& num)
{
    return num /= 2;
}

int main()
{
    double n = 20;
    half(n);
    cout << n; // 10이 출력된다.
}

 


 

3. 다음과 같이 작동하도록 Combine() 함수를 작성하라.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

string combine(string &text1, string &text2, string &text3)
{
    return text3 = text1 + ' ' + text2;
}

int main()
{
    string text1("I love you"), text2("very much");
    string text3;
    combine(text1, text2, text3);
    cout << text3;
}
 

 

4. 아래와 같이 원형으로 주어진 bigger()를 작성하고 사용자로부터 2개의 정수를 입력받아 큰 값을 출력하는 main()을 작성하라. bigger()는 인자로 주어진 a, b가 같으면 true, 아니면 false를 리턴하고 큰 수는 big에 전달한다.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

bool bigger(int a, int b, int& big)
{
    if (a == b)
        return true;
    else
    {
        int max = a;
        if (a < b)
            max = b;
        big = max;
        return false;
    }
}

int main()
{
    int a, b, big = 0;
    cout << "두개의 정수를 입력하세요 >> ";
    cin >> a >> b;
    cout << bigger(a, b, big) << ' ' << big << endl;
}

 


 

5. 다음 Circle 클래스가 있다. -> Circle 객체 b를 a에 더하여 a를 키우고자 다음 함수를 작성하였다. -> 다음 코드를 실행하면, increaseBy()함수는 목적대로 실행되는가? -> main() 함수의 목적을 달성하도록 increaseBy() 함수를 수정하라.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

class Circle
{
    int radius;
public: 
    Circle(int r) { radius = r;}
    int getRadius() { return radius; }
    void setRadius(int r) { radius = r; }
    void show() { cout << "반지름이 " << radius << "인 원" << endl; }
};

void increasedBy(Circle &a, Circle &b)
{
    int r = a.getRadius() + b.getRadius();
    a.setRadius(r);
}

int main()
{
    Circle x(10), y(5);
    increasedBy(x, y);
    x.show();
}

 


 

6. find() 함수의 원형은 다음과 같다. 문자열 a에서 문자 c를 찾아 문자 c가 있는 공간에 대한 참조를 리턴한다. 만일 문자 c를 찾을수 없다면 success 참조 매개 변수에 false를 설정한다. 물론 찾게 되면 successtrue를 설정한다.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

char& find(char a[], char c, bool &success)
{
    int size = sizeof(a);
    for (int i = 0; i < size; i++)
    {
        if (a[i] == c)
        {
            success = true;
            return a[i];
        }
           
    }
}

int main()
{
    char s[] = "Mike";
    bool b = false;
    char& loc = find(s, 'M', b);
    if (b == false)
    {
        cout << "M을 발견할 수 없다." << endl;
        return 0;
    }
    loc = 'm';
    cout << s << endl;
}

 


 

7. 다음과 같이 선언돤 정수를 저장하는 스택 클래스 MyIntStack을 구현하라. MyIntStack 스택에 저장훌 수 있는 정수의 최대 개수는 10개이다. -> MyIntStack 클래스를 활용하는 코드와 실행 결과는 다음과 같다.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

class MyIntStack
{
    int p[10];
    int tos = 0;
public:
    MyIntStack() {}
    bool push(int n);
    bool pop(int& n);
};

bool MyIntStack::push(int n) 
{
    if (tos > 9)
        return false;
    else 
    {
        p[tos] = n;
        tos++;
        return true;
    }
}

bool MyIntStack::pop(int& n) 
{ 
    tos--;
    if (tos < 0)
        return false;
    else 
    {
        n = p[tos];
        return true;
    }
}

int main()
{
    MyIntStack a;
    for (int i = 0; i < 11; i++)
    {
        if (a.push(i))
            cout << i << ' ';
        else
            cout << endl << i + 1 << "번째 stack full" << endl;
    }

    int n;
    for (int i = 0; i < 11; i++)
    {
        if (a.pop(n))
            cout << n << ' ';
        else
            cout << endl << i + 1 << "번째 stack empty";
    }
    cout << endl;
}

 


 

8. 문제 5번의 MyIntStack를 수정하여 다음과 같이 선언하였다. 스택에 저잘할 수 없는 정수의 최대 개수는 생성자에서 주어지고 size 멤버에 유지한다. MyIntStack 클래스를 작성하라.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

class MyIntStack
{
    int* p;
    int size = 0;
    int tos;
public:
    MyIntStack() {}
    MyIntStack(int size) { this->size = size; p = new int[size]; tos = 0; }
    MyIntStack(const MyIntStack& s);
    ~MyIntStack() { delete[]p; p = NULL; }
    bool push(int n);
    bool pop(int& n);
};

MyIntStack::MyIntStack(const MyIntStack& s)
{
    this->size = size;
    this->tos = tos;
    this->p = new int[s.size];
    for (int i = 0; i <= s.tos; i++)
        this->p[i] = s.p[i];
}

bool MyIntStack::push(int n) 
{
    if (tos > size)
        return false;
    else 
    {
        p[tos++] = n;
        return true;
    }
}

bool MyIntStack::pop(int& n) 
{ 
    if (tos < 0)
        return false;
    else 
    {
        n = p[--tos];
        return true;
    }
}

int main()
{
    MyIntStack a(10);
    a.push(10);
    a.push(20);
    MyIntStack b = a;
    b.push(30);

    int n;
    a.pop(n);
    cout << "스택 a에서 팝한 값 " << n << endl;
    b.pop(n);
    cout << "스택 b에서 팝한 값 " << n << endl;
}

 


 

9. 클래스 Accumulator add() 함수를 통해 계속 값을 누적하는 클래스로써, 다음과 같이 선언된다. Accumulator 클래스를 구현하라.

[결과]

[소스 코드]

#include<iostream>
using namespace std;

class Accumulator
{
    int value;
public:
    Accumulator(int value) { this->value = value; }
    Accumulator& add(int n);
    int get() { return value; }
};

Accumulator & Accumulator :: add(int n)
{
    value += n;
    return *this;
}

int main()
{
    Accumulator acc(10);
    acc.add(5).add(6).add(7);
    cout << acc.get();
}

 


 

10. 참조를 리턴하는 코드를 작성해보자. 다음 코드와 실행 결과를 참고하여 append() 함수를 작성하고, 전체 프로그램을 완성하라. append()Buffer 객체에 문자열을 추가하고 Buffer 객체에 대한 참조를 반환하는 함수이다.

[결과]

[소스 코드]

#include<iostream>
#include<string>
using namespace std;

class Buffer
{
    string text;
public:
    Buffer(string text) { this->text = text; }
    void add(string next) { text += next; }
    void print() { cout << text << endl; }
};

Buffer& append(Buffer& s, string g) {
    s.add(g);
    return s;
}

int main()
{
    Buffer buf("Hello");
    Buffer& temp = append(buf, "Guys");
    temp.print();
    buf.print();
}

 


 

11. 책의 이름과 가격을 저장하는 다음 Book 클래스에 대해 물음에 답하라.

 

11-1. Book 클래스의 생성자, 소멸자, set() 함수를 작성하라. set() 함수는 멤버 변수 title에 할당된 메모리가 있으면 먼저 반환한다. 그러고 나서 새로운 메모리를 할당받고 이곳에 매개 변수로 전달받은 책 이름을 저장한다.

[생성자, 소멸자, set()함수]

class Book
{
	char* title;
	int price;
public:
	Book(const char* title, int price);
	~Book();
	void set(char* title, int price);
	void show() { cout << title << ' ' << price << "원" << endl; }
};

Book::Book(const char* title, int price)
{
	this->price = price;
	int len = strlen(title);
	this->title = new char[len + 1];
	strcpy(this->title, title);
}

Book::~Book()
{
	delete title;
}

void Book::set(char* title, int price)
{
	if (this->title)
		delete[] this->title;
	this->price = price;
	int len = strlen(title);
	this->title = new char(len + 1);
	strcpy(this->title, title);
}

11-2. 컴파일러가 삽입하는 디폴트 복사 생성자 코드는 무엇인가?

[디폴트 복사 생성자]

Book::Book(const Book& b)
{
    this->title = b.title;
    this->price = b.price;
}

11-3. 디폴트 복사 생성자만 있을 때 아래 main() 함수는 실행 오류가 발생한다. - 이 오류가 발생하지 않도록 깊은 복사 생성.

[소스 코드]

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
using namespace std;

class Book {
    char* title; 
    int price; 
public:
    Book(const Book& b);
    Book(const char* title, int price);
    ~Book();
    void set(const char* title, int price);
    void show() { cout << title << ' ' << price << "원" << endl; }
};

Book::Book(const char* title, int price) 
{
    this->price = price;
    int size = strlen(title) + 1;
    this->title = new char[size];
    strcpy(this->title, title);
}

Book::Book(const Book& b) 
{
    this->price = b.price;
    int size = strlen(b.title) + 1;
    this->title = new char[size];
    strcpy(this->title, b.title);
}

Book::~Book() 
{
    delete[] title;
}

void Book::set(const char* title, int price)
{
    if (this->title) delete[] this->title;
    this->price = price;
    int size = strlen(title) + 1;
    this->title = new char[size];
    strcpy(this->title, title);
}


int main() {
    Book cpp("명품 C++", 10000);
    Book java = cpp;
    java.set("명품자바", 12000);
    cpp.show();
    java.show();
}

11-4. 문제 3 에서 실행 오류가 발생하는 원인은 Book 클래스에서 c-스트링(char *title) 방식으로 문자열을 다루었기 때문이다. 복사 생성자를 작성하지 말고 문자열을 string 클래스를 사용하여, 문제 3의 실행오류가 발생하지 않도록 Bool 클래스를 수정하라

[결과]

 
 

[소스 코드]

#include<iostream>
#include<string>
#include<cstring>
using namespace std;

class Book
{
	string title;
	int price;
public: 
	Book(string title, int price) { this->title = title; this->price = price; }
	void set(string title, int price) { this->title = title; this->price = price; }
	void show() { cout << title << ' ' << price << "원" << endl; }
};

int main()
{
	Book cpp("명품 C++", 10000);
	Book java = cpp;
	java.set("명품자바", 12000);
	cpp.show();
	java.show();
}

 


 

12. 학과를 나타내는 Dept 클래스와 이를 활용하는 main()을 보여준다.

 

12-1. main()의 실행 결과가 다음과 같이 실행되도록 Dept 클래스에 멤버들을 모두 구현하고, 전체 프로그램을 완성하라.

#include <iostream>
using namespace std;

class Dept
{
	int size;
	int* scores;
public:
	Dept(int size)
	{
		this->size = size;
		scores = new int[size];
	}
	//Dept(const Dept& dept);
	~Dept();
	int getSize() { return size; }
	void read();
	bool isOver60(int index);
};

/*Dept::Dept(const Dept& dept)
{
	this->size = size;
	
}*/

Dept :: ~Dept()
{
	delete[] scores;
}

void Dept::read()
{
	cout << size << "개 정수 입력 >> ";
	for (int i = 0; i < size; i++)
	{
		cin >> scores[i];
	}
}

bool Dept::isOver60(int index)
{
	if (scores[index] > 60)
		return true;
	else 
		return false;
}

int countPass(Dept dept)
{
	int count = 0;
	for (int i = 0; i < dept.getSize(); i++)
	{
		if (dept.isOver60(i))
			count++;
	}
	return count;
}

int main()
{
	Dept com(10);
	com.read();
	int n = countPass(com);
	cout << "60점 이상은 " << n << "명";
}

12-2. Dept 클래스에 복사 생성자 Dept(const Dept& dept); 가 작성되어 있지 않은 경우, 컴파일은 되지만 프로그램 실행 끝에 실행 시간 오류가 발생한다. (복사 생성자를 뺀 채 실행해보라). 위의 코드 어느 부분이 실행될 때 복사 생성자가 호출되는지 설명하고, 복사 생성자가 없으면 왜 실행오류가 발생하는지 설명하라.

int countPass(Dept dept) // '값에 의한 호출'로 객체가 전달될 때 복사 생성자가 호출되기 때문이다.
{
	int count = 0;
	for (int i = 0; i < dept.getSize(); i++)
	{
		if (dept.isOver60(i))
			count++;
	}
	return count;
}

12-3. Dept 클래스에 복사 생성자를 제거하라. 복사생성자가 없는 상황에서도 실행오류가 발생하지 않게 하려면 어느 부분을 수정하면 될까? 극히 일부분의 수정으로 해결된다. 코드를 수정해보라.

[결과]

[수정된 코드]

. . .
int countPass(Dept &dept)
{
	int count = 0;
	for (int i = 0; i < dept.getSize(); i++)
	{
		if (dept.isOver60(i))
			count++;
	}
	return count;
}

int main()
{
	Dept com(10);
	com.read();
	int n = countPass(com);
	cout << "60점 이상은 " << n << "명";
}

 


책에서 나오는 힌트나 조건들의 일부는 저작자 존중을 위해 일부러 작성하지 않았습니다. 

개인 공부용으로 올리는 만큼 풀이에 대한 지적 감사하겠습니다.

반응형