내일배움캠프 2주차 1일차 TIL - 에러 틀어막기

백흰범·2024년 4월 22일
0
post-thumbnail

# 위 이미지는 미국 강력 테이프 광고 영상의 일부를 프로그래밍 meme화한 이미지입니다.
# 위 이미지는 본 내용의 해결 방식과는 아무런 연관이 없음을 알립니다.

오늘 한 일

  • 스파르타 코딩클럽 진도 나가기 (1-1 ~ 2-3)
  • 1주차 숙제 제출하기 (오늘 쓸 내용)

오늘은 진도를 나가야하기 때문에 새로 배운 코드는 없지만, 마침 숙제가 있는데 단순히 풀기만 하지 않고 어떻게하면 어떤 상황이 와도 이 입력의 에러들을 다 받아칠 수 있을까하면서 숙제를 풀어보기로 했다.

1주차 숙제 제출목록

첫번째 문제

문제 내용

사용자로부터 입력 받기
- 이름과 나이를 입력 받고 출력하는 코드를 작성하세요.

생각해보기

어디서 에러가 날까? 무엇이 에러일까를 생각해보면, 나이 부분에서 논리적 오류가 있을 거라고 생각했다. (이름은 잠시 넘어가자...)

# 에러 조건 : 나이가 숫자로 입력되지 않고, 음수일 시 + 그 외의 추가적인 에러

코드 짜기

	static void Main(string[] args)
	{
		Console.Write("이름과 나이를 입력해주세요. \n 예시) 르탄이 23\n 입력창 : ");
	    string[] str = Console.ReadLine().Split(" ");	// "이름 나이" 입력
	    str[1] = CheckAge(str[1]);	// 나이 체크 함수 호출

	    Console.Write($"{str[1]}세 {str[0]}님 반갑습니다.");
	}

    static string CheckAge(string strAge)
    { 
        while (true)	// 제대로 입력할 때까지 못 나감
        {
            if (int.TryParse(strAge, out int x) && x > 0)	// 숫자이면서 양수인가요?
            {
                return strAge;	// 들고 돌아가기
            }
            else if (x < 0)	// 숫자가 음수인가요?
            {
                Console.Write("나이는 음수가 될 수 없습니다.\n제대로된 숫자를 입력해주세요.\n나이 : 23\n 입력창 : ");
                strAge = Console.ReadLine();
            }
            else	// 그 이외의 답인가요?
            {
                Console.Write("나이는 숫자로 입력해주세요.\n나이 : 23\n입력창 : ");
                strAge = Console.ReadLine();
            }
        }
    }
  • 이 코드는 먼저 두 항목 '이름 나이'를 입력 받은 다음에 나이에서 문제가 생겼을 경우 나이값만 다시 입력함으로써 나이 값을 정리되게 받은 코드이다.

입력 결과

  • 의도된대로 잘 출력된다.

! 하지만 조금이라도 에러에 민감한 사람이라면 빠진 문제가 하나 보일 것이다.
그 버그는 바로 띄어쓰기로 항목 구분을 안하고 하나만 전달받을 경우의 버그인 것이다.

버그 발생!

// 버그 걸린 라인
11 str[1] CheckAge(str[1]);

왜 버그가 발생했을까?

  • 답은 매우 간단하다. 르탄23을 입력하게 된다면 " "로 쪼갤 것이 없어 str list에게 스플릿되지 않고 오직 하나의 인덱스만 전달 받게 됨(str[0]이 최대)으로써 str[1]이 존재하지 않아 Index 바깥의 값을 가져오게 되는 버그인 IndexOutOfRangeException(인덱스 범위 바깥의 예외)가 발생하게 되었다.
  • 그림으로 이해해보기

해결 방법

  • arr.Length를 이용해 해당 길이가 2보다 작다면 다시 입력하는 방식을 이용했다.
while (str.Length < 2)	// 배열의 길이가 2보다 작을 시 계속 실행한다. str[1]이 없다면 반복
{
	Console.Write("띄어쓰기로 둘을 구분해주십시오. \n 예시) 르탄이 23\n 입력창 : ");
	str = Console.ReadLine().Split() ;
}
...

보완된 코드

static void Main(string[] args)
{
    Console.Write("이름과 나이를 입력해주세요. \n 예시) 르탄이 23\n 입력창 : ");
    string[] str = Console.ReadLine().Split(" ");
   
    while (str.Length < 2)	//추가된 코드
    {
        Console.Write("띄어쓰기로 둘을 구분해주십시오. \n 예시) 르탄이 23\n 입력창 : ");
        str = Console.ReadLine().Split() ;
    }
    str[1] = CheckAge(str[1]);

    Console.Write($"{str[1]}세 {str[0]}님 반갑습니다.");
}
// 나이 체크 반환 함수
static string CheckAge(string strAge)
{
    while (true)
    {
        if (int.TryParse(strAge, out int x) && x > 0)
        {
            return strAge;
        }
        else if (x < 0)
        {
            Console.Write("나이는 음수가 될 수 없습니다.\n제대로된 숫자를 입력해주세요.\n나이 : 23\n 입력창 : ");
            strAge = Console.ReadLine();
        }
        else
        {
            Console.Write("나이는 숫자로 입력해주세요.\n나이 : 23\n입력창 : ");
            strAge = Console.ReadLine();
        }
    }
}

입력 결과

  • 여러번 잘못 입력한 것
  • 한번에 제대로 입력



두번째 문제

문제 내용

사용자로부터 입력 받기
- 이름과 나이를 입력 받고 출력하는 코드를 작성하세요.

생각해보기

처음에는 연산자를 입력 받은 다음에, 피연산자 2개를 받기로 했다. 여기서 연산자는 정수 범위를 정해서 받아준 다음 피연산자는 한 번에 2개를 받아서 if문으로 에러를 틀어막았다. 그리고 피연산자에서 받은 값을 통해 switch문으로 연산의 결과를 분류해뒀다. 그리고 연산자 에러로는 나눗셈을 0으로 할 때이니까. 이 점을 유의해주는 것이 좋다.

# 에러 조건 : 나눗셈을 0으로 나누려고할 시 + 그 외의 추가적인 에러

코드 짜기

internal class Program
{
    public static int choose;	// 연산자를 받을 친구
    public static int operand1, operand2;	// 피연산자들, 원한다면 float로 바꿔도 된다.

	static void Main(string[] args)
	{
	    ChooseOperator();
        ChooseOperands();
        switch (choose)	// 입력 받은 값대로 사칙연산 실행
        {
            case 1:	// 더하기
                Console.WriteLine($"{operand1} + {operand2} = {operand1 + operand2}");
	            break;
	        case 2: // 빼기
	            Console.WriteLine($"{operand1} - {operand2} = {operand1 - operand2}");
	            break;
	        case 3: // 곱하기
	            Console.WriteLine($"{operand1} * {operand2} = {operand1 * operand2}");
	            break;
	        case 4: // 나누기 (정수)
	            Console.WriteLine($"{operand1} / {operand2} = {operand1 / operand2}");
	            break;
	        case 5: // 나누기 (나머지)
	            Console.WriteLine($"{operand1} % {operand2} = {operand1 % operand2}");
	            break;
	  	}	// 이유는 모르겠지만 Main 안에 함수를 선언해도 문제가 생기지 않는다.
        // 코파일럿 왈 = C# 7.0 버전 부터는 로컬 함수라는 개념이 도입되어 메서드 내부에 다른 메서드 선언이 가능하다.

        static void ChooseOperator()	// 연산자 받는 함수
        {
            Console.Write("사용하고 싶은 사칙연산을 고르세요.\n숫자를 입력하시면 됩니다.\n 1. +\n 2. -\n 3. *\n 4. /\n 5. %\n 입력창 : ");
           
            while (true) 	// 제대로 입력할 때까지 나갈 수 없다.
            {
            	string x = Console.ReadLine();	// 입력 받기
                if (int.TryParse(x, out choose) && choose > 0 && choose < 6)	// 숫자이면서, 정해진 숫자 안에 들어가나요?
                    return;	// 제대로 받았으니 돌아가자
                else
                {
                    Console.Write("제대로 입력해주세요.\n 입력창 : ");
                }
            }
        }

        static void ChooseOperands()	// 피연산자 받는 함수
        {
            Console.Write("연산할 입력값을 입력해주세요\n 예시) 10 23\n 입력창 : ");            

            while (true)	// 제대로 입력할 때가지 나갈 수 없다.
            {
            	string[] x = Console.ReadLine().Split(" ");		// 피연산자 받기
                if (x.Length < 2)   // 배열 길이 검사 (에러 방지)
                {
                    Console.Write("두번째 항목도 넣어주세요.\n 예시) 10 23\n 입력창 : ");
                }
                else if (int.TryParse(x[0], out operand1) && int.TryParse(x[1], out operand2)) // 둘 다 숫자로 바꿀 수 있을 경우
                {
                    if (choose > 3 && operand2 == 0)	// 나눗셈이면서 두번째 피연산자가 0인 경우
                    {
                        Console.Write("나눗셈은 0으로 나눌 수 없습니다. \n 입력창 : ");
                    }
                    else
                        return;		// 제대로 받았으니 돌아가자
                }
                else
                {
                    Console.Write("제대로 입력해주세요.\n 예시) 10 23\n 입력창 : ");
                }
            }
        } 
    } // static void Main(string[] args)
}
  • 나눗셈을 0으로 나누려할 경우 오류가 걸리기 때문에 사전에 차단해뒀다.

입력 결과

  • 정상적으로 입력
  • 최대한 틀리게 입력
    의도된대로 최대한의 버그를 틀어막았다.

Console.Clear()를 사용한다면 깔끔하게 치워줄 수 있다!
그 외의 2문제는 연구할 요소가 적은 탓에 넘어가자




그 외에 알게된 점

문자열 포맷팅

  • 문자열 형식화
string name = "John";
int age = 30;
string message = string.Format("My name is {0} and I'm {1} years old.", name, age);
  • 문자열 보간
string name = "John";
int age = 30;
string message = $"My name is {name} and I'm {age} years old.";	// 연산도 가능
// 난 이 타입이 제일 좋은 것 같다.

삼항 연산자

  • 3항 연산자 if문의 간단한 형태로, 조건식의 결과에 따라 두 값을 선택하는 연산자입니다.
	변수 = (조건식) ? 참일 경우 값 : 거짓일 경우 값;

디버깅하는 방법

  • F9 - 브레이크 포인트

  • F5 - 디버그 시작 (브레이크 포인트에서 시작한다.)

  • F10 - 다음으로 이동 (브레이크포인트 부터 순차적으로 진행된다.)
  • 위 이미지는 해당 브레이크 포인트에서 F10을 누르면 넘어가는 다음 코드이다. (노란색 코드)
    이를 이용하면 코드의 흐름을 좀 더 자세하게 알 수 있다.



오늘 배우면서 느낀점

처음에는 뭐 배울지 막막하다 생각했는데, 지식을 쌓고 쌓다보니까. 점점 뭘 배울 지 보이는 게 많아지고 상호작용할 수 있는 요소가 점점 많아지니까 과연 내가 이 많은 것들을 감당할 수 있을까라는 생각부터 든다. 나중에 작업의 복잡성을 줄이기 위해서 기획을 잘해야겠다.




내일 나갈 진도

  • 스파르타 코딩클럽 진도 4장까지 돌파하기
  • 이번 주 프로젝트인 텍스트 RPG의 기획 짜보기
profile
게임 개발 꿈나무

0개의 댓글