======C++ 스터디 #6: 함수====== | 시간 | 2021년 5월 20일 목요일 20:30 ~ 22:10 | | 장소 | Google Meet | | 참가자 | 강동륜 김도형 김석호 김진우 김희연 김도균 문준영 박경민 시주성 심훈용 안영현 엄경현 오성근 우재원 윤호연 이미경 이언상 임승환 정인하 정지웅 조동민 김지훈 최원섭 함영석 홍제준 황선용 | {{youtube>WhLaQKUCjNc?medium}} =====1. 변수의 범위 (scope)===== ====1.1. 지역변수와 전역변수==== * 지역변수: 특정 블록 내에 선언된 변수는 그 블록 내에서만 사용할 수 있다. { int a = 1; } cout << a; // Error code E0020: 식별자 "a"이(가) 정의되어 있지 않습니다. * 전역변수: 가장 밖에 선언된 변수, 모든 곳에서 접근이 가능하다. #include using namespace std; int a = 1; int main() { cout << a << endl; // 1 { cout << a; // 1 } return 0; } ====1.2. 블록 (block)==== 블록은 중괄호로 묶인 부분이다. 블록 내에 선언된 변수는 블록에 진입할 때 생성되고 블록을 빠져나올 때 소멸한다. cout << a; // Error code E0020: 식별자 "a"이(가) 정의되어 있지 않습니다. { int a = 1; cout << a; // 1 } cout << a; // Error code E0020: 식별자 "a"이(가) 정의되어 있지 않습니다. * 쉐도잉 (shadowing) 블록 내부의 변수는 외부의 변수와 같은 이름을 가질 수 있다. 이 경우 내부와 같은 이름의 외부의 변수는 잠시 가려진다. int a = 1; { int a = 2; cout << a; // 2 } -> 이런 식으로 사용할 수는 있지만 이런 코드는 유지·보수 뿐만 아니라 프로그램의 작동을 이해하기 어렵기 때문에 지양해야 한다. \\ =====2. 함수와 매개변수===== ====2.1. 함수 (function)==== 함수는 특정 작업을 수행하기 위해 짜인 코드 덩어리이다. 함수를 사용하면 같은 긴 코드를 반복해서 사용하는 것을 막을 수 있다. 프로그램에서 특정 작업을 반복해야 할 때는 해당 작업을 수행하는 함수를 작성해서 프로그램이 필요할 때마다 호출할 수 있다. 함수는 메인함수 앞에 다음과 같이 선언한다. <반환 자료형> <함수 이름> (<매개변수>) { <함수 몸체> } int add(int a, int b) { return a + b; } * 반환 자료형 : 함수의 실행을 마치고 반환하는 데이터의 자료형을 나타낸다. 반환하는 값이 없다면 void형을 사용한다. * 함수 이름 : 함수의 이름은 해당 함수의 기능을 쉽게 알 수 있도록 짓는 편이 좋다. * 매개변수 : 함수를 호출할 때 전달되는 인수의 값을 저장하는 변수를 나타낸다. * 함수 몸체 : 함수의 기능이 작성된다. ====2.2. 매개변수 (parameter)==== 매개변수는 함수에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 변수이다. 함수 매개 변수는 함수 블록 내에서만 사용되는 지역변수로, 함수 밖에서는 사용할 수 없다. 인수는 함수를 호출할 때 함수에 전달한 값이다. add(1, 2); // add라는 함수에 1과 2라는 인수를 전달한다. ====2.3. 함수 원형(prototype) 선언==== 사용자 정의 함수를 메인함수 앞에 선언하는데 이때 함수가 길어지거나 많아지게 되면 메인함수를 찾기 힘들고 코드를 보기 힘들어지므로 함수를 메인함수 다음에 선언할 수 있다. 하지만 컴파일러가 위에서부터 차근차근 읽기 때문에 사용자 정의 함수를 메인 함수 밑에 선언하게 되면 메인 함수 내에서 호출하는 함수를 인식할 수 없다. 이를 해결하기 위해 메인 함수 전에 함수 원형을 선언하여 컴파일러에게 해당 함수를 사용하겠다고 알려줘야 한다. 함수 원형은 다음과 같이 선언한다. <반환 자료형> <함수 이름> (<매개변수>); int add(int a, int b); 함수 원형을 메인 함수 이전에 선언하면 메인 함수 다음에 반드시 해당 함수를 정의해야 한다. - 사용자 정의 함수 원형 선언 - 메인 함수 - 사용자 정의 함수 정의 함수 정의는 메인 함수 위에 사용자 정의 함수를 선언할 때와 똑같이 해주면 된다. ====2.4. 인수 전달 방식==== ===2.4.1. 값으로 전달(pass by value)=== 인수를 값으로 전달하는 방식은 지금까지 함수를 호출할 때 사용하던 방식이다. add(1, 2); // add함수에 인수 1과 2를 값으로 전달한다. 인수를 값으로 전달할 때에는 함수 매개변수에 인수 값을 복사한다. 따라서 함수 내에서 매개변수로 받은 값을 변경한다고 해서 메인 함수의 변수 값이 실제로 변경되지 않는다. #include using namespace std; void change(int num); int main() { int a = 1; cout << "a = " << a << endl; change(a); cout << "a = " << a; } void change(int num) { cout << "num = " << num << endl; num = 2; cout << "num = " << num << endl; } // 출력 // a = 1 // num = 1 // num = 2 // a = 1 ===2.4.2. 참조로 전달(pass by reference)=== 인수를 참조로 전달할 때에는 매개 변수를 인수에 대한 참조로 선언하여 원본 데이터로 직접 전달하므로 함수에서 데이터를 직접 수정할 수 있다. 참조로 전달할 때는 함수를 선언할 때 매개변수를 참조자로 선언하므로 int&와 같이 &를 써서 int형 변수에 대한 참조임을 나타낸다. 함수를 호출할 때에는 값으로 전달할 때와 마찬가지로 &를 사용하지 않는다. #include using namespace std; void change(int& num); int main() { int a = 1; cout << "a = " << a << endl; change(a); cout << "a = " << a; } void change(int& num) { cout << "num = " << num << endl; num = 2; cout << "num = " << num << endl; } // 출력 // a = 1 // num = 1 // num = 2 // a = 2 \\ =====3. 재귀함수===== * 재귀호출 : 함수에서 자기 자신을 호출하는 방식 #include using namespace std; void hello() { cout << "Hello \n"; hello(); } int main() { hello(); return 0; } 재귀호출을 사용할 경우, 예시와 같이 자기 자신을 계속 호출하게 되는 스택 오버플로우를 주의해야 한다. 이를 막기 위해 재귀호출을 사용할때 다음과 같이 종료 조건을 만들어주어야 한다. #include using namespace std; void hello(int count) { if (count == 0) { return; // count가 0이 되면 종료 } cout << "Hello \n"; hello(--count); // --count는 count-1과 같음 } int main() { hello(10); return 0; } \\ =====4. 함수 오버로딩===== * 함수 오버로딩 : 같은 함수의 이름을 가지고 있지만, 매개변수나 리턴 타입 등의 특징이 다른 여러 함수를 만드는 것 함수 오버로딩은 컴파일 에러를 일으킬 것 같아 보이지만, 컴파일러는 함수 호출에 사용된 인수를 기반으로 호출할 함수를 결정하기 때문에 에러를 일으키진 않는다. 매개변수들의 합을 출력해주는 add() 라는 함수를 생각해보자. int add(int x, int y) { return x + y; } double add(double x, double y) { return x + y; } 위의 두 함수는 매개변수가 각각 int 와 double 형으로 다르므로, 함께 선언될 수 있다. int add(int x, int y, int z) { return x + y + z; } 이 함수는 매개변수의 개수가 3개로 다르므로, 함께 선언될 수 있다. 그러나 함수 오버로딩에서는 함수의 반환 타입은 고려하지 않는다. 예를 들어 랜덤 숫자를 반환하는 함수를 선언하려 한다 생각해보자. int getrandomvalue(); double getrandomvalue(); 이 두 함수는 함께 선언될 수 없다. () 속의 매개변수가 같기 때문이다. (둘 다 없으므로 : 같음) 이처럼 매개변수의 차이가 없을때는 함수 오버로딩을 사용할 수 없고, 서로 다른 이름의 두 함수를 선언해야 한다. \\ =====5. 예제===== ====5.1. 최대공약수 최소공배수 구하기==== 주어진 두 자연수의 최대공약수와 최소공배수를 구하는 함수를 만들어 출력하는 프로그램 작성하기 12 30 최대공약수 : 6 최소공배수 : 60 \\ ====5.2. 변수 값 교환하기==== 두 변수의 값을 교환하는 함수 작성하기 5 10 a = 5, b = 10 swap a = 10, b = 5 \\ ====5.3. 터틀봇으로 다각형 그리기==== 터틀봇은 전진과 제자리 회전만 가능한 로봇이다. 주어진 코드의 빈칸을 채워서 터틀봇이 변 개수와 변 길이를 입력받아 전진하고 회전하며 다각형을 그리는 프로그램을 완성하라. #include using namespace std; void moveForward(________) { cout << ________________ << endl; } void rotate(________) { cout << ________________ << endl; } void drawPolygon(________________) { ________________________________ ________________________________ ________________________________ ________________________________ } int main() { ________________________________ ________________________________ ________________________________ ________________________________ ________________________________ ________________________________ drawPolygon(________________); return 0; } \\ 변 개수 : 6 변 길이 : 2 2만큼 전진 60도 회전 2만큼 전진 60도 회전 2만큼 전진 60도 회전 2만큼 전진 60도 회전 2만큼 전진 60도 회전 2만큼 전진 60도 회전 \\ ====5.4. 재귀함수로 최대공약수 구하기==== 최대공약수를 구하는 재귀함수 작성하기 48 32 최대공약수 : 16 \\