c__

Page 1

©copyright 2010

C++프로그래밍(CPA220)

교과목 소개

한국기술교육대학교 한국기술 육대학 컴퓨터공학부 김상진

강의목표 1학년에는 두 학기를 걸쳐 C언어를 통해 기초적인 프로그래밍 능력과 기술을 배양하였음. 이번 학기에는 C++ 언어를 통해 객체지향 프로그래밍 언어 언어를 학습함. 객체지향 프로그래밍의 원리 표준 C++ 문법 C++ 표준 라이브러리 사용법 프로그래밍 래밍 능력과 기술, 문제해결 능력을 한 단계 업 업그레이드함. 레이 함

2/9


강의정보 교수 정보 연구실: 제4공학관 B301호 전화번호: 교내 490 (041-560-1490) 전자우편: sangjin@kut.ac.kr 강의홈페이지: 강의홈페이지 el.kut.ac.kr http://infosec.kut.ac.kr/sangjin/class/cpp2010-01/ 교재 Walter Savitch, Absolute C++, 4th Ed., Addison Wesley, Wesley 2009 2009. 객체지향 원리로 이해하는 Absolute C++, 2판, 교보문고, 2009.

3/9

강의정보 – 계속 강의 평가 방법 출석: 5%, 실습/숙제: 10%, 프로젝트: 20%, 실습시험: 15%, 중간: 25%, 기말: 25% 참고. 바뀔 수도 있음 1시간 이상 지각할 경우 지각 처리함 합당한 사유를 사전에 통보하면 결석 처리하지 않음 결석할 경우에 경우에도 실습 내용을 숙제 숙제로 전부 제출해야 함 Pre-requiste C프로그래밍I, II (프로그래밍기초, 프로그래밍언어) 강의 준비물 강의 노트를 강의 홈페이지에서 다운받아 준비해야 함.

4/9


강의정보 – 계속 C++ 관련 추천 도서 H.M. Deitel, P.J. Deitel, C++ How to Program, 제4판(한글판), 피어슨에듀케이션코리아 2003 피어슨에듀케이션코리아, Scott Meyers, More Effective C++, Addison-Wesley, 1996. Scott Meyers, y More Effective C++, 2nd Ed., Addison-Wesley, y 1997. Bjarne Stroustrup, The C++ Programming Language, 3rd Ed., y, 2000. Addison-Wesley,

5/9

강의계획 1

강의소개/C++ 소개 강의소개

9

문자열

2

흐름 제어

10 포인터

3

함수 기초

11 파일 입출력

4

파라미터/오버로딩

12 상속/다형성

5

배열

13 실습시험

6

구조체/클래스/생성자

14 Template

7

연산자 오버로딩

15 예외처리/STL

8

중간시험

16 기말시험

6/9


설계 과제 설계 안내서 제공 2인 이하 (혼자 가능), 3인 이상 절대 불가 C++언어를 이용 가급적 객체지향적으로 설계해야 함. 강의 후반이 되어야 C++의 C 의 객체지향 요소를 배우기 때문에 C++의 고급 내용을 활용하는 것이 어려울 수 있음. 사용자 인터페이 인터페이스는 는중 중요하지 하지 않음 않음. 문제 정의와 문제를 해결하는 창의적 알고리즘이 있어야 함. 예) 엘리베이터 시뮬레이션 일정표 4주까지 주제 제안서 제출 중간고사 이후 중간보고서 제출 기말고사 이후 최종보고서 제출 및 결과시연 양식제공함 7/9

기타 Micrsoft Visual Studio 2008 반드시 이 컴파일러를 사용할 필요는 없음. 표준 C++를 지원하는 어떤 컴파일러도 사용 가능 예) eclipse와 cygwin(gnu g++)

8/9


이번 학기에는 프로그래밍언어 교육은 수업시간에 배우는 내용이 지속적으로 활용되기 때문에 결석하거나 그 수업에서 집중력이 떨어지면 다음 수업 내용을 이해하기 매우 어렵다. 어렵다 외우기 보다는 이해하도록 노력한다. 열심히 최선을 다한다. 다한다 수업시간에 능동적으로 참여한다. 어렵게 느끼더라도 포기하지 않는다. 모르면 반드시 물어본다. 숙제는 최대한 스스로 한다.

9/9


C++프로그래밍(CPA220) 강의노트 01

©copyright 2010

C C++ 기초

한국기술교육대학교 한국기술 육대학 컴퓨터공학부 김상진

강의목표 C++ 기초 C++ 언어 소개 변수, 표현식, 할당문(대입문) 콘솔 입출력 라이브러리와 namespace

2/55


C와 C++ 언어의 역사 1967년 M. Richard는 BCPL이라는 프로그래밍 언어를 개발하였음. 이 언어는 운영체제와 컴파일러를 개발하기 위해 개발되었음. 1970년 Bell Lab.의 K. Thompson은 BCPL을 모델링한 B라는 프로그래밍 언어를 개발함. Thompson은 이 언어를 이용하여 초기 UNIX 운영체제를 개발함. BCPL이나 B는 타입이 없는 언어임. 1972년 Bell Lab.의 D. Ritchie는 B를 확장한 C라는 프로그래밍 언어를 개발함. 범용 고급 프로그래밍 언어(하위 수준 언어의 기능 포함) C의 인기는 UNIX와 밀접한 관련이 있음 1989년에 년에 처음 처음으로 표준 준 C가 가 승인되어, 90년에 년에 발 발표됨. 됨 표준번호: ANSI/ISO/IEC 9899

3/55

C와 C++ 언어의 역사 – 계속 1980년 B. Stroustrup은 C를 확장하여 객체지향 프로그래밍이 가능하도록 한 C++라는 프로그래밍 언어를 개발하였음. C++는 C의 포함집합(superset)임. 객체지향 프로그래밍의 장점 코드의 재사용성 향상 기존에 개발된 클래스를 이용한 개발이 용이함. 실세계를 보다 다 가깝게 모델링할 델링할 수 있음 있음. C++ 표준: 1998년에 첫 표준이 발표됨. 표준번호: ANSI/ISO/IEC 14882

4/55


C++와 객체지향 프로그래밍 객체지향 프로그래밍의 3가지 핵심 요소 캡슐화: 데이터와 함수의 결합 상속: 코드의 획기적인 재사용 기존 클래스를 이용하여 새 클래스를 만들 수 있음. 다형성 이름의 재사용 다형성: C++는 객체지향을 지원하지만 순수 객체지향 언어는 아님. C를 확장한 언어임. 언어임 C++의 특징 함수와 연산자 오버로딩(재정의) 가능함. template 기능을 통한 범용 프로그래밍 가능함. 메모리는 프로그래머 스스로 관리해야 함. 예외 처리 기능 제공함. 제공함 (오류를 처리하는 또 다른 방법)

5/55

C++ 프로그래밍 환경 .cpp .cxx .cc 편집기

C++ 소스 코드

전처리

컴파일

전처리기 컴파일러 (preprocessor) (compiler)

object code 라이브러리 파일

링 링크

.exe

링커 (linker) 실행 파일

컴파일러는 소스코드를 기계어로 번역하는 프로그램임. 프로그램임 순차적으로 번역함. 번역을 쉽게 하기 위해 소스코드는 정해진 문법에 따라 작성되어야 함. 프로그래밍 언어의 문법은 비교적 쉽게 습득할 수 있음. 이 과목에서는 MS Visual Studio Vis al St dio 2008을 이용하여 실습함. 실습함 MS의 최신 개발 환경을 사용함. C++ 위주로 교육함. 이 과목에서는 표준 C 6/55


welcome.cpp // This is our first C++ Program #include <iostream> // This is our first C++ Program #include <iostream> using namespace std; int main(){ cout << "Welcome to C++!\n"; return 0; }

int main(){ std::cout << "Welcome to C++!\n"; C \ return 0; // This was our first C Program } #include <stdio.h> int main(){ printf("Welcome to C!\n"); return 0; }

C++는 자바와 마찬가지로 대소문자를 구별함. 즉, main과 Main은 다른 Thi is i our first fi t C++ Program P // This 식별자임. #include <iostream> using namespace std; void main(){ cout << "Welcome to C++!\n"; } 7/55

주석 주석 주석(comment): 컴파일러에 의해 번역되지 않는 부분 프로그램의 이해를 돕기 위해 프로그램에 대한 설명을 주석을 이용하여 첨가하며, 프로그램 문서화의 중요한 부분임. C++의 주석 // end-of-line end of line 주석 /* … */ C와 동일한 형태의 전통적인 주석 이 형태의 주석은 여러 줄을 걸쳐 작성할 수 있음. 문자열 자열 상수("…") 상 안에 등장하면 장하면 주석으로 석 간 되지 않음. 간주되지 않 대부분의 프로그램은 프로그램 주석이라고 하는 주석으로 시작함. 이 주석에는 프로그램의 용도, 작성자, 작성 날짜 등과 같은 정보를 포함함. /* File: welcome.cpp 주석 사용의 주의점 /* Programmed by Sangjin Kim (2010.3) */ 중첩된 주석은 허용하지 않음. 않음 *// 주석은 프로그램의 어떤 위치에도 추가할 수 있지만 프로그램의 가독성을 저해하는 위치에 추가하는 것은 바람직하지 않음 않음. 8/55


전처리기 지시자 // This is our first C++ Program #include <iostream> …

전처리기 지시자 지시자(preprocessor directives) 주목 일반 프로그래밍 문장은 ‘;’ 주목. ; 기호로 끝남. 끝남 따라서 위 문장은 일반 프로그래밍 문장이 아님. 전처리기(preprocessor)란 전처리기 처리기(p p 처리기 ) 컴파일러가 번역하기 역하기 전에 에 처리 처리한다는 다 것을 의미함. 즉, 소스코드를 전처리기가 처리한 다음에 그 결과를 컴파일러가 번역함. 전처리기 지시자들은 전처리기가 할 일을 가르쳐주는 문장으로서 ‘#’ 기호로 시작함. (C와 동일) #기호와 전처리문 사이에는 보통 공백을 사용하지 않음. #include는 무엇을 포함한다는 것을 의미함.

9/55

라이브러리 library라는 영어 단어는 보통 도서관을 뜻하지만 수집 도서/문서를 library라고도 함. 프로그래밍 언어에서 라이브러리는 다른 사람들이 만든 프로그램들의 모음(함수들의 모음, 클래스들의 모음)을 말함. 자주 사용하는 것을 매번 만들어야 한다면 번거롭다. 번거롭다 따라서 한번 만든 후에 동일한 용도가 필요하면 이미 만들어진 것을 다시 사용하고 싶다. 이것을 해주는 것이 라이브러리임. 표준라이브러리( t d d library)란 표준라이브러리(standard 표준라이브러리 lib )란 프로그래밍언어와 함께 제공되는 라이브러리를 말함. 다른 프로그래머가 래머가 만든 프로그램을 램을 내 프로그램에서 램에서 사용하 사용하고 싶으면 그것을 사용할 것이라는 것을 컴파일러에게 알려주어야 함. 이와 같은 정보가 제공되지 않으면 컴파일러는 제대로 번역할 수 없음. 없음 이 때 사용하는 것이 #include 전처리기 명령임.

10/55 10 /55


#include 문 C언어에서는 printf 함수를 이용하여 콘솔 출력을 수행하였음. printf 함수를 사용할 경우에는 이 함수와 관련된 정보를 컴파일러가 알아야 번역할 수 있음. 있음 이를 위해 C언어에서는 #include <stdio.h>라는 전처리기 문장을 사용하였음. C++도 동일한 용도로 #include 문을 사용함. C언어에서 사용했던 대부분의 기능을 C++ C++에서도 에서도 같은 용도로 그대로 사용함. 사용함. #include 문의 문법 #include <filename> 보통 시스템 라이브러리 헤더 파일을 포함할 때 사용 <> 내부에 보통 공백을 사용하지 않음 C와 달리 .h 확장자를 사용하지 않음 #include "filename" 보통 사용자가 직접 작성한 헤더 파일을 포함할 때 사용 이 경우에는 확장자를 사용함. (.hpp 확장자를 사용하기도 함) 실제로 두 문법은 헤더 파일을 찾는 순서만 다름. 11/55 11 /55

main 함수 C 프로그램은 함수들의 집합으로 구성되어 있으며, 이 중 main 함수가 가장 먼저 실행되며, 이 함수가 종료되면 프로그램도 종료됨. 함수는 특정한 작업을 수행하여 주는 목적으로 구성된 일련의 프로그램 문장들의 집합을 말함. 프로그램: 함수들의 집합 함수: 프로그램 문장들의 집합 함수는 입력 입력을 받아 처리 처리한 다음 출력 출력을 주는 것이 일반적임. 함수는 필요할 때마다 여러 번 호출하여 실행할 수 있어야 하므로 각 함수를 독특하게 구분할 수 있는 함수의 이름이 필요함. 함수를 정의할 때에는 입력부분, 입력부분 처리부분, 처리부분 출력부분을 각각 정의해야 하며, 함수 정의 형태는 다음과 같음. 반환값의유형 함수이름(형식매개변수목록){ 함수몸체 입력부분 } 처리부분

welcome.cpp는 pp main 함수만 수 하나 정의한 프로그램임. 여기서 main의 출력값은 정수타입, 입력은 없음.

출력부분

12/55 12 /55


main 함수 함수를 정의할 때 입력은 여러 개가 존재할 수 있지만 하나의 값만 출력할 수 있음. 컴파일러는 입력/출력되는 데이터가 어떤 유형(type)의 유형(t )의 값인지 알아야 함. 함 입력은 여러 개가 있을 수 있으므로 이들을 구별하여 int sum(int a, int b){ 사용하기 위해서는 각 입력마다 이름이 있어야 함. return a+b; }

모든 C++ 프로그램도 main 함수가 있어야 하며, C와 마찬가지로 프로그램이 었 때 처음으로 실행되는 함수가 main임. 실행되었을 int를 생략한 main(), int 대신에 void main()으로 사용하는 경우도 있지만 int main()이 가장 일반적인 형태임. 비고 main() 대신에 main(void)도 같은 의미임. 비고. 의미임 return 0; 함수에서 값을 반환할 때 사용하는 문장으로 main 함수에서 0을 반환하면 프로그램이 정상적으로 종료되었음을 나타냄. 나타냄 return이 반환하는 값의 유형을 함수의 반환값의 유형이 수용할 수 있어야 함. 13/55 13 /55

표준 출력 std::cout << "Welcome to C++!\n"; 이 문장은 화면에 "Welcome to C++!\n" 문자열을 출력하여 줌. C++도 ';'을 이용하여 문장의 끝을 나타냄. std::cout은 표준 출력(화면)을 나타내는 객체임. (객체지향언어) " td "의 의미는 cout은 "std::"의 t은 std td namespace에 에 정의되어 있음을 의미함. using g namespace p std;를 ;를 사용하면 std::cout 대신에 cout만 만 사용하여 프로그래밍할 수 있음. 비고.. cerr은 표준 오류를 나타내는 객체 비고 비고.. cout은 비고 t은 ostream t 클래스의 인스턴스임. 인스턴스임 C에서는 printf 함수를 사용하여 출력하였지만 C++에서는 객체를 이용하고 있음 이용하 있음. 문장의 형태도 함수를 호출하는 형태가 아님. << 연산자를 오버로딩(재정의)한 형태임. (어렵다!!!) 14/55 14 /55


표준 출력 <<: stream insertion 연산자 연산자로 사용된 부등호 문자의 방향을 유심히… 문자열을 cout로 두 개의 문자가 결합되어 연산자가 될 경우에는 두 문자 사이에 공백이 있으면 절대 안됨. 안됨 C++도 C와 마찬가지로 확장 문자열을 통해 표시할 수 없는 문자를 문자열에 내의 포함함. 예) \n, \t C++는 C를 포함하고 있으므로 printf를 사용하여 출력이 가능함. 다음은 coutt << "Welcome "W l to t C++!\n";와 C !\ " 와 결과가 같음. 같음 cout << "Welcome "; cout << "to to C++!\n C++!\n";;

cout << "Welcome " << "to C++!\n"; 평가 결과는 cout

<< 연산자의 결합순서는 왼쪽에서 오른쪽, 표현식의 평가값은 cout임. 15/55 15 /55

namespace namespace는 프로그램에 정의되는 여러 이름의 중복을 관리하기 위해 사용되는 개념 C에서는 헤더파일만 포함하면 되었지만 C++에서는 헤더파일을 포함하고 어떤 namespace에 이름이 정의되어 있는지 추가적으로 알려주어야 함 함. ‘::’: scope resolution operator 표준 라이브러리에서 사용하는 이름은 대부분 std라는 namespace에 에 정의되어 있음. 있음 특정한 namespace를 사용하고 싶을 경우 using이라는 문을 사용함. namespace에 있는 일부 이름만 // This is our first C++ Program 사용하고 싶을 경우에는 각 이름을 #include <iostream> 개별적으로 using 문을 통해 사용가능 using std::cout; 하도록 만들 수 있음. 있음 int main(){ 이 때 namespace는 사용하지 않음. cout << "Welcome to C++!\n"; return 0; } 16/55 16 /55


두 번째 프로그램 // This is our 2nd C++ Program // It adds two numbers #include <iostream> using namespace std; int main(){ int n1, n2, sum; cout << "Enter first number: "; cin >> n1;; cout >> "Enter second number: "; cin >> n2; total = n1+n2; cout >> n1 >> "+" >> n2 >> "=" >> sum >> endl; return 0; }

// This was our 2nd C Program #include <stdio.h> int main(){ int n1, n2, sum; printf("Enter first number: "); scanf("%d", &n1); printf("Enter second number: "); ( , &n2); ); scanf("%d", total = n1+n2; printf("%d+%d=%d\n", n1, n2, sum); return 0; }

17/55 17 /55

cout를 이용한 표준 출력 cout << n1 << "+" << n2 << "=" << sum << endl; 한 문장에 다양한 타입의 데이터를 출력하고 있음. 함수 오버로딩의 특징 (나중에 설명) endl: “end line”의 약자로서 cout에 출력되면 newline을 출력하고 사용하는 버퍼를 비움. 비움 cout << '\n'과 cout << endl의 차이는 후자는 추가로 버퍼까지 비움.

18/55 18 /55


식별자 식별자(identifier): 프로그램 내에서 사용자가 정의하는 이름 예) 변수 이름, 함수 이름, 클래스 이름 등 C++는 대소문자를 구분함(case-sensitive). 식별자 규칙 알파벳 문자, 문자 숫자, 숫자 밑줄문자(‘_’)로 밑줄문자(‘ ’)로 구성됨. 구성됨 숫자로 시작할 수 없음. 밑줄 문자로 시작하는 이름은 가급적 사용하지 않는 것이 좋음. 좋음 식별자의 길이는 제한이 없으나 31문자 이내로 사용하는 것이 호환성에 좋음. C++의 키워드(예 예: int)를 식별자로 사용할 수 없음. C++ 표준 라이브러리에서 사용하는 이름은 식별자로 사용하지 않는 것이 바람직함. 예) cout, cin 대소문자가 구분되더라도 동일 프로그램에서 대소문자만 다른 식별자를 사용하는 것은 바람직하지 않음. 19/55 19 /55

식별자 식별자는 의미가 있도록 명명해야 함.

x = y*z; distance = speed*time; p ;

식별자의 종류마다 구분될 수 있도록 특정한 규칙을 정하여 명명하는 것이 좋음. 낙타표기법(camel case): 여러 단어를 이용하여 식별자를 만들 때 각 단어의 첫 문자만 대문자로 사용하는 표기법. 예) printInteger 변수: 소문자로 시작, 낙타표기법. 예) studentNumber 함수: 소문자로 시작, 낙타표기법. 예) printInteger 함수 이름은 함수 호출에 사용되며, 함수 호출 연산자인 괄호를 통해 변수와 구분됨. 구분됨 예) printf( printf("\n"); \n ); 상수: 모두 대문자. 예) PI 클래스 이름(새 타입 이름) 클래 이름): 대문자 대문자로 시작 . 예) Student

20/55 20 /55


데이터 프로그램을 작성하기 전에 반드시 분석해야 하는 것 중 하나는 이 프로그램에서 어떤 데이터가 필요한지 분석하는 것임. 프로그램에서 사용되는 데이터는 크게 상수 상수(constant)와 변수 (variable)로 구분될 수 있음. 상수: 프로그램이 실행되는 동안 변하지 않는 값 변수: 프로그램이 실행되는 동안 값이 변할 수 있는 데이터 프로그램에서 필요한 데이터의 종류는 다양하며, 데이터의 종류를 자료유형 또는 타입 타입(type)이라 함. 학생의 나이를 기록할 때에는 정수가 필요하고, 학생 성적의 평점을 기록할 때에는 실수가 필요하고, 필요하고 'F'와 같은 문자 데이터, "KUT"와 같은 문자열 데이터도 필요함. C++ 언어 언어도 C와 와 마찬가지 마찬가지로 이런 데이터를 표현하기 현하기 위해 몇 가지 기본 자료유형을 제공함. 문자형, 정수형, 부동소수형, 문자열형 21/55 21 /55

변수 long

변수 어떤 값을 저장하는 곳 변수: int 컴퓨터에서 값이 저장되는 곳은 주기억장치 프로그램 과정에서 데이터를 일시적으로 보관하기 위해 사용함. 일시적으로 저장한다는 것은 나중에 다시 사용한다는 것을 말함. 따라서 저장하는 값마다 이름을 할당해야 그것을 나중에 접근할 수 있음. 이 이름을 변수 이름 이름이라 한다 한다. 변수를 사용하기 위해서는 먼저 변수를 선언해야 하며 하며, 이 때 어떤 종류의 데이터를 저장할 것인지(자료유형 자료유형), 그리고 이 데이터를 어떤 이름(변수이름 변수이름)으로 접근할지를 알려주어야 함. sum

22/55 22 /55


자료유형 자료유형은 다음 두 가지 특성에 의해 정의됨. 도메인: 어떤 한 자료유형이 가질 수 있는 값들의 집합 자료유형에 적용할 수 있는 연산들의 집합 자료유형에 따라 필요한 공간의 크기가 다르며, 크기에 의해 자료유형에 저장할 수 있는 값의 범위가 결정됨. 결정됨 예) 크기가 1바이트이고 양의 정수만 저장한다면 0에서 255까지만 저장할 수 있음. 정수형 타입에는 곱셈이라는 연산이 존재하지만 문자형의 경우에는 의미가 없는 연산임. 정수형과 부동소수형은 모두 나눗셈 연산을 가지고 있지만 그것의 평가 방법은 다름. 예) 3/2 = 1, 3.0/2.0 = 1.5 어떤 연산을 데이터에 적용하기 전에 해당 연산이 적용하고자 하는 자료유형에 정의되어 있는지 있다면 어떤 기능을 수행하는지 알고 있어야 함. 23/55 23 /55

기본 자료유형 문자형 정수형

정수형

부동소수형 불형 형

char

signed char

unsigned char

[signed] short [int]

[signed] [int]

[signed] long [int]

unsigned short [int]

unsigned int

unsigned long [int]

float

double

long double

bool

char와 bool은 정수값을 유지할 수 있으며, 메모리를 절약하기 위해 char를 이용하여 정수값을 유지하고 계산하는 경우도 있음. 하지만 바람직한 방법은 아님. 은 false로 나머지는 나머지 bool 타입에 정수값을 대입할 경우 정수값 0은 모두 true로 유지됨. 거꾸로 bool 변수를 정수에 대입하면 1(true) 또는 0(false)이 저장됨.

24/55 24 /55


signed vs. unsigned signed와 unsigned의 차이 signed는 음수/양수를 모두 나타낼 수 있지만 unsigned는 양수만 나타냄. 부호가 있는 경우에는 첫 비트는 부호 비트로 사용해야 하며, 양수만 표현할 경우에는 부호 비트가 필요 없음. 없음 따라서 4비트로 수를 표현하면 signed(2의 보수)는 –8에서 7, unsigned는 0에서 15까지 표현할 수 있음. unsigned을 사용하고 싶을 경우에만 unsigned를 사용한고, signed는 주로 생략함. 따라서 정수형들은 기본형과 unsigned형 두 가지만 기억하면 됨. 됨

25/55 25 /55

기본 자료유형의 크기 보통 char는 1 byte, short는 2 byte, int는 4 byte, long은 4 byte 이상이다. 하지만 컴파일러마다 차이가 있을 수 있다. 하지만 다음은 항상 성립함. 성립함 sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) 정수형에서 기본이 되는 형은 int임. int임 보통 float는 4 byte, double는 8 byte, long double은 8 byte 이상이다. 하지만 컴파일러마다 차이가 있을 수 있다. 하지만 다음은 항상 성립함. 성립함 sizeof(float) ≤ sizeof(double) ≤ sizeof(long double) 부동소수형에서 기본이 되는 형은 double임. double임

26/55 26 /55


자료유형 관련 주의점 오버플로우(overflow) 특정한 자료유형은 고정된 크기의 공간을 사용하므로 변수에 저장할 수 있는 값의 범위는 제한적임. 예) unsigned char 변수의 크기는 보통 1 byte이므로 이와 같은 변수에는 0에서 255까지의 값만 유지할 수 있음. 있음 unsigned char n1 = 200; unsigned char n2 = 100; n1 1 = n1 1 + n2; 2

하지만 n1에는 크기 제한 때문에 이 저장될 수 없다 없다. 300이

이와 같이 유지할 수 있는 값보다 큰 값을 저장하고자 할 때 발생하는 현상을 오버플로우 오버플로우(overflow)라 함. 함 C++ 언어는 자료유형에 대해 엄격한 언어가 아님. 따라서 오버플로우가 버플 우가 일어나면 오류가 류가 발생하지 않 않고,, 현재 형이 수용할 수 있는 형태로 바뀜. (경고를 발생하여 주는 경우도 있음) 예) 300의 이진형태 100101100이므로 n1에 실제 저장되는 값은 00101100 = 44임 44임. 27/55 27 /55

자료유형 관련 주의점 정수형들을 사용할 때에는 오버플로우만 걱정하면 되지만 부동소수형들을 사용할 때에는 언더플로우 언더플로우(underflow)도 걱정해야 함. 언더플로우: 0과 가까운 매우 작은 수를 나타낼 수 없는 현상 하지만 부동소수형을 사용할 때 가장 주의해야 하는 것은 round round--off 오류임. 오류임 예를 들어 8비트를 이용하여 부동소수를 표현한다고 가정하면 256개의 다른 소수값 밖에 나타낼 수 없음. 즉, 특정 소수값의 표현은 불가능하며, 가장 가까운 값으로 대신 표현할 수 밖에 없으며, 이 차이에 의해 발생하는 오류를 류라 함 함. round-off 오류라

28/55 28 /55


변수 선언 선언(declaration) 위치: 함수 외부 또는 함수 내부 함수 외부에 선언된 변수: 전역 변수 변수(global variable) 함수 내부에 선언된 변수: 지역 변수 변수(local variable) 클래스 내부에 선언된 변수: 멤버 변수 함수 내부에 변수를 선언할 때 선언 위치: 위치 제한 없음. 없음 C언어: 블록 시작 부분에서만 선언 가능하며, 변수를 선언하는 문장이 아닌 다른 문장이 기술된 이후에는 선언할 수 없음 없음. 변수 선언 문법 typename variablename; sum 예) int sum; 동일 유형의 여러 개의 변수를 동시에 선언할 수도 있음. 예) int sum, sum n1 n1, n2; 하지만 한 줄에 하나의 변수만 사용하며, 변수의 용도를 주석처리 하는 것이 가장 좋은 변수 선언 방법임. 29/55 29 /55

변수 초기화 변수는 선언과 동시에 초기화할 수 있음. 즉, 값을 선언과 동시에 저장할 수 있음. 문법 1. typename variablename = expression; 문법 2. typename variablename(expression); sum 예) int i t sum = 0; 0 예) int sum(0); 변수를 선언한 후에 나중에 대입문을 이용하여 초기화할 수 있음. 있음 하지만 두 가지 방법의 차이가 프로그램에 영향을 주지 않으면 선언과 동시에 초기화하는 것이 효율적임. 예) int sum; sum = 0;

초기화하지 않은 변수에는 어떤 값이? 예) int sum; cout << sum;

변수의 종류에 따라 다르지만 지역변수가 초기화되지 않은 경우에는 이 변수가 초기에 어떤 값을 가지게 될지는 알 수 없음. Visual Studio 환경에서는 경고를 주며, 실행하면 실행시간 오류를 발생함. 발생함 30/55 30 /55


가시영역 변수는 선언된 이후에만 사용할 수 있음. (번역이 순차적…) 선언된 줄 이후부터 사용할 수 있음. C++는 변수 선언 위치에 대한 제한이 없지만 프로그램에 가독성을 저해하는 위치에는 선언하지 않는 것이 바람직함. 지역변수는 그것이 선언된 함수 내에서만 사용할 수 있음. 있음 변수가 사용될 수 있는 범위를 가시영역 가시영역(scope)이라 함. 사용할 수 있는 범위가 같은 영역에 같은 이름의 변수를 선언할 수 없음.

31/55 31 /55

표현식 표현식 표현식(expression): 항(term)과 연산자 연산자(operator)로 구성된 식을 말하며, 표현식은 평가(evalutate)되어 어떤 결과 값을 주게 됨. 항이 될 수 있는 것 3+6 상수, 변수, 함수 호출, 괄호로 된 표현식 n+2 산술 연산자 ((보통 이항연산자)) sqrt(2) + 3.5 (4+2) / 3 +: 덧셈 (단항연산자로 사용 가능) –: 뺄셈 (단항연산자로 사용 가능) *: 곱셈 /: 나눗셈 (정수 나눗셈과 부동소수 나눗셈의 의미가 다름) %: 나머지 (두 피연산자가 모두 양의 정수) 비교 연산자: >, >=, <, <=, ==, != 논리 연산자: &&, ||, ! 대입 연산자: = =, += +=, -=, -= *= =, /= /=, %=

32/55 32 /55


평가방법 표현식의 평가에 있어 중요한 것은 연산자의 우선순위 우선순위(precedence) 와 결합순서 결합순서(associativity)임. 표현식 a+b*c는 a+(b*c)와 같이 평가됨. 즉, + 연산자보다 * 연산자가 우선순위가 높음. 두 개의 연산자가 공통되는 피연산자를 가지면 우선순위가 높은 연산자부터 평가됨. 표현식 a*b*c는 (a*b)*c와 같이 평가됨. 첫 번째 * 연산자와 두 번째 * 연산자는 모두 b라는 공통된 피연산자를 가짐. 따라서 우선순위를 고려해야 하는데, 동일한 연산자이므로 우선순위가 같음. 같음 우선순위가 같으면 결합순서에 따라 평가방법이 결정됨. 결합순서란 평가하는 순서 방향을 말함. * 연산자는 왼쪽에서 오른쪽으로 평가됨.

33/55 33 /55

연산자 우선순위와 결합순서 C와 동일 알기 쉬운 연산자 우선순위 단항 연산자가 이항 연산자보다 우선순위가 높음. 산술 연산자 중에는 곱셈 계열의 연산자가 덧셈 계열의 연산자보다 우선순위가 높음. 높음 산술 연산자 > 관계 연산자 > 논리 연산자 > 대입연산자 알기 쉬운 결합순서 단항 연산자는 대부분 오른쪽에서 왼쪽으로 이항 연산자는 대부분 왼쪽에서 오른쪽으로 이항 연산자 중 대입 연산자는 오른쪽에서 왼쪽으로

34/55 34 /55


대입문 대입문(assign statement)은 변수에 값을 저장하기 위해 사용하는 프로그램 문장을 말함. sum = n1+n2; variable = expression; l-value = expression; 대입 연산자 오른쪽에 있는 표현식을 평가하여 결과 값을 왼쪽 변수에 저장함. 따라서 대입문 왼쪽에 반드시 변수가 와야 한다. 한다 보다 다 정확하게 표현하면 현하면 l-value가 가 와야 함. 함 대입문 자체도 표현식이며, 대입되는 값이 평가의 결과 값이 됨. 예) n = ((m = 2); ); 예) n = m = 2; 두 개의 = 연산자는 m이라는 공통 피연산자를 가지고 있음. 동일 연산자이므로 결합순서에 의해 평가 순서가 결정됨. 결정됨 = 연산자의 결합순서는 오른쪽에서 왼쪽 왼쪽이다. 즉, m = 2가 먼저 평가됨. 35/55 35 /55

대입 연산자 – 계속 예)

int n; n = 5.5;;

// n = 5

대입식에서 왼쪽 평가 결과의 자료유형과 오른쪽 변수의 자료유형은 기본적으로 같아야 바람직함. 바람직함 하지만 다를 경우에는 왼쪽 평가 결과 값이 자동으로 오른쪽 타입으로 변환됨. 이 때 정보손실이 발생 발생할 수도 있음. 만약 자동으로 변환할 수 없는 경우에는 오류가 발생함. 예) int n; n = "abc"; // error

이항 연산자의 두 피연산자 타입이 다르면 정보손실이 발생하지 않도록 하나의 타입을 다른 타입으로 바꾼 후에 연산을 수행함. 수행함 예5.8) 5/2.5  5/2가 아니고 5.0/2.5 36/55 36 /55


약식 대입 연산자 대입 표현식을 축약하여 주는 약식 대입 연산자를 제공함. variable = variable operator expression  variable operator= expression 예) +=, -=, *=, /=, %= 비고.. 약식 대입 연산자를 사용하면 보다 빠른 코드를 생성하는 비고 컴파일러도 있음. 약식 대입 연산자는 대입 연산자와 같은 우선순위를 가지며, 대입 연산자와 마찬가지로 결합순서는 오른쪽에서 왼쪽임. 예) a1 += a2 += a3 + 2; int a1 = 2, a2 = 3, a3 = 4; a1 += a2 += a3 + 2; // a1 = 11, a2 = 9, a3 =4

+는 는 += 보다 다 우선순위가 높음 높음. +=의 결합순서는 오른쪽에서 왼쪽임. a1 += (a2 += (a3+2));

a1 += a2 += 4 + 2;; a1 += a2 += 6; a1 += a2 = a2 + 6; a1 += a2 = 3 + 6; a1 += a2 = 9; a1 += 9; a1 = a1 + 9; a1 = 2 + 9;; a1 = 11; 37/55 37 /55

타입 변환 한 타입의 데이터가 다른 타입으로 변환하는 것을 타입 변환이라 함. 타입 변환은 크게 자동 타입 변환과 강제 타입 변환으로 구분됨. 자동 타입 변환이 일어나는 곳 경우 1. 산술 연산: 예) 1+3.2  1.0 + 3.2 이 경우에는 정보 손실이 없게 타입 변환됨. 변환됨 이것을 확장변환 확장변환(widening conversion, promotion)이라 함. 경우 2. 대입 연산: 예) int n = 3.5; // n에 정수 3이 대입됨. 대입연산의 경우에는 확장변환이 일어날 수도 있지만 위 예처럼 축소변환(narrowing conversion, demotion)이 일어날 수 있음. 축소변환 Visual Studio 2008에서는 에서 경 경고가 가 발생함 발생함. 경우 3. 함수 호출에서 인수 전달 (추후에 설명함) 경우 4. 함수에서 값 반환 (추후에 설명함) 경우 2부터 4는 목적 타입으로 타입 변환되며, 변환되며 이 때 정보 손실이 발생할 수 있음. 자동 타입 변환이 가능하지 않으면 오류가 발생함. 38/55 38 /55


강제 타입 변환 나눗셈 연산의 경우에는 종종 강제 타입 변환이 필요함. 예) int n = 9, m = 2; double f = n/m; // 4.0 C++에서도 C에서 사용하던 방법을 사용할 수 있음. 예) double f = n/(double)m; 하지만 C++에서는 다음과 같은 형태를 사용하는 것이 올바른 방법임. 예) double f = n/static_cast<double>(m); ( ); C++에서 가능한 타입 변환 메커니즘 static_cast<type>(expression) const_cast<type>(expression) // 상수와 관련 dynamic_cast<type>(expression) // 상속에서 사용 reinterpret cast<type>(expression) reinterpret_cast<type>(expression)

39/55 39 /55

상수 상수 상수(constant): 변하지 않는 값을 상수라 함. 보통 자료값 자체를 프로그램에 직접 표현하면 이들은 모두 상수로 간주됨. 예) int sum = 0; 여기서 0은 정수 상수 값 동일한 상수를 여러 번 사용할 경우에는 값 자체를 직접 표현하지 않고, 상수에도 이름을 할당하여 값 대신에 이름을 사용할 수 있음. 이 방법의 장점 가독성 향상 수정 용이 및 오류 방지

40/55 40 /55


상수 – 계속 정수 상수 보통 10진수로 표현하지만 8진수 또는 16진수로 표현 가능 8진수는 앞에 '0'을, 16진수는 앞에 "0x" 또는 "0X"를 붙임. 예) 10, 012, 0xA U 또는 u 접미사: 접미사 unsigned i d 타입의 상수 정의 L 또는 l 접미사: long int 타입의 상수 정의 부동소수점 상수 일반적인 표기법과 과학적 표기법 두 가지 방법으로 표현 가능 예) 2.9978, 2.99E-2(=0.0299), 7E+2 접미사를 사용하지 않는 부동소수점 상수는 double 타입임. F 또는 f 접미사: float 타입의 상수 정의 L 또는 l 접미사: 접미사 long l double d bl 타입의 상수 정의

41/55 41 /55

상수 – 계속 문자열 상수: 큰 따옴표를 붙여 표현 예) "KUT" 문자열 상수는 끝에 null 문자 '\0'(=0)를 포함함. 문자열 상수들은 컴파일 시간에 결합할 수 있으며, 이 기능은 긴 문자열을 여러 줄에 걸쳐 작성하는데 널리 사용됨. 사용됨 예) "한기대 " "컴퓨터공학부"와 "한기대 컴퓨터공학부"는 같다. 문자 상수: 작은 따옴표를 붙여 표현 예) 'K' 'K'와 "K"는 큰 차이가 있다. 있다 전자는 단일 문자이며, 문자이며 후자는 단일 문자로 구성된 문자열임. bool 타입 상수 상수: true,, false

42/55 42 /55


세 번째 프로그램 // This is our 3rd C++ Program p new balance after // It computes #include <iostream> using namespace std; int main(){ const double RATE = 4.5; unsigned int deposit; cout << "입금액: 입금액 ";; cin >> deposit; unsigned int newBalance; newBalance = deposit + static_cast<int>(deposit*(RATE/100)); cout << "1년 후 금액: " << newBalance << endl; return 0; }

43/55 43 /55

상수 변수 C++에서는 const 키워드를 이용하여 상수 변수를 선언함. 예) const double PI = 3.14159; PI는 프로그램 내에서 다른 값을 가지도록 변경할 수 없음. C처럼 define 전처리기문을 이용할 수 있다. 예) #define #d fi PI 3 3.14159 14159 #define은 전처리기에 의해 처리되므로 타입 검사가 이루어지지 않지만 const 변수는 타입 검사가 이루어짐 이루어짐. const 변수는 상수 값이 저장되는 공간이 필요하지만 #define은 별도 공간을 사용하지 않음. 상수는 보통 모두 대문자를 이용하여 정의함. 정의함

44/55 44 /55


산술연산자 산술 연산자의 종류: 모두 이항 연산자 연산자

피연산자 유형

+

정수/부동소수

-

정수/부동 수 정수/부동소수

*

정수/부동소수

/

정수/부동소수

%

정수

비고

두 피연자가 모두 정수일 경우에만 정수 나눗셈을 함

정수 나눗셈과 부동소수 나눗셈 예) 3/4 = 0 예) 3/2.0 = 1.5 % 연산자는 두 피연산자가 모두 양의 정수일 때 그 해석이 명확함. 명확함 두 피연산자 중 하나가 음수이면 그 결과는 컴파일러마다 다를 수 있음 있음. 45/55 45 /55

증감연산자 정수/부동소수형 변수 값을 1 증가 또는 감소시킬 때 약식 대입 연산자 보다 축약하여 사용할 수 있는 단항연산자인 증감연산자가 있음. ++는 피연산자를 1 증가시키고 --는 피연산자를 1 감소시킨다. 예) x++;는 x += 1; 그리고 x = x+1;과 같다. 이 연산자는 피연산자 앞에 올 수도 있고(전치(prefix)형태), 있고(전치(prefix)형태) 뒤에 올 수 도(후치(postfix)형태) 있음. 그러나 그것의 의미와 우선순위는 다름 예) int x, x y y, z; int n, n y, y z; x = 3; y = 1 + x++; z = x; // x = 4, y = 4, z = 4

x = 3; y = 1 + ++x; z = x; // x = 4, y = 5, z = 4

피연산자가 뒤에 오면 평가값은 1 증가 증가//감소하기 이전 값이 되며, 피연산자가 앞에 오면 면 평가값은 1 증가 증가//감소한 감 한 값이 됨 됨. 피연산자는 그것의 위치와 관계없이 다음 시퀴언스 포인트 (sequence point) 전에 1 증가 증가//감소 감소함. 46/55 46 /55


증감연산자 – 계속 장점: 코드의 간결화와 속도 향상 단점: 가독성을 저해할 수 있으며, 피연산자의 위치에 따라 평가 방법이 다르기 때문에 주의해야 함. 예) 출력값

변수 x 값

출력값

변수 x 값

int x = 10;

10

int x = 10;

10

x = x + 1;;

11

x++;;

11

x = x – 1;

10

--x;

10

cout << x+1 << endl;

11

10

cout << x++ << endl;

10

11

dl coutt << x << endl;

10

10

dl coutt << ++x << endl;

12

12

cout << x–1 << endl;

9

10

cout << x-- << endl;

12

11

cout << x << endl;

10

10

cout << --x << endl;

10

10

예) 여기서 잠깐! a---b는 어떻게 해석? a-- - b로 해석됨. 큰 입 떼어먹기( 떼어먹기(maximal munch)) 규칙 47/55 47 /55

증감연산자 – 계속 시퀴언스 포인트 포인트란 프로그램 실행 위치 중 위치 전에 등장한 모든 부작용(side-effect)의 실행이 완료되어 있어야 하는 위치를 말함. 부작용이란 표현식의 평가과정에서 변수의 값이 변경되는 것을 말함. 증감연산자는 부작용이 있는 대표적인 연산자임. 대표적인 시퀴언스 포인트는 현 프로그램 문장의 실행이 종료된 후를 말함. 지금 시점에서는 다음 프로그램 문장이 실행되기 전에 값이 증가 또는 감소된다고 생각하면 됨. 증감연산자는 하나의 정수 또는 부동소수형 변수를 피연산자로 가져야 함. 함 예) int x, y, z; x = 3; y = ++(x+1); z = 300++;

// error // error

48/55 48 /55


증감연산자 – 계속 독립적으로 사용할 경우에는 전치형태를 사용하는 것이 바람직함. 예) int x; int x; x = 3; x++;

x = 3; ++x; // more efficient, 별로 중요하지 않음

복잡하게 사용하지 마라. 마라 프로그래머의 스타일에 따라 다르지만… 다르지만 예) int x, y, z; x = 3; 3 y = ++x * x++; //?

그러면 왜 알아야 하나? 다른 사람이 작성한 코드를 이해하기 위해

49/55 49 /55

형식화된 출력 C에서는 printf를 사용하여 형식화된 출력을 할 수 있었음. C++에서 cout를 사용할 경우에는 printf를 사용할 때보다 약간 복잡함. 방법1. 방법 1. ostream에 정의된 멤버함수를 이용하는 방법 방법2 방법2. 방법 2 manipulator를 이용하는 방법 2. #include <iostream> using namespace std; int main(){ double f = 12.347; 12 347; cout.setf(ios::fixed); cout.precision(2); cout << f << endl; return 0; }

#include <iostream> #include <iomanip> using namespace std; int main(){ double f = 12.347; cout << fixed << setprecision(2) << f << endl; return 0; }

방법2

방법1

50/55 50 /55


형식화된 출력 대부분 한번 설정하면 그것을 해지할 때까지 계속 적용됨. 예외. width cout이 객체이기 때문에 가능 형식화된 출력을 위해 많이 사용하는 멤버함수 setf: tf 독립적인 플래그 설정 flags: 정수의 진수, 부동소수 표기법, 정렬방식 관련 플래그 설정 unsetf: 설정된 플래그를 해지 precision: 소수점 아래 출력의 정확도 width: 출력의 최소폭 fill: 채움문자 설정

51/55 51 /55

형식화된 출력 관련 플래그 상수

설정되었을 때 효과

b l l h boolalpha

b l 변수의 값을 true와 bool t 와 false로 f l 로 출력

showbase

정수 출력에서 진법에 따른 접두사를 출력함 (예: 0xA5)

showpoint

부동소수를 출력할 때에는 항상 소수점 출력 (예: 12.00)

showpos

양의 수를 출력할 때 +기호 출력

정수 진법 basefield

dec

10진수로 출력

hex

16진수로 출력

oct

8진수로 출력

부동소수 표기법 floatfield

fixed

정렬방식 adjustfield

left

독립 플래그

scientific

right

과학적표기법 (예: 1.825e-5)

독립 플래그는 setf를 이용하고 나머지는 flags을 이용 예) cout.setf(ios::showpoint); 예) cout.flags(ios::fixed); g ( );

(예: 000015)

52/55 52 /55


형식화된 출력 예 double n = 12.358; cout.flags(ios::fixed); cout.precision(2); cout precision(2); cout.width(6); cout << n << endl;

출력결과: _12.36 즉, 총 6 공간을 사용하여 출력하며, 반올림하여 소수점 2자리까지만 출력함. 출력함 정렬 방식을 지정하지 않았으므로 기본적으로 오른쪽으로 정렬되어 출력됨. ios::fixed의 의미: ios 클래스에 정의된 상수를 나타냄. 비고. ios는 std와 달리 namespace가 아님. 즉, :: 연산자는 여러 가지 용도로 사용됨. 출력결과: 12.36_ 12 36 비트논리합연산자를 이용하여 여러 개 플래그를 동시에 설정할 수 있음.

double n = 12.358; 12 358; cout.flags(ios::fixed|ios::left); cout.precision(2); ( ); cout.width(6); cout << n << endl; double n = 12.0; coutt << n << endl; dl

출력결과: 12 fi d를 설정하지 않으면 소수점 부분을 생략하고 fixed를 출력함.

53/55 53 /55

형식화된 출력 예 int n = 25; cout.flags(ios::hex); cout << n << '\n'; \n ; cout.setf(ios::showbase); cout << n << endl; int number = 12345; cout.fill('0'); cout.width(10); cout << number << '\n'; \n ; cout.width(10); cout.flags(ios::left); cout.setfill('%'); cout << number << endl;

출력결과: 19 0x19

출력결과: 0000012345 12345%%%%%

54/55 54 /55


cin 객체를 이용한 입력 C에서는 scanf 함수를 이용하여 입력 받았음. 이 때 주소연산자 &를 사용하였음. 예) scanf("%d", &n); C++에서는 cin 객체를 이용하여 키보드로부터 데이터를 입력 받음. cin은 표준 입력(키보드)을 나타내는 객체임. >>: stream t extraction t ti 연산자라 함. 함 하지만 C와 달리 주소연산자를 사용하지 않음. 예) cin >> n; cout과 마찬가지로 다양한 타입을 한 줄에 섞어 입력 받을 수 있음. 있음 double weight; int age; cout << "나이와 나이와 무게를 입력하시오: ";; cin >> age >> weight;

55/55 55 /55


C++프로그래밍(CPA220) 강의노트 02

©copyright 2010

흐름 제어

한국기술교육대학교 한국기술 육대학 컴퓨터공학부 김상진

강의목표 비교연산자, 논리연산자 단축계산 조건문: if, switch, 조건연산자 반복문: while, do while, for b break와 k와 continue ti 열거형 타입: enum

2/34


비교연산자 불 표현식(boolean expression)이란 평가 결과 값이 true/false인 표현식을 말함. 가장 간단한 불 표현식: 비교연산자를 이용한 비교식 비교연산자는 모두 이항 연산자이며 결과가 참이면 1, 거짓이면 0으로 평가됨. 평가됨 C++ 언어에서 0은 false를 의미하며, 0 이외에 모든 수는 true로 인식됨. 연산자

피연산자

>

정수/부동소수

<

정수/부동소수

==

정수/부동소수

!=

정수/부동소수

>=

정수/부동소수

<=

정수/부동소수

비고

= 연산자와 혼동하지 않도록 주의해야 한다.

3/34

논리연산자 논리연산자는 여러 개의 비교식을 결합하여 다양한 조건을 나타내는 불 표현식을 만들기 위해 사용됨. 예) x는 100보다 크지만 200보다 작아야 함. 첫 번째 조건: x>100 두 번째 조건: x<200 두 조건을 동시에 만족해야 하므로 논리곱: x>100 && x<200 C++ 언어는 논리곱 &&,, 논리합 ||, 논리부정 !,, 세 개의 논리연산자를 제공함. 논리곱과 논리합은 이항 연산자이며, 논리부정은 단항 연산자임. 논리곱은 두 피연산자의 값이 모두 참일 때에만 참으로 평가됨. 평가됨 논리합은 두 피연산자의 값이 모두 거짓일 때에만 거짓으로 평가됨. 논리부정은 피연산자 앞에 붙으며, 피연산자의 값의 반대로 평가됨.

4/34


논리연산자 C++ 언어에서 논리곱과 논리합 연산자는 왼쪽 피연산자를 항상 먼저 평가함. 이 때 왼쪽 피연산자의 평가값에 따라 오른쪽 피연산자를 평가하지 않아도 전체 표현식의 결과가 정해지면 평가가 중단됨. 이와 같은 평가 방식을 단축 계산 계산(short short--circuit evaluation)이라 short evaluation 함 함. 단축 계산의 반대는 완전 계산(complete evaluation)이라 함. 예) x, y, z가 정수 변수일 때 (x != 0) && (z = y/x); 위 표현식은 (x != 0) 부분을 먼저 평가하게 됨. x가 가 0이면 (x ( != ! 0)의 평가값은 거짓이므로 전체식은 (z ( = y/x)의 / )의 평가값과 상관없이 거짓이 됨. 따라서 (x != 0)을 평가한 후에 이 표현식의 평가는 종료됨. 즉, (z = y/x) 부분은 평가되지 않음. 이와 같은 형태로 평가되기 때문에 &&와 ||은 시퀴언스 포인트가 됨.

5/34

논리연산자 예) int x, y, z; x = 0; y = 0; z = x++ || (y=x);

// x = 1, y = 2, z = 1

예) 정수 변수 x가 가 0과 10사이인지 검사하는 표현식을 0<=x<=10 위처럼 잘못 코딩할 수 있지만 0< 0<=x<=10은 x< 10은 문법적 오류는 아님. 아님 <= 연산자는 왼쪽에서 오른쪽 방향으로 평가됨. 따라서 0<=x<=10은 (0<=x)<=10과 같음. x가 0보다 크면 (0<=x)은 참이므로 평가값은 1이 되며, 반대로 x가 0보다 작으면 (0<=x)은 거짓이므로 평가값은 0이 된다. 따라서 (0<=x)<=10은 항상 참이 됨. 됨 이 예는 다음과 같이 코딩되어야 함. x>=0 && x<=10

6/34


논리연산자 예) 카운터값이 제한값을 넘지 않았는지 검사하는 표현식 시도1. 시도 1. !counter>threshold 문법적 오류는 아님. !counter에서 counter가 0이 아니면 이 식은 false로 평가되며, false는 0이므로 위 표현식은 0>threshold의 평가결과에 의해 결정됨. 시도 2. !(counter>threshold) 시도 3. counter<=threshold ! 연산자를 사용하지 않고 표현가능하면 그렇게 하는 것이 보통 가독성 향상에 좋음. 좋음 예) ==과 =의 혼동 if(x=1) ( ) cout << "hi\n";; // 문법적 오류는 류는 아님 If(1=x) cout << "hi\n"; // 문법적 오류 (1==x)는 OK.

7/34

C++ 흐름제어 C++도 C와 마찬가지로 다음과 같은 3개의 선택문과 3개의 반복문을 제공함. 선택문(if, if/else, switch) 반복문(for, while, do/while) 이들 문의 문법적 구조는 기존 C와 큰 차이가 없음. 없음 C++에서 조건식은 true/false 아니면 정수로 평가되어야 평가 함.

8/34


if 문 if문의 종류 if(expression) statementT; if(expression){ statements t t t T; }

if(expression) statementT; else statementF; if(expression) statementT; else statementF; if(expression){ statementsT; } else{ statementsF; }

if(expression if( i 1){ statements1; } else if(expression2){ statements2; } … else{ l { } 마지막 else 블록은 선택사항임.

9/34

if 문 예 double grade; … if(grade<2.0) printf("학사경고입니다."); iintt n; … if(n%2==0) printf("짝수입니다."); else printf( printf("홀수입니다."); 홀수입니다. ); int score; … if(score>=90) printf("A 학점"); else if(score>=80) printf("B 학점"); else if(score>=70) printf("C 학점"); else printf( printf("F F 학점 학점"); );

10/34 10 /34


dangling else 문제 dangling-else 문제: else는 가장 가까운 if문과 연관됨. 예) if(y==8) else 문은 가장 가까운 if문 연관되므로 이 예제에서 y=8, x=4이면 @@@@@이 출력되고, y=3이면 아무것도 출력되지 않으며, $$$$$ 출력됨. 출 y=8, x=5이면 $$$$$이

if(x==5) printf("$$$$$"); else printf("@@@@@"); if(y==8){ if(x==5) printf("$$$$$"); else printf("@@@@@"); }

if(y==8){ if(x==5) printf("$$$$$"); } else printf("@@@@@");

Tip. 코드를 작성할 때에는 적절한 들여쓰기를 해야 하며, 때로는 가독성을 높이기 위해 불필요한 중괄호를 사용해야 함. 함

11/34 11 /34

if 문 사용 Tip 즉, if 문은 조건식을 어떻게 작성하느냐에 즉 따라 효율성의 차이가 있음.

Tip.

int n; … if(n%2==0) printf("짝수입니다."); else printf("홀수입니다.");

int n; … if(n%2) printf("홀수입니다."); else printf("짝수입니다.");

두 예제는 모두 동일한 결과를 주는 문장이지만 효율성 측면에서는 두 번째 예제가 더 효율적임. ① n%2 ② n%2의 계산 결과와 0 비교 ③ 위 결과를 가지고 판단

① n%2 ② 위 결과를 가지고 판단

Tip. if(a <= b) b = b – a; if(a if( > b) b = b – c;

if(a <= b) b = b – a; else l b = b – c;

경우에 따라 b는 두 번 변할 수 있음 있음.

b는 무조건 한번만 변함

if 문 조건식에 사용되는 변수가 if 문의 결과에 따라 변할 경우에는 사용하는 방식에 따라 결과가 다르므로 주의해서 사용해야 함.

12/34 12 /34


if 문 사용 Tip – 계속 Tip. 중첩된 if/else 구조는 중간에 중단될 수 있으므로 일련의 if문보다 효율적임. 예) if(grade=='A') printf("very good"); else if(grade== if(grade=='B') B ) printf("good"); printf( good ); else printf("poor");

if(grade=='A') printf("very good"); if(grade=='B') if(grade== B ) printf( printf("good"); good ); if(grade=='F') printf("poor");

Tip. p 중첩 if/else 구 구조에서는 에서는 참이 될 확률이 높은 것을 먼저 검사하는 것이 효과적임. 예) if(score>=90) printf("A"); else if(score>=80) printf("B"); else printf("F");

if(score<80) printf("F"); else if(score<90) printf("B"); else printf("A");

13/34 13 /34

조건 연산자 조건 연산자는 C++ 언어에서 유일한 삼항 연산자임. 이 연산자는 다음과 같은 if 문을 축약할 때 사용함. 예) if(n1>n2) max = n1; else max = n2;

max = (n1>n2)? n1: n2;

문법 expressionC ? expressionT : expressionF expressionC를 평가하여 이 값이 0이 아니면(참이 아니면) expressionT의 평가값이 전체 표현식의 값이 되며, 반대로 0으로 평가되면 expressionF의 평가값이 전체 표현식의 평가값이 됨. 됨 예) 정수 변수 x의 절대값을 정수 변수 abs에 저장 abs = (x>0)? x: –x; x;

14/34 14 /34


switch 문 중첩된 if 문에서 모든 조건식이 동일한 표현식을 문자나 정수형과 같은지 비교하고 있으면 중첩된 if 문 대신에 switch 문을 사용할 수 있음. 있음 문법 switch(expressionC){ case value l 1: statements1; break; case value2: statements2; break; … case value l n: statementsn; break; default: statementsD; break; }

if(expression if( i C==value l 1){ statements1; } ( p else if(expression C==value2){ statements2; } … else l if(expression if( i C==value l n){ statementsn; } else{{ statementsD; }

15/34 15 /34

switch 문 – 계속 case부터 다음 case 또는 default가 나올 때까지 그 사이에 있는 문장들을 case 절이라 함. default와 연관된 문장들을 default 절이라 함. C++ 언어 구조 중 유일하게 일련의 프로그램 문장을 중괄호를 이용하여 묶고 있지 않음. 않음 case 절의 상수는 정수형 상수나 문자 상수이어야 함. 상수가 같은 case 절은 허용되지 않음. case 절의 상수 위치에 변수가 포함된 표현식을 사용하는 것은 오류임. digit a; int digit, 예) … switch(digit){ case 1–1: printf("one"); break; // ok case a–1: printf("two"); break; // error default: printf("error"); break; } // switch

16/34 16 /34


switch 문 – 계속 break 문은 switch 문에서 case 절이 실행이 끝난 후에 switch 문을 벗어나게 해줌. case 절마다 반드시 있어야 하는 것은 아님. case 절에서 break를 사용하지 않으면 그 다음 case 절이 수행됨. 이런 현상을 “fall fall through” through switch(month){ 행위라 함. case 4: case 6: case 9: case 11: numberOfDays = 30; default 절은 선택적으로 사용할 break; 수 있으나, 항상 사용하는 것이 case 2: 좋은 프로그래밍 습관이다. numberOfDays = 28; break; default 절의 위치는 고정되어 default: 있는 것은 아니지만 보통 switch numberOfDays = 31; 문의 마지막 절로 사용한다. } // switch 마지막 절로 사용할 때에 default 절은 break 문이 필요 없다.

17/34 17 /34

열거형 타입 어떤 타입의 도메인에 속한 모든 요소들을 나열하여 그 타입을 정의할 수 있으며, 이와 같은 타입 열거형 타입(enumeration 타입 type) 이라 함. 함 열거형 타입을 컴퓨터로 표현하는 가장 직관적인 방법은 열거형 타입 의각원 원소에 에 정수 값을 할당하여 표현하는 현하는 것임 것임. 열거형 타입은 enum이라는 키워드를 이용하여 정의함. 예) #define SUN 0 #define MON #define TUE #define WED #define THU #define FRI #define SAT

1 2 3 4 5 6

int wday; wday = SUN; … if( d == SAT) … if(wday

enum weekdays { SUN, MON, TUE, WED, THU, FRI, SAT};

enum Weekdays { SUN, MON, TUE, WED, THU, FRI, SAT};

enum weekdays wday; wday = SUN; … if(wday == SAT) …

Weekdays wday; wday = SUN; … if(wday == SAT) …

여기서 weekdays는 열거형을 구분하기 위한 태그

C++ 태그가 필요 없으며, typedef를 사용하지 않고 새 타입을 정의가능

18/34 18 /34


열거형 타입 – 계속 열거형 타입의 각 원소의 값을 별도로 지정하지 않으면 자동적으로 첫 번째 원소는 0의 값을 가지고, 그 다음부터는 차례대로 정수값을 할당 받음. 받음 예) enum Gender {MALE, FEMALE}; 이 타입에서 MALE은 0, 0 FEMALE은 1임. 1임 순서적으로 0부터 값을 할당하지 않고, 다르게 할당하고 싶으면 직접 지정할 수 있음. 예) enum Month {JAN=1, FEB, MAR, …, DEC}; 이 타입에서 FEB은 2, MAR은 3임. 예) enum Example {AA = 10 10, BB BB, CC= CC=-2, 2 DD}; 이 타입에서 BB는 11, DD는 -1임.

19/34 19 /34

열거형 타입 – 계속 열거형 타입에 열거형 상수 값에 대응되는 정수값을 할당하는 것은 오류임. 예) enum Direction {NORTH, SOUTH, EAST, WEST}; Direction d1 = 1; // error Direction d2 = SOUTH; // ok

열거형 타입을 cout를 를 이용하여 출력하면 해당 정수값이 출력됨 출력됨. 예) enum Direction {NORTH, SOUTH, EAST, WEST}; Direction d2 = NORTH; cout << d2 << endl; 0이 출력됨.

열거형 타입은 switch switch문에서 문에서 case 절 상수로 널리 사용됨 사용됨..

20/34 20 /34


반복문 반복문이란 일련의 문장들을 되풀이하여 실행할 수 있도록 해주는 프로그램 구조를 말함. 어떤 조건이 만족되면 되풀이되는 과정이 종료됨. 아무리 되풀이하여도 조건이 종료되지 않으면 프로그램은 종료되지 않고 이 과정만 계속 되풀이함. 되풀이함 이와 같은 현상을 무한루프 무한루프라 하며, 무한루프가 되지 않도록 반복문을 작성할 때에는 주의해야 함. 따라서 반복문은 크게 제어줄 제어줄(control line)과 몸체 몸체(body)로 구성됨. 제어줄은 반복을 종료하는 조건을 제어함. 몸체는 제어줄에 의해 계속 되풀이되는 프로그램 문장들로서 프로그램의 가독성을 높이기 위해 별도의 줄에 작성하며, 다른 문장들을 구별하기 위해 들여쓰기를 함.

21/34 21 /34

반복문의 종류 while(condition) { body }

do {

int sum = 0; int i = 1; while(i<=10) { sum += i; i++; }

int sum = 0; int i = 1; do { sum += i; i++; } while(i<=10);

int sum = 0; int i = 1; while(i<=10){ sum += i++; }

body }while(condition);

for(init; condition; step){ body }

색인변수 제어변수

int sum = 0; for(int i=1; i<=10; i++) { sum += i; } int sum = 0; for(int i=1; i<=10; sum += i , i++);

바람직한 프로그래밍 스타일은 아님

22/34 22 /34


반복문 – 계속 while과 for 문의 몸체는 한번도 실행되지 않을 수 있음. do while 문의 몸체는 반드시 최소 한번 실행됨. 모든 반복문은 while 문으로 작성가능함. 반복문 작성할 때 어떤 반복문을? 항상 정해진 횟수만큼 반복될 경우  for문, f 문 몸체가 최소 한번 실행된다는 것을 강조하고 싶으면  do while문 나머지는  while문 for문 제어줄에 색인 변수를 선언하면 이 변수의 가시영역은 for문 몸체로 제한됨. int sum = 0; 선언되지 않은 변수임 for(int i=1; i<=10; i++) { sum += i; } cout << "1부터 " << i-1 << "까지 합은 " << sum << endl;

23/34 23 /34

반복문 – 계속 루프가 반복되는 횟수 (가정. b>a) for(i=a; i<b; i++){ … }

b–a

for(i=a; i<b; i+=c){ … }

(b–a)/c

ffor(i=a; (i i< i<=b; b i++){ i ){ … }

b–a+1

ffor(i=a; (i i< i<=b; b i+=c){ i ){ … }

(b–a)/c+1

for(i=0; i<10; i++){ … }

10–0=10

for(i=0; i<=10; i++){ … }

10–0+1=11

for(i=10; i<=100; i+=5){ … } (100–10)/5+1=19

24/34 24 /34


for 문 for 문의 작성원칙: for 문은 기본적으로 init 부분에 제어 변수를 초기화하고, condition 부분에는 반복 횟수 조건을 서술하고, step t 부분에서는 제어 변수를 증가 또는 감소하여 결국에는 for f 문이 종료되도록 해야 함. for 문의 제어줄은 이 원칙대 원칙대로 꼭 작성할 필 필요는 는 없지만 이 원칙에 충실하게 작성하는 것이 가장 바람직함. for 문의 제어줄의 세 가지 요소는 모두 생략이 가능하지만, 위 원칙이 더 중요함. 중요함 for 문의 제어줄에는 여러 개의 변수를 초기화할 수 있음. for 문의 제어줄에는 반복 횟수와 관련된 색인 변수만 사용하 사용하고,, 다른 요소들은 제어줄에 포함하지 않는 것이 바람직함. 예) int j(10); for(int ( i(0), ( ), j(10); j( ); i<10;; i++,, j--){ j ){ … }

for(int i<10; ii++){ f (i t i(0); i(0) i<10 ){ … j--; } 25/34 25 /34

for 문과 쉼표 연산자 쉼표연산자가 아님 for(int i(0), j(10); i<10; i++, j--){ … } 쉼표연산자 int i; double f; f (i 1 ff=1.5; for(i=1, 1 5 i<10 i<10; i++, i++ j++){ … }

for문 제어줄에 변수를 선언할 경 한 타입의 변수들만 경우 변 만 선언할 수 있음. 하지만 서로 다른 종류의 변수를 있음 초기화할 수는 있음.

for(int i(1), double f(1.5); i<10; i++){ … 오류 }

26/34 26 /34


for 문 for 문 사용의 주의점 부동소수형을 제어변수로 사용할 경우에는 round-off 오류를 주의해야 함. 종료 조건에서 != 연산자를 사용하는 것은 피해야 한다. 예) for(i=0; i!=n; i+=2){ … } n이 짝수가 아니면 무한루프가 된다. for 문의 몸체에서 제어 변수의 값을 변경하는 것은 바람직하지 않음. 이것은 가독성을 크게 저해하는 요소가 될 수 있음.

27/34 27 /34

쉼표 연산자 두 개의 표현식이 쉼표 연산자로 분리되면 쉼표 왼쪽에 있는 피연산자 부터 평가되며, 전체 표현식의 값은 오른쪽 피연산자의 평가 값이 됨. C 연산자 중에 가장 우선순위가 낮은 연산자임. 예) int x, y; y = (x = 1, 2)

// y = 2, x = 1

예) int x, y; y = (x = 1, x + 3)

// y = 4, x = 1

예) int x, y, z; y = (x = 1, z = 3, x + z)

// y = 4, x = 1, z = 3

주의. 표준에 의하면 쉼표 연산자의 결합순서는 왼쪽에서 오른쪽임. 주의. 하지만 이것을 따르지 않는 컴파일러가 종종 있음. 예) int x = 1, y = 1, z; z = (x++, x) z = (++y, y)

// x = 2, z = 2 // y = 2, z = 2

28/34 28 /34


쉼표 연산자 즉, 쉼표 연산자도 시퀴언스 포인트이다. 지금까지 배운 시퀴언스 포인트는 다음과 같다. 프로그램 문장 끝 &&, || 연산자 쉼표 연산자 함수 호출에서 인자를 분리할 때 사용하는 쉼표는 쉼표 연산자가 아님. 즉, C++에 아님 에 등장하는 모든 든쉼 쉼표가 가 연산자는 아님 아님. 예) f1(++a, a);는 두 개의 인자를 가진 함수 호출이며, 이 때 평가되는 순서는 정의되어 있지 않다. f2((++a, a));는 하나의 인자를 가진 함수 호출이며 이 경우 ++a가 먼저 평가됨. 호출이며, 평가됨

29/34 29 /34

중첩 반복문 한 반복문 내에 또 다른 반복문을 사용할 수 있음. 예) 구구단을 출력하시오. int i, j; for(int i(1); i<10; i++){ for(int j(1); j<10; j++){ cout << i << "x" << j << "=" << i*j; } }

중첩 반복문은 가독성이 떨어질 수 있으므로 내부 반복문은 함수로 작성하여 사용하는 것도 좋은 방법임.

30/34 30 /34


break, continue 문 break 문: 루프 중간에서 루프를 빠져나올 때 사용하는 문 switch 문의 case, default 절에서도 사용 continue 문: 루프 중간에서 루프 끝으로 이동할 때 사용하는 문 예) for 문의 경우 for 문 중간에서 continue 문을 만나면 그 다음에 for 문의 step 부분이 실행됨. 실행됨 중첩된 루프인 경우에는 break와 continue는 해당 문이 포함되어 있는 가장 안쪽 루프에만 적용됨. Tip. 모든 루프는 break와 continue 문을 사용하지 않고도 작성할 수 있음.

31/34 31 /34

루프중간탈출 문제 예) –1이 입력될 때까지 정수들을 입력받아 그것의 합을 구하라. sum = 0;; while(1){ cin >> n; if(n==–1) break; sum += n; } cout << n << endl;

sum = 0;; cin >> n; while(n!=–1){ sum += n; cin >> n; } cout << n << endl;

sum = 0; done = 1; while(done){ cin >> n; if(n== 1) done = 0; if(n==–1) else sum += n; } cout << n << endl;

루프중간탈출 문제 문제(loop-and-a-half problem): 루프 중간에서 루프가 종료되어야 하는 경우

32/34 32 /34


루프중간탈출 문제 – 계속 루프중간탈출 문제를 해결하는 방법

반복

break 문 사용

루프 시작 전에 미리 한번 수행

while(1){ prompt user and read a value if( l if(value==sentinel) ti l) break; b k process the data }

prompt user and read a value while(value!=sentinel){ process the th data d t prompt user and read a value }

루프 종료시키기 위한 추가 변수 사용 done = 1; while(done){ hil (d ){ prompt user and read a value if(value==sentinel) done = 0; else process the data }

33/34 33 /34

기타 무한루프를 만드는 방법 while(1){ … }

for(;;){ … }

실제 웹서버처럼 무한루프를 통해 구현되는 프로그램도 있음. 있음

반복문 내에 값이 변하지 않는 표현식은 사용하지 않는 것이 바람직함. 바람직함 예) int i, j, a, b, n; int i, j, a, b; for(i=0; i<10; i++){ j = a+b+i; cout << j; }

n = a+b;; for(i=0; i<10; i++){ j = n+i; cout << j; }

프로그램 내에 약간의 지연을 추가하는 방법 for(i=0; i<10; i++);

34/34 34 /34


©copyright 2010

C++프로그래밍(CPA220) 강의노트 03

함수 기초

한국기술교육대학교 한국기술 육대학 컴퓨터공학부 김상진

강의목표 함수개요 시스템 정의 함수 함수호출 및 라이브러리 함수의 활용 사용자 정의 함수 함수 선언 함수 정의 return 문 함수 호출 과정 가시영역과 수명 지역변수 전역변수

2/36


함수 개요 함수 함수(function)는 수학에서 유래한 개념으로서, 대응관계 대응관계(mapping)를 의미함. 함수라고 하는 상자에 수가 들어가면 그것에 대응되는 수가 생성됨. 3 인수(argument) 예) f(x) = x+3 프로그래밍에서는 함수를 함수(function) “작은 작은 프로그램 프로그램”이라는 의미로 +3 사용됨 사용됨. 서브프로그램(subprogram) 개념 서브프로그램 프로그래밍에서 함수는 결과 값을 주는 "KUT" 6 반환값(return value) KUT 것뿐만 아니라 다른 효과를 일으킬 수 있음. KUT 결과 값 외에 부수적으로 수행되는 효과를 부수효과 부수효과( id ff t)라 함. 부수효과(side-effect)라 함 printf 부수 효과

3

3/36

프로그램의 구성과 함수 종류 지금까지는 main 함수 하나만으로 구성된 C++ 프로그램을 작성하였음. C++ 프로그램은 반드시 main 함수가 존재해야 하며, 프로그램이 실행되면 가장 먼저 실행되는 함수이며, 이 함수가 종료되면 프로그램도 램 종 종료됨. 됨 따라서 다른 함수들은 직접 또는 간접적으로 main 함수에서 호출되어 실행됨. 프로그램에서 사용되는 함수는 크게 사용자가 새롭게 만든 함수 함수와 시스템에서 제공되는 함수로 함수 구분됨. 시스템에서 시 템에서 제공되는 함수를 사용하기 위해서는 그 함수의 정 정보가 가 기록되어 있는 헤더 파일을 #include 전처리문을 이용하여 프로그램에 포함해야 함.

4/36


함수를 이용하는 이유 코드의 중복을 피하기 위해 동일한 작업을 여러 번 해야 하면 이것을 한 번 정의하고 필요할 때마다 호출해서 사용할 수 있음. 예) 출력할 때마다 printf 함수를 호출하지 않고, 화면에 데이터를 출력하는 코드를 작성해야 하면 매우 번거롭다. 번거롭다 코드가 중복되어 있지 않으면 프로그램을 수정하기가 용이함. 동일한 작업을 함수로 분리해 작성하지 않은 경우, 이 작업의 내용을 일부 수정해야 하면 중복된 모든 코드를 수정해야 함. 큰 문제를 여러 개의 작은 문제로 나누어 생각할 수 있음. 복잡성을 줄여 문제 해결을 쉽게 해줌. 해줌 (divide-and-conquer) (divide and conquer) 여러 프로그래머가 작업을 나누어 프로그래밍을 할 수 있음.

5/36

모듈화 프로그램을 여러 개의 함수로 나누는 작업을 모듈화 모듈화라 하며, 각 함수를 모듈이라고도 함. 이 때 각 함수/모듈은 다음과 같은 특성을 가지고 있어야 바람직함. 느슨한 결합성 결합성(loosely-coupled): 모듈은 상호 독립적이어야 함. 한 모듈의 변경이나 오류가 다른 모듈에 영향을 주지 않아야 함. 함 높은 응집성 응집성(highly-cohesive): 잘 정의된 단일 작업만해야 함.

6/36


함수 호출 함수 호출의 형태 function-name(arguments) 인수는 호출하는 측에서 함수에게 전달하는 정보이며, 인수가 두 개 이상이 필요할 경우에는 쉼표로 구분함. 함수 호출은 하나의 표현식이며, 표현식이며 ()은 함수 호출 연산자임. 연산자임 따라서 함수호출은 표현식의 항으로 사용 가능함. 단, 이 함수에서 반환하는 값이 있어야 하며, 반환하는 값의 타입이 표현식에서 요구되는 타입과 일치해야 함. 함 함수를 호출할 때 제공하는 인수의 개수와 각 인수의 타입은 함수의 정의된 입력의 개수와 타입과 일치해야 함. 함수는 복귀 연산의 일부로서 수행 결과를 호출한 측에 넘겨 줄 수 있음. 함수를 호출하여 사용하기 위해서는 시스템 정의 함수: 해당 헤더 파일을 포함해야 함. 사용자 정의 함수: 함수의 선언 또는 정의가 먼저 선행되어야 함. 7/36

함수 호출 – 계속 C++에서 라이브러리 함수 호출 C와 마찬가지로 해당 헤더 파일을 포함해야 함. 차이점.. 헤더파일을 포함할 때 확장자가 없으며, 기존 C에서 차이점 사용하였던 헤더파일은 파일명 앞에 c가 붙음. 예) 기존 C: #include <math.h> <math h>  C++: #include <cmath> 추가적으로 using namespace std;가 필요함. #include <iostream> #include <cmath> using namespace std; i main(){ int i (){ double n; n = sqrt(9.0); cout << n << endl; return 0; } // main

8/36


함수 호출 – 계속 함수가 호출되어 실행된 후에 다시 호출된 위치로 돌아와 작업을 계속 수행하기 위해서는 함수가 호출될 때마다 시스템의 현재 상태를 보관해야 하며, 하며 함수가 종료되면 보관된 상태를 복원해야 함. 함 이 때문에 함수 호출은 비용(시간)이 많이 드는 연산임. 따라서 불필요한 함수 호출은 최소화하는 것이 바람직함. 바람직함 하지만 오늘날 프로그래밍에서는 중복을 최대한 줄여 유지보수와 가독성을 높이는 것이 효율성을 높이는 것보다 더 중요함. 예) int sum(int a, int b) int n, x, y, z; { return a+b; }

void printInteger(int a) { cout << a; }

x = y = z = 2; ( y) y); n = sum(x, n = sum(x, 3) + z; n = sum(x, y, z);

// n = 4; // n = 7; // error

int n, n x; x = 2; printInteger(x); n = printInteger(x);

// error 9/36

사용자 정의 함수 사용자가 새롭게 함수를 만들어 사용하기 위해서는 먼저 그 함수를 정의해야 함. 반환값의타입 함수이름(매개변수목록) 함수를 정의할 때 필요한 요소 { 함수몸체 반환 값의 타입: 없으면 void } int max(int a, int b)) ( 함수 이름 { return (a>b)? a: b; 매개변수 목록(parameter): 없으면 void } 함수의 몸체 함수를 정의하였다고 호출할 수 있는 것은 아님. 항상 기억해야 하는 것은 컴파일러는 순차적으로 번역을 함. 함수의 몸체는 0개 이상의 문장이 올 수 있으며, 적절한 들여쓰기를 해야 함. 함수 몸체 앞에 나타나는 부분을 함수 헤더(header)라 하며, 함수를 호출하기 위한 사용법을 알려줌. 예) max: (int, int)  int

10/36 10 /36


함수의 선언 #include <iostream> using namespace std; i t factorial(int int f t i l(i t n){ ){ int prod = 1; for(int i = 1; i<=n; i++){ prod *= i;; p } return prod; } // factorial int main(){ int n; while(1){ ( ){ cout << "정수 입력: "; cin >> n; if(n==-1) break; cout << n << "! = " << factorial(n) << endl; } // while return 0;; } // main

#include <stdio.h> using namespace std; int main(){ int n; while(1){ cout << "정수 입력: "; cin >> n; if(n== 1) break; if(n==-1) cout << n << "! = " << factorial(n) << endl; } // while return 0; } // main int factorial(int n){ int prod = 1; for(int i = 1; i<=n; i++){ prod *= i; } return prod; 아래에 factorial 함수가 정의되어 있지만 } 이 시점에서 컴파일러는 factorial이 이 뭔지 알 수 없다. 11/36 11 /36

함수의 선언 – 계속 앞 예에서 알 수 있듯이 함수를 호출하여 사용하기 위해서는 호출이 이루어지는 문장 이전에 컴파일러가 이 함수와 관련된 정보를 알 수 있도록 해주어야 함. 함 따라서 f라는 어떤 함수를 호출하고 싶으면 이 함수가 호출되는 함수 앞에 f 함수가 먼저 정의되어 있어야 함 함. 하지만 이와 같은 형태로만 프로그래밍을 해야 한다면 f 함수 내에서 g 함수를 호출하고 또 g 함수 내에서 f 함수를 호출 해야 하는 특수한 경우는 절대 프로그래밍을 할 수 없으며, 없으며 가독성을 저해할 수 있고, 함수를 별도 파일에 정의할 수 없게 됨. 됨 따라서 컴파일러가 번역하기 위해 필요한 정보만 미리 제공해 줄 수 있으며, 이것을 함수의 선언 또는 원형 원형(prototype)이라 함.

12/36 12 /36


함수의 선언 – 계속 함수 선언을 이용한 프로그래밍 #include <iostream> using namespace std;

함수 원형 끝에는 일반 문장과 마찬가지로 ;;으로 끝 끝난다. 다

int factorial(int); // 함수의 선언(함수의 원형) int main(){ … cout << n << "!! = " << factorial(n) << endl; … } // main int factorial(int n){ // 함수의 정의 … }

즉, 헤더 파일에 함수의 정의가 포함되어 있는 것은 아니고 함수의 원형이 포함되어 있음. 있음

13/36 13 /36

함수의 선언 – 계속 함수의 선언은 컴파일러가 번역할 수 있도록 미리 번역에 필요한 정보를 컴파일러에게 알려주는 것임. 컴파일러는 식별자를 보면 이것이 어떤 용도의 식별자인지 알아야 함. 이 때 식별자가 함수이름이라는 것을 알고, 이 함수를 호출하는 코드로 인식되면 다음을 검사함 검사함. 올바른 개수의 입력이 주어지고 있는지, 각 입력의 유형이 올바른지, 함수의 반환 값과 함수의 사용 용도가 일치하는지 검사 예) // 함수 선언 void f(void); int sum(int, int);

int a, b, n; n = f(); // 오류: f함수는 값을 반환하지 않음 n = sum(a); // 오류: sum 함수는 두 개의 입력이 필요함 n = sum(a sum(a,b); b); // OK

14/36 14 /36


함수의 선언 – 계속 따라서 함수 선언에는 반드시 다음 요소가 있어야 함. 반환 값의 타입 함수 이름 매개변수들의 타입 매개변수의 이름은 꼭 제시하지 않아도 됨. 됨 하지만 이름을 제시하면 가독성을 향상시킬 수 있음. 함수의 선언은 함수의 정의에서 몸체부분만 제외하 제외하고 ;을 붙여주면 됨 됨. 함수의 선언과 그 함수의 정의는 일치해야 함. 즉, 함수의 선언과 함수의 정의는 함수 이름, 반환 값의 타입, 인수들의 개수와 타입이 일치해야 함. 함 C와 달리 동일한 이름의 함수를 여러 개 정의할 수 있음.

15/36 15 /36

함수를 별도 파일에 정의하는 방법 #include #i l d <iostream> i t using namespace std; #include "factorial.h"

#ifndef __FACTORIAL_H #define __FACTORIAL_H int factorial(int n);

int main(){ int n; while(1){ coutt << "정수 입력: 입력 "; " cin >> n; if(n==-1) break; cout << n << "!! = " << factorial(n) << endl; } // while return t 0 0; main.cpp i } // main

#endif

factorial.h

#include "factorial.h" int factorial(int n){ int prod = 1; for(int i = 1; i<=n; i++){ prod *= i; } return prod; } // factorial

factorial.cpp 16/36 16 /36


return 문 반환 값이 있는 함수의 경우에는 함수 몸체에 최소한 하나의 return 문이 있어야 함. return 문의 문법 반환해야 하는 값이 있는 경우 return (expression); 반환해야 하는 값이 없는 경우 return;; 함수를 실행하는 도중에 return 문을 만나면 그 함수의 실행은 종료됨. 만약 return t 문의 표현식의 평가 값의 타입과 함수 반환 값의 타입이 일치하지 않으면 평가 값은 자동으로 함수의 반환 값의 타입으로 변환됨. 이 때 자동 변환이 가능하지 않으면 오류임.

17/36 17 /36

return 문 관련 오류 예) int f(void){ … return "hello"; // 오류 }

int f(void){ … } // return 문이 없으면 오류

void f(void){ int n; … if(…) ( ) return;; … return n; // 오류 } // 매개변수 목록 오류 void f(double a, b){ … } 변수를 선언할 때에는 가능하지만 매개변수를 선언할 때에는 각 변수이름마다 타입이 있어야 한다. 정확하게는 없으면 int로 간주함

int f(void){ … if(…) return 1; } 함수가 반환하는 값이 있는 경우 함수가 종료되는 모든 경우에 return 문이 있어야 함.

18/36 18 /36


순수 함수 함수는 연산자와 매우 유사함. 예) int add(int a, a int b){ return a+b; }

int x, y, z; x = 2; y = 3; z = x+y; z = add(x, y);

x+y와 add(x, y)는 동일한 효과를 줌. 보통 연산자는 피연산자를 이용하여 새 값을 생성하여 주지만 ++ 연산자처럼 부가적인 일(피연산자의 값을 증가시킴)을 하는 연산자도 존재함. 함수 중에도 위 예의 add처럼 dd처럼 받은 인수를 근거로 새 값을 생성하는 것 외에 다른 일을 하지 않는 함수들이 있음. 이와 같은 함수를 순수 함수 함수(pure function)라 함수(p )라 하며, 사용자 정의 연산자라고 볼 수 있으며, 가급적 프로그래머는 순수 함수를 많이 정의하여 사용하는 것이 좋음 좋음.

19/36 19 /36

프로시저 순수 함수와 정반대로 완전히 부수효과에 의존하는 함수도 존재함. 반환값이 없는 함수를 프로시저 프로시저(procedure)라 하는데, 이와 같은 함수들은 부수효과에만 의존하는 함수임. C++ 프로그램의 명령어들인 if, switch 등도 어떤 값을 생성하지 않기 때문에 프로시저는 C++ 프로그램의 명령어와 유사함. 유사함 이와 같은 측면 때문에 프로시저는 사용자 정의 명령어라고 볼 수 있음. void printInteger(int a){ cout << a; }

20/36 20 /36


술어함수 참 또는 거짓을 반환하는 함수를 술어함수 술어함수(predicate function)라 함. 보통 술어함수는 is 접두사를 사용하여 함수 이름을 명명함. 예) bool isOdd(int n) { return (n%2); }

조건식이 복잡할 경우에는 술어함수를 정의하여 사용하는 것이 가독성에 좋음. 예) if(((rate>=10) ((( ) && (rate<20)) ( )) || (rate==0)) ( )) { … }

if(appropriate(rate)) { … bool appropriate(int rate) } { return (((rate>=10) && (rate<20)) || (rate==0)); } 21/36 21 /36

함수 주석 함수 정의 앞에 보통 함수를 설명하는 주석을 포함함. 이 때 가장 좋은 방법은 함수의 사전조건 사전조건(precondition)과 사후조건(postcondition)에 대한 정보를 포함하는 것임. 사후조건 사전조건이란 함수가 실행되기 전에 성립해야 하는 조건을 말하며, 사후조건은 사전조건이 충족된 상태에서 함수가 종료된 후에 성립해야 하는 조건을 말함. 사전조건은 주로 전달하는 인수와 관련되어 있음. 사전조건이 만족되지 않으면 함수를 호출하지 말아야 함. 하지만 사전조건이 만족되지 않았음에도 불구하고 호출될 수 있으므로 함수 내부에서 이 조건을 검사해야 함. 함 사전조건이 위배된 경우 방법 1. 아무것도 하지 않음. 방법 2. 예외 처리 (추후에 설명함.)

22/36 22 /36


함수 주석 예) // 주어진 계좌에 주어진 금액을 입금함. // @사전조건 amount>0 // @사후조건 account.balance = account.balance + amount // @사후조건 : 입금이 성공적으로 수행되면 true를 그렇지 않으면 false를 반환함. 반환함 bool deposit(BankAccount &account, int amount);

23/36 23 /36

Tip 함수는 단일 작업을 해야 하며, 함수의 이름은 그 작업을 잘 나타내야 함. 만약 간결한 함수 이름을 정하는 것이 어려우면 그 함수는 아마도 너무 많은 일을 하고 있을 확률이 높음. 매개변수가 너무 많이 필요한 함수도 너무 많은 일을 하고 있을 확률이 높음. 매개변수가 가급적 3개 이내로… 함수의 이름뿐만 아니라 매개변수의 이름도 그 용도를 쉽게 파악할 수 있도록 의미있는 이름을 사용하는 것이 바람직함. 함수의 길이는 반 페이지 정도가 적당함. 적당함 조건문이나 반복문의 블록이 매우 길 경우에는 블록을 함수로 작성하는 것도 좋은 방법임.

24/36 24 /36


함수 호출 과정 main

myFunc() 호출

myFunc();

if(…) return; return 문에 의한 복귀 함수 끝에 도달하여 복귀

함수 호출이 이루어지면 호출한 함수(caller)는 호출된 함수(callee)가 종료할 때까지 수행을 멈추고 기다림. 위 예의 경우 main에서 myFunc 함수를 호출하면 main은 잠시 멈추고 myFunc 함수가 실행됨. 호출된 함수는 return 문을 만나거나 더 이상 실행할 문장이 없으면 종료되며, 호출한 함수는 다시 실행을 재개함.

25/36 25 /36

함수 호출 과정 – 계속 추상적으로 함수가 실행되면 함수를 위한 공간이 만들어지며, 이 공간에 함수의 매개변수와 지역변수를 저장하기 위한 공간이 만들어짐. 함수 호출 과정 단계 1. 1 각 인수를 나타내는 표현식을 평가함. 평가함 표현식의 평가 순서는 정의되어 있지 않음. 단계 2. 평가된 각 인수 값은 해당되는 매개변수 매개변수로 복사됨 복사됨. 이 때 필요하면 자동 타입변환이 일어날 수 있음. 단계 3. return 문을 만날 때까지 또는 함수 끝에 도달할 때까지 함수 몸체의 문장을 차례대로 수행함. 수행함 단계 4. 반환 값이 있는 경우에는 함수 호출 자리에 넘겨진 값으로 대치하고 함수가 호출된 대치하 출된 위치 이후부터 다시 수행을 계속함 계속함.

26/36 26 /36


함수 호출 과정 – 계속 #include <iostream> using namespace std; int sum(int, int); int main(void){ int n1, n2; cin >> n1 >> n2; cout << n1 << "+" << n2 << "=" << sum(n1,n2)); return 0; } // main int sum(int a, int b){ int c = a+b; return c; } // sum(int, int)

main n1 n2 임시

4 3 7

sum a b c

4 3 7

27/36 27 /36

함수 호출 과정 – 계속 #include <iostream> using namespace std; int sum(int, int); int main(){ int n1(3); ( ); double f(2.5); cout << sum(n1+2, f) << endl; return 0; } // main int sum(int a, int b){ int c(a+b); return c;; } // sum(int, int)

main n1 f 임시

3 2.5 7 5

sum a b c

5 2 7

28/36 28 /36


가시영역과 수명 변수를 사용할 때에는 그 변수의 가시영역 가시영역(scope)와 수명 수명(lifetime)을 잘 이해하고 사용해야 함. 가시영역이란 변수를 선언한 후에 그것을 프로그램 내에서 사용할 수 있는 영역을 말함. 함수 내부에 선언된 변수는 선언한 위치 이후부터 함수 끝까지 사용할 수 있음. 수명이란 프로그램이 실행되는 동안에 변수가 메모리에 공간을 차지하고 있는 사용되는 기간을 말함. 말함 함수가 호출되면 함수를 위한 공간이 만들어지며, 이 공간에 함수의 매개변수와 지역변수를 위한 공간이 생성됨 생성됨. 이 공간은 함수가 종료되면 반납됨. 따라서 지역변수와 매개변수의 수명은 함수의 수명과 같음.

29/36 29 /36

가시영역과 수명 가시영역의 종류 블록 영역 영역: 선언한 블록 내에서 선언한 위치부터 블록 끝까지 사용할 수 있는 경우를 말함. (지역변수) 파일 영역 영역: 선언한 위치부터 파일 끝까지 사용할 수 있는 경우를 말함 (전역변수) 말함. 현재 파일뿐만 아니라 다른 파일에서도 사용 가능할 수 있음. 클래스 영역 영역: 선언된 클래스 내에서 어디서든지 사용할 수 있는 경우를 말함. (멤버변수) 수명의 종류 함수 수명 수명: 함수가 실행될 때마다 메모리에 공간이 할당되며, 할당되며 함수가 종료하면 공간을 반납하는 경우를 말함. (대부분의 지역변수) 프로그램 수명 수명: 프로그램이 실행될 때 메모리에 공간이 할당되며, 프로그램이 종료할 때까지 공간을 유지하는 경우를 말함. (전역변수) 30/36 30 /36


지역변수 지역변수는 함수 내부에 선언된 변수를 말함. 보다 정확하게 말하면 중괄호 { }에 의해 형성되는 블록(block)이라고 하는 영역에 선언된 변수를 말함. C++는 C와 달리 블록 내부 어디에나 선언이 가능함. 예) void f(void){ int n = 5; cout << n << endl; int m = 0; // error in C but OK in C++ } // f()

새 지역마다 변수를 선언할 수 있다. 예)

void f(void){ int n = 5; cout << n << "\n"; { int m = 0; // ok cout << m << endl; } } // f() 31/36 31 /36

지역변수 – 계속 같은 지역 내에는 동일한 이름의 변수를 선언할 수 없음. 매개변수도 지역변수이며, 이 변수의 영역은 함수 몸체 전체임. 예) void f(int n){ void f(void){ int n = 5; int m = 3; int n = 2; // error cout << n << endl; } // f()

int n = 5; // error cout << n << endl;; } // f()

서로 지역이 구분되면 같은 이름의 변수를 선언할 수 있음. 예) void f(void){ ( ){ int n = 5; cout << n << "\n"; { int n = 0; // ok cout << n << "\n"; } cout << n << endl; } // f()

void f(int m){ int n = 5; cout << n << "\n"; { int m = 0; // ok cout << n << endl; } } // f() 32/36 32 /36


지역변수 – 계속 지역변수의 가시영역

void f(){ int n = 5; f (i t i(0); for(int i(0) i<n; i< i++){ int m = 2; } } // f void g(){ int m = 3 3; } // g

동일한 이름의 두 변수의 가시영역이 중첩되면 보다 작은 영역의 변수가 그 지역 내에서는 다른 변수를 void f(){ (){ 접근할 수 없도록 만듦. 만듦 int n = 5; cout << n << "\n"; 이것을 다른 말로 한 변수가 다른 { 변수를 가린다 가린다고 말함 말함. int n = 0; // ok cout << n << "\n";

} } // f() () 33/36 33 /36

전역변수 함수 밖에 선언된 변수를 전역변수 또는 광역변수라 함. 전역변수의 가시영역은 선언된 위치부터 파일 끝까지이며, 다른 파일에서도 접근할 수 있음. 예) void f(); int global_n = 0; void main(void){ coutt << global_n l b l << "\n"; "\ " f(); global_n++; cout << global g oba _n << e endl; d; } // main()

가시영역

수명

지역변수

블록영역

함수

전역변수

파일영역

프로그램

void f(){ global_n l b l = 5; 5 cout << global_n << "\n"; } // f()

34/36 34 /36


전역변수 – 계속 앞서 설명한 바와 같이 전역변수와 지역변수는 서로 영역이 구분되므로 전역변수와 동일한 이름의 지역변수를 선언할 수 있음. 이 때 지역변수가 전역변수를 가리게 되어, 그 지역변수의 영역에서는 같은 이름의 전역변수를 접근할 수 없게 됨. 예) void f(); int n = 0;

voidmain(void){ cout << n << "\n"; f(); n++;; cout << n << "\n"; } // main() void f(){ int n = 5; cout << n << "\n"; } // f() ()

// 지역 n 값이 출력

35/36 35 /36

전역변수 – 계속 전역변수를 활용하면 편리한 측면이 있지만 문제가 발생하였을 때 이를 수정하기 어렵고, 프로그램의 가독성이 떨어짐. 하지만 상수변수는 값이 변하지 않기 때문에 전역변수로 사용하여도 이와 같은 문제가 없음. 보통 전역상수변수는 전처리기문과 함수 선언 사이에 정의함. 정의함 #include <iostream> using namespace std; const double PI = 3.14159; int sum(int, int); int main(){ … } // main

36/36 36 /36


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.