======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
\\