본문 바로가기

프로그래밍언어/C++

C++ 스터디 14장 함수 1 – 관련된 코드를 모아서 담을 수 있는 가방

C++ 스터디 14장

함수 1 – 관련된 코드를 모아서 담을 수 있는 가방

 

Section 01 함수의 기본

함수의 가장 기본적인 특징은 바로 명령들, 즉 코드를 포함하고 있다는 점이다. 지금까지의 예제에서는 오로지 main()함수 하나만을 포함하고 있었지만 C++에서는 우리가 원하는 만큼의 많은 개수의 함수를 만들 수 있다.

우리가 나중에 가면 만들게 될 소스의 수는 몇 천 줄에서 몇 만 줄에 이르게 된다. 이렇게 되면 함수 하나에 담는 것보다 여러 함수로 나누는 것이 좋다.

 

#include <iostream>

using namespace std;

 

void sangjongmessage()

{

    cout << "Hi, My name is Park Sang Jong~!<<endl;

}

 

int main()

{

    //sangjongmessage() 라는 함수를 호출한다.

    sangjongmessage();

 

    return 0;

단순히 sangjongmessage()의 코드를 실행했음을 알 수 있다. 함수의 시작은 main() 함수에서 시작한다. 그안에서 sangjongmessage()함수를 호출하는 코드를 만나면 실행의 흐름은 sangjongmessage()로 이동한다. 거기서 다시 출력을 시작한 후 끝나면 다시 원래 위치로 돌아온다.

만약 이 위치를 바꾸면 어떻게 될까.

#include <iostream>

using namespace std;

 

 

int main()

{

    //sangjongmessage() 라는 함수를 호출한다.

    sangjongmessage();

 

    return 0;

}

    void sangjongmessage()

{

    cout << "Hi, Network Team Fighting~!"<<endl;

}

이렇게 출력을 하면 오류가 발생한다. 이유는 sangjongmessage라는 것을 해석하는 동안 도대체 sangjongmessage가 무엇인지 알 수가 없기 때문이다. 그렇다면 호출당하는 함수는 함수의 위쪽에 위치시켜야 되는 것인가라고 질문을 한다면 C++은 너무 비효율적일 것 이다.

이럴 경우에 main() 함수의 위쪽에 출력하려는 함수가 밑에 있다고 표시를 해주면 된다.

#include <iostream>

using namespace std;

 

    void sangjongmessage();

int main()

{

    //sangjongmessage() 라는 함수를 호출한다.

    sangjongmessage();

 

    return 0;

}

    void sangjongmessage()

{

    cout << "Hi, Network Team Fighting~!"<<endl;

}

 

여기서 함수의 위치를 정리하면 다음과 같다.

  • 함수는 자신을 호출하는 함수의 앞에 있어야 한다.
  • 혹은 함수의 원형이 앞에 있으면 된다.

 

반환 값

함수에는 반환 값이라는 개념이 존재한다. 함수가 실행된 후에는 다시 원래의 위치, 즉 함수를 호출한 곳의 다음 줄로 돌아간다는 사실을 배웠다. 이 때 함수는 하나의 값을 가지고 되돌아 갈 수가 있는데, 이 값을 반환 값이라고 부른다.

#include <iostream>

using namespace std;

 

//3을 반환하는 함수

int Three()

{

    return 3;

}

 

int main()

{

    //반환값을 담을 함수

    int ret = Three();

 

    //결과 출력

    cout <<"ret ="<<ret<< endl;

 

    return 0;

}

 

Section 02 인자의 전달

인자전달의 기본

인자라는 것은 함수를 호출하면서 함께 넘겨주는 값을 얘기한다.

 

기본적인 인자의 전달.

펙토리얼을 구하는 함수를 만들어보자.

 

#include <iostream>

using namespace std;

 

int main()

{

int n;

 

cout<<"정수를 입력하세요"<<endl;

cin>>n;

 

      

     int result = 1;

 

      

     for(int f = 1; f<=n; ++f)

     {

         result *=f;

     }

 

     cout <<n<<"!="<<result<<endl;

 

    return 0;

}

보기와 같이 숫자를 넣으면 팩토리얼로 계산하는 함수를 만들어 보았다.

 

인자 전달의 원리

인자가 두 개 이상인 경우에는 예제처럼 콤마를 사용해서 구분해 줄 수 있다.

 

인자의 전달과 메모리 구조

#include <iostream>

using namespace std;

 

//a와 b중에 큰 값을 반환하는 함수

int max(int a, int b)

{

    return a>b?a:b;

}

 

int main()

{

    //3과 5중에 큰값을 구한다

    int arg1 =3;

    int arg2 =5;

    int ret = max(arg1, arg2);

 

    return 0;

}

다음 표에서 int ret = max(arg1, arg2); 에서 max() 함수가 호출되면서 어떤 일이 발생하는지 생각해보자. arg1, arg2 의 값이 매개변수 a, b에 대입된다.

 

복합타입을 전달하기

 

포인터의 전달

30과 45의 최대공약수와 최소공배수를 만드는 함수를 만들어 보자.

#include <iostream>

using namespace std;

 

//최대 공약수와 최소 공배수를 구한다

void GCD_LCM(int a, int b, int* pgcd, int* plcm)

{

    //GCD를 구한다

    int z;

    int x =a;

int y =b;

    while(true)

    {

        z=x%y;

        if (0==z)

            break;

 

        x = y;

        y = z;

    }

 

    //결과를 저장한다

    *pgcd = y;

    *plcm = a*b / *pgcd;

}

 

int main()

{

    //30과 45의 최대 공약수와 최소 공배수를 구한다.

    int gcd = 0;

    int lcm = 0;

    GCD_LCM(30, 45, &gcd, &lcm);

 

    //결과를 출력한다.

    cout<<"GCD="<<gcd<<endl;

    cout<<"LCM="<<lcm<<endl;

 

    return 0;

}

위에서 GCD_LCM() 함수의 두 매개 변수의 타입을 int*타입으로 바꾸어 준다.

매개 변수 pgcd, plcm은 포인터 변수이기 때문에 주소 값을 보관하는 것이 이치에 맞다. 그렇기 때문에 인자는 int타입 변수의 주소 값이 되어야 하는 것이다.

포인터 타입의 인자를 이용해서 함수의 결과 값을 얻어오는 방법

  • 함수의 매개 변수는 포인터 타입으로 정의한다.
  • 인자를 넘겨줄 때는 값을 담고 싶은 변수의 주소를 넘겨준다.
  • 함수 안에서 결과를 넘겨줄 때는 매개 변수가 가리키는 곳에 값을 넣어준다.

 

배열의 전달

배열타입의 인자를 사용하는 방법

  • 매개 변수의 타입을 적어줄 때 '배열의 원소 개수' 부분은 적지 않는다.
  • 인자로 넘겨줄 때는 배열의 이름을 넘겨준다.
  • 인자로 넘어온 배열을 사용할 때는 그냥 평범한 배열을 사용하듯이 하면 된다.

#include <iostream>

using namespace std;

 

//배열을 인자로 갖는 함수의 원형

void UsingArray(char arr[]);

 

int main()

{

    //배열을 만들고 초기화 한다

    char array[20] = "Hi, study hard!";

 

    //함수에 배열을 넘겨준다

    UsingArray(array);

 

    //함수 호출 후의 배열 상태를 출력한다.

    cout<<"In main() : "<<array<<endl;

 

    return 0;

}

 

void UsingArray(char arr[])

{

    //넘겨받은 배열을 출력한다

    cout<<"In UsingArray() : " << arr<< endl;

 

}

Const를 사용해서 배열을 보호하는 법

호출된 함수의 안쪽에서 배열의 내용을 변경하게 되면 배열의 원본이 영향을 받는다. 함수 안에서 배열의 내용을 보기만 할 수 있고 고칠 수는 없게 하고 싶을 때가 있을 때는 const를 사용해서 배열의 수정을 막을 수 있다.

 

 

구조체의 전달

구조체 타입 인자의 전달은 기본적인 규칙을 잘 준수하고 있다. 구조체 변수의 크기는 멤버의 개수에 따라서 엄청나게 커질 수가 있다. 성능저하를 해결하기 위한 방안을 배열의 전달 방식에서 발견할 수 있다. 실제적으로는 배열이 아닌 포인터가 사용되었던 것처럼, 구조체의 포인터나 레퍼 런스를 전달하는 방법을 사용할 수 있다. 물론 사용이 간편한 레퍼런스를 주로 사용한다.

간단하게 정리하면 다음과 같다

  • 구조체를 인자로 넘겨줄 때는 레퍼런스를 사용하자
  • 함수의 안쪽에서 구조체의 내용을 읽기만 한다면 const와 레퍼런스를 사용하자.

 

CRT함수의 사용

CRT란 C Runtime Library의 약자로 C++언어와 함께 제공되는 라이브러리들을 의미한다. 그 중에서 사용할 함수는 수학함수의 일부로 sqrt()와 pow()다.

Sqrt()는 제곱근을 구해주는 함수이고 pow()는 거듭제곱을 구해주는 함수이다.

Sqrt()함수는 double타입의 인자를 하나 받고, double타입의 값을 반환한다. Pow()함수는 double타입의 인자를 두개 받고, double타입의 값을 반환한다.

Sqrt()와 pow()함수의 사용

#include <iostream>

#include <cmath>

using namespace std;

 

int main()

{

    //2의 제곱근을 구한다.

    double sqrt_2 = sqrt(2.0);

 

    //12의 제곱을 구한다.

    double pow_12_2 = pow(12, 2);

 

//결과 출력

    cout<<"2의 제곱근 = "<<sqrt_2<<endl;

    cout<<"12의 제곱 = "<<pow_12_2<<endl;

 

    return 0;

}

 

수학과 관련된 함수를 사용하기 위해서는 #include <cmath>라는 것을 써 주어야 한다.

함수를 사용하는 것은 어렵지 않은데 sqrt()의 경우에는 인자로 넘긴 값에 대한 제곱근을 반환하고 pow()의 경우는 첫번째 인자를 두번째 인자만큼 제곱한 값을 반환한다.

'프로그래밍언어 > C++' 카테고리의 다른 글

성적나누기 프로그램  (0) 2012.08.02
Chapter 04. 변수 – 정보를 담는 방법  (0) 2010.12.27