[C#] void VelogWrite(string sincerity)

Lingtea_luv·2025년 3월 14일
0

C#

목록 보기
4/37
post-thumbnail

함수


지금까지 main 메서드 안에 한 줄씩 입력했지만 함수를 사용하면 여러 줄이 하나의 기능을 수행할 경우, 이를 묶어 반복적으로 활용하는 것이 가능해진다.

학습목표

  • 함수의 개념 이해
  • 함수의 4가지 형태 실전 활용
  • Ref, 인자값, 리턴값의 이해

함수란?

사용자에게 특정 숫자의 입력을 원하는 기능을 생각해보자

Console.Write("숫자를 입력해주세요 : ");
string input = Console.ReadLine();
int num;
int.TryParse(input, out num); 

혹시 사용자에게 숫자를 입력 받고 싶을 때마다 해당 코드를 모두 작성해야할까?

이처럼 특정 기능을 수행하는 여러줄의 코드가 반복적으로 필요할 경우, 이를 함수(= 숫자 ! )로 표현하여 더 간편하게 작성하는 것이 가능하다. 이를 위해 우리가 생각해야하는 것은 다음과 같다.

  • 무엇을 만들 것인지
  • 어떤 입력을 요구하는지
  • 어떤 결과를 요구하는지

반환값이 없는 함수

  • 입력값이 없는 경우
static void PrintJoke()
{
    Console.WriteLine("밤에 성시경이 두명 있으면?");
    Console.Write("야간");
    Console.Write("투");
    Console.WriteLine("시경");
}

함수 실행 이후 반환값을 특별히 사용하지 않는 경우 void를 사용한다.

주의. 함수명은 파스칼 표기법을 따른다.

static void Main(string[] args)
{
    PrintJoke();
}   
밤에 성시경이 두명 있으면?
야간투시경

이처럼 함수를 지정한 경우 Main 메서드 내에서 다시 재활용하는 것이 가능하여, 반복되어 필요한 경우 함수로 입력하면 된다.

  • 입력값이 있는 경우
static void GradeMyjoke(string inputString)
{           
    Console.WriteLine("당신의 농담은 " + inputString + "입니다.");
}

위의 코드처럼 입력값에 따라 결과값이 달라지는 함수를 만들 수 있는데, 이 경우 입력값의 형태를 지정할 필요가 있다.

static void Main(string[] args)
{
    GradeMyjoke(Console.ReadLine());    //    input : 최악
}
  당신의 농담은 최악입니다.

이처럼 사용자의 입력에 따라 출력값이 달라진다.

반환값이 있는 함수

지금까지 void를 사용하여 반환값이 없을 경우의 함수를 사용했으나, 반환값이 존재하는 경우의 함수를 지정해보자.

  • 입력값이 없는 경우
static double GetPI()
{
    double pi = 3.141592;
    Console.WriteLine("파이값을 반환하였습니다.");
    return pi;
}  

위의 코드는 pi라는 값을 double 형태로 지정하고 해당 값을 return을 통해 함수 GetPI( )에 할당한 것이다. 이처럼 반환값이 존재하고 그 값을 사용할 경우 void가 아닌, 저장될 형태를 지정하여 함수를 설정한다.

  • return
static string MakeFishCake(string taste, int time)
{
    if(taste == "")
    {
        Console.WriteLine("속 없는 붕어빵은 만들 수 없습니다.");
        return "";
    }

    Console.WriteLine($"반죽물을 붓습니다.");
    Console.WriteLine($"{taste} 앙금을 넣습니다.");
    if (time > 10)
    {
        Console.WriteLine($"익을 때까지 {time}초 기다립니다.");
        Console.WriteLine($"탄 붕어빵 완성!!");
        return "탄 붕어빵";
    }
    else
    {
        Console.WriteLine($"익을 때까지 {time}초 기다립니다.");
        Console.WriteLine($"{taste} 붕어빵 완성!!");
        return $"{taste} 붕어빵";
    }
}  

return 은 값이 도출되었을 경우 해당 값을 반환시키고, 함수를 종료하겠다는 의미이다.
위의 함수에서 만약 사용자가 붕어빵의 속을 공백으로 냈다면, 함수값을 공백으로 반환하고 함수를 종료하는 것이다. 즉 아래의 긴 코드는 실행되지 않는다.
return은 값을 반환할 때 쓰이기도 하지만, 예외사항 또는 특수한 경우가 있는 경우 함수 맨 위에 작성하여 해당 상황에서는 계산할 필요 없이 함수를 조기 종료시키는 경우에 더욱 유용하게 사용이 가능하다.

  • 입력값이 있는 경우
static void Main(string[] args)
{
    Console.Write("붕어빵 안에 넣을 속을 정해주세요 : ");
    string selectedTaste = Console.ReadLine();
    Console.Write("붕어빵을 굽기 위한 시간을 말씀해주세요 : ");
    int selectedTime;
    int.TryParse(Console.ReadLine(), out selectedTime);

    MakeFishCake(selectedTaste, selectedTime);
}

위에서 정의한 MakeFishCake를 사용하여 입력값에 따라 함수값이 달라지도록 설정해보았다.
함수 내부 내용과 시간에 따라 설정한 함수에 의해 출력되는 내용이 달라지는 것을 확인할 수 있다.

  • 추가 반환 out
  static bool isAreaBigger(double height, double width, out double area)
{
    area = height * width / 2;
    bool isBigger = area > 100;
    return isBigger;
}

위 코드에서 사용된 isAreaBigger 함수는 boolean 값을 반환받도록 되어있지만 추가로 area 값을 double 형태로 반환 받는 것도 가능하다. 이처럼 하나의 함수에서 동일한 매개변수로 연산된 다른 반환값을 추가로 얻고자 할 때 out을 사용한다.

참고 기능


ReadKey( )

static void Main(string[] args)
{
    while (true)
    {
        switch ((Console.ReadKey(true).Key))
        {
            case ConsoleKey.W:
            case ConsoleKey.UpArrow:
                MoveForward();
                break;
            case ConsoleKey.A:
            case ConsoleKey.LeftArrow:
                MoveLeft();
                break;
            case ConsoleKey.S:
            case ConsoleKey.DownArrow:
                MoveBackward();
                break;
            case ConsoleKey.D:
            case ConsoleKey.RightArrow:
                MoveRight();
                break;
        }
    }
}

지금까지는 입력 후 enter키를 눌러서 값을 컴퓨터에게 전달했다면, ReadKey( ) 는 입력과 함께 값을 바로 전달하는 함수 이다.
특히 ReadKey(True)의 경우 콘솔 창에 입력값을 표시하지 않고 입력값에 따라 바로 결과가 나온다는 점에서 굉장히 유용하게 쓰인다.

Call by reference

static void ToSwapNum(int swapNum1, int swapNum2)
{
    int temp;
    temp = swapNum1;
    swapNum1 = swapNum2;
    swapNum2 = temp;

    Console.WriteLine($"스왑이 진행되었습니다. \na : {swapNum1}, b : {swapNum2} 입니다.");
}  

위의 함수는 입력한 두 수의 값을 서로 바꿔주는 기능이다. 다만 이 경우 실제로 swapNum1과 swapNum2의 실제 값이 바뀐 것은 아니다. 함수 내에서 출력을 할 때 그렇게 보이도록 만든 것일 뿐 값은 여전히 그대로인 것이다.

참고. temp를 사용한 이유는 swapNum1의 값을 덮어씌울 때 기존의 값이 사라지기에 이를 temp에 넣어준 것이다.

static void Main(string[] args)
{
    int a = 10;
    int b = 20;

    Console.WriteLine($"스왑하기 전. \na : {a}, b : {b} 입니다.");

    ToSwapNum(a, b);

    Console.WriteLine($"스왑 이후. \na : {a}, b : {b} 입니다.");
}

예를 들어 두 코드를 이어서 실행한다고 했을때의 결과를 보면 다음과 같다.

스왑하기 전.
a : 10, b : 20 입니다.
스왑이 진행되었습니다.
a : 20, b : 10 입니다.
스왑 이후
a : 10, b : 20 입니다.

결과를 보면 함수 자체에서 출력되는 2번째 결과는 스왑이 되어 값이 바뀌지만, 여전히 외부 값은 바뀌지 않은 채 3번째 결과처럼 그대로인 것을 볼 수 있다.

그럼 외부 값도 바꿔주려면 어떻게 해야되는데?

이때 사용하는 것이 바로 ref이다. 기존 함수가 입력 값을 복사해서 함수에서 사용했다면, Ref 함수의 경우 입력된 값을 실제로 참조해서 함수를 진행하기에 이에 따라 참조된 값 또한 변경되는 것이다.

static void ToSwapNumRef(ref int swapNum1, ref int swapNum2)
{
    int temp;
    temp = swapNum1;
    swapNum1 = swapNum2;
    swapNum2 = temp;

    Console.WriteLine($"스왑이 진행되었습니다. \na : {swapNum1}, b : {swapNum2} 입니다.");
}

위와 같이 ref를 함수 뒤, 매개변수 앞에 붙여주면 ref 함수의 기능을 하도록 명령이 가능하다. 따라서 아래 코드도 살짝 바꿔서 실행하면 다음과 같다.

static void Main(string[] args)
{
    int a = 10;
    int b = 20;

    Console.WriteLine($"스왑하기 전. \na : {a}, b : {b} 입니다.");

    ToSwapNumRef(ref a, ref b);

    Console.WriteLine($"스왑 이후. \na : {a}, b : {b} 입니다.");
}
스왑하기 전.
a : 10, b : 20 입니다.
스왑이 진행되었습니다.
a : 20, b : 10 입니다.
스왑 이후
a : 20, b : 10 입니다.

이렇게 스왑이 진행되어 외부값 또한 바뀐 것을 확인할 수 있다. 이때 ref 함수는 Call by reference 라고 하며, 일반 함수는 Call by value 라고 한다.
보통 1회용 데이터를 사용할 때 Call by value를 활용하기에, 게임 개발에서 활용하는 함수는 Call by reference인 경우가 더 많을 것 같다.

과제


해당 구문에 있는 함수들을 의도에 맞도록 구현하시오

static void Main(string[] args)
{
    int playerHealth;

    while (true)
    {
        _repeatCount++;

        playerHealth = InputPlayerHealth();

        PrintRepeatCount();

        if (IsZero(playerHealth))
        {
            Console.WriteLine("Game Over - 게임 종료");
            break;
        }
    }
}  

1. IsZero 함수 구현

value값이 0 이하인 경우 true가 반환되도록 설계

static bool IsZero(int value)
{
    bool isDied = (value <= 0);
    return isDied;
}  
  • 가독성
return (value <= 0);      // 둘 중에 무엇이 가독성이 더 좋은걸까...?

2. InputPlayerHealth 함수 구현

0이상 100이하의 숫자만을 입력받도록 설계

static int InputPlayerHealth()
{
    double inputDouble;
    Console.Write("플레이어의 체력을 입력해주세요 : ");
    bool isInt = double.TryParse(Console.ReadLine(), out inputDouble);
    while (!isInt)
    {
        _repeatCount++;
        Console.Write("다시 입력해주세요 : ");
        isInt = double.TryParse(Console.ReadLine(), out inputDouble);
    }
    while (inputDouble < 0 || inputDouble > 100)
    {
        _repeatCount++;
        Console.Write("다시 입력해주세요 : ");
        double.TryParse(Console.ReadLine(), out inputDouble);
    }
    return (int)inputDouble;
}
  • 숫자가 아닌 경우
    double.TryParse로 정수가 아닌 숫자로 범위를 확장해서 boolean값으로 반복문 구성
  • 0이상 100이하의 숫자
    논리합을 활용해 범위 밖의 숫자의 경우 다시 입력하도록 설계

3. PrintRepeatCount 함수 구현

반복문이 실행될 때마다 카운트가 올라가고 출력이 되도록 설계

static void PrintRepeatCount()
{
    Console.WriteLine($"반복문이 출력된 횟수는 {_repeatCount++}입니다.");
    _repeatCount = 0;
}
  • 반복문 횟수
    while 구문마다 실행될 때마다 1씩 증가하도록 설계
  • 초기화
    체력을 입력하고 해당 카운트가 입력된 경우 다시 초기화 되도록 설계
profile
뚠뚠뚠뚠

0개의 댓글