함수

윤형찬·2020년 10월 28일

C++

목록 보기
8/10
post-thumbnail

매개변수와 실인자의 구분

  • 매개변수는 함수가 끝나면 사라진다.

예제

int foo(int x, int y)
{
    return x + y;
} // x and y are destroyed here

int main()
{
    int x = 1 , y= 2;
    
    foo(6, 7); // 6, 7 arguments (actual parameters)
    foo(x, y + 1);
    
    return 0;
}
  • foo 함수가 끝나는 지점에서 foo 함수의 매개변수로 선언된 x와 y는 함수가 종료되면서 없어진다.
  • main 함수 안에서 foo 함수가 호출되어 사용될 때 들어가는 것들을 인자 (argument) 라고 한다.


값에 의한 인수 전달

예제

void doSomething(int y)
{
    cout << "In func " << y << " " << &y << endl;
}

int main() {
    doSomething(5);
    
    int x = 6;
    
    cout << "In main " << x << " " << &x << endl;
    
    doSomething(x);
    doSomething(x + 1);
    
    return 0;
}

In func 5 0x7ffeefbff45c
In main 6 0x7ffeefbff478
In func 6 0x7ffeefbff45c
In func 7 0x7ffeefbff45c

  • doSomething 함수의 파라미터로 값으로 전달되는 인자는 다른 변수의 값으로 전달될 때 값이 복사가 되어서 새로운 메모리 공간을 가진 값이 전달이 된다.
  • 결과를 보면 변수 x 의 5를 함수의 인자로 사용하여 함수를 호출했을때, 변수 x의 주소와는 다르다.
  • 값으로 호출 시 함수안에서 사용하는 값은 변수에 영향을 미치지 않는다.


참조에 의한 인수 전달

예제

void addOne(int &y)
{
    y = y + 1;
}

int main()
{
    int x = 5;
    cout << x << " " << &x << endl;
    
    addOne(x);
    
    cout << x << " " << &x << endl;
    
    return 0;
}

5 0x7ffeefbff478
6 0x7ffeefbff478

  • 참조에 의한 호출에서는 그냥 변수 자체를 넘기는 것이기 때문에 주소도 똑같고, 새로 인자를 넘기기 위한 복사 및 메모리할당도 일어나지 않는다.

구현 예제

#include <iostream>
#include <cmath> // sin(), cos()

using namespace std;

void getSinCos(const double degree, double &sin_out, double &cos_out)
{
    // 함수 호출될 때마다 새로 정의되지 않고 한번만 될 수 있도록 static
    static const double pi = 3.141592;  // 헤더로 뽑을수도 있음
    
    const double radians = degree * pi / 180.0; // degree 는 안바뀌므로 매개변수 선언시 const로
    
    sin_out = std::sin(radians);
    cos_out = std::cos(radians);
}

int main()
{
    double sin(0.0);
    double cos(0.0);
    
    getSinCos(30.0, sin, cos);
    
    cout << sin << " " << cos << endl;
    
    return 0;
}

pointer 로 전달 예제

typedef int* pint;
//void foo(int *&ptr)
void foo(pint &ptr)
{
    cout << ptr << " " << &ptr <<  endl;
}

int main()
{
    int x = 5;
    int *ptr = &x;
    
    cout << ptr << " " << &ptr <<  endl;
    
    foo(ptr);
    
    return 0 ;
}

0x7ffeefbff478 0x7ffeefbff470
0x7ffeefbff478 0x7ffeefbff470

array를 parameter로 전달하는 방법

#include <iostream>
#include <vector>

using namespace std;

void printElement(vector<int> &arr)
//void printElement(int &arr[4])
{
    
}

int main()
{
    // int arr[] {1, 2, 3, 4 };
    vector<int> arr {1, 2, 3, 4};
    
    printElement(arr);
    
    return 0 ;
}


인라인 함수

  • 작은 함수들이 자주 반복되는 경우
  • 함수를 계속 호출하고 반복적인 과정이 많이 생긴다.
  • 그 과정을 줄이기 위해 사용된다.

예제

inline int min (int x, int y)
{
    return x > y ? y : x;
}

int main()
{
    cout << min(5, 6) << endl;
    cout << min(3, 2) << endl;
    
    // 컴파일러가 위에 코드를
    // cout << (5 > 6 ? 6 : 5) << endl 라고 본다
    return 0;
}


함수 오버로딩

  • 들어오는 매개변수가 다른데 수행하는 기능은 비슷할 때 사용
  • 오버로딩된 함수 중 어떤걸 사용할 지는 컴파일 할 때 결정되어야 한다.
  • 매개변수 매치가 안되거나 모호하게 매칭이 되지 않게 주의해야한다.

예제

int add(int x, int y)
{
    return x + y;
}

double add(double x, double y)
{
    return x + y;
}

int main()
{
    cout << add(1,2) << endl;
    cout << add(3.0, 4.0) << endl;
    
    return 0;
}


매개변수의 기본값

  • 매개변수가 여러개가 있을때 매번 모든 매개변수 값을 다 넣어주는 것은 번거롭다.
  • 기본값을 설정해서 argument 설정을 생략 할 수 있다.
  • 보통 선언자에 기본값을 넣고, 정의구문에서 생략한다.
  • 파라미터가 여러개일때 뒤에 부터 넣을 수 있다.
  • 함수 호출시에 인자는 앞에서 부터 들어간다.

예제

void print(int x = 10, int y = 20, int z = 30); // in header

void print(int x, int y, int z)
{
    cout << x << " " << y << " " << z << endl;
}

int main()
{
    print();
    print(100);
    print(100, 200);
    print(100, 200, 300);
    
    return 0;
}

10 20 30
100 20 30
100 200 30
100 200 300



함수 포인터

  • 함수도 메모리에 들어가고, 함수를 호출하면 해당 메모리를 찾아서 함수를 호출한다.

사용 예제

#include <iostream>
#include <array>

using namespace std;

bool isEven(const int& number)
{
    if(number % 2 == 0) return true;
    else return false;
}

bool isOdd(const int& number)
{
    if(number % 2 != 0) return true;
    else return false;
}

void printNum(const array<int, 10>& my_array, bool (*check_fcn)(const int&) = isEven) // 함수 포인터 기본값 선언
{
    for(auto element : my_array)
    {
        if(check_fcn(element) == true) cout << element;
    }
    cout << endl;
}

int main()
{
    std::array<int, 10> my_arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    
    printNum(my_arr);
    printNum(my_arr, isOdd);
    
    return 0;
}


스택과 힙

  • 스택
    - 아래에서 부터 쌓이고 위부터 빠지는 구조
    - 현재 실행시켜야 할게 가장 위에있음
    - 속도가 비교적 빠름
    - 크기가 작음 (stack overflow 발생가능)

  • - 스택 단점 보완을 위해 사용
    - 동적 메모리가 할당이 되면 힙에 메모리가 잡힌다.
    - 크기가 크다
    - 어디에 생길지 예측을 하기가 힘들다.
    - 메모리를 delete 으로 지우면 힙에있는 메모리 자체는 반납이 되지만 주소는 값으로 계속 갖고 있다.


std::vector를 스택처럼 사용하기

  • 동적 할당 메모리를 직접 관리하는거보다 vector를 사용하는 것이 훨씬 편하다
  • vector를 잘 사용하려면 내부에서 이루어지는 new 와 delete 이 어떻게하면 적게 호출될것인가 생각하면서 사용해야한다.
  • capacity() : 실제로 갖고있는 메모리
  • size() : 그 중에 사용하는 메모리

예제

int main()
{
    std::vector<int> v { 1, 2, 3 };
    
    v.resize(2);
    
    for(auto &e : v) 
        cout << e << " ";
    cout << endl;
    
    cout << v.size() << " " << v.capacity() << endl;
    
    int *ptr = v.data();
    
    cout << ptr[2] << endl;
    
    return 0;
}

1 2
2 3
3

메모리에 실제로 값은 저장되어있지만, vector 는 없는척 한다.

Vector 를 이용한 Stack 구현

  • (vector).puch_back(); : 쌓기
  • (vector).pop_back(); : 맨위 뽑기
#include <iostream>
#include <vector>

using namespace std;

void printStack(const std::vector<int> &stack)
{
    for (auto &e : stack)
        cout << e << " ";
    cout << endl;
}

int main()
{
    std::vector<int> stack;
    // stack.reserve(1024); // 메모리의 용량을 미리 확보한다, size에는 포함 안된다.
    
    stack.push_back(3);
    printStack(stack);
    stack.push_back(5);
    printStack(stack);
    stack.push_back(7);
    printStack(stack);
    stack.pop_back();
    printStack(stack);
    stack.pop_back();
    printStack(stack);
    stack.pop_back();
    printStack(stack);
    
    return 0;
}

3
3 5
3 5 7
3 5
3



재귀적 함수 호출

  • 자기하고 이름이 똑같은 함수를 다시 호출하는 것
  • 종료조건을 만드는게 중요하다.

예제 1)

void countDown(int count)
{
    cout << count << endl;
    if(count > 0)
        countDown(count - 1);
}

int main() {
    countDown(10);
    return 0;
}

예제 2)

int sumTo(int sumto)
{
    if (sumto <= 0)
        return 0;
    else if (sumto <= 1)
        return 1;
    else
        return sumTo(sumto - 1) + sumto;
}

int main() {
    cout << sumTo(5) << endl;
    
    return 0;
}

예제 3)

피보나치

#include <iostream>
using namespace std;

int fibonacci(int num)
{
    if (num <= 1)
        return num;
    else
    {
        return fibonacci(num - 1) + fibonacci(num - 2);
    }
}

int main() {
    cout << fibonacci(15) << endl; 
    return 0;
}


profile
https://github.com/velmash

0개의 댓글