1. 문제

 

영문 텍스트와 모스(Morse) 부호 변환기

 

아래 <표 5-1>을 참고하여 영문 텍스트, 숫자, 몇 개의 특수 문자로 구성되는 텍스트를 모스 부호로 변환하는 프로그램을 작성하라. 모스 부호는 전보를 쳐서 통신하는 시절에 사용된 유명한 코딩 시스템이다. 각 모스 코드들을 하나의 빈칸으로 분리되고, 영문 한 워드가 모스 워드로 변환되면 워드들은 3개의 빈칸으로 분리된다. 실행 예는 다음과 같다. 영문 텍스트를 입력받아 모스 부호로 변환하여 출력하고, 변환이 잘 되었는지 확인하기 위해 다시 모스 부호를 영문 텍스르로 변환하여 원문을 출력한 사례이다.

 

 

2. 결과

 

 

 

 

3. 코드

 

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

class Morse {
	string alphabet[26];
	string digit[10];
	string slash, question, comma, period, plus, equal;
public :
	Morse();
	void text2Morse(string text, string& morse);
	bool morse2Text(string morse, string& text);
};

Morse::Morse() {
	string alphamorse[26] = { ".-", "-...", "-.-.", "-..", ".",
							 "..-.", "--.", "....", "..", ".---",
							 "-.-", ".-..", "--", "-.", "---",
							 ".--.", "--.-", ".-.", "...", "-",
							 "..-", "...-", ".--", "-..-", "-.--", "--.."};
	string digitmorse[10] = { "-----", ".----", "..---", "...--", "....-",
							".....", "-....", "--...", "---..", "----." };
	int i;

	for(i=0; i<26; i++)
		alphabet[i] = alphamorse[i];
	for(i=0; i<10; i++)
		digit[i] = digitmorse[i];
	slash = "-..-.";	question = "..--..";	comma = "--..--";
	period = ".-.-.-";	plus = ".-.-.";		equal = "-...-";
}
void Morse::text2Morse(string text, string& morse) {

	morse = "";

	for(int i=0; i<text.length(); i++) 
	{
		char temp = text.at(i);
		if( isalpha( temp ) ) {
			if( temp >= 65 && temp <= 90 ) tolower( temp );
			morse = morse + alphabet[ temp-97 ] + " ";
		}
		else if( temp == ' ')
			morse += "  ";
		else if( isdigit( temp ) )
			morse = morse + digit[ temp -48 ] + " ";
		else {
			if( temp == '/' ) morse = morse + slash + " ";
			else if( temp == '?' ) morse = morse + question + " ";
			else if( temp == ',' ) morse = morse + comma + " ";
			else if( temp == '.' ) morse = morse + period + " ";
			else if( temp == '+' ) morse = morse + plus + " ";
			else if( temp == '=' ) morse = morse + equal + " ";
		}
	}
}
bool Morse::morse2Text( string morse, string& text) {
	int before;
	int pos = -1;
	string retext;
	bool exit = true;

	string al[26] = {"a", "b", "c", "d", "e", "f", "g", "h", "i",
					"j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
					"t", "u", "v", "w", "x", "y", "z"};
	string di[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

	while(1) {

			before = pos +1;
			pos = morse.find(" ", before);

			string temp = morse.substr( before, pos-before);
			for(int i=0; i<26; i++) {
				if( temp == alphabet[i] ) {
					retext.append(al[i]);
					exit = false;
					break;
				}
			}
			if( exit) {
				for(int i=0; i<10; i++) {
					if( temp == digit[i] ) {
						retext.append(di[i]);
						break;
					}
				}

		if( temp == slash ) retext.append("/");
			else if( temp == question ) retext.append("?");
			else if( temp == comma ) retext.append(",");
			else if( temp == period ) retext.append(".");
			else if( temp == plus ) retext.append("+");
			else if( temp == equal ) retext.append("=");
		}

		exit = true;

		if( pos == morse.size()-1 ) break;   //while문 종료

		while( morse.at(pos) == ' ' && morse.at(pos+1) == ' ' && morse.at(pos+2) == ' ' ) {
			retext.append(" ");
			pos += 2;
		}

	}

	if( retext == text ) return true;
	else return false;
}

int main() {

	string text, morse;
	Morse m;

	cout << "아래에 영문 텍스트를 입력하세요. 모스 부호로 바꿉니다." << endl;
	getline(cin, text);
	m.text2Morse( text, morse );
	cout << morse << endl << endl;

	cout << "모스 부호를 다시 영문 텍스트로 바꿉니다." << endl;
	
	if( m.morse2Text( morse, text) )
		cout << text << endl;
	else
		cout << "모스 부호가 아닙니다." << endl;

}

 

 

4. 설명

 

Morse 클래스 생성자에서 <표 5-1>의 문자들을 초기화 하여 줍니다.

 

저는 새로운 배열을 하나 선언한 후 for문을 이용하여서 Morse 클래스 멤버 변수들을 초기화 하였습니다. 이 방법이 아니면 alphabet[0] = ; alphabet[1] = ; alphabet[2] =; 이렇게 일일이 다 초기화 해주어야 합니다.

 

----------

text2Morse() 멤버 함수는 우선 text.at(i)로 문자열 text에서 인덱스 값이 i인 문자를 가져와서 temp에 저장합니다.

 

이 temp가 isalpha()를 사용하여서 알파벳인지 검사를 합니다. 알파벳이라면 temp >= 65 && temp <= 90 일 경우 즉, 대문

 

자일 경우 tolower(  )함수를 사용하여서 temp를 소문자로 고쳐줍니다.

 

그 후 morse = morse + alphabet[ temp-97] + " "; 여기서 "temp - 97"인 이유는 temp가 소문자이므로 temp의 값 범위는 temp >= 97 && temp <= 123 입니다. 여기서 temp가 'a'라면 97로서 alphabet[0] 즉 a의 해당하는 모스부호를 morse 변수에 추가합니다. 그 후 + " "로 한칸을 띄어 줍니다.

 

숫자인 경우도 isdigit()을 사용하여서 숫자이면 digit[ temp - 48 ]로서 해당하는 모스부호를 추가시 켜 줍니다.

 

 

※ 주의하실 점은 temp == ' '일 경우 입니다. 이 경우는 띄어쓰기일 경우인데 이 경우 모스부호로 바꾸었을 때는 3개의 공간을 비워주어야 합니다. 하지만 조건문이 temp == ' '인 if문에서 morse += "  "; 로서 2칸만 띄어쓰기를 해주셔야 합니다.
그 이유는 다른 문자를 추가하고서 + " "로 이미 한칸을 띄어쓰기 하였기 때문입니다.

 

------------

morse2Text() 멤버 함수가 가장 어려웠던 것 같습니다.

 

우선 변수들을 선언 합니다. before은 한 모스 부호의 시작 부분의 인덱스를, pos는 그 모스 부호 끝의 다음 " "부분의 인덱스 값을 저장합니다.

 

그리고 알파벳들을 저장하고 있는 배열과 숫자 0~9를 저장하고 있는 배열을 선언, 초기화 해줍니다.

 

string temp = morse.substr( before, pos-before ) : substr() 함수는 문자열 morse의 인덱스 before부터 pos-before(개)를 return 합니다. pos는 " "의 인덱스 값이므로 pos-before(개)만큼 return하여야 합니다.

 

모스 부호 하나를 temp 변수에 저장 하였으면 Morse클래스의 멤버 변수들을 이용하여서 어떤 문자인지를 구하여 retext변수의 추가하여 줍니다.

 

->여기서 exit는 알파벳인 것을 구하였다면 다음 숫자 또는 기호인지 검사할 필요가 없으므로 시간 절약을 위하여 선언하였습니다.

 

if( pos == morse.size()-1 ) break; 일 경우 while문을 종료합니다.

여기서 중요한 것은 morse의 인덱스 morse.size()-1인 부분은 맨 끝으로 " "이라는 것 입니다.

-> 모든 문자들 끝에 띄어쓰기가 추가되었기 때문에

그러므로 모스 부호 단어 끝 " "의 인덱스 번호를 저장하는 pos를 이용하여서 종료시점을 정할 수 있습니다.

 

 

while( morse.at(pos) == ' ' && morse.at(pos+1) == ' ' && morse.at(pos+2) == ' ' )는 띄어쓰기가 있을 경우 " "을 retext의 추가 해준다음 pos값을 +2하여서 다음 단어의 pos값을 구할 수 있도록 합니다.

 

여기서 while문을 사용한 이유는 띄어쓰기를 연속적으로 2번 하였을 시 알맞게 출력하기 위해서 입니다. 하지만 정작 text2Morse()함수에서는 띄어쓰기가 연속적으로 2번 하였을 시를 알맞게 코딩하지 않았습니다.

 

그러니 연속적인 띄어쓰기를 입력하지 않는다면, 이 부분에서는 while문 말고 if문을 사용하셔도 무관합니다.

 

 

1. 문제

 

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

 

(1) Book 클래스의 생성자, 소멸자, set() 함수를 구현하라.

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

(3) 디폴트 복사 생성자만 있을 때 아래 main() 함수는 실행 오류가 발생한다.

 

다음과 같이 실행 오류가 발생하지 않도록 깊은 복사 생성자를 작성하라.

 

 

2. 결과

 

 

 

3. 코드

 

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

class Book {
	string s;
	int price;
public:
	Book(string s, int price);
	~Book();
	/* 디폴트 복사 생성자
	Book(Book& b) {
	this->title = title;
	thie->price = price;
	}
	*/
	Book(Book &b);
	void set(string s, int price);
	void show() { 
	
	cout << s << ' ' << price << "원" << endl; }
};

Book::Book(string s, int price) {
	this->s = s;
	this->price = price;
}
Book::~Book() {
	
}
void Book::set(string s, int price) {
	this->s = s;
	this->price = price;
}
Book::Book(Book &b) {
	this->s = b.s;
	this->price = b.price;
}

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

 

 

4. 설명

 

디폴트 복사 생성자는 주석처리로 했습니다. 

 

디폴트 복사 생성자는 얕은 복사로 오류가 많이 발생하니 깊은 복사를 사용하시는 것이 좋습니다.

 

strlen()함수는 C-string 문자열의 길이를 return 합니다

 

strcpy 함수는 C-string 문자열을 복사 합니다.

 

 

 

1. 문제

 

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

 

 

2. 결과

 

 

 

3. 코드

 

#include <iostream>
using namespace std;

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

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

 

 

4. 설명

 

Accumulator(int value)생성자에서 총 값 value를 입력된 매개변수로 초기화합니다.

 

Accumulator& add(int n) 로 입력된 n을 value의 더한 후 return *this;를 하여 줍니다.

 

이로써 main()에서 acc.add(5).add(6).add(7) 이렇게 연속적으로 add함수를 실행 할 수 있습니다.

 

 

 

1. 문제

 

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

 

MyIntStack 클래스를 활용하는 코드와 실행 결과는 다음과 같다.

 

 

2. 결과

 

 

 

3. 코드

 

#include <iostream>
using namespace std;

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

bool MyIntStack::push(int n) {
	tos++;
	if( tos == 10 ) 
		return false;
	else {
		p[tos] = n;
		return true;
	}
}
bool MyIntStack::pop(int &n) {
	if( tos == -1 )
		return false;
	else {
		n = p[tos];
		return true;
	}
	tos--;
}
MyIntStack::MyIntStack(MyIntStack& s){ 
	this->p = new int[s.size];
	this->size = s.size;
	this->tos = s.tos;
	for(int i=0; i<=s.tos; i++)
		this->p[i] = s.p[i];
}

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;
}

 

 

4. 설명

 

5번과 다른점은 생성자의서 int형 변수를 하나 입력받아서 그만큼 배열을 동적 생성하고 또한 클래스 변수간의 "="를 사용

 

하기 위한 MyIntStack( MyIntStack& s); 생성자와 소멸자가 추가되었습니다.

 

MyIntStack( MyIntStack& s);의서는 깊은 복사를 하여서 정확하게 복사가 되도록 구현하였습니다.

 

 

소멸자에서는 동적으로 생성하였던 배열 p를 해제하여 줍니다.

 

 

 

1. 문제

 

5. 다음과 같이 선언된 정수를 저장하는 스택 클래스 MyIntStack을 구현하라.

 

MyIntStack 스택에 저장할 수 있는 정수의 최대 개수는 10이다.

 

MyIntStack 클래스를 활용하는 코드와 실행 결과는 다음과 같다.

 

 

2. 결과

 

 

 

3. 코드

 

#include <iostream>
using namespace std;

class MyIntStack {
	int p[10];
	int tos;
public : 
	MyIntStack(){ tos = 0; }
	bool push(int n);
	bool pop(int &n);
};
bool MyIntStack::push(int n) {
	if( tos == 10 ) 
		return false;
	else {
		p[tos] = n;
		tos++;
		return true;
	}
}
bool MyIntStack::pop(int &n) {
	tos--;
	if( tos == -1 )
		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;
}

 

 

4. 설명

 

Stack은 선입선출의 구조로 가장 나중에 들어온 데이터가 가장 먼저 나갑니다.

 

Stack을 예로 들어 설명하면 책을 쌓는 것과 유사하다고 할 수 있습니다. 

 

책(데이터)이 쌓여서 만들어진 책 더미의서 책(데이터)을 추가할려면 가장 위(top)에다가 책을 추가합니다.

 

여기서 가장 위 top(높이)를 저장하고 있는 값이 멤버 변수 tos 입니다.

 

 

※ 배열의 인덱스는 0부터 시작하므로 클래스 MyIntStack의 생성자에서 tos = -1로 초기화 해줍니다.

 

 

 

1. 문제

 

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

 

 

2. 결과

 

 

 

 

3. 코드

 

#include <iostream>
using namespace std;

char& find(char a[], char c, bool& success);

char& find(char a[], char c, bool& success) {

	for(int i=0; i< sizeof(a); i++)
		if( a[i] == c ) { 
			success = true;
			return a[i]; 
		}
		return *a;
}

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;
}

 

 

4. 설명

 

함수 find(s, 'M', b)는 문자열 s에서 'M'을 찾아서 존재한다면 false로 초기화 되어있는 success를 success = true;로 초기화 합니다.

 

또한, 참조에 의한 호출로서 문자 하나를 return 합니다.

 

return한 문자는 char& loc에 저장을 하였고 참조에 의한 호출이기 때문에 loc값을 바꾸면 함수 find()에서 return했던 값도 loc값에 따라 바꾸어집니다.

 

 

 

1. 문제

 

3. 다음 Circle 클래스가 있다.

 

Circle 객체 b를 a에 더하여 a를 키우고자 다음 함수를 작성하였다.

 

다음 코드를 실행하면 increaseBy() 함수는 목적대로 실행되는가?

 

main() 함수의 목적을 달성하도록 increaseBy() 함수를 수정하라.

 

 

2. 결과

 

 

 

3. 코드

 

#include <iostream>
using namespace std;

class Circle;
void increaseBy(Circle &a, Circle b);

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 increaseBy(Circle &a, Circle b) {
	int r = a.getRadius() + b.getRadius();
	a.setRadius(r);
}

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

 

 

4. 설명

 

문제 해결 전 주어진 void increaseBy(Circle a, Circle b)를 보면 어느 값도 return 하지 않는 void형 입니다.

 

그런데 매개변수들도 보면 둘 다 값에 의한 호출로서, 이 함수 increaseBy()에서 어떤 명령을 실행시켜도 increaseBy() 함수 공간에서만 실행되고 이 함수가 끝나면 increaseBy() 공간이 사라지게 됩니다.

 

 

그러므로 변한 값이 유지되도록 값이 변경될 Circle a를 값에 의한 호출이 아닌 참조에 의한 호출로서 바꾸어 주어서 increaseBy()함수 내에서 Circle a의 변한 값이 유지되도록 만들어 줍니다.

 

 

 

1. 문제

 

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

 

 

2. 결과

 

 

 

3. 코드

 

#include <iostream>
using namespace std;

bool bigger(int a, int b, int& big);

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

int main() {
	int n=5, nn=9, big;

	if( bigger(n, nn, big) )
		cout << "두 수는 같습니다." << endl;
	else
		cout << "더 큰 수는 " << big << "입니다" << endl;

}

 

 

4. 설명

 

bool bigger() 함수는 두 수가 같은 경우 return true;를 두 값이 다른 경우 더 큰 값을 big에 저장한 후 return false;를 해줍니다.

 

return형이 bool이기 때문에 return은 true, false 값으로 해주셔야 합니다.

 

또한, 문제에서는 사용자로부터 2개의 정수를 입력받은 후 큰 값을 출력해야 되지만 저는 그냥 변수 2개를 초기화 한 후 비교하였습니다.

 

+ Recent posts