[C++] 함수 Basic - 정의, 인수 전달, 포인터

2022. 6. 23. 23:29♣ C++

 

이번 포스팅에선 함수에 대해 알아보도록 하겠습니다.

함수 : 하나의 목적으로 수행하고, 하나의 결괏값을 내놓는 기능을 합니다.

int형끼리 더하고 싶을 때, 문자열을 특정 방법으로 편집할 때 등

특정 목적을 위해 함수를 정의해서 사용합니다.

 

개발 환경 : VSCode, Windows 10

 

 

 

 

 

기본 개발 세팅은 다음과 같습니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;

int main()
{
	return 0;
}

 

 

 

 

 

📌 함수의 정의 및 선언

 

먼저 간단한 함수를 구현한 코드입니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;


int Substract(int, int);

int main()
{   
    int result;
    result = Substract(5, 6);
    cout << "함수의 결과는 " << result << " 입니다." << endl;
    return 0;
} 


int Substract(int a, int b)
{
    return a - b;
}

이 코드를 하나씩 뜯어보면서 함수 선언과 규칙을 알아보도록 하겠습니다.

 

 

함수를 정의하기 전, 함수의 원형을 미리 정의해줘야 합니다.

* 함수의 원형이란? 함수의 대략적인 형태와 받는 인수 타입을 지정해주는 코드를 말합니다.

타입 함수이름(인수 타입);

int Substract(int, int);

 

 

함수를 사용할 땐, 그저 함수를 쓰고 안에 인수를 전달하면 됩니다.

함수(인수, 인수);

Substract(5, 6);

 

 

마지막으로 main 함수 뒤에, 함수 기능과 인수를 정의해줍니다.

타입 함수이름(인수, 인수){기능 return 결과물};


int Substract(int a, int b)
{
    return a - b;
}

 

 

함수를 정의할 때, 인수의 타입은 꼭 맞춰야 합니다.

함수 앞에 적는 타입(예시에선 int형)은 return되는 결과물이 어떤 타입이냐를 명시합니다. string형이면 string을 붙여야 하고, double형이면 double을 붙여야 합니다. 만약 return되는 결과물이 없다면 void를 붙입니다.

 

 

 

 

 

📌 인수 전달 방법

 

인수는 함수에 전달될 데이터를 말합니다. 

Substract(5, 6);

Substract(5, 6)에선 5와 6이 인수가 됩니다. 

함수에 인수를 전달하는 방법은 크게 두 가지가 있습니다.

(1) 값에 의한 전달

(2) 참조에 의한 전달

 

 

 

🎨 값에 의한 전달

 

앞 예시처럼 변수의 값을 함수 내의 매개변수에 복사하는 방식입니다.

매개변수와 전달된 변수는 별개이므로, 서로 아무런 영향을 끼치지 않습니다.

 

int Check(int);

int main()
{   
    int num = 5;
    Check(num);
    cout << "Check는 " << num << " 입니다." << endl;
    return 0;
} 


int Check(int num)
{
    num += 20;
}

 

결과

Check는 5 입니다.

Check 함수에서는 num에 20을 더했습니다. 하지만 함수가 종료됨과 동시에 함수의 매개변수도 메모리에서 사라졌습니다. 따라서 기존의 변수 Check(=5)만 남았기에 5가 출력된 것을 볼 수 있습니다.

 

 

 

 

🎨 참조에 의한 전달

 

값에 의한 전달과 달리 변수의 원본을 그대로 전달합니다. 

따라서 함수에서 값이 바뀌면 원본도 바뀝니다.

원형 - 타입 함수이름(타입&);
본체 - 타입 함수이름(타입 &변수이름);

참조자(&)를 통해 변수의 주소에 직접 접근했습니다.

다음은 예시 코드입니다.

 

int Check(int&);

int main()
{   
    int num = 5;
    Check(num);
    cout << "Check는 " << num << " 입니다." << endl;
    return 0;
} 


int Check(int &num)
{
    num += 20;
}

 

결과

Check는 25 입니다.

원본을 그대로 전달한 결과, 함수에서 20 더한 것이 원본에도 그대로 반영되었습니다.

이것이 참조에 의한 인수 전달 방법입니다.

 

 

 

🎨 main() 함수에도 인수 전달.

 

main() 함수의 원형

void(또는 int) main(int argc,char *argv[]);

int형 변수 argc는 인수로 전달되는 문자열의 개수를 명시합니다.

char형 포인터의 포인터인 argv는 인수로 전달된 각각의 문자열이 포함되는 배열을 가리킵니다.

 

 

 

 

📌 재귀 호출

 

C++ 함수도 재귀 호출이 가능합니다. 

재귀 호출이란 자기 자신을 계속해서 호출하는 함수를 말하며, 조건을 만족하면 종료합니다.

직관적인 것이 장점입니다.

 

int Recursive_Func(int);

int main()
{   
    cout << "1-100까지의 합은 " << Recursive_Func(100) << " 입니다." << endl;
    return 0;
} 


int Recursive_Func(int n)
{
    if (n<=1){
        return 1;
    }
    return n + Recursive_Func(n-1);
}

Recursive_Func은 n=1이 될 때까지 계속해서 n-1을 대입한 자기 자신을 불러옵니다.

 

 

결과

1-100까지의 합은 5050 입니다.

반복문을 써서 코드를 구현할 수도 있겠지만, 재귀 호출을 씀으로써 가독성을 높이고 코드를 단순화했습니다.

 

 

 

 

 

📌 함수 포인터

 

함수도 프로그램이 실행될 때 메인 메모리에 올라갑니다.

그 뜻은 함수에게도 주소 값이 있다는 말이 됩니다. 함수 포인터는 함수의 주소 값을 가리키는 변수입니다.

 

=> 포인터 개념 이해하러 가기 

 

[C++] Pointer 개념, 연산에 대해 알기

이번 포스팅에선 C++의 포인터에 대해 알아보도록 하겠습니다. 포인터 : 다른 변수, 혹은 그 변수의 메모리 공간 주소를 가리키는 변수 즉, 특정 변수가 저장되어 있는 메모리 주소 개발 환경 : VSC

mengu.tistory.com

 

 

함수의 이름 = 함수의 시작 주소를 가리키는 포인터 상수

포인터 상수가 곧 함수 포인터.

* 포인터 상수는 주소 값을 변경할 수 없는 포인터를 의미합니다.

 

예시를 통해 함수 포인터 개념을 이해하도록 하겠습니다.

예시에선 (1) 사칙연산 함수, (2) 사용자가 원하는 연산을 입력하면 그에 따라 연산을 수행하는 함수를 정의하고 사용합니다.

 

 

(1) 함수 원형 선언

double Add(double, double);
double Sub(double, double);
double Mul(double, double);
double Div(double, double);
double Calculator(double, double, double(*func)(double, double));

일반적인 함수를 선언하듯이 원형을 선언합니다. 다만, Calculator 함수는 후에 함수 포인터를 인수로 받습니다. 함수 포인터를 인수로 받을 땐 다음과 같이 씁니다.

타입(*함수이름)(인수타입);

double(*func)(double, double);

 

 

(2) main 함수 코드

double(*calculator)(double, double) = NULL;

main() 함수에서 calculator라는 함수 포인터를 선언하고, NULL 값으로 설정합니다.

 

 

main함수 전체 코드입니다.

int main()
{
    int a = 30, b = 10;
    double(*calculator)(double, double) = NULL;
    int pointer_func;
    char oper;
    cout << "어떤 연산을 진행하시겠습니까? (+, *, -, /) : ";
    cin >> oper;

    switch (oper)
    {
    case '+':
        calculator = Add;
        break;
    case '-':
        calculator = Sub;
        break;
    case '*':
        calculator = Mul;
        break;
    case '/':
        calculator = Div;
        break;
    default:
        cout << "사칙연산만을 지원합니다.";
        break;
    }
    
    pointer_func = Calculator(a, b, calculator);
    cout << "결과 값은 " << pointer_func << " 입니다." << endl;
}

함수 포인터와 변수들을 선언하고, 사용자에게 원하는 연산을 입력받습니다.

switch문을 통해 연산자에 맞는 함수와 함수 포인터를 연결합니다.

연결이 끝났다면 이제 Calculator 함수에 인수로 전달만 하면 됩니다.

 

 

(3) 함수 정의

함수 정의도 함수 원형과 거의 똑같습니다.

double Add(double a, double b){return a + b;}
double Sub(double a, double b){return a - b;}
double Mul(double a, double b){return a * b;}
double Div(double a, double b){return a / b;}
double Calculator(double a, double b, double(*func)(double, double)){return func(a, b);}

사칙연산 함수들은 return 코드를 짜줍니다. Calculator 함수는 인수를 그대로 쓰고, 본문에선 인수 부분에서 정의한 함수 포인터 이름(func)을 그대로 써주면 됩니다.

 

 

결과

어떤 연산을 진행하시겠습니까? (+, *, -, /) : +
결과 값은 40 입니다.

어떤 연산을 진행하시겠습니까? (+, *, -, /) : -
결과 값은 20 입니다.

어떤 연산을 진행하시겠습니까? (+, *, -, /) : *
결과 값은 300 입니다.

어떤 연산을 진행하시겠습니까? (+, *, -, /) : /
결과 값은 3 입니다.

 

 

 

지금까지 함수 정의와 인수전달, 포인터에 대해 알아보았습니다.

다음 포스팅에선 함수에 대한 좀 더 다양한 이야기들을 들고 오겠습니다.

수고하셨습니다.