[C++] 심화프로그래밍 Week4

Yoons·2022년 10월 3일
0
post-thumbnail

실습 보고서 작성 요령


문제분석

  • 결과 화면을 캡쳐 하여 첨부, 해당 결과가 도출된 이유와 타당성 분석

프로그램 설계 및 알고리즘

  • 해결 방법에 따라 프로그램 설계 및 알고리즘 등 기술
  • e.g.) 문제 해결 과정 및 핵심 알고리즘 기술

소스코드 및 주석

  • 소스코드와 그에 해당하는 주석 첨부
  • 각각의 함수가 수행하는 작업, 매개변수, 반환 값 등을 명시
  • 소스코드 전체 첨부(소스코드 화면 캡처X, 소스코드는 복사/붙여넣기로 첨부)

결과 및 결과 분석

  • 결과 화면을 캡쳐 하여 첨부, 해당 결과가 도출된 이유와 타당성 분석

소감

  • 실습 문제를 통해 습득할 수 있었던 지식, 느낀 점 등을 기술

Prob 1

문제분석

시, 분, 초를 입력 하면 시간을 HH:MM:SS의 형식으로 출력하고 시간을 초로 변환해주는 프로그램이다. HH:MM:SS의 형식으로 출력하기 위해 출력형식을 지정해줘야 하는데, 이를 처리하기 위해 iomanip이라는 헤더파일을 전처리한다. 처리조건에 맞춰 Time 클래스를 선언한다. 클래스 내부에는 public 접근지정자를 이용하여 시, 분, 초를 받는 변수와 각각을 초로 변환하여 더하는 함수를 생성한다.단 클래스 외부에서 함수를 구현해야하기 때문에 클래스 내부에서는 함수 선언만 실행한다. 소스파일에서는 시간을 초로 변환하는 멤버함수를 구현하고 main함수에서 사용장에서 시, 분 초를 입력 받은 후 HH:MM:SS의 형식으로 출력한다. 그리고 멤버 함수를 이용해 각각 초로 변환한 시간을 모두 더하여 출력하면 된다.

프로그램 설계 및 알고리즘

  1. (Time.h) 소스 파일 외부에 Time.h 헤더파일을 생성한다.
  2. (Time.h) Time 클래스를 생성하고 public 접근 지정자를 이용하여 시, 분, 초를 받는 변수와 각각을 초로 변환하는 함수를 선언한다.
  3. prac_1.cpp 파일로 돌아와 정의한 헤더파일과 출력 지정자인 <iomanip>을 전처리한다.
  4. (transTime function) Time 클래스에서 선언한 함수를 구현한다. 시, 분, 초를 각각 초로 변환하여 반환한다.
  5. (main function) 객체를 선언하고 시, 분, 초를 입력 받는다.
  6. (main function) HH:MM:SS의 형식으로 출력하기 위해 <iomanip/에 정의되어있는 setw()와 setfill()을 사용하여 출력한다.
  7. (main function) 시간을 초로 변환하기 위해 위에서 구현한 transTime을 호출하고 출력한다.

소스코드 및 주석

Time.h

#pragma once

class Time{ // Time 클래스 생성
public: // 접근 지정자
    int inHour; // 시 입력 값 저장 변수
    int inMinute; // 분 입력 값 저장 변수
    int inSecond; // 초 입력 값 저장 변수
    int transTime(int inHour, int inMinute, int inSecond); // 입력된 시간을 초로 변환하는 함수
};

prac_1.cpp

#include <iostream>
#include <iomanip> // 출력 형식 지정 헤더파일
#include "Time.h" // 사용자 정의 헤더파일 전처리
using namespace std;

int Time::transTime(int inHour, int inMinute, int inSecond){ // 매개변수로 입력된 시, 분, 초를 받음
    return inHour*3600 + inMinute*60 + inSecond; // 시, 분, 초를 모두 초로 변환하여 더한 값을 반환
}

int main(){
    Time ts; // 객체 선언

    cout << "시간을 입력해주세요 : " << endl;
    cout << "몇 시? ";
    cin >> ts.inHour; // 시 입력
    cout << "몇 분? ";
    cin >> ts.inMinute; // 분 입력
    cout << "몇 초? ";
    cin >> ts.inSecond; // 초 입력

    cout << "입력한 시간 = ";
    cout << setw(2) << setfill('0') << ts.inHour << ":"; // "시:" 출력, setw로 입력 칸을 지정하고 setfill로 빈 곳은 0으로 채움
    cout << setw(2) << setfill('0') << ts.inMinute << ":"; // "분:" 출력, 위의 방식과 동일
    cout << setw(2) << setfill('0') << ts.inSecond << endl; // "초" 출력

    cout << "시간을 초로 변환 = ";
    cout << ts.transTime(ts.inHour, ts.inMinute, ts.inSecond) << endl; // transTime 함수를 호출하고 시간을 초로 변환하여 출력
}

결과 및 결과 분석


시, 분, 초를 입력하면 입력 값에 맞게 HH:MM:SS의 형식으로 잘 출력되는 것을 확인할 수 있다. 또한 입력한 시간이 초로 잘 변환되는 것 또한 확인할 수 있다.

소감

C++을 배우기 전에 C언어를 먼저 배우다 보니 출력 지정자가 없는 것이 조금 불편했다. 이번 과제를 하면서 이라는 것을 배우고 써보면서 출력 지정자가 있는게 얼마나 편한 것인지 느낀 것 같다. 만약 이 헤더파일을 사용하지 않았더라면 조건문을 써가면서 형식을 맞춰야 했을 것이다. 이번 과제에서는 헤더파일도 분리해서 코드를 작성했는데, 처음에는 적응이 안돼서 이렇게 하는게 맞나하는 느낌을 많이 받았다. 하나의 궁금증이 생긴 것은 '헤더파일을 만들 때 꼭 소스파일과 같은 폴더에 있어야하는건가?', '다른 폴더에 넣고 경로를 지정해줄 수는 없나?'라는 것이었다. 이 부분에 대해서는 더 찾아봐야겠다. 간단한 과제였지만 헤더파일 분리, 헤더파일 사용 등 사용법을 익히고 구현해볼 수 있는 과제였어서 추후 구현에 큰 도움이 될 것이라고 생각한다.


Prob 2

문제분석

예금주, 계좌번호를 출력하고 출금, 예금 및 잔액을 확인하는 프로램이다. 문제에서는 출금, 예금 기능을 넣고 출금, 예금을 확인하면서 잔액을 확인할 수 있게끔 구현한 것 같은데, 실생활에서 사용성을 높이기 위해 출금, 예금, 잔액확인, 종료로 나눠 선택할 수 있게끔 구현하려고 한다. 우선 사용자 정의 헤더파일을 이용해야하므로 클래스를 외부에 만들고 예금주, 계좌번호, 잔액을 받는 멤버 변수와 출금, 예금, 잔액확인, 종료와 같은 업무 번호를 저장한 멤버 변수를 생성한다. 문제 처리 조건으로 함수를 클래스 내부에 생성해야하므로 생성자, 소멸자, 예금, 출금, 잔액확인 함수를 선언 및 구현한다. 소스파일에서는 헤더파일을 전처리하고 예금주, 계좌번호를 입력 및 업무 번호에 따라 함수를 호출하여 실행하면 된다.

프로그램 설계 및 알고리즘

  1. (BankClient.h) 소스파일 외부에 헤더파일을 생성한다. 내부에 클래스를 생성하고 public 접근 지정자를 이용하여 예금주, 계좌, 잔액 및 업무 번호를 저장할 멤버 변수를 선언한다.
  2. (BankClient.h) 클래스 내부에서 함수를 구현해야하므로 생성자, 소멸자, 예금, 출금, 잔액확인 함수를 선언 및 구현한다.
  3. (BankClient.h) 예금, 출금 함수의 경우 saveM, outM이라는 매개변수를 받고 그 금액 만큼 예금, 출금한다.
  4. (main function) 헤더파일을 전처리하고 객체를 생성한다.
  5. (main function) 예금주, 계좌번호를 입력하고 잔액을 지정한다.
  6. (main function) 예금주와 계좌번호를 출력하고 예금할지, 출금할지, 잔액 확인을 할지, 프로그램을 종료할지 번호를 선택한다. 이때 무한 loop를 이용한다.
  7. (main function) 조건문을 이용하여 각각의 번호에 대한 함수를 호출하여 실행한다. 종료의 경우 break를 통해 loop를 빠져나간다.

소스코드 및 주석

BankClient.h

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

class BankClient { // BankClient 클래스 생성
public: // 접근 지정자
    string client; // 예금주 입력 값 저장 변수
    string account; // 계좌변호 입력 값 저장  변수
    int work; // 업무 선택번호 저장 변수
    int remain; // 잔액 저장 변수

    BankClient(){
        cout << "객체가 생성 되었습니다." << endl; // 생성자
    }

    ~BankClient(){
        cout << "객체가 소멸되었습니다." << endl; // 소멸자
    }

    int now(){ // 현재 잔액을 확인하는 now 함수
        return remain; // 그대로 remain return
    }

    int save(int saveM){ // 예금 함수
        remain = remain + saveM; // remain에 매개변수로 받은 savaM을 더함
        return remain; // 값 return
    }

    int out(int outM){ // 출금 함수
        remain = remain - outM; // remain에 매개변수로 받은 outM을 뺌
        return remain; // 값 return
    }
};

prac_2.cpp

#include "BankClient.h" // 사용자 정의 헤더파일 전처리
#include <iostream>
using namespace std;

int main(){
    BankClient obj; // obj 객체 생성

    cout << "예금주 입력 : ";
    cin >> obj.client; // 예금주 입력
    cout << "계좌번호 입력 : ";
    cin >> obj.account; // 계좌번호 입력
    obj.remain = 150000; // 잔액 지정

    cout << "예금주 : " << obj.client << endl; // 예금주 출력
    cout << "계좌번호 : " << obj.account << endl; // 계좌번호 출력

    while(true){ // 무한 loop, break를 만나야 loop에서 빠져나갈 수 있음
        cout << "번호 선택 (1:예금 / 2:출금 / 3:잔액 조회 / 4:종료)" << endl;
        cin >> obj.work; // 번호 선택

        if (obj.work == 1){ // 1(예금)을 선택했다면
            cout << "잔액 : " << obj.save(30000) << endl; // save(30000) 실행 후 출력
        }
        else if (obj.work == 2){ // 2(출금)을 선택했다면
            cout << "잔액 : " << obj.out(15000) << endl; // out(15000) 실행 후 출력
        }
        else if (obj.work == 3){ // 3(잔액 조회)을 선택했다면
            cout << "잔액 : " << obj.now() << endl; // now() 실행 후 출력
        }
        else if (obj.work == 4){ // 4(종료)을 선택했다면
            cout << "프로그램을 종료합니다." << endl; // 메세지 출력 후
            break; // loop 빠져나감
        }
    }
}

결과 및 결과 분석


코드를 실행하면 생성자에 의해 객체가 생성되었다는 메세지를 확인할 수 있다. 소스코드의 순서대로 예금주와 계좌번호를 입력 받고 어떤 업무를 수행할지 번호를 입력 받는다. 1번을 선택할 경우 소스코드에 save(30000)이라고 매개변수를 지정해두었으므로 30,000원이 예금됨을 확인할 수 있다. 2번을 선택할 경우 소스코드에 out(15000)이라고 매개변수를 지정해두었으므로 15,000원이 출금됨을 확인할 수 있다. 3번을 선택할 경우 현재 남아있는 잔액이 출력됨을 확인할 수 있고 4번을 선택할 경우 break문을 만나 프로그램이 종료된다는 메세지와 함께 무한 loop를 빠져나간다. 마지막으로는 소멸자를 통해 객체가 소멸됨을 확인할 수 있다.

소감

예시로 나와있는 결과를 봤을 때 소스코드를 어떻게 구성한 것인지 잘 몰라서 실용성 있게 코드를 변형하되 문제에서 요구하는 기능은 모두 들어가도록 코드를 짰다. 문제 처리 조건에서 조건문을 어디에 작성하라는 것인지 감은 잘 안왔지만 나는 업무 번호를 선택하게 하고 각 번호에 해당하는 함수를 실행하게 하는 것으로 조건문을 사용했다. 처음에 save(), out()함수를 구현하면서 remain값 return만 해줬었는데, 그 결과 최초 1회만 예금, 출금이 제대로 되는 문제를 발견했다. 그 이유는 처음에 remain값을 지정해줬기 때문에 같은 remain값이 넘어가 1회 이후에는 계속 같은 값이 출력되는 것이었다. 이 문제를 해결해주기 위해 save()와 out()의 매개변수를 다르게 하고 기존 remain값에서 빼주거나 더해주는 방식으로 작성하여 문제를 해결했다. 이번 과제를 진행하면서 생성자와 소멸자의 역할과 사용 방법에 대해 알았고 과제 중 문제를 해결하면서 다음에 이런 문제가 또 생기면 어떻게 대처해야할지 알게 되었다.


Prob 3

문제분석

학생 정보 처리 프로그램으로서 저장할 인원을 입력해 이름, 학번, 점수를 입력하고 점수를 환산하여 출력하는 프로그램이다. 사용자 정의 헤더파일을 사용해야하므로 헤더파일 생성 후 내부에 클래스를 선언한다. public 접근 지정자를 이용하여 여러 학생들의 정보를 입력 받을 배열 형태의 맴버 변수를 선언한다. 클래스 내부에 이름, 학번, 점수를 입력 받고 저장하는 함수와 모든 학생들의 정보를 출력하는 함수를 선언한다. 함수는 클래스 외부에 구현해야 하므로 소스파일에서 이름, 학번, 점수, 전체 조회 함수를 구현한다. main 함수에서는 객체를 생성하고 어떤 업무를 실행할지 조건문을 통해 선택 후 각 번호에 맞는 함수를 호출 및 실행하면 된다.

프로그램 설계 및 알고리즘

  1. (Student.h) 헤더파일 생성 후 클래스를 선언한다.
  2. (Student.h) public 접근 지정자를 이용하여 정보 순서를 위한 변수 2개, 배열 형태의 이름, 학번, 점수, 환산점수를 저장할 변수를 선언한다.
  3. (Student.h) 함수 구현은 클래스 외부에서 해야하므로 이름, 학번, 점수, 전체 조회에 대한 함수는 선언만 진행한다.
  4. 소스파일에서 헤더파일을 전처리하고 함수를 구현한다.
  5. (Name function) 이름을 입력 받고 매개변수를 이용하여 해당 번호의 배열에 저장한다.
  6. (Number function) 학번을 입력 받고 매개변수를 이용하여 해당 번호의 배열에 저장한다.
  7. (Score function) 점수를 입력 받고 매개변수를 이용하여 해당 번호의 배열에 저장한다. c_score 변수에는 환산 점수를 계산하여 배열에 저장한다.
  8. (All function) 지금까지 저장된 인원 수를 변수 a에 저장하여 a만큼 이름, 학번, 점수, 환산점수를 출력한다.
  9. (main function) 객체를 생성한다.
  10. (main function) 입력, 출력, 전체 조회 중 어떤 업무를 실행할지 택하고 해당 번호에 맞는 함수를 호출 및 실행한다. 이 과정은 무한 loop로 진행된다.
  11. (main function) 종료의 경우 break문을 통해 무한 loop를 빠져나갈 수 있도록 한다.

소스코드 및 주석

Student.h

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

class Student { // Student 클래스 생성
public: // 접근 지정자
    int n; // 정보 순서를 위한 변수 선언 1
    int a; // 정보 순서를 위한 변수 선언 2
    string name[30]; // 이름 저장 배열
    string number[30]; // 학번 저장 배열
    int score[30]; // 점수 저장 배열
    double c_score[30]; // 환산 점수 저장 배열

    void Name(int n);
    void Number(int n);
    void Score(int n);
    void All(int a);
};

prac_3.cpp

#include <iostream>
#include <string>
#include "Student.h" // 사용자 정의 헤더파일 전처리
using namespace std;

void Student::Name(int n){ // 이름을 저장하는 Name 함수
        cout << "이름 : ";
        cin >> name[n]; // n번째 배열에 저장
    }

void Student::Number(int n){ // 학번을 저장하는 Number 함수
    cout << "학번 : ";
    cin >> number[n]; // n번째 배열에 저장
}

void Student::Score(int n){ // 전체 점수를 저장하는 Score 함수
    cout << "전체 점수(0-200) : ";
    cin >> score[n]; // n번째 배열에 저장
    c_score[n] = ((double)score[n]/200)*100;
    cout << endl;
}

void Student::All(int a){ // 전체 정보를 출력하는 All 함수, a는 총 저장된 개수
    cout << "이름 : " <<  name[a] << endl; // 이름 출력
    cout << "학번 : " << number[a] << endl; // 학번 출력
    cout << "전체 점수 : " << score[a] << endl; // 전체 점수 출력
    cout.precision(2);
    cout << "환산 점수 : " << fixed << c_score[a] << endl << endl; // 환산 점수 출력
}

int main(){
    Student db; // 객체 생성
    int work; // 업무 번호 저장 변수

    while (true){ // 무한 loop, break를 만나야 loop에서 빠져나갈 수 있음
        cout << "업무 선택(1:입력 / 2:전체 정보 출력 / 3: 종료) : ";
        cin >> work; // 번호 선택

        if (work == 1){ // 1(입력)을 선택했다면

            cout << "몇 명의 학생 정보를 입력할까요? ";
            cin >> db.n; // 입력할 명 수 입력

            for (int n = 1; n <= db.n; n++){ // 입력한 수 만큼 반복문 실행
                cout << n << "번째 학생 정보를 입력하세요." << endl;
                db.Name(n); // 이름 입력 및 저장
                db.Number(n); // 학번 입력 및 저장
                db.Score(n); // 전체 점수 입력 및 저장
            }
        }
        else if (work == 2){ // 2(전체 정보 출력)을 선택했다면
            cout << "---------------------------------------" << endl;
            cout << "[전체 학생 정보 출력]" << endl;
            db.a = db.a + db.n; // a에 지금까지 입력된 명 수를 저장

            for (int a = 1;  a <= db.a; a++){ // 전체 수 만큼 반복문 실행
                cout << a << "번째 학생 정보를 출력합니다." << endl;
                db.All(a); // 모든 정보 출력
            }
        }
        else if (work == 3) { // 3(종료)을 선택했다면
            cout << "프로그램을 종료합니다." << endl;
            break; // loop 빠져나감
        }
    }
}

결과 및 결과 분석

업무 번호를 선택하고 조건문을 통해 특정 함수를 호출하게 했다. 결과를 보면 선택하는 업무에 따라 함수를 잘 호출해내는 것을 볼 수 있다. 3명의 학생정보를 입력했을 때 3회 반복문을 통해 이름, 학번, 점수를 잘 받는 것을 확인할 수 있다. 전체 학생 조회를 선택했을 때 지금까지 입력된 모든 학생 수만큼 이름, 학번, 전체 점수, 환산 점수 모두 잘 출력하는 것을 볼 수 있다. 종료를 선택했을 때도 프로그램이 잘 종료되는 것을 확인할 수 있다.

소감

이 문제와 비슷한 문제를 본 듯 했지만 어떻게 해야할지 고민을 많이 한 문제였다. 비슷한 문제를 기초프로그래밍 과제를 하면서 본 것 같은데, 그 문제는 구조체 관련 문제였다. 구조체를 사용하면 조금 더 간단하게 풀 수 있었을 것이라는 생각이 든다. 배열만으로 이 문제를 해결하기 위해서 하나의 매개변수(배열 순서 변수)를 여러 함수에 적용할 수 밖에 없었다. 물론 이름, 학번, 점수를 하나의 함수에 넣을 수도 있었지만 응용성을 높이기 위해 세분화해서 코드를 작성했다. 처음 코드를 작성하고 실행했을 때 생기는 문제로는 환산점수가 모두 0으로 나오는 문제가 있었다. 환산점수는 200으로 나누고 100을 곱해서 나오는데 환산점수를 저장하는 변수가 int형이기 때문에 200으로 나누는 과정에서 1보다 작은 값이 나오면 모두 0으로 처리하기 때문이다. 이 문제를 해결하기 위해 환산점수 저장 변수인 c_score를 double형으로 바꾸었다. 그리고 함수 내부에서 int형 변수인 score를 형변환연산자를 이용해 double형으로 바꾼 후 계산했다. 소수점을 출력하기 위해 cout.precision()과 "cout << fixed"를 사용했다. 이번 문항을 해결하면서 어려가지 오류가 발생했다. 입력하지 않은 배열에 이상한 숫자가 나오는 오류, 3명만 입력했는데 30개의 정보가 모두 출력되는 오류, 3명의 정보가 모두 같게 나오는 오류, 환산 점수가 모두 0으로 나오는 오류 등이 있었다. 문제를 하나하나 해결해 나가면서 의미있는 문제가 되었다고 생각한다.

Reference

profile
모든 글은 저의 눈물을 머금으며 작성한 글이니..재밌게 봐주세요 :) 깃헙 맞팔@

0개의 댓글