[C++] 함수에 관한 모든것(함수 특징/Call by value/call by reference/지역변수/전역변수/함수 오버로딩)

 

함수

하나의 작은 목적을 수행하기 위해 여러 문장을 모아 놓은 것

// 함수 헤더
returnValueType functionName(list of parameters)    
{
    // 함수 몸체 : 할 일 정의
}

 
// 함수 호출 : 함수 사용
functionName(actual parameter);

 

 * 함수 헤더 : 함수의 반환값 유형(returnValueType), 함수 이름(functionName), 매개변수로 구성

  ** 매개변수 : 함수 헤더에 작성된 변수. 함수가 호출될 때 값이 전달되어 저장되는 변수

  ** 실매개변수(인수) : 호출하는 쪽의 매개변수

 

 

함수의 특징 

5   int max(int num1, int num2)
6   {
7      int result;
8   
9      if(num1 > num2)
10         result = num1;
11     else
12         result = num2;
13     return result;
14  }
15
16  int main()
17  {
18     int i = 5;
19     int j = 2;
20     int k = max(i, j);
21
22     cout << "the maximum between" << i << "and" << j << " is" << K;
23     // cout << max(i,j);
24
25     return 0;
26  }

결과 : the maximum between 5 and 2 is 5

 

해설 : 

위 코드 프로그램 제어 순서 : 16 ~ 19줄  5 ~ 14줄  20 ~ 25줄

22번째와 같이 하나의 변수처럼 사용할 수도 있으며 23번째 줄과 같이 수식에서도 사용 가능하다

 

 

- 함수는 값을 반환한다 (O)

- 함수는 반환내용 없이 주어진 일을 처리한다 (O) 

 * void 함수 : 반환값이 없는 함수

    ** void 함수의 호출은 하나의 문장으로 작성해야 함, 즉 수식이나 대입 식에 void 함수를 포함시킬 수 없음

 

 - 함수를 사용하면 프로그램이 읽기 쉽고 유지보수도 좋아진다.

- 그러나 함수 호출은 실행 오버헤드(인수전달, cpu 레지스터를 스택으로 이동, 함수간의 제어 전달, context switch overhead 등)가 발생

- 프로그램에서 함수를 호출하게 되면 프로그램 제어는 호출하는 함수 쪽으로 넘어간다. 호출된 함수에서는 반환 문이 실행되거나 함수의 끝에 도달했을 때 호출자에게 제어를 되돌려준다.

- main도 함수이나 프로그램을 시작하기 위해서 운영체제에 의해 호출된다는 점이 일반함수와 다르다.

 

- 함수는 호출되기 전에 선언되어야 한다.

→ 함수 호출 전 함수 원형 선언 필요

  * 함수 원형(prototype);: 함수의 구현(몸체)이 없는 선언

- 함수 원형에서는 매개변수의 이름을 작성할 필요는 없고 매개변수 유형만 있어도 된다.

  * 함수 시그니처 : 함수이름, 매개변수

  ** 반환 타입은 함수 시그니처 아님!

 

 

o 인라인 함수

함수처럼 호출되는 것이 아니라 컴파일러에 의해 인라인 함수를 호출하는 지점으로 함수 내용을 복사하는 방식

- 함수 선언 앞에 inline 키워드 사용

- c++ 컴파일러가 인라인 함수를 호출하는 지점에 인라인 함수를 복사해 넣어 코드를 확장하는 것이다.

- 함수의 길이가 짧은 경우에만 적합, 여러 곳에서 호출되는 큰 함수의 경우 부적합

→ 인라인 함수로 처리할지 무시할지의 결정은 컴파일러에게 달려있다.

 

 

 

인수 전달 방법

매개변수가 있는 함수를 호출할 때 인수 값 전달

 

1) Call-by-value(값에 의한 전달)

인수가 변수라면 변수의 값이 매개변수로 전달됨

함수 안에서 매개변수의 값이 변경되더라도 호출한 곳에서 인수로 사용된 변수의 값은 변화가 없음

 

void increment(int n)
{
   n++;
   cout << "n inside the function is " << n << endl;
}

int main()
{
   int x = 1;
   cout << "before the call, x is " << x << endl;
   
   increment(x);
   cout << "after the call, x is" << x << endl;
   
   return 0;
}

 

결과 :

before the call, x is 1

n inside the function is 2

after the call, x is 1

 

해설 : 

함수 호출 후에도 함수의 값은 변하지 않는데(호출전, 후 값 모두 x는 1) 인수의 값이 매개변수로 전달되었기 때문이다. 이는 매개변수와 인수가  서로 독립적인 공간을 사용하기 때문에 인수의 값이 변경된다 해도 원 변수의 값은 변화가 없는 것이다.

 

- x를 n으로 이름을 바꾸면 어떻게 될까?

 여전히 두 값의 변경은 이루어지지 않는다. 호출자의 인수와 함수의 매개변수가 같은 이름을 가진다 하더라도, 함수의매개변수는 함수가 호출될 당시에 호출자 인수와는 상관없이 자신만의 메모리 공간을 할당받는다. 이 매개변수를 위한 메모리 공간은 함수의 실행이 끝나고 호출자로 되돌아갈 때 사라지게 된다.

 

void swap(int n1, int n2)
{
   cout << "Inside the swap function" << endl;
   cout << "Before swapping n1 is" << n1 << "n2 is" << n2 << endl;

   int temp= n1;
   n1 = n2;
   n2 = temp;

   cout << "After swapping n1 is" << n1 << "n2 is " << n2 << endl;
}

int main ()
{
   int num1 = 1;
   int num2 = 2;

   cout << "Before invoking the swap function, num1 is " << num1 << 
           "and num2 is " << num2 << endl;
   
   swap(num1, num2);

   cout << "After invoking the swap function, num1 is "<< num1 << 
           "and num2 is" << num2 << endl;

   return 0;
}

결과 :

Before invoking the swap function, num1 is 1 and num2 is 2

Inside the swap function

Before swapping n1 is 1 and n2 is 2

After swapping n1 is 2 and n2 is 1

After invoking the swap function, num1 is 1 and num2 is 2

 

 

2) Call-by-reference(참조에 의한 전달)

o 참조변수

원 변수를 참조하기 위해 함수의 매개변수로 사용되는 변수

- 참조변수는 변수에 대한 별칭으로 동작하여, 참조 변수에 수정을 하면 원 변수에도 수정된 내용이 반영됨

- 참조변수를 선언할 때는 변수 앞에 엠퍼샌드&를 붙인다

 

type &ref_var;
ref_var = orgin_var;
→ type &ref_var = orgin_var;

 

 

int main()
{
   int count = 1;
   int &refCount = count;
   
   refCount++;

   cout << " count is " << count << endl;
   cout << "refCount is" << refCount << endl;
   
   return 0 ;
}

결과 :

count is 1

refCount 2

 

해설 :

함수 매개변수에서도 참조변수를 사용할 수 있으며 호출하는 측에서는 일반 변수를 사용하여 호출하면 된다. 이 때 매개변수는 원 변수에 대한 별칭이 된다.

  

 

 

* 즉, 다시한번 정리하면 함수에 매개변수를 전달하는 두가지 방법

- Call-by-value, Call-by-reference

- 값에 의한 전달은 독립적인 변수에 값을 복사하는 것이고, 참조에 의한 전달은 같은 변수를 공유하는 것

 

 

 

함수 오버로딩 

하나의 파일 안에 이름은 같고 매개변수 목록만 다른 함수 여러 개 사용

- 함수 오버로딩은 프로그램을 보다 간결하게 하고 읽기 쉽게함

- 함수 호출 시 가장 가까운 함수를 찾음

 

 * max(3, 4) :  3, 4가 int형이므로 max(double, double)보다는 max(int, int)를 호출

 * max(1, 2) :  max(int, double), max(double, int)이 있는 경우 모호한 호출 에러

   → 이름이 같되, 매개변수 목록이 달라야 함(반환 유형은 상관없음) 

 

- 기본 인수 값으로 함수를 선언할 수 있는데, 인수없이 함수를 호출하면 기본 값이 매개변수로 전달된다.

- 함수의 장점 중 하나는 다른 프로그램에서 함수 재사용이 가능하다는 것이다.

- #include 전처리 지시자를 사용하여 함수를 포함한 프로그램의 헤더 파일을 포함시키면 된다.

- 헤더 파일에서 main 함수를 작성하지 말아야 한다.

 

 

지시자#

#: 컴파일하기 전에 ~부터 하라.

 

* #include <iostream> : 컴파일하기 전에 iostream 헤더파일을 인쿠르드하여라!

* 표기 

 - 표준 헤더 파일 : < >안에 표기, 

 - 사용자 정의 헤더 파일 : " " 안에 표기

 

 

지역변수와 전역변수

o 지역변수 : 함수 안에 선언된 변수

o 전역변수 : 함수 외부에서 선언되어 파일 내 모든 함수에서 접근이 가능한 변수

 

- 지역변수는 기본 값이 없지만, 전역 변수는 기본 값이 0으로 설정된다.

- 변수의 범위는프로그램에서 변수가 어떤 범위까지 참조되는 것인지에 관한 것으로 지역변수의 범위는 선언한 지점으로부터 해당 블록이 끝날 때까지이고,  전역변수의 범위는 변수 선언한 지점으로부터 프로그램이 끝날 때까지이다.

- 매개변수는 지역변수다.

 

* 변수는 사용하기 전에 먼저 선언되어 있어야함

 

int main() 
{
   t1();
   t2();
   
   return 0;
}

int y;    // 전역변수, 초기값 0

void t1()
{
   int x = 1; // 지역변수
   cout << x <<" " << y << endl;

   x++; y++;
}

void t2() 
{
   int x = 1;
   cout << x <<" " << y << endl;
}

 

결과 :

1 0

1 1

 

해설 :

- t1()의 x와 t2()의 x는 이름만 같은 것이지 실제로 다른 메모리 영역에 저장되어 있기 때문에 서로 다른 변수이다. (t1의 x의 값의 변경이 t2의 x에 아무런 영향을 미치지 않음)

- 지역 변수의 이름과 전역 변수의 이름이 동일한 경우, 함수 내에서는 지역 변수의 이름만 접근할 수 있다.

→ 함수 내에서 전역 변수에 접근하고자 하는 경우에는 :: 전역변수 를 사용하여 전역변수에 접근할 수 있다.

 

 

* 정적 지역 변수

함수 실행이 완료되어도 사라지지 않는 지역변수

- static 키워드 사용

- 지역 변수를 사용하기 위해 지역변수에 저장된 값을 유지하고자 할 때 사용

- 프로그램이 끝날 때까지 메모리가 사라지지 않고 계속 유지된다.

 

void t1()
{
   stiatic int x = 1;  // 정적지역변수 
   int y = 1;          // 지역변수
   
   x++; y++;
   cout << x << " " << y << endl;
}

 

※ 스택

메모리 영역. LIFO 형태

- 함수가 호출될 때마다 인수와 변수들을 스택 메모리 영역에 저장

- 함수가 다른 함수를 호출하면 현재 함수의 스택 공간은 유지되고, 호출된 함수를 위해 새로운 메모리 공간이 생성됨

 

반응형
그리드형

댓글

❤️김세인트가 사랑으로 키웁니다❤️