1 / 45

프로그램과 데이터의 구조화 ORGANIZING PROGRAMS AND DATA

Chapter 4. 프로그램과 데이터의 구조화 ORGANIZING PROGRAMS AND DATA. 4 장에서는 …. 3.2.2 절의 프로그램이 생각했던 것보다 긴가요 ? 하지만 vector 나 string, sort 가 없었다면 훨씬 더 길어졌을 것입니다 . 표준 라이브러리 의 힘입니다 . 프로그램이 커지면 , 프로그램을 여러 독립적인 부분으로 분할하고 개별 관리 C++ 는 이런 방법을 제공 : 함수 와 자료구조

curran-tate
Download Presentation

프로그램과 데이터의 구조화 ORGANIZING PROGRAMS AND DATA

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 4 프로그램과 데이터의 구조화ORGANIZING PROGRAMS AND DATA

  2. 4 장에서는… • 3.2.2절의 프로그램이 생각했던 것보다 긴가요? 하지만 • vector나 string, sort 가 없었다면 훨씬 더 길어졌을 것입니다. 표준 라이브러리의 힘입니다. • 프로그램이 커지면, • 프로그램을 여러 독립적인 부분으로 분할하고개별 관리 • C++는 이런 방법을 제공: 함수와 자료구조 • 그리고 함수와 자료구조를 하나의 이름으로 묶는 클래스 제공 (클래스 만드는 법은 9장에서 공부) • 4장은, • 함수와 자료구조 (struct)를 이용하여 프로그램의 구조화 방법 • 프로그램을 여러 파일로 나누어 독립적으로 컴파일 하는 방법

  3. 4.1 함수를 이용한 구조화하기 • 만일 같은 계산을 하는 코드가 여러 곳에 있다면… • 성적 계산 방식이 바뀌면… • 수십만 라인의 프로그램의 곳곳에 퍼져 있다면, 재앙… • 함수를 사용 • 계산을 매번 반복하지 않고, 함수를 만들고, 그 함수를 이용한다 • 변경하고 싶을 때 바꾸기가 쉽다 int main( ) { … cout …<< 0.2*midterm+0.4*final+0.4*sum/count ; … … cout …<< 0.2*midterm+0.4*final+0.4*sum/count ; return 0; }

  4. 함수의 구조 • ret-type: 함수가 결과로 리턴하는 값의 타입 • function-name: 함수의 이름 • param-decls: 함수의 매개변수. 여러 개 일 때 콤마(,)로 구분 • 함수는 이름, 매개변수, 몸체, 그리고 리턴 타입으로 구성 • 함수 호출을 할 때, 인자는 개수와 타입이 일치해야 한다 • 값에 의한 호출 (call-by-value): 매개변수가 지역변수로 생성되고, 인자의 값이 1:1로 복사된다 ret-type function-name (param-decls) { // 함수 정의 // 함수 본체 }

  5. 함수 만들기: 성적 계산 함수 매개변수 (parameter) • 성적계산 grade() 함수 double grade(double midterm, double final, double homework) { return 0.2*midterm+0.4*final+0.4*homework; } • 매개변수를 지역변수로 보고, • 인자 전달 과정을 지역변수 초기화로 볼 수 있음 int main( ) { … cout …<< grade(midterm, final, sum/count) ; … … cout …<< grade(midterm, final, sum/count) ; return 0; } 인자 (argument) grade()함수 호출

  6. 함수 만들기: 중앙값 찾기 • 무엇을 받고무엇을 리턴 해야 할까? : 함수 설계의 첫 단계 • 여러값을 저장한 vector 객체를 받고, 중앙값을 리턴 // 이 함수를 호출하면 vector 인자 전체를 복사한다는것에 유념 double median( vector<double> vec) { typedef vector<double>::size-type vec_sz; vec_sz size=vec.size(); if(size==0) throw domain_error(“median of an empty vector”); sort(vec.begin(), vec.end()); vec_sz mid=siz/2; return size%2==0? (vec[mid]+vec[mid-1])/2: vec[mid]; } • 매개변수 복사에 시간이 소요됨 • vector 에 담겨있는 값이 많을수록 많은 시간이 걸린다 • sort()에 의해 값이 변경되므로, 시간이 걸리더라도 복사가 유용함

  7. 예외 처리 (Exception Handling) • 오류가 났을 때 어떻게 대처해야 하나? • 3.2.2절 (p.98)에서는 그곳에서 즉시 오류 처리했음 • 여기서는 예외상황(exception)을 throw(발생)시킴 • domain_error 객체를 throw 했음:<stdexcept> 헤더에 정의됨 • 그러면 median()을 호출한 곳에서 throw된 것을 catch하여 적절히 오류 처리함 • 예외가 발생하면, • throw 위치에서 실행을 멈추고, 예외상황 객체 (exception object)를 가지고, 나머지 부분을 건너뜀. • 이 예외상황 객체는 호출한 곳에서 적절히 대처하는데 필요한 정보를 담고 있음

  8. 함수 만들기: 성적 계산식 다시 구현하기 • 또 다른 grade() 함수 • 여러 과제 성적을 받아, 중앙값을 계산하고, 그것으로 최종 성적을 계산하는 기능 • 이전 grade()함수는 이미 계산된 중앙값 또는 평균값을 받았음 // 중간, 기말, 과제성적을 이용하여 전체 성적 계산 double grade(double midterm, double final, const vector<double>& hw) { if(hw.size()==0) throw domain_error(“student has done no homework”); return grade(midterm, final, median(hw)); } • 몇 가지 생각해 볼 것은… • 이전에 이미 사용한 grade()라는 함수 이름을 중복해 써도 되나? • 세 번째 매개 변수에 있는 &는 무엇인가? • grade()가 grade()를 호출했네? 순환 호출 (recursive call)인가?

  9. 레퍼런스(reference) 변수 • 레퍼런스 또는 참조변수는 객체에 대한 또 다른 이름 vector<double> homework; vector<double>& hw=homework; // hw는 homework에 대한 별칭 vector<double>& hw1 = hw; // hw1은 ” const vector<double>& chw=homework; // chw, chw1는 homework에 대한 constvector<double>& chw1=chw; // 읽기전용별칭 • 참조에 의한 호출 (call-by-reference) • 함수 매개변수에레퍼런스 &를 넣으면,해당 인자를 복사하지 않으므로, 복사에 따른 간접비용 없음 • const를 넣으면 인자의 값을 바꾸지 않겠다고 구현시스템에 알려줌

  10. call by reference • 참조에 의한 호출 예. void foo(int & r) {    r = 10; } void main() {    int x = 20;    foo(x);    cout << x; } • swap() 함수 예 // 옳게 작동 안 함 void swap(int a, int b) { int tmp; tmp=a; a=b; b=tmp; } // 옳게 작동 (레퍼런스 버전) void swap(int& a, int& b) { int tmp; tmp=a; a=b; b=tmp; }

  11. 함수오버로딩(overloading) • 오버로딩: 함수 오버로딩과 연산자 오버로딩 • 함수 오버로딩 • 여러 함수가 같은 이름을 가질 수 있다. • 예. 두 개의 서로 다른 grade() 함수 double grade(double midterm, double final, double homework) { … } double grade(double midterm, double final, const vector<double>& hw) { … } • 호출되었을 때, 컴파일러는 어떤 것을 기동할지 어떻게 알지?

  12. 함수 오버로딩 예 • 함수 오버로딩에서는 두 함수의 매개변수의 순서, 개수또는타입이 달라야 한다. void foo(int) { ... }; // 1 void foo(double) { ... }; // 2 void foo(int, int) { ... }; // 3 void foo(int, double) { ... }; // 4 int foo(int); // Compiler Error! void main() { foo(3); // Calls 1 foo(5, 3.14); // Calls 4 }

  13. 과제 성적 읽기 • 읽어 들이는 기능을 함수로 만들어 보면, • 리턴해야 할 것이 두 가지 • 읽은 값을 리턴 해야 하고, • 또한 제대로 읽었는지 (오류 여부) 리턴 해야 함. • 함수는 하나만 리턴 할 수 있다 • 레퍼런스 매개 변수를 이용하여 읽은 값을 리턴 하자! • 함수의 골격은 아래와 같이… // 입력 스트림으로부터 vector<double>에 과제 성적을 읽어 들임 istream& read_hw( istream& in, vector<double>& hw) { // 채워야 할 곳… return in; } int main() { vector<double> homework; if( read_hw(cin, homework) ) { /*… */ } }

  14. 과제 성적 읽기: 함수 구현 • 처음 시도해 본 코드. 아래와 같이 하면 될까? • 문제점은 • hw가 깨끗하다는 보장이 있나? (hw는 함수를 호출한 곳에서 넘겨준 것) • 이전에 사용되어 벡터에 성적이 담겨있다면? • 만일 입력 도중에 오류가 난다면? 이후에 다른 함수에서 일어나는 입력 기능이 제대로 될까? • 입력 실패: (1) EOF 만났을 때 (2) 성적이 아닌 값을 입력되었을 때 • in이 깨끗할까? 만일 in이 이전에 사용되어 무엇이 남아 있다면? • 입력 실패 후 in의 내부에 있는 오류 상태 리셋 필요 • 다음 학생 성적 입력 전에 정리 필요 istream& read_hw(istream& in, vector<double>& hw) { double x; while( in>>x ) hw.push_back(x); return in; }

  15. 과제 성적 읽기: 함수 구현 • read_hw() 완전한 코드 istream& read_hw(istream& in, vector<double>& hw) { if(in) { // 이전 내용 삭제 hw.clear(); // 과제 성적을 읽어 들임 double x; while(in>>x) hw.push_back(x); // 다음 학생의 데이터를 읽을 수 있도록 스트림을 모두 삭제 in.clear(); } return in; } • hw벡터: 빈 벡터로 시작하도록 함 • istream 객체: 오류상태 리셋, 입력 작업을 계속하도록 함 http://www.cppreference.com/wiki/io/eof

  16. 함수 매개변수 양식 세가지 • call-by-value: • 복사하면 간접비용 든다. 하지만 그래야 할 경우가 있다. • call-by-reference: • 이 함수에서 인자의 값을 변경할 의도가 있다. 인자는 lvalue(변수)이어야 함 • const인 call-by-reference: • 이 함수에서 인자의 값을 변경하지 않고, 읽기만 한다. • 어떤경우에 무엇을 쓸지 판단해야 한다. doublemedian( vector<double> vec) { …} double grade(double midterm, double final, double homework) { …} doublegrade(double midterm, double final, const vector<double>& hw) { …} istream& read_hw( istream& in, vector<double>& hw) { …}

  17. 함수를 이용한 성적계산 - 전체프로그램 #include <algorithm> #include <iomanip> #include <iostream> #include <stdexcept> #include <string> #include <vector> using namespace std; // compute the median of a `vector<double>' // note that calling this function copies // the entire argument `vector' double median(vector<double> vec) { typedef std::vector<double>::size_type vec_sz; vec_sz size = vec.size(); if (size == 0) throw domain_error("median of an empty vector"); sort(vec.begin(), vec.end()); vec_sz mid = size/2; return size % 2 == 0 ? (vec[mid] + vec[mid-1]) / 2 : vec[mid]; }

  18. // compute a student's overall grade from midterm and // final exam grades and homework grade double grade(double midterm, double final, double homework) { return 0.2 * midterm + 0.4 * final + 0.4 * homework; } // compute a student's overall grade from midterm and final // exam grades and vector of homework grades. // this function does not copy its argument, because `median‘ // does so for us. double grade(double midterm, double final, const vector<double>& hw) { if (hw.size() == 0) throw domain_error("student has done no homework"); return grade(midterm, final, median(hw)); }

  19. // read homework grades // from an input stream into a `vector<double>' istream& read_hw(istream& in, vector<double>& hw) { if (in) { // get rid of previous contents hw.clear(); // read homework grades double x; while (in >> x) hw.push_back(x); // clear the stream so that input will work for next student in.clear(); } return in; }

  20. int main() { // ask for and read the student's name cout << "Please enter your first name: "; string name; cin >> name; cout << "Hello, " << name << "!" << endl; // ask for and read the midterm and final grades cout << "Please enter your midterm and final exam grades: "; double midterm, final; cin >> midterm >> final; // ask for the homework grades cout << "Enter all your homework grades, followed by end-of-file: "; vector<double> homework; // read the homework grades read_hw(cin, homework); // compute and generate the final grade, if possible try { double final_grade = grade(midterm, final, homework); streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error) { cout << endl << "You must enter your grades. " “Please try again." << endl; return 1; } return 0; }

  21. 프로그램 뜯어 보면 • 함수 호출 순서를 잘 살펴보자. • 누가 누구에게 일을 시키는지 잘 따져봐야 합니다. • main()이 read_hw()을 호출하여 데이터 읽어들이고, • grade()를 호출하고, • grade()는 인자 위치에서 median()호출하고 • 이어 (이름은 같지만 매개변수가 다른) grade()를호출

  22. try와 catch에 의한 오류 처리 int main() { … try { double final_grade = grade(midterm, final, homework); streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error) { cout << endl << "You must enter your grades. " “Please try again." << endl; return 1; } return 0; } • <stdexcept> header • exception • logic_error • domain_error • invalid_argument • length_error • out_of_range • runtime_error • range_error • overflow_error • underflow_error double grade(double midterm, double final, const vector<double>& hw) { if(hw.size()==0) throw domain_error(“student has done no homework”); return grade(midterm, final, median(hw)); }

  23. try와 catch에 의한 오류 처리 try { A } catch (domain_error) { B } • A를 try(시도)하다가 • 오류(예외)가발생하면, • 오류 발생지점에서 예외상황 객체를 throw한다 • catch가 그것을 받아 B를실행하여 오류 처리한다. (대부분의 경우, A에서 호출되는 함수 속에서 throw함) • 예외상황이 발생한 그 다음의 코드는 실행이 안 된다. • 오류가 발생하지 않으면, • catch의 B를 무시하고,다음 문으로 이동한다.

  24. try와 catch에 의한 오류 처리 - 부적절 • 아래와같이 하면어떤 문제가 숨어 있나? • 문제점.. • << 연산자가 왼쪽에서 오른쪽 순서로 실행하지만, 피연산자들을 그 순서대로 계산(평가)하지는 않는다. • 출력스트림의 정밀도를 3으로 설정한 후, 원래 값으로 되돌리는 두번째 호출을 실행하지 못할 수도 있다. • 전적으로 구현시스템에 의존 try { streamsize prec=cout.precision(); cout<< “Your grade is “ <<setprecision(3) <<grade(midterm,final,homework)<<setprecision(prec); } catch (domain_error) { … }

  25. 예외 처리 • 예외란 우리가 당연하다고 가정한 상황이 거짓이 되는 경우를 말한다. • 대표적인 예외의 경우 • 컴퓨터에 사용 가능한 메모리가 부족한 경우 • 당연히 있을 것이라 생각한 파일이 없는 경우 • 사용자가 잘못된 값을 입력하는 경우 • 예외 처리란 이러한 상황이 발생한 경우에도 프로그램이 올바르게 동작할 수 있도록 처리하는 것을 말한다. • 예) 컴퓨터에 사용 가능한 메모리가 부족해서 동적 메모리 할당이 실패한 경우에 예외 처리를 잘 하지 못한 프로그램은 비정상 종료할 수 있다. 반면에 예외 처리를 잘 한 프로그램은 사용자가 작업 중이던 정보를 잘 보관한 후에 정상적으로 종료할 수 있다.

  26. 예외처리 메커니즘 • C++ allows you to throwvalue of any data type, including standard library's exception classes and your own exception classes. throw 20; throw "Something went wrong"; throw domain_error("reason comes here");

  27. 예외 처리 예 int main(void) { int a, b; cout<<"두 개의 숫자 입력 : "; cin>>a>>b; try{ cout<<"try block start"<<endl; if(b==0) throwb; cout<<"a/b의 몫 : "<<a/b<<endl; cout<<"a/b의 나머지 : "<<a%b<<endl; cout<<"try block end"<<endl; } catch(int exception){ cout<<"catch block start"<<endl; cout<<exception<<" 입력."<<endl; cout<<"입력오류! 다시 실행 하세요."<<endl; } cout<<"THANK YOU!"<<endl; return 0; } • 예외가 발생하면 • try 블록의 나머지 부분 무시 • 예외 처리 후 • catch 블록 이후부터 실행

  28. 4.2 데이터 구조화하기 • 지금까지는 한 학생 성적 계산하는 프로그램 • 그냥 계산기로 처리하는 게 더 간편할 듯 • 실제에서는 여러 학생 성적 처리 필요 입력 Smith 93 91 47 90 92 73 100 87 Carpenter 75 90 87 92 93 60 0 98 … 출력 Carpenter 86.8 Smith 90.4 … • 문제가 복잡해 졌다: 각학생들의 이름과 성적들을 함께 저장해야 한다 • 학생 이름 순서대로 출력 • 점수 위치를 맞추어서 출력

  29. 데이터 구조화하기 • 여러 학생의 정보를 저장하기 위한 자료구조 필요 • 한 학생은 <이름, 중간, 기말, 과제 성적>이 있다 • 한 학생의 과제 성적을 저장할 때, 과제성적이 모두 double이므로 vector<double> 타입이면 OK • 이제는 vector<???> • ???에 {이름, 중간, 기말, 과제 성적}을 담는 무엇인가가 필요 • 게다가 여러 학생의 데이터를 저장하는 데에도 vector 필요

  30. 학생의 데이터를 모두 함께 저장하기 • 학생 데이터를 위한 자료구조 struct Student_info { string name; double midterm, final; vector<double> homework; }; • Student_info는 struct 타입이다 • 이 타입은 네 개의 데이터 멤버를 가지고 있음 • 타입이므로이런 것이 된다. • Student_info s; // 한 명의 학생 정보 • vector<Student_info> students; // 여러 명의 학생 정보

  31. 학생레코드 관리하기 • 한 학생의 레코드를 읽어 들이려면, • 최종 성적을 계산하려면, istream& read(istream& is, Student_info& s) { is>>s.name>>s.midterm>>s.final; read_hw(is, s.homework); return is; } • 매개변수를 • Student_info& s로 한 이유는? • const Student_info& s로 한 이유는? double grade( const Student_info& s) { return grade(s.midterm, s.final, s.homework); }

  32. 학생레코드 관리하기-이름으로 정렬 • 이름 순으로 정렬해야 하는데, 이렇게 하면 될까? sort(students.begin(), students.end()); // 안된다. 왜? // 도대체 무엇을 기준으로 정렬하란 말인가? • 이 상황에서는 비교할 방법을 알려줘야 한다. • 이름 순으로 정렬한다면, 우선 compare() 함수를 정의한다. • 라이브러리 함수인 sort()의 세 번째 인자로 전달해서 호출한다 sort( students.begin(), students.end(), compare); bool compare(const Student_info& x, const Student_info& y) { return x.name < y.name; }

  33. 보고서 양식 출력하기 • 몇군데주목해 볼만한 곳은, • 위치 맞추어 출력하기 (가장긴 이름을 기준으로) Carpenter 86.8 Smith 90.4 • 오류 처리새로운 형태의 catch int main() { vector<Student_info> students; Student_info record; string::size_type maxlen = 0; // read and store all the records, and find the length of the longest name while (read(cin, record)) { maxlen = max(maxlen, record.name.size()); students.push_back(record); }

  34. // alphabetize the records sort(students.begin(), students.end(), compare); for (vector<Student_info>::size_type i = 0; i != students.size(); ++i) { // write the name, // padded on the right to `maxlen' `+' `1‘ characters cout << students[i].name << string(maxlen + 1 - students[i].name.size(), ' '); // compute and write the grade try { double final_grade = grade(students[i]); streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec); } catch (domain_error e) { cout << e.what();// call what() member function of domain_error } cout << endl; } return 0; }

  35. 독립 컴파일 (separate compile) • 프로그램이커지면 독립 컴파일이 필수적이다. • 관련있는 함수와 자료구조를 모아 독립된 파일로 만든다 • ___.cpp와 ___.h 파일 • 각 파일을 독립적으로 컴파일 한 후, 목적 파일을 링크하여 하나의 실행 파일을 만든다 • 예. median() 함수를 독립된 파일로 해 보자. • 파일 이름은 median.cpp와 median.h • (함수이름을 따는 것이 관례)

  36. 중앙값 계산 소스파일 - median.cpp median()이 필요로 하는 헤더를 모두 include // source file for the `median' function #include <algorithm> // to get the declaration of `sort' #include <stdexcept> // to get the declaration of `domain_error' #include <vector> // to get the declaration of `vector' using std::domain_error; using std::sort; using std::vector; #include "median.h” // compute the median of a `vector<double>' double median(vector<double> vec) { … } 컴파일러에게 이 위치에 median.h의 내용을 복사해서 넣어라는 의미 C++ 구현시스템이 제공하는 표준 헤더 < > 우리가 만든 헤더 ””

  37. 헤더 파일 median.h • 헤더파일에는 함수의 선언문 (프로토타입)만 적는다 • 헤더 파일에는 꼭 필요한 이름만 선언한다 • using 사용 자제해야한다. 왜? – 함수에서 using을 사용하지 않을수도 있음. • 초기 버전 • #ifndef 지시문을사용해서 정의해야한번 이상 include되어도 안전!! • 이렇게 하지 않으면 위험한가?왜? • 최종 버전 #include <vector> double median(std::vector<double>); // 함수 선언부에서 vector를사용하므로 #ifndef GUARD_median_h #define GUARD_median_h #include <vector> double median(std::vector<double>); #endif // 전처리기 변수

  38. 계속해 보자. • 이제 무엇을 묶을까? • 무엇이 남아 있나? • 자료 구조:Student_info • 함수: compare(), read(), read_hw(), 오버로드 된 grade()들 • 이들 각각을 하나의 파일로 할까? • 아니면 관련 있는 것들을 모아 하나로 할까? • Student_info와 관련 함수를 묶자 • Student_info • compare(), read(), read_hw(),

  39. Student_info 헤더 파일- Student_info.h • Student_info와 관련 함수를 묶자 #ifndef GUARD_Student_info #define GUARD_Student_info // `Student_info.h' header file #include <iostream> #include <string> #include <vector> struct Student_info { std::string name; double midterm, final; std::vector<double> homework; }; bool compare(const Student_info&, const Student_info&); std::istream& read(std::istream&, Student_info&); std::istream& read_hw(std::istream&, std::vector<double>&); #endif

  40. Student_info 소스파일 - Student_info.cpp // source file for `Student_info'-related functions #include "Student_info.h" using std::istream; using std::vector; bool compare(const Student_info& x, const Student_info& y) { return x.name < y.name; } istream& read(istream& is, Student_info& s) { … } istream& read_hw(istream& in, vector<double>& hw) { … }

  41. 따져 보자 • 이들을 하나로 묶은 것은 잘한 일인가? • 논리적으로 관련성이 있나? • compare()는 어떤가? • .cpp에 .h를 include하면, • .cpp 파일 안에 함수의 선언 (declaration)과 정의 (definition)를 모두 갖게 되는데, 적절한 일인가? • 이 구조체를 사용할 때에만 사용하는 함수들이므로구조체 정의와 함께 모아 놓는 것이 좋다 중복은 문제 될 것이 없다. 사실 좋은 아이디어다. 왜냐하면 컴파일러는 선언부와 정의부가 일치하는지 체크할 수 있기 때문. 불완전하다.

  42. 성적 계산 프로그램 – grade.h • 오버로드 된 grade() 함수를 한 눈 에 볼 수 있어서 좋다. • 왜 Student_info.h를 include했을까? #ifndef GUARD_grade_h #define GUARD_grade_h // `grade.h' #include <vector> #include "Student_info.h" double grade(double, double, double); double grade(double, double, const std::vector<double>&); double grade(const Student_info&); #endif

  43. 성적 계산 프로그램 – grade.cpp #include <stdexcept> #include <vector> #include "grade.h" #include "median.h" #include "Student_info.h" using std::domain_error; using std::vector; double grade(double midterm, double final, double homework) { … } double grade(double midterm, double final, const vector<double>& hw) { … } double grade(const Student_info& s) { … }

  44. 이제 main()을 완성하면 끝– main.cpp #include <algorithm> #include <iomanip> #include <ios> #include <iostream> #include <stdexcept> #include <string> #include <vector> #include "grade.h" #include "Student_info.h" int main() { vector<Student_info> students; Student_info record; string::size_type maxlen = 0; // the length of the longest name // read and store all the students' data. // Invariant: `students' contains all the student records // read so far, `maxlen' contains the length of the longest name in `students‘ while (read(cin, record)) { // find length of longest name maxlen = max(maxlen, record.name.size()); students.push_back(record); } • 주석문 다는 방법에 주목해 보자.

  45. // alphabetize the student records sort(students.begin(), students.end(), compare); // write the names and grades for (vector<Student_info>::size_type i = 0; i != students.size(); ++i) { // write the name, padded on the right to `maxlen' `+' `1' characters cout << students[i].name << string(maxlen + 1 - students[i].name.size(), ' '); // compute and write the grade try { double final_grade = grade(students[i]); streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec); } catch (domain_error e) { cout << e.what(); } cout << endl; } return 0; }

More Related