본문 바로가기

Unity 개발 공부

[내배캠] 본캠 6일차. 기초문법 변수,자료형 그리고 기초연산문제 복습

오늘 배운것:

 

 

c#

.net 프레임워크
프로그래머는 각각 언어를 가지고 컴파일링함

중간언어가 생성됌.
ios, 윈도우등
자기한테 맞는 방식으로 변환해서 사용함.




namespace는 클래스들의 묶음, 기능들의 묶음

using System; 은 기본적으로 제공하는 네임스페이스 사용을 위한 코드, Console 클래스 사용을 위해 필요.

Main 메서드는 프로그램실행을 위해 필수적임

cs 상단에 using문이 안보이는데, 프로젝트탭, 속성탭의 전역 using 탭으로 들어가면
이미 자주 사용하는 using문에 대해서는 사용이 되고있음이 체크되어있다. 실제로는 사용하고있는것.

Console.WriteLine 메소드는 인수로 전달된 값 출력하고 줄바꿈 문자열을 추가한다.
Console.writeLine( value ); 의 value는 출력할 값으로 문자열, 숫자, 변수, 연산식등 어떤 값이든 사용할 수 있다.

Console.Write은 출력후 줄바꿈을 안한다. 

-------------------

이스케이프 시퀀스
문자열 내에 특수한문자를 포함시키기 위해 사용되는 특별한 문자 조합

\' 작은따옴표 삽입
\" 큰따옴표 삽입
\\ 역슬래시 삽입
\n 새줄(줄바꿈) 삽입
\r 현재 줄 맨 앞으로 이동
\t 탭 삽입
\b 백스페이스 삽입

Console.WriteLine("C:\\MyDocuments\\Projects\\")
이러면 C:\MyDocuments\Projects\ 로 표기된다 경로같은걸 표기가능
\t는 8칸 기준으로 칸이 띄여진다.
\b는 커서를 왼쪽으로 한칸만 이동하는것. 뭔가를 출력하면 덮어쓴다.

-----------------------

주석
한줄 주석: //
여러줄 주석: /* */

주석은 코드를 대체하지않음. 코드를 더 직관적으로 작성하는게 중요
주석의 내용은 정확하고 명확해야함
주석은 업데이트 되어야함, 코드가 변경되면 주석도 변경되어야함.

주석은 필요한경우에만 사용해야한다.


--------------------
자동완성기능과 보조기능 사용해보기
IntelliSense 기능
ctrl + space 를 누르면 자동완성이 꺼진 라인에서 다시 자동완성기능을 띄울 수 있다.

------------------
기본 자료형 복습

정수형
int 
long
실수형
float 
double
.
.
.
세분화 하여 사용하는이유
메모리 효율적인 사용을 위해
정확한 데이터 표현 
타입 안정성 

리터럴: 프로그래밍에 직접 사용하는 상수값.

int num1, num2, num3 = 10; 할경우 num3만 초기화됌, 나머지는 선언만 된다.
num1 = num2 = num3 = 10; 할경우 한꺼번에 초기화됌.

c#에서 쓰겠다고 하는 키워드를 쓸 수 있음.


그것들을 제외하고는 식별자란 우리가 써주는 이름을 말함.

변수명은 숫자로 시작불가
하이픈 - 사용불가
특수문자 $ 사용불가

변수명을 단순하게 하면 안좋다.
x1, a 이런식으로 짜면 의미를 알기어려움.

키워드랑 같은 이름을 사용할 수 는 없음.

코드컨벤션: 개발자들 사이에서 약속된 코드 작성 규칙
1. 식별자 표기법
PascalCase: 클래스, 메서드, 프로퍼티 이름 등에 사용되어 첫글자는 대문자로 시작. 이후 단어의 첫글자도 대문자
예: ClassName, MethodName

2. 들여쓰기
탭 또는 스페이스 4칸을 사용하여 코드 블록을 들여씁니다.

3. 중괄호 위치
중괄호 { } 는 항상 새로운 줄에서 시작합니다.

4. 빈 줄 사용

관련없는 코드 사이에는 빈줄을 사용하여 구분합니다.
메서드, 클래스 등의 블록 사이에는 두 줄을 띄어씁니다.

5. 주석
...

더 자세한 코딩규칙은 링크로.. 마이크로소프트 코딩규칙 참고


---------------------------

형변환
자료형이 바뀌는것을 의미함.


1. 명시적형변환
int num1 =10;
long num2 = (long)num1; 
예시와 같이 (자료형) 형식을 입력하고 변수내지는 리터럴앞에 붙여주면된다.
이때 한시적으로 num1이 가지고 있는 10이 long으로 바뀌어서 num2에 넣는방식으로 처리될뿐이다.
num1이 long형식으로 바뀌는건아님.


2. 암시적 형변환
2-1.작은 데이터 타입에서 더 큰 데이터 타입으로 대입하는 경우
byte, short, char 등 작은 데이터타입에서 int, long , float 등 더 큰 데이터 타입으로 대입할때 암시적 형변환 발생
byte num1 = 10;
int num2 = num1; // byte형에서 int 형으로 암시적 형변환

2-2. 리터럴값이 대입되는경우
float result = 1; //1은 int형 리터럴 값이지만 float형으로 암시적 형변환 , float이 좀더 큰 형태이므로 따라가는것임

2-3. 정수형과 부동소수점형 간의 연산을 수행할경우
둘중에 큰 형태로 따라간다. int, float을 연산하면 float이 더 큰 형태이므로 float을 따라간다.

int num1 = 10;
float num2 = 3.14f;
float result = num1 + num2; // int 형과 float 형의 덧셈에서 float형으로 암시적 형변환


암시적인경우 코드는 간결하지만 신중하게 체크해줘야함.

-----------------------
Console.ReadLine 이용한 입력
콘솔 입력을 받을때 사용하는 메서드.

string input = console.ReadLine();

예제
Console.Write("Enter your name: ");
string name = Console.ReadLine();
Console.WriteLine("Hello, {0}!", name);

WriteLine( ) 소괄호 안에 구성을 보자면 ( " string 내용, {순서 }",  변수 ) 
앞에 string 내용은 그대로 출력 { } 중괄호 안에는 int형 정수로 0부터 시작되는 대응 순서, 
그다음 쉼표 뒤에는 순서대로 출력이 되게끔하는 선언혹은 할당한 변수 가 자리한다.

   Console.Write("Enter your name: ");
   string name = Console.ReadLine();
   Console.Write("Enter your age: ");
   string agetxt = Console.ReadLine();
   int age;
   bool agecheck = int.TryParse(agetxt,out age);

   Console.WriteLine("Hello, {0}, your age is {1}!", name , age);

이런식으로 쓰면, 뒤에 연달아서 입력값을 출력도 가능하다.
----------
주석 걸기
Ctrl+k 한번 ctrl 누른채로 c한번 

반대로 주석 풀기
ctrl + k 한번 ctrl 누른채로 u한번

Split / 한줄에 여러값 입력받기.
특정한 구분자 값으로 문자열을 나눠줄수있음
 string[] numbers = input.Split(' '); 
 // { "10", "20" } // 문자열을 공백으로 구분하여 배열로 만듦
 int num1 = int.Parse(numbers[0]);     // 첫 번째 값을 정수로 변환하여 저장
 int num2 = int.Parse(numbers[1]);     // 두 번째 값을 정수로 변환하여 저장

.Split(' ') 의 경우 소괄호 (' ') 안을 공백으로 구분하여 배열로 만든다.
배열의 형태로 들어가는 소괄호 안의 인자는
숫자처럼 생긴 문자를 실제 정수로 바뀌는것은형변환과 다름, 변화하고자 하는 자료형한테 요청해야함.

string str = "Hello, world!" ;
string [ ] words = str.Split(','); // 이 콛는 str문자열을 쉼표(,)로 구분하여 분할한 문자열 배열 words를 생성합니다.


-----------------
var은 컴파일러가 들어오는 값에 따라 자동으로 자료형을 맞춰줌

var num = 10; // int 자료형으로 결정됨.

익숙해지기전까지는 잘 안쓰기.
다른사람의 코드를 가져다 쓸때 그사람의 자료형이 불확실할때 var 키워드를 쓰면 유용할 수 있다.
변수명은 약어로 너무 줄이면 코드 가독성이 떨어진다.


------------------------------------

연산자와 문자열 처리

산술 연산자
+
-
*
/
% 나머지 

관계연산자 ( = 이라는 부호는 항상 오른쪽에붙음)

==
!=
>
<
>=
<=

논리연산자

&& 피연산자 둘다 참이라면 참
|| 피연산자 둘중하나라도 참이라면 참
! 피연산자가 참이면 거짓, 거짓이면 참이다.

비트연산자

& 두비트값이 모두 1일때 1을 반환
|  두비트값중 둘중 하나라도 1일때 1을 반환
^ 두비트값이 서로 다를때 1을 반환
~
<< 
>>

비트연산자 <<의 계산법

int c= 0b1011;일 경우 1011 이며 2진수로 10진수일경우 11
int leftShift = c << 2; 일경우 왼쪽으로 2칸 가는것 실제론 1011. 소숫점이있다 생각하고 뒤에 두칸 00 달아주면 된다.
그러면 101100은, 0b101100 은 10진수로 44다
반래도
int rightShift =c >> 1; 일경우 오른쪽으로 1칸 가는것인데, 1011. 소숫점이 있다생각하고 왼쪽으로 움직이면서 뒤에 1버려서
101 표현식은 0b0101 10진수로 5다.

~ 는 부정이다. 1100 이면 0011로 뒤집어주면된다.


----------------
복합대입 연산자, 증감연산자 활용

복합대입연산자란
x = x+y; 그럴때 x+=y; x는 x에 y를 더해놓을것이다.

+=
-=
*=
/=
%=


...

증감연산자
전위형 후위형 달라진다.
++
--
++x는 이미 더하고 x를 사용함 (전위형)
x++ x를 쓰고 ; 세미콜론 이후에, 그러니까 다 끝나고 ++증감을 사용함 (후위형)

------
연산자 우선순위가 있음
c#에선
1번부터 가장 빠르다.
1.괄호가 가장 우선순위
2. 그다음 단항연산자 ( ++,--,+,-,! 등)
3. 산술 연산자 ( *, / ,% , + ,- )
4. 시프트연산자 (<< >>)
5. 관계연산자 (< , > ,<=, >=, == ,!=)
6. 논리연산자 (&&, ||)
7. 할당연산자 ( =, +=, -=,*=,/= 등)

----------
new 로 문자와, 정수로 소괄호를 표현하여 반복되는 문자열 생성
string str1 = " Hello, World" ; // 리터럴 문자열 사용
string str2 = new string('H', 5); // 문자 H를 5개로 구성된 문자열 생성 HHHHH

--------
인덱스 찾기
string str = "Hello, World!";
int index = str.IndexOf("World");
Console.WriteLIne( index); 하게되면 World 문자열의 가장 첫번째 인덱스를 찾아 index 변수에 저장한다. 여기선
쉼표와 띄어쓰기까지 합쳐서 7이라는 숫자를 내놓는다. 문자하나씩 계산하여 0부터 W까지 세거나,
 1부터 인덱스 전인 W 전까지 세면된다.

------------
대체
string str = "Hello, World";
string newStr = str.Replace("World" , "Universe");
Console.WriteLine(newStr); // Hello, Universe

가져와서 새로 만들어주는거임, 기존것은 바뀌지않음. str은 여전히 Hello, World 인샘
---------
값 비교 대소비교

string str1 = "Hello";
string str2 = "World";
bool isEqul = str1 == str2;// false

string str1 = "Apple";
string str2 = "Banana";
int compare = string.Compare(str1, str2);// 이 코드는 str1 문자열, str2 문자열을 대소비교후
compare 변수에 그 결과 저장하는데, compare 변수는 0보다 작으면 str1이, str2보다 작고, 0이면 str1과 str2가 같으며,
0보다 크면 str1이 str2보다 크다. 


문자열은 사전식 비교를 하는데, 사전의 뒤에 나올수록 더 높은것이다. 문자의 길이가 아님
앞에있는게  Apple이면 Banana보다 작으므로, 값을 출력해보면 -1이 나온다. 
반대였다면 1이 나왔을것.

str1 = "World";
str2 = " hhhhh";
일때,
Console.WriteLine(string.Compare(str1,str2));
하면 -1이 나오는데 소문자가 더 크기때문(사전에서 더 뒤이기때문)


---------------
포멧팅
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.";

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

먼저, 이름과 나이를 순서대로 입력받게 시키고,
만약에 이름과 나이를 제대로 입력하지않는다면 계속해서 입력 제대로하라고 뿜어낸다. 
체크하고 맞으면 넘어간다. 틀리다면, 넘어가지않고 반복한다.
name과 age를 Split을 이용한 배열로 뽑아서 출력할 예정이다.
이때 컴파일 에러를 방지하기위해 여러가지를 체크해볼 수 있는데, 
1. 여백을 두지않고 바로 썼을때
즉 input.Length !=2 일때다. 풀어보자면, input 값으로 형성된 배열의 길이가 2가 되어야만 input[] = { name, age };
값을 출력하도록한다.
2. 이름이 char 타입이아니거나, 공백이거나, 비할당되었을때 
두가지 문법을 이용해 체크가능한데,
먼저 string.IsNullOrEmpty(name) 은 name이라는 string이 null이거나 공란인것을 반환한다.
그리고 name.All(Char.IsLetter) 은 name안의 charater들이 알파벳인지를 체크한다.
여기서 name이라는 배열의 모든 요소가 All( )소괄호 안의 조건을 만족하는지를 체크해서 boolean 값으로 반환한다.
소괄호 안은 람다식으로 풀어서 쓴것을 줄인것이다.
name.All(c => Char.IsLetter(c)) 이다.

Char.IsLetter(A) 는 true를 반환하고
Char.IsLetter(1)는 false를 반환한다.
참고로 유니코드 기준으로 판단되므로, 라틴 문자 뿐아니라 한글, 그리스 문자등 다양한 언어의 알파벳도 인식한다.

즉, !string.IsNullOrEmpty(name) && name.All(Char.IsLetter) 인지를 체크하면 된다.

여기서 Where과 All의 차이도 잠깐 짚고 넘어가보자.
둘다 LINQ에서 제공하는 확장 메서드로, 컬렉션의 각 요소에 대해서 조건을 검사한다.

먼저 Where은 조건에 맞는 요소들의 새로운 시퀀스(IEnumerable<T>)를 반환한다고 생각하면 된다.
예시로는
int [ ] numbers = { 1 , 2, 3, 4, 5 };
var evenNumbers = numbers.Where( n => n%2 ==0);
일때
evenNumbers [ ] = { 2, 4 }; 가 될것이다. 
이런식으로 리스트나 배열에서 조건에 맞는 여러 요소들을 선별해서 새로운 시퀀스로 필터링할때 쓴다.

All은 컬렉션의 모든 요소가 지정한 조건을 만족하는지 검사하여 모두 만족하면 true, 하나라도 해당 조건을 만족하지않다면
false를 반환하는것이다. 참고로 컬렉션이 비어있으면(예를 들어 배열에 기본값), All은 true를 반환한다.

int [ ] numbers = { 2, 4, 6, 8};
bool areAllEven = numbers.All( n => n%2 == 0); // true 로 나온다.




3. 숫자가 정수형으로 0보다 크게 입력이 잘되었는지 체크한다.
이건 형변환의 TryParse를 사용하면 좋다.
여기서는 입력값이 age라는 int 변수에 할당되었을때 
int age = int.Parse(input[1]); 인 상태라면
bool isAgeValid = int.TryParse( input[1], out age )
처럼 표기하여 참과 거짓을 체크가능하다. 이때 {age}를 출력하게되면 
입력값이 참이라면, 즉 int값으로 캐스팅이 되게끔 정수타입의 string으로 입력이된다면
 age를 반환하고 거짓이라면 false가 되며 기본값 0을 반환한다.


그다음 입력을 잘못했다면 제대로할때까지 입력을 반복하도록 while문을 만들어주는데 이슈가있었다.
while문을 사용하는데, 입력값을 받는다하더라도 그것에대해
매번 해당 문을 빠져나오기위해 조건의 유효성을 재검사해줘야만 빠져나올 수 있다.
그렇지않으면 이전의 입력값의 유효성만 검증하기때문에 빠져나올 수 없다.

처음엔
나름 머리를 굴려봤지만 while문을 벗어나지못했다.
      Console.WriteLine("이름과 나이를 순서대로 입력하세요.");



            string[] input = Console.ReadLine().Split(' ');
            string name = input[0];
            int age = int.Parse(input[1]);
            bool isNameValid = !string.IsNullOrEmpty(name) && name.All(Char.IsLetter);
            bool isAgeValid = age > 0 && int.TryParse(input[1], out age);

            Console.WriteLine($"이름: {name}, 나이: {age}");

            while (!isNameValid || !isAgeValid)
            {                
                Console.WriteLine("이름과 나이를 제대로 입력해주세요");
                input = Console.ReadLine().Split(' ');
                name = input[0];
                age = int.Parse(input[1]);

                if(isNameValid && isAgeValid)
                {
                    Console.WriteLine($"이름: {name}, 나이: {age}");
                    break;
                }
            }

그 이유를 보자면, while문의 조건은 선언한 isNameValid 또는 isAgeValid 둘중 하나라도 거짓이라면 참이되서 반복되는데
다시 input 값을 입력받아서 
name과 age가 갱신되었다고 해도,
그전에, 이미 예를들어 사용자가 30, 30 으로 입력했다면 bool isNameValid = false; bool isAgeValid = true;
로 저장되어있기때문에 
다시 유효성 검사를 하지않으면 그대로 할당되어있기때문에 벗어나지못하는것이다.
while 문안에 if문을 써서 조건을 쓰는것은 큰 의미가 없다 여기선. 유효성 검사를 따라서 한번더 해준다.

            while (!isNameValid || !isAgeValid)
            {
                Console.WriteLine("이름과 나이를 제대로 입력해주세요");
                input = Console.ReadLine().Split(' ');  
                name = input[0];
                agetxt = input[1];

                isNameValid = !string.IsNullOrEmpty(name) && name.All(Char.IsLetter);
                isAgeValid = int.TryParse(agetxt, out age) && age>0;
                
            }

만약에 할당이 새롭게 갱신되서 둘다 true가 된다면 while문을 벗어난다.
몇가지 문법적 오류가 더있었는데,
 int age = int.Parse(input[1]);
bool isAgeValid = age > 0 && int.TryParse(input[1], out age);
이부분이 문제였다.

int age = int.Parse(input[1]); 우선 여기서 이미 input[1]이 Tom 같은 문자열로 입력되면 예외가 발생해버렸다.
그리고 이미 예외가 발생한 age에 대해서
bool isAgeValid = age > 0 && int.TryParse(input[1], out age); 은 체크를 할수 없는것이다.
또한 논리 연산자 &&는 왼쪽 조건이 false인경우 오른쪽을 조건체크하지않는 단락평가를 하는데,
int.Parse를 사용하는 부분은 이미 실행된 상태이다. 그래서 입력값이 정수형이 아니면 무조건 예외발생으로 실행종료되어
버린다.

논리 연산자 &&의 경우 단락평가를하기에,
 앞부분에 사용되는 변수가 할당받지않고 선언만 될때도 문제가되었었다.
예를 들어
string ageTxt = input[1];
int age ;
라고 선언만하고
bool isAgeValid = age > 0 && int.TryParse(ageTxt, out age); 라고했을때
age는 할당(초기화)가 안되어있어서 데이터값이 없는상태이며 >0 인지 비교할 수 가없다.
그런데,
bool isAgeValid =  int.TryParse(ageTxt, out age) && age > 0; 하면 비교가 가능해진다.


그다음엔, input에 처음에 입력할때 Tom 30 이런식으로 여백으로 Split (' ') 하여서 값이 나오게 했으나
3030 혹은 Tom30 이런식으로 입력했을때의 경우다. "3030" "Tom30" 은 문자열 하나로 취급이 된다.
즉 
string [ ]input의 배열의 인자 수는 1개다. 그 길이를 체크해서 2개가 아니라면 다시 제대로 작성하라는 출력을 뽑아내고싶다.

여기서는 
while (input.Length != 2)
{
    Console.WriteLine("입력 형식이 잘못되었습니다. 이름과 나이를 공백으로 구분하여 입력해주세요.");
    input = Console.ReadLine().Split(' ');
}
라고 써줘도 된다.
앞선 while과 조금 다른데, 자세히 보자면
input.Length는 input 배열의 프로퍼티에 접근한것이다. 그래서 바로 조건을 검증하고 참이라면 
스코프 안의 내용을 실행한다. 이때 input으로 다시 사용자 입력값을 받아 할당하면 그 즉시
input.Length를 체크할 수 있도록 input이 갱신되기때문에 input.Length !=2라는 조건을 바로 체크 할 수 있어지며
부가적인 유효성 체크는 필요가 없다. 조건에만 맞게 입력된다면 while문을 바로 벗어날 수 있다.

이름과 나이를 다시 입력해달라는 문구 출력후에도, 또 형식에 맞지않게 배열을 두개가 아닌 한개, 여러개로 
입력 할 수도있다. while문이 대부분 조건으로 체크하지만 놓치는 부분이 이런것들인데
이럴때 input을 입력받고나서 한가지 체크해준다.

if 조건문안에 input.Length !=2 를 한번 더 체크하고
틀렸다고 경고하는 문구를 출력하며
continue; 를 이용해 while 문의 아래쪽 유효성 체크 코드는 무시하고

while 반복으로 처음으로 다시 돌아가 input 값을 받아보도록 요구한다. 


최종 완성은 아래와 같다.

     Console.WriteLine("이름과 나이를 순서대로 입력하세요.");



     string[] input = Console.ReadLine().Split(' ');
     while(input.Length != 2)
     {
         Console.WriteLine("이름과 나이를 공백을 포함해서 순서대로 하나씩 입력하세요.");
         input = Console.ReadLine().Split(' ');
     }


     string name = input[0];
     string agetxt = input[1];
     int age;
     bool isNameValid = !string.IsNullOrEmpty(name) && name.All(Char.IsLetter);
     bool isAgeValid = int.TryParse(agetxt, out age) && age > 0;

     while (!isNameValid || !isAgeValid)
     {
         Console.WriteLine("이름과 나이를 제대로 입력해주세요");
         input = Console.ReadLine().Split(' ');
         if (input.Length != 2)
         {
             Console.WriteLine("이름과 나이를 공백을 포함해서 순서대로 하나씩 입력하세요.");
             continue;
         }
         name = input[0];
         agetxt = input[1];

         isNameValid = !string.IsNullOrEmpty(name) && name.All(Char.IsLetter);
         isAgeValid = int.TryParse(agetxt, out age) && age>0;
         
     }
     Console.WriteLine($"이름: {name}, 나이: {age}");
-----------------------------

사칙연산 계산기 만들기

계산기의 사칙연산은 덧셈,뺄셈, 곱셈, 나눗셈이다.
소숫점 7자리까지 계산가능하도록 만든다.

알아둘점:
float, double 같은 소수들은 이진수로 표현될때 무한소수로 근사치로 값이 나온다. 분수형태에 2의거듭제곱을
실행하기때문이며, 따라서 같은 자료형이라면 기본적으로 반올림하여 보기좋은값으로 표시되나,
혼용하여 연산할 경우 float값이 double값으로 암묵적변환이 되며 이때 float에 저장된 근사값이 그대로 유지되는데
double의 더 높은 정밀도로 인해 그 근사값이 더 많은 소숫점 자리수까지 드러나게된다.
이래서 예를들면
  float x = 0.1f;
            double y = 0.1;

            Console.WriteLine(x+y);
하면 0.2가 아닌
0.20000000149011612이 출력된다.


x 값과 y값은 int, float, double 값으로 받는다.
x값을 먼저 입력하게하고, 
사칙연산 부호를 입력하게하고
y 값을 입력하게한다.

결과값을 내놓는다. 간단하게 스위치 case문으로 연산부호에 따라 다른 결과값을 내도록 한다.


            Console.WriteLine("사칙연산 계산기");
            Console.WriteLine("첫번째 수를 입력해주세요");
            
           

            String input = Console.ReadLine();
            Console.WriteLine("연산부호를 입력해주세요 *, /,+,-");
            String input2 = Console.ReadLine();
            Console.WriteLine("두번째 수를 입력해주세요");
            String input3 = Console.ReadLine();

            bool num1Valid = float.TryParse(input, out float num1);
            bool num2Valid = float.TryParse(input3, out float num2);

            if(num1Valid && num2Valid)
            {
                switch(input2)
                {
                    case "+":
                        Console.WriteLine($"{num1} + {num2} = {num1 + num2}");
                        break;
                    case "-":
                        Console.WriteLine($"{num1} - {num2} = {num1 - num2}");
                        break;
                    case "*":
                        Console.WriteLine($"{num1} * {num2} = {num1 * num2}");
                        break;
                    case "/":
                        if (num2 == 0)
                        {
                            Console.WriteLine("0으로 나눌 수 없습니다.");
                        }
                        else
                        {
                            Console.WriteLine($"{num1} / {num2} = {num1 / num2}");
                        }
                        break;
                    default:
                        Console.WriteLine("잘못된 연산자입니다.");
                        break;
                }
            }
            else
            {
                Console.WriteLine("잘못된 숫자입니다.");
            }



-----------------
섭씨온도를 입력하면 화씨온도로 바꿔주는 프로그램

            Console.WriteLine("섭씨 온도를 입력하면 화씨온도로 변환해줍니다.");
            Console.Write("섭씨온도 : ");
            string input = Console.ReadLine();
            bool isC = float.TryParse(input, out float C);
            if (isC)
            {
                float F = C * 9.0f / 5.0f + 32.0f;
                Console.WriteLine($"화씨온도 : {F}");
            }
            else
            {
                Console.WriteLine("잘못된 입력입니다.");
                
            }

-----------
BMI 지수 계산하는 프로그램

체질량지수는 체중kg을 키m의 제곱으로 나눈값으로 계산하며

BMI가 18.5 미만이면 저체중
18.5이상 ~24.9미만 정상
25.0 이상 ~ 29.9 미만 과체중
30.0 이상 ~ 34.9 미만 비만
35.0이상 ~ 39.9 미만 고도비만
40이상이면 초고도 비만

키입력값 받고
kg 입력값 받고
몸무게 kg / (키 m)제곱 

여기서 제곱연산자는 없는데,
System.Math 클래스의 Math.Pow를 쓰거나 그냥 x*x 를 하는 직접 곱셈을 연달아 하는 방법이 있다.

double result = Math.Pow(x,2); 이런식으로 하여 
두번째 인자인 2는 제곱을 의미한다. double 타입으로 저장된다.

double result = x * x; 호출 하는게 더 빠르고 간단하다.
더 복잡한 거듭제곱 계산이나 소수지수를 사용할때 Math.Pow( x, 2); 방식을 사용하면된다.
여기서 x는 밑이고 2는 지수인 정수타입 2제곱근이 된다. 

예를들어, 소수 지수나 음수 지수 계산할때는 Math.Pow가 필요하다.

double value = 16;
doulbe squareRoot = Math.Pow( value, 0.5);

Console.WriteLine($"16의 0.5승 제곱근은 {squareRoot}입니다"); // 출력 : 4

혹은 복잡한 수학 공식 구현에도 Math.Pow가 쓰인다.

// 복리 계산: A = P * (1 + r/n)^(n*t)
double principal = 1000;   // 원금
double rate = 0.05;        // 연 이자율 (5%)
int n = 12;                // 이자 계산 횟수 (월별)
int t = 10;                // 투자 기간 (10년)
double amount = principal * Math.Pow((1 + rate / n), n * t);
Console.WriteLine($"10년 후 금액은 {amount:C}입니다.");

혹은 동적 지수 계산시에도 쓰일 수 있다.

// 사용자로부터 밑과 지수를 입력받아 거듭제곱 계산
Console.Write("밑: ");
double baseValue = double.Parse(Console.ReadLine());
Console.Write("지수: ");
double exponent = double.Parse(Console.ReadLine());
double result = Math.Pow(baseValue, exponent);
Console.WriteLine($"{baseValue}의 {exponent}제곱은 {result}입니다.");

돌아가서 BMI 지수는 그럼 어떤방식이 좋을까?
항상 지수가 2로 고정되어있으니 직접곱셈방식을 사용하는게 효율적임.

소숫점 한두자리수까지만 표현하고싶을때 F2 (소숫점 두자리) 예: 123.45678 을 F2 하면 123.46
N2( 천 단위 구분 기호와 함께 소숫점 두자리) 예 : 12345.6789 를 N2 하면 12,345.68
할수있고 그밖에도 이런 형식지정자라 불리는 문법을 이용해 
백분율
double rate = 0.1234;
Console.WriteLine($"{rate:P2}"); // 결과: 12.34%
통화
double price = 1234.56;
Console.WriteLine($"{price:C}"); // 결과: $1,234.56 (문화권에 따라 다름)
Exponential
double value = 12345.6789;
Console.WriteLine($"{value:E2}"); // 결과: 1.23E+004 (환경에 따라 다를 수 있음)
등을 표현할수있으며

문자열 보간을 사용하여 : (콜론)을 이용하면 
{value:N2} 같은 방식으로 어디까지 표현할껀지 작성가능하다.

문자열 보간을 안쓴다면
.ToString("N2") 를 이용하여 표현 가능하다.
 


최종 결과물은 아래와 같다. 키를 보통 cm로 입력하니 m로 변환해서 계산해주도록 설정하였다.

            Console.WriteLine("BMI 지수를 계산하는 프로그램입니다.");
            Console.Write("키(cm)를 입력하세요: ");
            String heightInput = Console.ReadLine();
            Console.Write("몸무게(kg)를 입력하세요: ");
            String weightInput = Console.ReadLine();

            bool isHeightValid = double.TryParse(heightInput, out double heightCM);
            bool isWeightValid = double.TryParse(weightInput, out double weight);

            double height = heightCM * 0.01;



            if (!isHeightValid || !isWeightValid)
            {
                Console.WriteLine("잘못된 입력입니다. 숫자를 입력하세요.");

            }
            else
            {
                double BMI = weight / (height * height);
                if (BMI >= 18.5 && BMI < 24.9)
                {
                    Console.WriteLine($"당신의 BMI는 {BMI:F2}입니다. 정상 체중입니다.");
                }
                else if (BMI >= 25.0 && BMI < 29.9)
                {
                    Console.WriteLine($"당신의 BMI는 {BMI:F2}입니다. 과체중입니다.");
                }
                else if (BMI >= 30.0 && BMI < 34.9)
                {
                    Console.WriteLine($"당신의 BMI는 {BMI:F2}입니다. 비만입니다.");
                }
                else if (BMI >= 35.0 && BMI < 39.9)
                {
                    Console.WriteLine($"당신의 BMI는 {BMI:F2}입니다. 고도비만입니다.");
                }
                else if (BMI >= 40.0)
                {
                    Console.WriteLine($"당신의 BMI는 {BMI:F2}입니다. 초고도비만입니다.");
                }
                else
                {
                    Console.WriteLine($"당신의 BMI는 {BMI:F2}입니다. 저체중입니다.");
                }