본문 바로가기
개발/Unity 내일배움캠프 TIL

[내일배움단] 사전캠프 C# TIL 6. 함수

by 석시 2023. 7. 21.



함수의 기본적인 형태

메소드(method)라고도 한다.

C++에선 함수(Function), 다른 언어에서는 Procedure라고도 하지만 C#은 아무래도 객체가 메인이라 메소드를 주로 사용하는듯.

코드를 재사용할 수 있게 기능들을 묶어 만들어놓은 구조이다.

사실 지금까지 Console.Writeline()이나 int.TryParse() 등 여러 가지 함수를 사용해오고 있었다.

함수를 언급할 때 뒤에 괄호 ()를 꼭 붙이는 건 이것이 함수라고 명시해주는 것.

함수 형식은 다음과 같다.

[한정자] [반환 형식] [함수 이름] ([매개변수]) { [함수 실행 내용] }

쉽게 말해 함수 이름 앞에 오는 반환 형식은 함수가 출력으로 뱉는 데이터의 자료형을 의미한다.

Console.Writeline()입력으로 string, 출력은 아무것도 없는 (void) 함수이고, Console.Readline()입력으로 아무것도 없고 (void), 출력은 string인 함수인 것이다.

한정자는 보통은 static을 붙인다. 클래스에서 다루도록 하자.

return

return은 가장 기본적으로는 함수를 끝내는 문이다.

int hp = 5;

Attack();    // 데미지 : 1    현재체력 : 4
Attack();    // 데미지 : 1    현재체력 : 3
Attack();    // 데미지 : 1    현재체력 : 2
Attack();    // 데미지 : 1    현재체력 : 1
Attack();    // 데미지 : 1    현재체력 : 0
Attack();    // Console X

void Attack()
{
    if (hp < 1)  return;

    --hp;
    Console.WriteLine("데미지 : 1    현재체력 : " + hp);
}

뭔가 break랑 똑같다고 생각할 수 있지만, 함수의 반환 형식이 void가 아니라면 이야기는 달라진다.

int Point = GetPoint();

int GetPoint()
{
    Console.WriteLine("보상으로 100 포인트를 획득합니다.");
    return 100;
}

이처럼 함수를 끝냄과 동시에 특정 데이터를 출력으로 반환해줄 수 있게 된다.

주의할 점 하나는 반환 형식이 void 일 경우는 중괄호 {} 스코프가 끝나면 함수 실행이 종료되기 때문에 return을 써주지 않아도 괜찮지만, 반환 형식이 void가 아닌 다른 자료형일 경우 반드시 return문을 사용해야한다.

매개변수

매개변수. 말이 거창하지만 함수의 입력, 인풋이다.

void Attack(int damage)
{
		if(hp < 1)
		{
		    return;
		}

		--hp;
		Console.Write("데미지 : 1    현재체력 : " + hp);
}

당연히 한개말고 두개 세개 넣을 수 있다.

void DisplayMyInfo(int level, string name, string job)
{
		Console.WriteLine("레벨 : " + level + "이름 : " + name + "직업 : " + job);
}

함수를 호출할 때에도 매개변수의 순서를 지켜야 함에 주의.

매개변수의 복사

다음과 같은 코드를 보자.

void AddOne(int number)
{
    number += 1;
}

int a = 0;
AddOne(a);

Console.WriteLine(a);

콘솔에 1이 출력되어야 할 것만 같은 코드이지만, 0이 출력된다.

함수가 호출될 때 방식 때문에 그런데,

a라는 변수 바구니를 집어넣는 것이 아니라, a 안의 데이터를 복사해서 가져다가 함수에 넣어주기 때문.

따라서 함수 안에서 값의 변경이 일어나도 복사한 데이터가 바뀌기 때문에 원래 데이터는 전혀 변하지 않는다.

값을 바뀌게 하고 싶다면 복사 방식이 아니라 참조 방식으로 인자를 넘겨주면 된다.

그 방법은 매개 변수 앞에 ref를 붙이는 것.

참조 방식 (ref)

void AddOne(ref int number)
{
    number += 1;
}

int a = 0;
AddOne(ref a);

Console.WriteLine(a);

참조 방식은 쉽게 말하면 함수에 원본 데이터를 넘겨주는 것이다.

복사 방식이 a라는 데이터 바구니에서 0을 빼서 가짜를 만들어 넘겨주는 방식이라면,

참조 방식은 a라는 데이터 바구니를 그대로 주는 느낌.

ref와 비슷한 기능을 하는 것 중에 out이라는 것이 있다.

out

void Divide(int a, int b, out int share, out int remainder)
{
    share = a / b;
    remainder = a % b;
}

int num1 = 10;
int num2 = 3;

int result1;
int result2;
Divide(10, 3, out result1, out result2);

Console.WriteLine(result1);
Console.WriteLine(result2);

동작 방식은 ref와 같다고 보면 되지만, 함수가 끝나기 전에 해당 매개 변수에 데이터를 반드시 줘야한다는 것이 차이.

ref에다가 return의 제약조건을 붙인 것이다.

ref는 직접적으로 데이터를 조작하기에, 신중히 다뤄야하고 실수가 없어야 하기 때문에 참조 방식으로 데이터를 다루기로 했다면 그 데이터에 아무 변경도 가하지 않는 실수를 없애기 위한 것인듯.

함수 오버로딩

함수 이름을 재사용하는 것인데, 다른 언어를 하다가 느껴본 것일테지만, 한 함수가 여러 형태의 매개 변수를 받는 것을 본 적이 있을 것이다.

그런 경험이 없더라도, 함수가 int를 받을 수도, float을 받을 수도 있도록 하는 것이 필요한 상황이 있을 것이다.

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

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

    static void Main(string[] args)
    {
        int a = Add(2, 3);
        float b = Add(2.0f, 3.0f);
    }

}

지금까지는 최상위문을 사용했었는데, 지금 이 예제 코드들은 최상위문에서 쓸 수가 없기에…..

중요한 건 함수 Add()를 두 번 선언했다는 것이다.

이런 방식으로 정수도 더할 수 있고, float도 더할 수 있게 되는데, 주의할 점은 오버로딩 할 때 동일한 매개 변수 형식을 가진 함수가 두 개 이상 존재해서는 안된다는 것이다.

특정 인자의 기본 옵션을 정해줄 수도 있다.

class Program
{
    static int Add(int a, int b, int c = 0)
    {
        return a + b + c;
    }

    static void Main(string[] args)
    {
        int a = Add(2, 3);
    }

}

다음과 같이 한 번의 함수 작성으로 두 가지의 매개 변수 형식을 갖게할 수 있다.

class Program
    {
        static int Add(int a, int b, int c = 0, float d = 1.0f)
        {
            return (int)((a + b + c) * d);
        }

        static void Main(string[] args)
        {
            int a = Add(2, 3, d:2.0f);
        }

    }

이건 좀 보면서도 놀랐다.

특정 인자만 쏙쏙 골라서 넣어줄 수 있다니.

C나 C++에선 상상도 할 수 없던 기능이다.


Uploaded by N2T