# 위 이미지는 미국 강력 테이프 광고 영상의 일부를 프로그래밍 meme화한 이미지입니다.
# 위 이미지는 본 내용의 해결 방식과는 아무런 연관이 없음을 알립니다.
오늘 한 일
- 스파르타 코딩클럽 진도 나가기 (1-1 ~ 2-3)
- 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의 기획 짜보기