본문 바로가기
개인공부/Rookiss C++ 프로그래밍 입문

Chapter 4 - 함수

by 하고싶은건많은놈 2023. 3. 29.

함수 기초

반환타입 함수이름(인자타입 매개변수)
{
    함수 내용
    return ---;
}

void PrintHelloWorld()
{
    cout << "Hello World" << endl;
}

input으로 무엇을 받고, output으로 무엇을 반환할지 정해줘야함
입력 혹은 출력이 없는 경우 타입을 void형으로 지정
return을 만나는 순간 함수를 완전히 빠져나오게됨

void PrintNumber(int n)
{
    cout << "넘겨주신 숫자는 " << n << "입니다" << endl;
}

int MultiplyBy2(int a)
{
    return a * 2;
}

int MultiplyBy(int a, int b)
{
    return a * b;
}

매개변수는 해당 함수 내에서만 유효함
매개변수는 여러개 있을 수 있음


스택 프레임

디버깅시 프로시저 단위 실행과 단계별 코드 실행을 선택할 수 있음

스택은 높은 메모리 주소에서 낮은 메모리 주소 순서로 채워짐
함수 호출시 매개변수, 반환 주소값, 지역변수가 메모리에 올라감
스택은 결국 함수들끼리 돌려 사용하는 메모장같은 느낌이라고 볼 수 있음


지역 변수와 값 전달

전역 변수는 데이터 영역, 지역 변수는 스택 영역에 속함
지역 변수는 함수 내에 정의하며, 해당 함수 내에서만 사용할 수 있음

전역 변수는 관리가 어렵기 때문에 사용을 지양해야함

void increase(int hp)
{
    hp = hp + 1;
}

int main()
{
    int hp = 1;
    cout << "increase 호출 전 : " << hp << endl;
    increase(hp);
    cout << "increase 호출 후 : " << hp << endl;

    return 0;
}

매개변수로 전달된 지역변수는 복사본으로 사용되어 해당 함수 내에서만 변경됨
이를 값에 의한 전달이라고 함


호출 스택

void Func1();
void Func2(int a, int b);
void Func3(float a);

void Func1()
{
    cout << "Func1" << endl;
    Func2(1, 2);
}

void Func2(int a, int b)
{
    cout << "Func1" << endl;
    Func3(10);
}

void Func3(float a)
{
    cout << "Func3" << endl;
}

int main()
{
    cout << "main" << endl;
    Func1();
    return 0;
}

함수를 정의 순서에 상관없이 사용하기 위해서는 함수 선언이 필요함
함수 선언시 매개변수에는 이름을 붙이지 않아도 되고, 정의에서의 이름과 달라도 됨
함수가 어떤 경로로 호출되었는지를 호출 스택에서 확인할 수 있음


함수 마무리

int Add(int a, int b)
{
    return a + b;
}

int Add(float a, float b)
{
    return a + b;
}

int main()
{
    int result = Add(1.5f, 2.1f);
    return 0;
}

오버로딩 : 함수 이름의 재사용
함수의 매개변수 개수 혹은 타입이 다른 경우(순서가 다른 경우도 포함) 동일한 이름의 함수를 중복 정의할 수 있음
단, 반환형식만 다른 경우에는 오버로딩할 수 없음

void SetPlayerinfo(int hp, int mp, int attack, int guildid = 0)
{
    ...
}

int main()
{
    SetPlayerinfo(100, 40, 10);
    SetPlayerinfo(111, 40, 10, 1);
    SetPlayerinfo(120, 40, 10);
    ...
}

매개변수의 기본값 설정시 함수를 호출할 때 해당 인수를 지정하지 않아면 기본값으로 설정됨
단, 기본값을 설정할 매개변수는 반드시 끝쪽에 있어야 함

int Factorial(int n)
{
    if (n <= 1)
        return 1;
    return n * Factorial(n - 1);
}

int main()
{
    int result = Factorial(1000000);
    cout << result << endl;
}

함수가 지나치게 호출될경우 스택 오버플로우가 발생할 수 있음


TextRPG

// textRPG

#include <iostream>
using namespace std;

struct ObjectINfo
{
    int type;
    int hp;
    int att;
    int def;
};

ObjectINfo player;
ObjectINfo monster;

void select_job();
void select_do();
void select_mon();
void select_battle();

int main()
{
    srand(time(0)); 
    while (true)
    {
        cout << "---------------\n";
        cout << "로비에 입장했습니다!\n";
        cout << "---------------\n";

        select_job();

        select_do();
    }
    return 0;
}

void select_job()
{
    const int KNIGHT = 1;
    const int ARCHER = 2;
    const int MAGE = 3;

    while (true)
    {
        cout << "직업을 골라주세요!\n";
        cout << "(1) 기사 (2) 궁수 (3) 법사\n";
        cout << "> ";

        cin >> player.type;

        switch(player.type)
        {
            case KNIGHT:
            {
                cout << "기사 생성중... !\n";
                player.hp = 150;
                player.att = 10;
                player.def = 5;
                return ;
            }
            case ARCHER:
            {
                cout << "궁수 생성중... !\n";
                player.hp = 100;
                player.att = 15;
                player.def = 3;
                return ;
            }
            case MAGE:
            {
                cout << "법사 생성중... !\n";
                player.hp = 80;
                player.att = 25;
                player.def = 0;
                return ;
            }
        }
    }
}

void select_do()
{
    cout << "---------------\n";
    cout << "(1) 필드 입장 (2) 게임 종료 \n";
    cout << "> ";

    int input;
    cin >> input;

    if (input == 1)
    {
        while (true)
        {
            cout << "---------------\n";
            cout << "필드에 입장했습니다!\n";
            cout << "---------------\n";
            cout << "[PLAYER] HP : " << player.hp << " / ATT : " << player.att << " / DEF : " << player.def << endl;

            select_mon();
            select_battle();
            if (player.hp == 0)
                return;
        }
    }
    else
        return;
}

void select_mon()
{
    enum MonsterType
    {
        SKELETON = 0,
        SLIME = 1,
        ORC = 2
    };

    monster.type = rand() % 3;

    switch(monster.type)
    {
        case SKELETON:
        {
            cout << "해골 생성중...! (HP : 80 / ATT : 15 / DEF : 5)\n";
            monster.hp = 80;
            monster.att = 15;
            monster.def = 5;
            break;
        }
        case SLIME:
        {
            cout << "슬라임 생성중...! (HP : 15 / ATT : 5 / DEF : 0)\n";
            monster.hp = 15;
            monster.att = 5;
            monster.def = 0;
            break;
        }
        case ORC:
        {
            cout << "오크 생성중...! (HP : 40 / ATT : 10 / DEF : 3)\n";
            monster.hp = 40;
            monster.att = 10;
            monster.def = 5;
        }
    }
}

void select_battle()
{
    cout << "---------------\n";
    cout << "(1) 전투 (2) 도주\n";
    cout << "> ";

    int input;
    cin >> input;
    if (input == 1)
    {
        while (monster.hp > 0 && player.hp > 0)
        {
            int damage = player.att - monster.def;
            if (damage < 0)
                damage = 0;
            monster.hp = monster.hp - damage;
            if (monster.hp < 0)
                monster.hp = 0;
            cout << "몬스터 남은 체력 : " << monster.hp << endl;
            if (monster.hp == 0)
            {
                cout << "몬스터를 처치했습니다!" << endl;
                return ;
            }

            damage = monster.att - player.def;
            if (damage < 0)
                damage = 0;
            player.hp = player.hp - damage;
            if (player.hp < 0)
                player.hp = 0;
            cout << "플레이어 남은 체력 : " << player.hp << endl;
            if (player.hp == 0)
            {
                cout << "당신은 사망했습니다... GAME OVER" << endl;
                return ;
            }
        }
    }
    else
        return ;
}

구조체가 유용하게 쓰임
구조체의 멤버들이 단일 타입이 아닐 경우 패딩으로 인해 크기가 조정됨

댓글