본문 바로가기
Programming/C++

C++ 언어 기초 (5) - 함수

by 롱일스 2020. 8. 26.
반응형

▣ 함수의 정의와 호출

 ●  함수(function)란?

  ▷ 필요한 작업을 수행하는 프로그램 문장들을 하나의 단위로 모아 놓고 이름을 부여한 것을 말한다

 

●  함수 정의 형식

ReturnType functionName(fParameterList)  // 머리부
{                                        // 몸체 블록
	Type localVar1;     // 지역변수 선언
    Type localVar2;
    
    ...
    statement1;   // 처리할 작업을 수행하는 문장
    statement2;
    ...
    return returnExpression;  // 결과값을 반환

 

 ●  return 명령?

  함수를 마치고 함수를 호출한 곳으로 복귀하는 명령

  ▶ 함수 안의 어느 곳이든 복귀를 위해 사용 가능

   반환값이 없는 함수의 ReturnType은 void로 선언

  ▶ main 함수에서는 return 명령을 만나지 않은 상태로 함수의 끝에 도달하면 'return 0;'를 실행한 것과 같다.

 

●  함수 호출 형식

   functionName ( aParameterList );

   반환값 유무에 관계없이 사용 가능하다.

  ▶ varName = functionName ( aParameterList );

   ReturnType이 void가 아닌 함수에 사용할 수 있다.

 

 ●  함수 사용 예시 - ConvFtoC.cpp

#include <iostream>
using namespace std;

//화씨온도를 섭씨온도로 변환하는 함수
//매개변수 float fahr : 화씨온도
//반환값 섭씨온도(float)

float FahrToC(float fahr)
{
	return (fahr - 32) * 5 / 9;
}

int main()
{
	float fTemp, cTemp;
	
	cout << "화씨온도 : ";
	cin >> fTemp;
	cTemp = FahrToC(fTemp); //함수 호출
	cout << "---> 섭씨온도 : " << cTemp << endl;
	return 0; 
 } 
 

 

●  함수 사용에 따른 장점 & 단점

   장점

  • 의미 있는 작업 단위로 모듈화 -> 간결하고 이해하기 쉬운 프로그램 생성 가능
  • 반복 사용되는 코드의 중복 방지
  • 잘 설계된 함수는 다른 응용에서 재사용 가능

  ▶ 단점

  • 함수 호출과 복귀 과정에서 처리 시간이 추가된다
  • 매우 효율적으로 동작해야 하는 함수면 inline 함수로 선언하는 게 좋다

 

▣ 인수와 매개변수

 ●  인수란?

  ▷ 함수 호출 문장에서 함수에 전달하는 값

  ▶ 매개변수를 통해 인수를 전달한다

 

●  매개변수

  ▷ 실 매개변수(actual parameter)

     함수 호출 문장에서 함수의 형식 매개변수에 전달할 값

  ▶ 형식 매개변수(formal parameter)

     인수를 전달받기 위해 함수에 선언된 매개변수로 함수 헤더에 매개변수의 자료형과 이름을 선언한다.

 

 ●  인수 전달 방식 - 값 호출 (call-by-value)

  ▷ 실 매개변수의 값을 형식 매개변수에 복사한다.

  ▶ 장점

    실 매개변수와 형식 매개변수는 별개의 데이터라서 불필요한 부작용이 안 생긴다.

   단점

    구조체와 같이 많은 양의 데이터로 구성된 인수 전달하게 되면 데이터 복사량이 많아진다.

 

●  인수 전달 방식 - 참조 호출 (call-by-reference)

  ▷ 실 매개변수의 참조를 형식 매개변수에 복사한다.

  ▶ 함수에서 형식 매개변수의 값을 변경하는 것은 실 매개변수의 값을 변경하는 것과 같다.

  ▷ 형식 매개변수에 복사되는 데이터 양은 실 매개변수의 크기와 관계없이 일정하다. (구조체 인수에 효율적)

  ▶ 함수 호출의 효율성을 위해서 참조 호출 하지만 실 매개변수 값이 변경되길 원하지 않는 형식 매개변수에는 const 한정어를 지정하여 실 매개변수를 보호한다.

  ▷ 참조 호출 예시 (+const 한정어로 실 매개변수 보호)

struct SalesRec {
	char pID[10];
	int dYear, dMonth, dDate;
	char deliverAddr[40];
};

void PrSalesRec(SalesRec srec)   //64바이트 복사 
void PrSalesRec(SalesRec &srec)   //4바이트 복사  // 구조체의 값을 변경할 수 있다.
void PrSalesRec(const SalesRec &srec)   
//4바이트 복사 // 함수 내에서 구조체의 값을 변경할 수 없다.
// 함수 내에서 구조체 값을 변경하는 문장이 있으면 컴파일 에러가 발생한다.
// 함수 내의 문장들은 모두 읽기 전용이라고 생각하면 된다.
{
	cout << "품목코드 : " << srec.pID << endl;
	cout << "배달일자 : " << srec.dYear << "년";
	cout << srec.dMonth << "월";
	cout << srec.dDate << "일" << endl;
	cout << "배달주소 : " << srec.deliverAddr << endl;

  구조체가 10 + 3*4 + 40 = 62바이트인데 데이터를 보통 4바이트씩 끊어서 전달하기 때문에 char pID에 12바이트를 할당해서 총 64바이트로 만들어서 메모리 효율을 높여준다. --> 정렬(Alignment)

 

●  디폴트(default) 인수

  ▷ 인수의 디폴트 값을 지정하는 방법

    일반적으로 사용되는 디폴트 값이 있는 인수는 함수 정의할 때 그 값을 미리 지정할 수 있다.

  ▶ 예시 - 반올림 함수 Round.cpp

#include <iostream>
#include <cmath>
using namespace std;

//함수 선언만 먼저해서 main함수에서 사용할 수 있게 해주자.
double Round(double x, int d = 0); //d: 소수점 아래 자리수

int main()
{
	double a;
	cout << "값 = ";
	cin >> a;
	cout << "반올림 --> " << Round(a) << endl;
	cout << "            " << Round(a, 1) << endl;
	cout << "            " << Round(a, 2) << endl;
	cout << "            " << Round(a, 3) << endl;
	return 0;
}

double Round(double x, int d)  
// 인수에 int d = 0이라고 다시 지정해주면 안된다. 이미 위에서 했기 때문에
{
	double a = x >= 0 ? 0.5 : -0.5;
	double pow10 = pow(10, d);
	return trunc(x * pow10 + a) / pow10; 
}

 

 

▷ 디폴트 인수는 인수 중 끝에만 위치할 수 있다.

void f(int x, int y=10, int z=20);  // OK!
void g(int x, int y=10, int z);  // 오류!!!!!!!

f(5);    // x = 5, y = 10, z = 20 전달
f(5,100);  // x = 5, y = 100, z = 20 전달
f(5,100,200); // x = 5, y = 100, z = 200 전달
f(5, , 300); // 오류!!!!  f(5, 10, 300); 으로 작성해야 함.

 

 

▣ 함수 다중정의

● 다중정의(overloading)란?

  ▷ 동일한 이름에 대하여 여러 가지 의미를 부여하는 것

 

● 함수 다중정의

  ▷ 동일한 이름을 갖는 함수를 여러 개 정의하는 것

   동일한 개념의 처리를 여러 데이터나 객체에 대해 각각 대상에 맞게 처리해야 할 경우 사용

   다중정의된 함수 구분인수의 개수와 자료형으로 한다. 

   함수의 반환 자료형으로 함수를 구분할 수 없다!!!!!!

 

● 모호한 함수 다중정의 경우들

 

void f(int a){
   cout << a * a;
}

void f(int a, int b){
   cout << a * b;
}

void f(int a, int b){     //에러!!! 바로 위 함수와 반환 자료형만 다르기 때문에 구분될 수 없음!! 에러!!
   cout << a * b;
}

int main(){
   f(10);
   f(10, 20);
}

 

void g(int a)
{
    cout << a * a;
}

void g(int a, int b = 100)
{
    cout << a * b;
}

int main()
{
    g(10, 20);
    g(10);     //에러!!!!!!!! 선택 기준이 모호하다.
    ...
}

 

void h(int a)
{
    cout << a * a;
}

void h(float a)
{
    cout << a * b;
}

int main()
{
    h(10);
    h(10.0f);     
    h(10.0);     // 에러!! 형 변환 대상이 모호하다
    //10.0은 double 형이기 때문에 int나 float형으로 
    // 형변환이 일어나야 하는데 둘 중 무슨 함수를 써야하는 지 모호해서 오류남.
    ...
}

 

 

▣ inline 함수

 ● inline 함수 개념

  ▷ 함수 호출 절차를 따르지 않고 함수 호출 위치에 함수의 처리 문장이 삽입되게 번역하도록 선언된 함수

  ▷ 함수의 모듈화 장점을 살리면서 함수 호출에 따른 부수적인 처리 시간이 생략된다.

  ▷ 코드 최적화가 가능해진다.

  ▷ 아주 빈번히 호출되는 함수에 사용하면 좋다. 

 

 ● inline 함수 주의사항

  ▷ inline 함수로 선언하더라도 반드시 inline으로 컴파일러가 번역하는 건 아니다

  ▷ 다음의 경우에는 inline 선언을 무시하고 일반 함수로 번역한다.

  • 함수가 너무 큰 경우
  • 순환 호출(recursive call)을 하는 경우
  • 프로그램 내에서 그 함수에 대한 포인터를 사용하는 경우

  ▷ inline 함수의 예

inline void SwapValues(int &x, int &y)
{
	int temp = x;
	x = y;
	y = temp;
}

int main()
{
	int a, b;
	
	cout << "두 수를 입력하세요 : ";
	cin >> a >> b;
	if(a < b) SwapValues(a, b); //순서를 바꿔서 a에 큰 값 대입
		cout << "큰 수 = " << a << " 작은 수 = " << b << endl;
	return 0; 
}
728x90
반응형