C# 공부정리 - 기초문법 1 (연산자)
사칙연산
간단한 사칙연산부터 해보자
static void Main(string[] args)
{
Console.Write("국어 점수 입력하세요?");
int kor = int.Parse(Console.ReadLine());
Console.Write("영어 점수 입력하세요?");
int eng = int.Parse(Console.ReadLine());
Console.Write("수학 점수 입력하세요?");
int math = int.Parse(Console.ReadLine());
Console.Write("과학 점수 입력하세요?");
int sci = int.Parse(Console.ReadLine());
int sum = kor + eng + math + sci;
float avg = sum / 4f;
}
국어 영어 수학 과학 4개 과목의 점수를 입력받고 그것의 평균을 구하는 알고리즘이다.
입력 받은 수를 int로 변환하여 읽어드리고
그렇게 받은 값 4개를 4로 나누어 평균을 구한다.
여기서 주의해야할 점이 avg의 끝에서 f라는 접미사를 붙인다는 것이다.
산술 연산자
산술연산자는 +, -, *, /, % 로 총 5개의 연산자가 있다
순서대로 덧셈, 뺄셈, 곱셉, 나눗셈, 나머지연산이다.
static void Main(string[] args)
{
int a = 18;
int b = 6;
int c = a + b;
Console.WriteLine("c: " + c); //a+b는 24
Console.WriteLine("100 - 10 = " + (100 - 10)); //100 - 10은 90
int d = a / b;
Console.WriteLine("d: " + d); //a 나누기 b는 3
int e = a * (b + c);
Console.WriteLine("e: " + e); //a 에 b와 c를 더한것을 곱하면 540
int f = (a + b) % 2; // 24를 2로 나눈 나머지는 0
Console.WriteLine("f: " + f);
}
나머지 연산이 조금 생소할 수 있는데 이건 짝수홀수 판별할 때 자주 사용한다.
증감 연산자
1만큼 더 올리냐 빼냐의 기능을 한다.
int num = 10;
Console.WriteLine("num: {0}", num++); //후치 연산
Console.WriteLine("num: {0}", num);
Console.WriteLine("num: {0}", ++num); //전치 연산
Console.WriteLine("\nnum: {0}", num--); //후치 연산
Console.WriteLine("num: {0}", num);
Console.WriteLine("num: {0}", --num); //전치 연산
++는 1을 증가, --는 1만큼 감소시킨다.
부호가 앞에 있으면 전치연산, 뒤에 있으면 후치연산인데
이는 이 증감연산자가 어느 타이밍에 실행되어야 하는지를 나타낸다.
보통 후치연산을 많이 사용한다.
위의 코드를 출력하면 다음과 같다.
num: 10
num: 11
num: 12
num: 12
num: 11
num: 10
num의 처음 값은 10이었다.
후치연산은 먼저 10이라는 값을 보여주고 그 다음 값을 더하는 것이다.
때문에 두 번째 콘솔에서 11이 나왔다.
반면 전치연산은 결과를 보여주기 전에 1을 더한다
때문에 세 번째 콘솔에서 12가 나온 것이다.
할당 연산자
=, +=, -=, *=, /=, %=
할당연산자는 위에 표시된 총 6개가 있다.
겉보기에는 복잡해보이지만 사실 알고 보면 굉장히 단순하다.
먼저 = 은 왼쪽의 대상에게 오른쪽 값을 넣는다는 뜻이다.
즉 a = 10; 은 a에다가 10을 넣겠다는 뜻이다.
a += 10; 은 a = a + 10 과 같다.
즉 a += 10은 a에다가 10을 넣은 값을 넣어주겠다는 뜻이다.
나머지 할당연산자들도 모두 동일하다.
정리하면
a += 10 a = a + 10
a -= 10 a = a - 10
a *= 10 a = a * 10
a /= 10 a = a / 10
a %= 10 a = a % 10
이렇게 정리할 수 있다.
관계 연산자
뭐가 더 크냐 작냐를 표현하는 연산자다.
< > <= >= == !=
이렇게 6개가 있다.
먼저 <랑 >는 초과, 미만을 나타내고 =가 붙은 것은 이상과 이하를 나타낸다.
문제는 ==과 !=인데
==는 이 연산자 좌 우에 위치한 식이 일치하는가를 묻는 것이고
!=는 반대로 좌 우에 위치한 식이 일치하지 않는가를 묻는 것이다.
관계연산자는 이러한 특징상, 그 값이 bool로 출력된다.
예를 들어보자
result = (10 > 1);
Console.WriteLine(result);
10은 1보다 크다.
때문에 result는 true가 된다.
result = (10 < 1);
Console.WriteLine(result);
반대로, 위 식은 거짓이 된다.
result = (10 != 1);
Console.WriteLine(result);
하나만 더 해보자
10과 1은 같은 값이 아니다.
고로 위의 result는 true가 된다.
논리 연산자
&& || !
총 3가지가 있다.
&&는 AND연산이고 ||는 OR 연산이다.
!는 NOT연산이다.
AND연산이란, &&의 양 옆으로 있는 식이 둘 다 true면 true를 나타내고
OR연산은 ||의 양 옆으로 있는 식이 둘 중 하나라도 true 면 true를 나타낸다.
NOT연산은 참 거짓을 뒤집는다. 즉 true는 false로, false는 true로 만든다.
아래 예시를 보자
static void Main(string[] args)
{
bool result;
int a = 100;
int b = 1000;
result = (a == 100) && (b == 1000); //true , true
Console.WriteLine("(a == 100) && (b == 1000): {0}", result);
}
아래 result를 보자, a값은 100이 맞다.
그리고 b값도 1000이 맞다.
a와 b가 모두 참이므로 result는 true가 된다.
bool result;
int a = 100;
int b = 1000;
result = (a == 100) && (b == 100); //true , false
Console.WriteLine("(a == 100) && (b == 100): {0}", result);
같은 식을 살짝 수정해 봤다.
이번에는 b값이 1000임에도 불구하고 b == 100으로 입력되어 있다.
AND연산은 둘 다 true여야지 true가 되기 때문에 result는 false가 된다.
조건연산자
위 사진에서 ?가 조건연산자에 해당한다.
사실 위 사진은 삼항연산자로 먼저 조건에 해당하는 식을 작성하고 ?를 붙인 뒤, 조건이 참이면 처리1을, 거짓이면 처리 2를 실행한다.
비트연산자와 비트논리 연산자
이건 잘 안쓸것 같지만 일단 알아보고 가자
비트연산자로는 << 와 >>가 있고
비트논리연산자로는 & | ^ ~ 가 있다.
아무튼 비트란 무엇일까?
숫자 15는 2진수로 1111 이다.
이를 비트로 표현하면 0000 0000 0000 0000 0000 0000 0000 1111 이다.
0이 굉장히 많은데, 0은 4개씩 2묶음 그리고 이것이 총 4묶음이 있다.
즉, 비트란 총 32개의 2진수 숫자로 이루어져있다.
정리하자면 우리가 흔히 쓰는 십진수 숫자를 이진수로 변환한 다음
그 값을 32개의 2진수 숫자로 표현한 것을 비트라고 보면 된다.
그렇다면 비트 연잔사와 비트 논리연산자는 무엇을 하는 걸까
두 개의 숫자를 예로 들어보자
int a = 15; // 0000 0000 0000 0000 0000 0000 0000 1111
int b = 22; // 0000 0000 0000 0000 0000 0000 0001 0110
위의 두 숫자 a와 b를 비트로 표현해보았다.
이제 이 두 숫자를 기반으로 예시를 만들어 보자
int a = 15; // 0000 0000 0000 0000 0000 0000 0000 1111
int b = 22; // 0000 0000 0000 0000 0000 0000 0001 0110
int c = a & b; // 0000 0000 0000 0000 0000 0000 0000 0110 => 6
int d = a | b; // 0000 0000 0000 0000 0000 0000 0001 1111 => 31
int e = a ^ b; // 0000 0000 0000 0000 0000 0000 0001 1001 => 25
int f = a << 2; // 0000 0000 0000 0000 0000 0000 0011 1100 => 60
int g = a >> 2; // 0000 0000 0000 0000 0000 0000 0000 0011 => 3
int h = ~a; // 1111 1111 1111 1111 1111 1111 1111 0000 => -16
&연산자는, 두 비트를 비교했을 때, 둘 다 1일 경우 1이 되고 둘 중 어느 것도 0이라면 0이 된다.
때문에 a & b 는 위에 나타난 식 처럼 6이 된다.
|연산자는, 두 비트를 비교했을 때, 둘 중 하나라도 1이면 1이 된다.
때문에 a | b 는 위에 나타난 식 처럼 31이 된다.
^연산자는, 두 비트를 비교했을 때, 서로의 값이 다르면 1, 같으면 0이 된다.
때문에 a ^ b 는 위에 나타난 식 처럼 25가 된다.
<< 연산자는, 비트를 숫자만큼 왼쪽으로 밀고 그 빈칸에 0을 넣는 연산이다.
때문에 a << 2는 왼쪽으로 두 칸 밀고 그 빈자리에 0을 넣으면서 60이 된다.
>> 연산자는, 비트를 숫자만큼 오른쪽으로 밀고 그 빈칸에 0을 넣는 연산이다.
때문에 a >> 2는 오른쪽으로 두 칸 밀고 그 빈자리에 0을 넣으면서 3이 된다.
참고로 맨 오른쪽의 1은 사라진다.
<< 연산자와 >> 연산자는 단순히 밀어버리는 것처럼 보일 수 있지만
<<는 2배씩 증가하는 효과를, >>는 2배씩 감소하는 효과를 보여준다.
때문에 15에 <<를 2번하면 60이, 15에 >>를 2번하면 3(소숫점은 버림)이 나온다.
~ 연산자는 NOT 연산으로 1과 0을 뒤집어주는 역할을 한다.
때문에 ~a는 -16이 된다.
참고로 마이너스로 변환 될 때는 1 더 적은 숫자로 표현된다.
양수일 때는 0을 포함해야 되기 때문이다.
참고로 (~a) >> 2; 처럼 NOT 하고 비트연산을 해버리면 그 빈자리를 0으로 넣을 수도 있고
1로 넣을 수도 있다.
이 결과는 CPU에 따라 다른 결과가 나올 수 있다.
이는 심각한 문제를 초례할 것으로 보이지만 애초에 비트연산 자체가 잘 안쓰이다보니
실제로 문제가 될 경우는 잘 없을 것 같다.
null 병합 연산자
null 값을 체크하는 연산자다.
예시로 확인해보자
int? a = null;
int b = 10;
int result;
result = a ?? b;
result의 값은 10이 된다.
a값이 null이기 때문에 result에는 b의 값이 대입되는 것이다.
다른 예시를 보자
int? a = null;
int b = 10;
int? c = null;
int d = 100;
int result;
result = a ?? c ?? d;
a는 null이고 c도 null이다. 고로 result에는 d의 값이 대입된다.
만약 아래 식처럼 c가 null이 아니라면 어떨까?
int? a = null;
int? c = 999;
int d = 100;
int result;
result = a ?? c ?? d;
이 경우, result에는 c의 값이 대입된다.