-Summary-
사칙 연산, 증감 연산자, 자료형 확장-축소, if else if else 조건문, 비교 연산자, bool 자료형, 비트 단위 연산자
02-17 (Unit 12.1 ~ Unit 19.5)
-+, --
+, -는 파이썬과 동일하게 더하고 빼주는 기능의 연산자다.
<값> + <값>
<값> - <값>
이런식으로 써줄 수 있고
<변수> <+ or -> <값>
<변수> <+ or -> <변수>
이런식으로 변수끼리의 연산도 가능하다.
또한 <변수> = <변수> - <값> 또는 <변수> = <변수> + <값>이라면 파이썬에서 배웠던 것 처럼 +=, -=으로 줄여쓸 수 있다.
<변수> += <값>
<변수> -= <값>
이런식으로 +, -를 이용해 값과 변수끼리 플러스 마이너스 연산이 가능하다.
실수도 역시 동일한 방법으로 가능하다.
값이나 변수를 더할 때는 <변수> = <값 혹은 변수> + <값 혹은 변수>로 써주면 된다.
b : num1과 더할 값이 없다. <더할 값> + num1이 되야한다. X
답 : b
num1의 값을 10 감소시키는 방법은 num1 -= 10; 혹은 num1 = num1 - 10;으로 해주면 된다.
답 : c
num1 = num1 + 2; 는 num1 += 2;로 사용할 수 있다.
답 : d
num1을 100으로 만들어서 100을 출력하는 것이 목적이다. num1 = 10 - num2이므로 결국 num1에는 5가 들어가니 95를 더해준다면 100이 출력될 것 같다.
#include <stdio.h>
int main()
{
int num1;
int num2 = 5;
num1 = 10 - num2;
num1 += 95;
printf("%d\n", num1);
return 0;
}
주어진 빈칸에 95를 넣음으로써 num1이 100이 되도록 작성했다.
실수 두 개가 입력되어 num1, num2에 저장되는데 이 두 실수를 더한 값에서 4.5를 감소시킨 값이 num3에 들어가도록 하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
float num1;
float num2;
float num3;
scanf("%f %f", &num1, &num2);
num3 = num1 + num2 - 4.5f;
printf("%f\n", num3);
return 0;
}
주어진 num3 변수의 값을 num1 + num2 - 4.5f식의 값으로 할당해줘서 풀었다.
-++, ---
++, -- 연산자는 파이썬과 마찬가지로 <변수> += 1;, <변수> -= 1;을 줄인 것과 같다. ++는 1을 증가시켜주고, --는 1을 감소해주는 역할을 한다. 파이썬과 다르게 포인터 개념이 있는 c언어에서는 ++, --가 포인터 연산에서 자료형 크기만큼 증감해주는 역할도 한다.
<변수>++;
<변수>--;
++<변수>;
--<변수>;
증감 연산자는 위처럼 쓸 수 있다. 이 증감 연산자의 위치에 따라 동작이 조금 차이가 있는데, 이는 밑에 정리해뒀다.
위처럼 ++, --연산을 int형 변수 a에 사용해보니 +=1, -=1과 동작이 같은 것을 볼 수 있다. 5행에서 선언과 동시에 a에 0을 할당해줬는데, 6행의 ++를 통해 a의 값이 1증가해 1로 변했고, 8행의 --로 a의 값이 1 감소해 다시 0이 됐다.
실수형에서도 잘 작동하는 것을 볼 수 있다. 3.14가 할당된 a를 ++ 시키니 4.14가 됐고, --를 시키니 다시 3.14가 됐다.
문자형에서도 잘 작동한다. a,b,c,d 이런 알파벳 끼리는 아스키 값이 서로 1씩 차이가 난다. 위의 a 변수에 'a'를 넣어주고 ++를 시키면 a 아스키 값에 1이 더해져, 해당 아스키 값의 문자인 b가 출력되고, 다시 --를 시키니 a가 출력되는 것을 볼 수 있다.
-<변수>++과 ++<변수>의 차이
먼저 <변수>++;과 같은 형식을 후위 연산자, ++<변수>와 같은 형식을 전위 연산자라고 한다. 실험을 해보면 전위, 후위 간의 큰 차이점이 보이지 않는데, 이 차이점은 연산자를 사용하면서 동시에 다른 변수에 할당할 때 보여진다.
위 사진을 보면 a, b에 5를 넣어주고 c, d는 각각 a와 b를 증감 연산자를 써준 후 그 값을 할당 받도록 설계했는데, a와 b는 정상적으로 1 증가해서 6이된 반면 c = a++;로 값을 넣어준 c는 5고 d = ++b로 값을 넣어준 d는 6인 것을 볼 수 있다. 이 상황이 바로 전위, 후위의 동작 차이다.
c = a++;같이 후위에 써준 경우 c에 a의 값을 할당한 후, a의 값을 1 증가시켜주고, d = ++b; 같이 전위에 써준 경우 d에 b 값을 할당하긴 전 b의 값을 먼저 증가시켜준다.
풀어서 써보면 c = a++; 코드는
c = a;
a += 1;과 같고 d = ++b; 코드는
b += 1;
d = b;와 같은 것이다.
즉 변수 할당에서의 전위와 후위의 차이는, 전위는 먼저 값을 증가시켜준 후 그 값을 할당을 해주고, 후위는 값을 할당해준 후 값을 증가시켜준다.
int num1 = 2;
num1 = num1++ + ++num1;
코딩 도장에 전,후 증감 관련해 재밌는 문제가 있어서 작성해봤다. 위 코드가 문제인데, 먼저 num1에 2를 넣어주고 num1 = num1++ + ++num1; 해준 후의 num1의 값을 구하는 것이 목적이다.
먼저 num1++ 부분은 후위 연산자이므로 해당 부분에 2가 들어간 후 num1의 값이 3으로 변한다. 저 상황에서는
num1 = 2 + ++num1과 같은 것이다. ++num1는 전위이므로 num1 +=1한 값이 바로 들어가준다. 그러면 식이 num1 = 2 + 4; 즉 num1은 6이다.
위처럼 함수의 인수로 넣어줄 때도 전위, 후위의 차이가 보여진다. 전위로 넣은 a++은 a의 값이 매개변수로 쓰인 후 += 1 연산이 수행됐고, 후위로 넣은 ++b는 b += 1이 수행된 후 매개변수로 쓰여진 것이다.
위처럼 전위, 후위에 따라 결과가 달라질 수 있으므로 사용시 주의해야한다. 예전에 들었던 보안 사고 얘긴데, 옛날에 OpenSSH라는 터미널 통신 프로그램이 단 1 차이의 오류가 있었다고 한다. 이 단 1차이의 오류로 프로그램을 공격한 공격자가 root 권한을 획득할 수 있었다고 하는데, 이처럼 전위, 후위 연산자 역시 오류를 발생시키지 않아, 버그를 발견하기 힘든만큼, 개발 시 주의해야할 것 같다.
num1의 값을 1 증가시키는 방법은, num1 = num1 + 1; 또는 num1 += 1; 그리고 ++ 연산자를 이용한 num1++;와 ++num1이 있다.
d : 이 코드는 num1을 1 증가시키는 코드가 아니다. num1 += 1;, 또는 num1 = num1 + 1;로 바꿔줘야한다. X
c1에는 'k'가 들어가 있다. 이 c1을 3행에서 --를 해줬는데 그러면 'k'에 해당하는 아스키 값이 - 1 되므로 k의 전 순서 알파벳이 될 것이다.(a, b, c, d, e, f, g, h, i, j, k)
답 : c
4.281756이 할당된 num1에 ++연산자를 사용해줬으므로 1이 증가한 5.281756이 된다.
답 : e
num1에 12가 들어가 있는 상태에서 num2 = num1++;을 해줬다. 여기서 포인트는 전위가 아닌 후위 연산자로 ++을 사용했으므로 num1 += 1한 값이 들어가는게 아닌
num2 = num1;
num1 += 1; 과 같게 된다. 따라서 num2의 값은 12다.
num1에 9가 들어간 상태에서 num2 = --num1;을 해줬다. 마찬가지로 포인트는 --연산자를 후위가 아닌 전위로 해줬으므로
num1 -= 1;
num2 = num1;과 같게 된다. 따라서 num2의 값은 8이 된다.
2와 7이 각 줄에 출력되도록 num3, num4의 값을 설정해야한다.
num3은 num1 ++;한 후 num3 = --num1;로 값을 할당받으므로 num1의 값이 핵심이다. num1은 +=1해주고 후위 연산자로 사용했으므로 -=1한 값이 들어가는데, 그럼 +1 -1 변화가 없으므로 num3에는 num1 값 그대로 들어간다 보면 된다.
num4는 --num2;를 한 후 num4 = num2++;이 들어가므로 역시 num2의 값이 핵심이다. num2 -= 1을 해주고 num4 = num2++; 연산이 수행되는데, 전위가 아닌 후위 연산자로 사용했으므로, num2 -= 1 값이 num4에 들어가는 것이다.
#include <stdio.h>
int main()
{
int num1 = 2;
int num2 = 8;
int num3;
int num4;
num1++;
num3 = --num1;
--num2;
num4 = num2++;
printf("%d\n", num3);
printf("%d\n", num4);
return 0;
}
num3은 num1의 값이 그대로 할당되므로 num1은 2를 할당해주고, num4는 num2 -= 1한 값이 할당되므로 출력할 값의 + 1한 값인 8을 넣어줬다.
입력으로 정수, 실수, 문자가 num1, num2, c1에 각각 입력되는데, 정수와 실수는 1씩 증가, 문자는 바로 앞 순서의 문자가 출력되도록 하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num1;
float num2;
char c1;
scanf("%d %f %c", &num1, &num2, &c1);
num1++;
num2++;
c1--;
printf("%d %f %c\n", num1, num2, c1);
return 0;
}
정수와 실수에 해당하는 num1, num2는 ++ 연산자로 1씩 증가시켜줬고, c1은 바로 앞 순서의 알파벳이 출력되도록 --를 해줬다.
-*, /-
파이썬과 똑같이 곱셈과 나눗셈은 *, /로 사용한다. 다른점은 파이썬 3.X 버전에서는 /를 썻을 때 실수 단위까지 계산해서 몫을 구해주기 때문에 값이 실수형으로 나왔지만, c언어는 실수끼리 나눗셈을 하지 않는 이상, 정수형끼리 연산에서는 값이 정수형으로 나온다.
<값> * <값>
<값> / <값>
<변수> * <변수>
<변수> / <변수>
사용은 +, -와 같은 형식으로 사용하면된다.
6, 7행은 정수와 실수끼리 각각 * 연산을 수행해줬다. *연산의 결과는 파이썬과 같은 것을 볼 수 있다.
8, 9행은 정수와 실수끼리 각각 / 연산을 수행해줬다. 정수끼리의 / 연산의 결과는 파이썬의 //와 같고, 실수끼리의 / 연산은 파이썬의 / 연산처럼 소수점 단위로 몫이 출력되는 것을 볼 수 있다.
파이썬처럼 0으로 어떤 수를 나누려 시도하면 파이썬의 ZeroDivide 에러처럼 c언어에서는 0으로 나눌 수 없다는 컴파일 에러가 뜬다.
위 사진처럼 변수에 10과 0을 담고 나눠주는 연산 코드를 짜면 컴파일은 되지만, 실수끼리 나눴을 시엔 무한을 의미하는 inf가 출력되고, 정수끼리 나눴을 때는 공백만 출력된다.
한 가지 신기한 점은 실수끼리 *, / 연산을 수행했을 때 오차가 있다는 것이다. 위 사진을 보면 오차가 안보였던 파이썬과 다르게 c언어에서는 실수끼리 연산할 때 약간의 오차가 보이는 것을 볼 수 있다.
*, / 연산도 마찬가지로 *=, /=으로 한 번에 사용이 가능하다.
<변수> = <변수> * <변수2>를 <변수> *= <변수2> 이런식으로 줄일 수 있다. / 연산도 마찬가지다.
a : *num1은 연산할 수 없다. X
c : 0으로 나누면 컴파일 에러가 뜬다.(정 나누고 싶다면 0을 변수에 담아서 나눠주자)
num1 = num1 * 12;는 num1 *= 12로 사용할 수 있다.
답 : c
삼각형의 넓이는 가로 X 높이 / 2다. base가 가로인 것 같고, height가 높이니 (base * height)/2의 값을 area에 넣어주면 될 것 같다.
#include <stdio.h>
int main()
{
int base = 20;
int height = 16;
int area;
area = (base * height) / 2;
printf("%d\n", area);
return 0;
}
base * height / 2로 해주면 혹시나 순서가 잘못되어 잘못된 값이 나올까봐 base * height 부분을 ()로 감싸서 작성했다.
뭔가 위쪽에 define으로 여러 코드가 작성되어 있다. 문제의 목적은 원의 지름이 입력되면 그 지름을 토대로 원의 넓이를 변수 area로 출력하는 것이 목적이다. 원의 넓이를 구하는 식이 내가 알기로 반지름 * 반지름 * 원주율(파이)로 기억한다. 따라서 입력된 지름을 /2해서 반지름을 구하고 반지름 * 반지름을 한 후 주어진 원주율 M_PI를 곱해주면 될 것 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
int main()
{
float diameter;
float radius;
float area;
scanf("%f", &diameter);
radius = diameter / 2;
area = radius * radius * M_PI;
printf("%f\n", area);
return 0;
}
지름의 길이가 입력된 diameter를 /2 연산을 수행하여 그 값을 반지름 변수인 radius에 넣어줬고, radius * radius * 정의된 파이의 값이 담긴 M_PI를 써주고 * 연산이 수행된 값을 넓이를 나타내는 변수인 area에 넣어서 풀어줬다.
참고로 저 #define은 구글링해보니 매크로 같이 무언가를 정의해줘서 사용해주는 것이라고 한다.
예를들어 위 사진의 2행처럼 #define a 100을 써준다면 a는 100으로 정의되어 코드에서 a를 사용하면 a에 정의된 값 100을 사용하는 것과 다름없게 되는 것이다.
-%-
% 역시 파이썬과 똑같은 기능을 한다. 확실히 c언어가 대부분의 언어가 모티브했다보니 비슷한 면들이 많은 것 같다.
%는 나머지를 구해주는 연산자다. 사용은 다른 연산자와 똑같은 형식으로 하면 된다.
마찬가지로 <변수> = <변수> % <변수2>는 <변수> %= <변수2>로 줄여서 사용할 수 있다.
5, 6행에서 정수형 변수 a와 b를 선언하고 각각 값을 7과 2를 넣어줬다. 그리고 printf 출력문에서 a % b를 써주니 나머지인 1이 출력되는 것을 볼 수 있다. 또한 9행에서 a = a % b를 줄여서 a %= b를 써줬는데, 이 또한 결과가 제대로 출력되는 것을 볼 수 있다.
%연산도 마찬가지지만 0으로 나누면 오류가 뜬다.
-음수의 나머지 연산
음수로 나눴을 때의 나머지의 부호가 애매하게 느껴지는데, 실제로 실습을 해본다면 나머지의 부호는 나누는 수의 부호에 따라 가는 것을 볼 수 있다.
위 사진은 코딩도장 Unit 15.2에 정리되어 있는 C99 표준이다.
식이 나오니 머리 아파지지만 어쨌든 나머지는 나누는 수의 부호를 따라간다.
-fmod, fmodf, fmodl
math.h 헤더파일을 include한다면 함수로도 나머지를 구해줄 수 있다. fmod, fmodf, fmodl이 나머지를 구해주는 함수인데, fmod는 double 형 실수에, fmodf는 float형 실수에, fmodl은 long double 형 실수에 사용한다.
c : %num1; 연산은 수행될 수가 없다.(컴파일 에러 뜬다.)
num1 = num1 % 3의 값이 1이 나오므로 값이 1이 되는 식을 고르면 된다.
b : 25 % 12 = 3 O
답 : b
암산이나 계산기를 통해서 답을 구할 수도 있지만, c언어를 배우는 입장이므로 코드를 쳐서 풀었다.
답 : d
num1, num2를 num3으로 나눴을 때 각각 나머지가 0이 되야한다. num1, num2에 할당된 값인 15, 27의 공배수를 써주면 될 것 같으니 num3에 최소 공배수인 3을 넣어주면 될 것 같다.
#include <stdio.h>
int main()
{
int num1 = 15;
int num2 = 27;
int num3 = 3;
num1 %= num3;
num2 %= num3;
printf("%d\n", num1);
printf("%d\n", num2);
return 0;
}
int num3 = 3;으로 작성해서 풀었다.
표준 입력으로 만 단위의 정수가 입력되면 각 자릿수의 값을 역순으로 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int value = 0;
scanf("%d", &value);
printf("%d %d %d %d %d", value % 10, (value % 100) / 10 , (value % 1000) / 100, (value % 10000) / 1000, value / 10000);
}
1의 자리는 입력 값을 10으로 나눴을 때의 나머지, 10의 자리는 입력 값을 100으로 나눴을 때의 나머지 / 10, 100의 자리는 입력 값을 1000으로 나눴을 때 나머지 / 100, 1000의 자리는 입력 값을 10000으로 나눴을 때 / 1000, 10000의 자리는 /10000를 해줘서 풀었다.
-자료형의 확장과 축소-
지금까지는 정수, 실수 나눠서 연산을 수행했는데, 만약 서로 다른 자료형끼리 연산을 한다면, 자료형 확장, 축소 현상이 일어난다.
-자료형 확장
정수와 실수를 함께 연산한다면 결과 값이 실수로 나온다. 이 이유는 실수가 정수보다 표현 범위가 넓기 때문이다.
위 사진처럼 결과가 실수로 나오는 것을 볼 수 있다.
c언어에서 자료형을 섞어서 연산한다면 컴파일러에서 암시적 형 변환을 하게 되는데, 이 때 자료형의 크기가 큰 쪽, 표현범위가 넓은 쪽으로 자동 변환이된다. 이를 형 확장이라한다.
다른 크기의 정수 자료형에서도 적용된다. int형 변수 a, long long형 변수 b를 연산한다면, 연산 결과는 long long 형이 되는 것을 볼 수 있다.
-자료형 축소
자료형 확장과 다르게, 계산 결과의 자료형을 정해준다면 그 자료형을 기준으로 값이 저장된다. 위처럼 int형 a와 long long형 b를 연산했지만 연산 결과를 int형인 a에 저장하니 int형의 값 범위에 맞춰서 연산되고 나머지는 버려지는 것을 볼 수 있다.
이처럼 크기가 작은쪽, 표현 범위가 좁은 쪽으로 변환되는 것을 형 축소라고 한다.
char 형도 마찬가지로 연산 결과를 char형에 저장하면 10000000002에서 2만 남게되어 28+3 연산이 수행되게 된다.
위 사진은 위 코드 예제에 해당되는 코딩 도장의 설명 사진이다. 왜 28 + 2가되냐면, char는 1바이트까지 저장이 가능하므로 int 값에서 1바이트만 가져오고 나머진 버려서 연산을 수행하는 것이다.
d : int형과 float형을 연산하면 범위가 더 넓은 float형으로 계산 결과가 나오므로 형 확장이다.
int와 float의 연산인데, 결과 값을 int형으로 저장하므로 원래 결과인 17.8에서 0.8을 때어낸 17이 결과 값이 된다.
답 : 17
문제를 처음 봤을 때는 좀 황당했다. 그냥 char형으로 num2를 선언하면 끝인 간단한 문제인데, 왜 형 확장, 축소의 연습문제로 나오는지를 모르겠지만, 생각해보니 형 확장으로도 풀 수 있을 것 같다. char보다 더 넓은 범위의 값을 저장할 수 있는 정수 자료형으로 선언하면 될 것 같다.
#include <stdio.h>
int main()
{
char c1 = 'a';
int num2 = c1;
printf("%c\n", num2);
return 0;
}
char보다 더 넓은 범위를 가지는 정수 자료형인 int로 num2를 선언했다.
실수형 값이 float형으로 입력이 되는데, 입력 값의 소수점을 버려서 출력하는 것이 목적이다. float에서 int로 형 축소가 된다면 소수점이 버려진다는 점을 이용하면 될 것 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
float num1;
scanf("%f", &num1);
int a = num1;
printf("%d", a);
return 0;
}
int형 변수 a를 선언해서 초기 값으로 float 형인 num1을 넣어주면, num1의 소수점을 버린 상태의 값을 a에 저장한다. 소수점이 버려진 입력 값이 들어간 a를 출력하도록 printf를 작성해서 풀었다.
-if-
if문은 파이썬과 똑같이 특정 조건이 참일 때 특정 코드를 실행해주는 역할을 한다.
파이썬과 달리 조건식은 ()로 묶어줘야하며 if문 내의 코드는 들여쓰기가 아닌 { }로 감싸줘야한다. 또한 처음 프로그래밍을 접할 때 자주했던 실수인데, if문 조건식에는 ;를 써주면 안된다.
if(<조건식>)
{
<참이면 실행할 코드>
}
위처럼 사용하면 된다.
만약 if문의 조건식이 참일 때 실행할 코드가 한 줄이라면 { } 없이
if(<조건식>)
<참이면 실행할 코드>
이렇게 써줄 수 있다.
두 줄 이상일 때
if(<조건식>)
<참이면 실행할 코드 1>
<참이면 실행할 코드 2>
이렇게 써주면 컴파일러가
if(<조건식>)
{
<참이면 실행할 코드 1>
}
<참이면 실행할 코드 2>
이렇게 인식하니 한 줄일 경우에만 써줘야한다.
-==
==은 앞의 값과 뒤의 값이 서로 같은지 판단해, 참과 거짓을 결정하는 연산기호로 파이썬의 ==와 같은 기능을 한다.
<값> == <값2> 이런식으로 사용하면 된다.
if문에 == 조건을 넣어본 모습이다. a == 1로 조건을 작성했는데, 앞서 선언한 a의 값이 1이 맞으므로 a == 1 식은 참이 되어 if문 안의 코드인 printf("1");이 실행돼 1이 출력 된 것이다.
위는 {}를 생략하고 if문을 쓴 것이다. 코드가 printf("1"); 이거 한 줄 밖에 없으므로 이렇게 {}를 생략하고 사용할 수 있다.
위처럼 실수형, 문자형 또한 ==으로 참과 거짓을 판별할 수 있다. char의 경우 아스키 코드 값과 문자를 비교할 수도 있다.
if, ==, scanf를 응용한다면 위 코드처럼 사용자의 입력을 받고, 해당 값에 맞는 문자를 출력시키도록 작성할 수도 있다.
입력 값이 1일 경우 9행의 코드를 실행하고 입력 값이 2일 경우 11행의 코드를, 입력 값이 3일 경우 13행의 코드를, 입력 값이 4일 경우 15행의 코드를 실행한다.
if 조건문으로 num1의 값이 10과 같을 때 문자열을 출력하려면
if(num1 == 10)
{
printf("<문자열>");
} 또는
if(num1 == 10)
printf("<문자열>");
이렇게 작성하면 된다.
답 : e
c1에 저장된 값이 소문자 a인지 검사하는 if 조건문은 if(c1 == 'a') 또는 if(c1 == 97)로 작성하면 된다.
답 : a, c
num1의 값이 10과 같을 때 문자열을 출력하는 if문은
if(num1 == 10)
{
printf("<문자열>");
} 또는
if(num1 == 10)
printf("<문자열>");
이렇게 작성하면 된다.
답 : b, d
if문안의 printf("k입니다.\n");를 실행시키기 위해 if문에 c1에 관련되어 참이되는 적절한 조건식을 써주는 것이 목적이다.
c1에 값이 'k'가 들어가 있으므로 c1 == 'k' 또는 c1 == <k의 아스키 코드 값> 이렇게 써주면 될 것 같다.
#include <stdio.h>
int main()
{
char c1 = 'k';
if (c1 == 'k')
{
printf("k입니다.\n");
}
return 0;
}
if 조건식에 c1 == 'k'를 써줘서 printf("k입니다.\n");가 실행되도록 했다.
나이가 입력되는데, 해당 나이가 18 아래라면 "청소년 관람 불가"를 출력하도록 하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int age;
scanf("%d", &age);
if (age < 18)
printf("청소년 관람 불가");
return 0;
}
<, >에 대해 17 챕터에서 다루지 않았던 것 같지만 문제가 이렇게 나와서 일단 풀었다.
미만인지를 판단하는 연산 기호인 <를 써서 나이가 18 미만인지 if문으로 체크하고 미만이라면 청소년 관람 불가가 출력되도록 printf를 작성했다.
혹시나 <, >에 대해 나왔지만 정리를 빼먹은 것일 수도 있으므로 정리를 하겠다.
>는 왼쪽 값이 오른쪽 값보다 크다면 참, 작다면 거짓이다.
<는 왼쪽 값이 오른쪽 값보다 작다면 참, 크다면 거짓이다.
>=는 왼쪽 값이 오른쪽 값과 같거나 크다면 참, 작다면 거짓이다.
<=는 왼쪽 값이 오른쪽 값과 같거나 작다면 참, 크다면 거짓이다.
-else-
c언어의 else는 파이썬에서의 else와 마찬가지로 if문의 조건이 거짓일 경우 특정 코드를 실행해주는 역할을 한다. if와 마찬가지로 else의 코드는 { }로 감싸주지만, else에는 조건식을 써주지 않는다.(조건에 만족하지 않을 경우 실행하기 때문에) 당연하게도 단독 사용은 불가능하고, 반드시 if문이 위에 있어야한다.
if(조건식)
{
<조건이 참일 시 실행할 코드>
}
else
{
<위의 조건이 참이 아닐 시 실행할 코드>
}
이런식으로 사용하면 된다. else도 ;를 붙여주면 안된다. 만약 붙여준다면
if(조건식)
{
<조건이 참일 시 실행할 코드>
}
else
{
}
<위의 조건이 참이 아닐 시 실행할 코드>
컴파일러가 이런식으로 인식해서 조건이 참이든 거짓이든 else 아래 코드는 무조건 실행하게 된다.
또한 else의 코드가 한 줄일 경우
else
<위의 조건이 참이 아닐 시 실행할 코드>
이런식으로 { }를 생략하고 작성할 수 있다.
위는 a의 값이 9가 맞을시 "9"를 출력하고, 아닐 경우 "9가 아님"을 출력하는 간단한 코드다. a의 값이 10이므로 a == 9 조건식은 거짓이 되므로 if 내의 코드는 실행되지 않고, 대신 else의 코드가 실행된다. 따라서 결과는 "9가 아님"이 출력됐다.
-if 조건문의 동작 방식-
파이썬과 똑같이 c언어에서의 if는 0만 거짓으로 인식하고 0이 아닌 다른 수들은 참으로 인식한다.
위 사진들을 보면 1은 참으로, 0은 거짓으로 인식함을 알 수 있다.
앞서 if(a = 10) 이런식으로 조건에 =을 써주면 안된다 정리했었는데, 이렇게 작성한 경우
if(a = 10) -> if(a) -> if(10) 즉 0을 넣어주지 않는 이상 무조건 참이 되게 되므로, 조건식을 쓰는 의미가 사라진다.
가끔 stackoverflow 같은 개발 관련 커뮤니티에서 알고리즘을 보면 if(10 == a) 같이 값과 변수를 거꾸로 쓴 조건식이 보였다. 처음에는 그냥 이것도 취향이라 생각했는데, 코딩도장을 보니 실수를 방지하는 코드라는 것을 알게 됐다.
그 까닭은 if(a = 10) 이렇게 적어주면 컴파일러가 오류없이 넘겨주지만, if(10 = a) 같이 써주면 10이 a의 변수 값이 될 수 없으므로 오류를 발생시킨다. 따라서 실수를 캐치하기 좋기 때문에 10 == a 이런식으로 조건식을 써준 것이었다.
-중첩 if문-
파이썬과 마찬가지로 c언어 역시 if문을 중첩해서 작성할 수 있다.
위는 a가 1이고 b가 0인지를 검사하는 중첩 if문이다. 맨처음 if(a==1) 코드로 a가 1인지 검사하고 만약 거짓이라면 "a는 1이 아닙니다."를 출력한다. 만약 1이 맞다면 그 다음 if문 b == 0을 체크해서 b가 0이라면 "a는 1, b는 0입니다!"를 출력, 아니라면 "a는 1이지만 b는 0이 아닙니다."를 출력한다.
-&&, ||-
&&, ||은 논리 연산자다. 각각 and, or를 나타내는데, 이는 파이썬에서의 and와 or의 기능과 같다.
파이썬에서 조건식을 여러 개 지정할 때 사용했던 and, or와 다르게 c언어에서는 &&, ||를 사용해서 조건식을 여러 개 사용한다.
<조건식 A> && <조건식 B> : A와 B의 조건식이 모든 참(true)이라면 참(true), 둘중 하나라도 거짓(false)이라면 거짓(false).
<조건식 A> || <조건식 B> : A와 B의 조건식중 하나만 참(true)라면 참, 둘다 거짓(false)이라면 거짓(false).
사실 ||는 코딩도장 Unit 18.5에서 다루진 않았지만, 겸사겸사 파이썬과 비교할 겸 미리 정리했다.
&&의 결과를 확인하기 위해 if문을 2개 썻다.
첫 번째 if문은 a == 1 && b == 0인데 a가 1이고 b가 0이면 true가 되는 것이다. a와 b가 각각 1과 0이므로 참이되어 true가 출력됐다.
두 번째 if문은 a == 0 && b == 0이다. a, b 둘다 0이면 true가 되는 것이다. b는 0이 맞지만 a는 0이 아니기에 else의 코드가 실행되어 false가 출력됐다.
||의 결과를 확인하기 위해 2개의 if문을 작성했다.
첫 번째 if문은 a가 1이거나 b가 0이면 true인데, 두 식 모두 true이므로 true가 출력된다. 둘 중 하나가 거짓이라도 다른 하나가 참이면 무조건 true를 출력한다.
두 번째 if문은 a가 0이거나 b가 1이면 true인데, 두 식 모두 false이므로 false가 출력된다. 둘 중 하나라도 참이 된다면, true가 출력될 것이다.
a : if의 코드는 조건식이 만족할 때 실행된다. X
b : else의 코드는 앞의 조건식들이 거짓이면 실행된다. O
c : else는 단독으로 사용할 수 없다. X
d : else의 코드가 1줄인 경우 {}를 생략할 수 있다. X
e : if는 단독으로 쓰일 수 있다. X
답 : b
e : else뒤에 ;를 붙여주면 아래 코드가 조건의 참, 거짓 여부에 상관 없이 무조건 실행되게 된다.
num1은 0이다. 다른 연산자 없이 num1만 써줄 경우 해당 값이 0이냐 0이 아니냐에 따라 참, 거짓이 가려지는데, 0일 경우 거짓이므로, else문이 실행되서 "거짓"이 출력된다.
답 : 거짓
조건식을 여러 개 지정하는 방법은 &&, || 같은 논리 연산자를 써주거나 중첩으로 if문을 작성하면 된다.
답 : c, e
num1은 4가 들어가고, num1 % 2 == 0, 즉 num1을 2로 나눴을 때 나머지가 0이라면 "짝수\n"을 출력하고 아니라면 "홀수\n"을 출력한다. 4는 2로 나눴을 때, 나머지가 0이므로 "짝수\n"가 출력된다.
답 : b
if(num1)이 if 조건식으로 주어져 있고, 이 조건식이 거짓일시 "거짓"을 출력해준다. 문제의 목적이 거짓을 출력시키는 것이므로, 주어진 num1의 값을 거짓이되도록 바꾸면된다. 정수형에서 거짓이 되는 값은 0이므로 0으로 초기화해주면 될 것 같다.
#include <stdio.h>
int main()
{
unsigned long long num1 = 0;
if (num1)
printf("참\n");
else
printf("거짓\n");
return 0;
}
필기 시험 점수가 80점 이상이면서 토익 점수가 850점 이상이면 합격을 출력하고, 아니라면 불합격을 출력하는 것이 목적이다. 앞서 배운 논리 연산자인 &&을 적절히 활요하면 두 조건 모두 만족할 때 합격을 출력할 수 있을 것이다.
#include <stdio.h>
int main()
{
int writtenTest = 78;
int toeic = 870;
if (writtenTest >= 80 && toeic >= 850)
printf("합격\n");
else
printf("불합격\n");
return 0;
}
필기 시험 점수인 writtenTest >= 80의 조건과 &&을 써줘서 toeic >= 850까지 두 조건을 모두 만족하다면 합격이 출력되고 아니라면 불합격이 출력되도록 작성했다.
입력된 문자가 a면 "a입니다."를 출력, 아니라면 "a가 아닙니다."를 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char a;
scanf("%c", &a);
if (a == 'a')
printf("a입니다.");
else
printf("a가 아닙니다.");
return 0;
}
입력 값을 받은 char형 변수 a를 선언하고 scanf 함수로 입력된 문자를 a에 넣어줬다. 그리고 if 문으로 a == 'a'가 참이라면 "a입니다."를 출력, 아니라면 "a가 아닙니다."를 출력하도록 작성했다.
국어, 영어, 수학, 과학 점수가 입력되는데, 이 값들의 평균이 85점이면 합격을 출력, 아니라면 불합격을 출력하는 것이 목적이다. 단 점수가 0~100 범위를 벗어날 시 "잘못된 점수"를 출력해야한다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int kor, eng, math, scien;
scanf("%d %d %d %d", &kor, &eng, &math, &scien);
if (kor >= 0 && 100 >= kor && eng >= 0 && 100 >= eng && math >= 0 && 100 >= math && scien >= 0 && 100 >= scien)
{
if ((kor + eng + math + scien) / 4 >= 85)
printf("합격");
else
printf("불합격");
}
else
printf("잘못된 점수");
return 0;
}
먼저 네 과목의 점수를 담을 변수 kor, eng, math, scien을 선언하고 scanf로 각 변수에 입력 값을 넣어줬다. 합격, 불합격, 잘못된 점수 여부는 중첩 if문을 통해 판별하도록했다. 먼저 각 변수의 값이 0~100 사이가 아니면 "잘못된 점수"를 출력시켜야 하므로, <변수> >= 0 && 100 >= <변수> 이렇게 각 변수가 모두 0~100 사이인지 검사해줬고 만약 모든 변수가 0~100사이라면 평균이 85가 넘는지 확인, 만약 하나라도 0~100 범위를 벗어난다면 "잘못된 점수"를 출력해주도록 작성했다.
모든 변수가 0~100 범위 안이라면 2번째 if문으로 가는데, 2번째 if문에서는 kor, eng, math, scien을 모두 더하고 4로 나눠서 평균을 구한 후 그 평균이 85 이상이라면 "합격" 미만이라면 "불합격"이 출력되도록 작성했다.
-else if-
else if는 파이썬의 elif와 같은 역할을 한다. if문의 조건이 거짓일시 -> else if의 조건 참, 거짓 확인 -> if, else if의 조건식 모두 거짓일 시 else의 코드 실행. else if문은 if문과 형식이 비슷하다. 또한 if와 else는 한 번만 사용할 수 있지만 else if는 여러 번 사용이 가능하다.
if(<조건식>)
{
<위 조건식이 참일 시 실행할 코드>
}
else if(<조건식>)
{
<위 조건식이 참일 시 실행할 코드>
}
이렇게 사용한다.
else와 마찬가지로 else if 단독으로 사용이 불가능하고 else if의 코드가 한 줄일 경우에는 { }를 생략할 수 있다.
위는 a의 값에 따라 출력이 달라지는 조건문이다. 먼저 a가 0이라면 a = 0을 출력하고 만약 a가 0이 아니라면 그 밑의 else if문의 조건인 a == 1을 검사한다. 만약 참이라면 a = 1을 출력, 아니라면 그 밑의 else if문의 조건 a == 2를 검사하고 맞으면 a = 2를 출력 아니라면 else의 코드가 실행되서 a는 0,1,2가 아닙니다.를 출력한다.
if와 else if, else를 같이 쓸 경우 if, else if문의 조건이 모두 거짓일 시에만 else의 코드가 실행된다. 따라서 else는 조건문의 가장 마지막 줄에 위치해야한다.
a : else는 여러 번 사용할 수 없다. X
b : else if는 여러 번 사용할 수 있다. O
c : else if에는 반드시 조건식을 지정해야 한다. O
d : else는 위의 조건들이 모두 거짓일 경우 실행되므로 if, else if의 뒤에 존재해야한다. X
e : else if는 단독으로 사용할 수 없다. if문과 같이 쓰여야 한다. O
e : else if에는 반드시 조건식이 있어야 한다. X
c를 출력하는 것이 목적이다. 보면 조건식으로 출력문들이 작성되어 있는데, c를 출력하는 경우는 두 번째 else if문이다. 조건은 c1 == 'c'로 c1의 값이 'c'라면 c를 출력하는 것이다. 따라서 c1의 값으로 'c'를 주거나 'c'에 해당하는 아스키 코드 값을 준다면 될 것 같다.
#include <stdio.h>
int main()
{
char c1 = 'c';
if (c1 == 'a')
printf("a\n");
else if (c1 == 'b')
printf("b\n");
else if (c1 == 'c')
printf("c\n");
else if (c1 == 'd')
printf("d\n");
else
printf("x\n");
return 0;
}
c1에 'c'를 할당해 줘서 c를 출력하는 조건식이 true가 되게끔 했다.
나이가 입력되는데, 이 나이에 맞는 요금을 교통 카드의 잔액에서 차감한 후 차감한 잔액을 출력되게 하는 것이 목적이다. if, else if, else를 적절히 사용해서 입력된 나이가 어린이, 청소년, 어른 중 어디에 해당하는지 판별하면 될 것 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int balance = 10000; // 교통카드 잔액
int age;
scanf("%d", &age);
int price = 0;
if (age >= 7 && age <= 12)
price = 450;
else if (age >= 13 && age <= 18)
price = 720;
else
price = 1200;
balance -= price;
printf("%d\n", balance);
return 0;
}
먼저 int형 price 변수를 선언해줬다. 나이에 따른 가격이 이 price에 저장되게 할 것이고, 맨 마지막에 잔액에서 이 price를 빼줄 것이다. 그 다음 age >= 7 && age <= 12, 즉 입력된 나이가 7 ~ 12 사이라면 price에 450을 할당해주고, age >= 13 && age <= 18, 즉 입력된 나이가 13~18 사이라면 price에 청소년 가격인 720을 할당해준다. 만약 7~12도 아니고, 13~18도 아니라면 19 이상인 경우 밖에 없으므로, else문을 써줘서 price의 값을 어른 가격인 1200으로 할당한다.
이 조건문을 거친 후 마지막에 잔액에 해당되는 변수인 balance -= price를 해준다.
02-18 (Unit 20.0 ~ Unit 24.7)
-c언어 비교 연산자-
비교 연산자는 c언어에서 값을 비교할 때 사용하는 연산자다. 비교 연산자로는 ==, >=, <=, !=, >, <이 있다. 이 연산자들을 파이썬에서도 있었는데, 기능은 똑같다.
a == b : a와 b가 같은지 확인
a != b : a와 b가 다른지 확인
a > b : a가 b보다 큰지 확인
a < b : a가 b보다 작은지 확인
a >= b : a가 b와 같거나 큰지 확인
a <= b : a가 b와 같거나 작은지 확인
비교 연산자들은 지금까지 if문에서 주로 사용했지만 while, for 등의 반복문의 조건식으로도 사용된다.
이 비교 연산자들은 비교 했을 때 참이라면 1을, 거짓이라면 0이 나온다.
int형 변수 a에 10을 넣고 비교 연산자들을 사용해 10과 비교해봤다.
첫 번째 a == 10, a는 10과 같은므로 1이 출력된다.
두 번째 a >= 10, a는 10보다 크진 않지만 같으므로 1이 출력된다.
세 번째 a <= 10, a는 10보다 작진 않지만 같으므로 1이 출력된다.
네 번째 a > 10, a는 10보다 크지 않으므로 0이 출력된다.
다섯 번째 a < 10, a는 10보다 작지 않으므로 0이 출력된다.
여섯 번째 a != 10, a는 10과 같으므로 0이 출력된다.
이렇게 if문과 같이 쓸 수도 있다. 당연하지만 실수나 문자 또한 비교 연산자를 통해 비교할 수 있다. 문자 같은 경우 아스키 값을 통해서 비교한다.
다만 실수는 반올림 오차가 발생하기 때문에 == 연산자로 정확한 값을 비교하는건 위험하다고 한다.
-삼항 연산자-
삼항 연산자는 연산에 필요한 값이 세 개인 연산자를 말한다. 단항 연산자, 이항 연산자도 있는데 이는 각각 연산에 필요한 값이 1개, 2개인 것이다.
단항 연산자의 예 : ++, -- 연산자(값이 한 개만 필요함)
이항 연산자의 예 : +, +=, -=, =, == 등 (값이 두 개 필요함)
삼항 연산자로는 ? :이 있다. 파이썬의 한 줄 if문과 비슷한 것인데
<조건식> ? <값1> : <값2>
이렇게 작성하면 된다. 이렇게 작성했을 때 조건식이 참이라면 <값1>이 반환(?)되고, 거짓이라면 <값2>가 반환되는 것이다.
<변수> = <조건식> ? <값1> : <값2>
이런식으로 변수에 할당하도록 작성하면 조건식이 참일 시 값1을 <변수>에 넣어주고 거짓일 시 값2를 변수에 할당해주는 것이다.
if문으로 쓴다면
int a = 0
if(a==0)
b = 10;
else
b = 20;
이런식으로 될 것이다. 여기서 a는 조건식에 사용할 변수, b는 조건에 따라서 값이 할당될 변수다.
위 사진처럼 ? :를 이용한다면 if문으로 길게 풀어써야할 코드도 이렇게 간단히 작성할 수 있다.
위 코드는 a가 0일시 "a는 0입니다."를 출력, 0이 아닐 시 "a는 0이 아닙니다."를 출력한다.
이를 if 조건문으로 사용한다면
int a = 0;
if(a == 0)
printf("a는 0입니다.");
else
printf("a는 0이 아닙니다.);
이렇게 길게 써야할 것이다.
위 코드에서는 a가 0이기 때문에 "a는 0입니다."를 서식 지정자 %s에 넣어줘 "a는 0입니다."를 출력한다.
조건식 부분을 괄호로 감싸준다면 좀 더 가독성 있는 코드가 될 수 있다. 위는 a가 0이면 10을, a가 0이 아니라면 20을 tmp 변수에 할당해주는 코드다. a는 0이므로 tmp에는 10이 들어갔다.
위 코드에서 a는 0이므로 당연히 tmp는 10이 할당됐다.
이 삼항 연산자는 긴 코드를 간결히 줄여쓸 수 있지만 축약 형식이라 가독성을 해칠 수 있다. 또한 한 줄에 조건식, 결과 값이 모여 있어서 디버깅하는데 어려움도 생긴다. 따라서 가독성을 해치지 않으면서 코드가 간결해지는 경우에 사용하는 것이 좋다.
코드를 암호처럼 복잡하게 만드는 것은 실력이 아니다. 누구나 알아볼 수 있는 코드를 작성하는 것이 진짜 실력이다.
c : 작거나 같다다. X
d : 다르다다. X
num2는 ? : 연산자를 통해 값을 할당 받는다. 조건식은 num1 하나만 있으므로 num1의 값으로 true, false를 가르는 건데, num1에는 false를 의미하는 값 0이 있으므로 조건식은 거짓이 된다. 따라서 num2에는 거짓일 때의 값인 7이 들어간다.
답 : c
a : 이항 연산자인데 값이 하나다. X
b : 이항 연산자인데 값이 하나다. X
c : 파이썬과 달리 c언어는 조건식을 ()로 감싸줘야한다. X
d : 올바르게 사용했다. O
e : =은 비교 연산자가 아니다. X
c : 참과 거짓에 해당하는 값들은 :로 나눠줘야한다. X
d : 조건식 뒤에는 ?를, 참과 거짓에 해당하는 값 사이에는 :를 써줘야한다. X
세 부분의 빈칸에 적절한 비교 연산자를 넣어서 모두 1을 출력하도록 하는 것이 목적이다.
#include <stdio.h>
int main()
{
int num1 = 27;
printf("%d\n", num1 > 10);
printf("%d\n", num1 != 5);
printf("%d\n", num1 >= 27);
printf("%d\n", num1 == 27);
printf("%d\n", num1 < 30);
printf("%d\n", num1 <= 27);
return 0;
}
1번 칸에는 10과 num1을 비교하므로 참이 되게끔 >를 넣어줬다.
2번 칸에는 27과 num1을 비교하는데, 서로 같은 값이므로 ==를 넣어줬다.
3번 칸에는 30과 num1을 비교하는데, 30보다 num1이 작으므로 <를 넣어줬다.
삼항 연산자를 사용하여 4.0f가 출력되게끔 하는 것이 목적이다. 첫 번째 칸은 거짓이 되는 비교 연산자, 두 번째 칸은 ?, 세 번째 칸은 :를 넣어주면 될 것 같다.
#include <stdio.h>
int main()
{
float num1 = 1.2f;
float num2;
printf("%f\n", num1 > 2.0f ? 3.0f : 4.0f);
return 0;
}
비교 연산자는 >를 넣어서 num1 > 2.0f가 거짓이 되도록 했고 그 뒤에는 삼항 연산자이므로 ?를 넣었고, 삼항 연산자는 참과 거짓일 때의 값을 :로 구분하므로 세 번째에는 :를 넣어줬다.
문자가 입력되는데, 첫 줄에는 입력 된 문자가 k와 다르면 참, 같으면 거짓을 출력. 두 번째 줄에는 h의 아스키 값보다 크면 참, 작거나 같으면 거짓을 출력한다. 세 번째 줄에는 o의 아스키 값보다 작거나 같으면 참, 크면 거짓을 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char a;
scanf("%c", &a);
printf("%s\n", (a != 'k') ? "참" : "거짓");
printf("%s\n", (a > 'h') ? "참" : "거짓");
printf("%s\n", (a <= 'o') ? "참" : "거짓");
return 0;
}
먼저 입력 된 문자를 담을 char형 변수 a를 선언했다. 그 다음 입력된 문자를 a로 받아오고 삼항 연산자를 써서 참, 거짓을 출력하도록 했다.
첫 번째 printf는 a != 'k', 즉 입력된 값이 k와 같지 않다면 "참", 같다면 "거짓"이 출력된다.
두 번째 printf는 a > 'h', 즉 입력된 값이 'h'의 아스키 코드보다 크다면 "참", 작거나 같으면 "거짓"이 출력된다.
세 번째 printf는 a <= 'o', 즉 입력된 값이 'o'의 아스키 코드보다 작거나 같으면 "참", 크면 "거짓"이 출력된다.
빈칸에 삼항 연산자를 넣어 입력 된 값이 들어간 num1이 7과 다르다면 1을 출력, 같다면 2를 출력하도록 하면 된다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num1;
scanf("%d", &num1);
printf("%d\n", (num1 != 7) ? 1 : 2);
return 0;
}
num1 != 7 ? 1 : 2로 문제를 풀었다. num1이 7과 같지 않다면 1을, 같다면 2를 출력하는 삼항 연산자다.
-논리 연산자-
앞서 배운 &&, ||과 같은 논리 연산자는 조건식이나 값을 논리적으로 판단해준다. 위에서 사용했던 것처럼 주로 if 조건식에서 사용한다.
a && b : a와 b가 모두 참일 때 참, 나머지는 거짓
a || b : a, b중 하나 이상 참이면 참, 나머지는 거짓
a! : a가 참이면 거짓, 거짓이라면 참.
&&, ||은 앞서 정리했지만 복습겸으로 한번 더 정리했다. !는 파이썬의 논리연산자 not과 같다. 참이면 거짓, 거짓이라면 참을 반환하는 것이다.
1, 2번째 printf문은 &&을 사용했다. 보면 둘다 참(1)일 때는 1이 출력되지만, 둘 중 하나라도 거짓이면 0이 출력됨을 알 수 있다.
3, 4번째 printf문은 ||을 사용했다. 보면 참이 하나 이상이면 1이 출력되지만, 둘 다 거짓(0)이면 0이 출력됨을 알 수 있다.
5, 6번째 printf문은 !을 사용했다. 보면 거짓일 때는 1, 참일 때는 0이 출력됨을 알 수 있다.
위처럼 사진처럼 조건식에서도 사용가능하다. 첫 번째 printf는 a > 9, a< 11 모두 만족하니 참, 두 번째는 a > 10, a < 11 둘 중 하나가 참이니 참. 세 번째 printf는 a > 10이 거짓이지만 not 연산이므로 참.
첫 번째 조건문은 a == 10, a % 2 == 0 모두 만족하니 참. 두 번째 조건문은 a != 10 || a % 2 == 0 둘 중 하나 만족하니 참, 세 번째 조건문은 a != 10이 거짓이지만 not 연산이므로 참.
a > 9 && a < 11 같이 조건을 여러 개 써줄 때는 조건 하나씩 ()로 감싸주면 가독성이 좋아진다.
예) (a > 9) && (a < 11)
논리 연산자는 기호만 다른거 빼면 작동은 파이썬과 c언어 둘다 동일한거 같다. 파이썬과 같이 단락평가도 적용된다. 만약 a && b 연산시 a가 거짓이라면 두 번째 조건은 검사하지 않는다.
위와 같은 코드가 있을 때 a를 b로 나누니 컴파일 오류가 뜰 것 같지만 단락 평가에 인해서, b != 0을 만족하지 않다면 두 번째 조건인 a % b == 0을 검사하지 않기 때문에 컴파일 오류가 뜨지 않는다. 신기하다.
삼항 연산자에서도 또한 논리 연산자를 사용할 수 있다. 위는 논리 연산자 &&으로 삼항 연산자의 조건식을 세운 모습이다. a != b && a > 8을 적었는데 a가 b와 같지 않고 8보다 크다면 true를 출력, 둘 중 하나라도 아니라면 false를 출력한다.
a : 1 && 1의 결과는 1이다. X
b : 0 && 0의 결과는 0이다. O
c : 0 && 1의 결과는 1이다. X
d : 1 && 0의 결과는 0이다. O
e : 5 && 9의 결과는 1이다. O
a : 1 || 0의 결과는 1이다. O
b : 1 || 1의 결과는 1이다. X
c : 1 || 1의 결과는 1이다. O
d : 0 || 1의 결과는 1이다. X
e : 6 || 0의 결과는 1이다. O
논릿값의 결과를 뒤집는 연산자는 not으로 c언어에서는 !이다.
답 : d
첫 번째 값만으로 결과가 확실하여 두 번째 값을 검사하지 것은 단락 평가를 의미하는데, &&에서는 첫 번째 값이 거짓일 때, ||에서는 첫 번째 값이 참일 때가 해당된다.
답 : b, c, e
논리 연산자로 주어진 칸을 채워서 모두 참이 출력되게 하는 것이 목적이다.
#include <stdio.h>
int main()
{
int num1 = 10;
int num2 = 0;
if (num1 && num1)
printf("참\n");
else
printf("거짓\n");
if (num1 || num2)
printf("참\n");
else
printf("거짓\n");
printf("%s\n", !num2 ? "참" : "거짓");
return 0;
}
맨 처음 if문은 num1과 num1을 비교하는 것이므로 && 또는 ||을 써주면 참이 출력된다. 두 번째 if문은 num1, num2를 비교한다. num1은 참이지만 num2는 거짓이므로 ||로 둘 중 하나라도 참이면 참을 출력하도록 작성했다. printf문은 삼항 연산자다. !가 주어졌으므로 num2를 넣어줘 참이 되도록 했다.
두 정수가 입력되는데 주어진 조건대로 두 정수를 검사하여 결과를 출력하는 것이 목적이다.
- 두 정수를 AND 연산했을 때 참이면 "참", 거짓이면 "거짓"
- 두 정수를 OR 연산했을 때 참이면 "참", 거짓이면 "거짓"
- 첫번째 정수를 NOT 연산했을 때 참이면"참", 거짓이면 "거짓"
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int a = 0, b = 0;
scanf("%d %d", &a, &b);
printf("%s\n", a && b ? "참" : "거짓");
printf("%s\n", a || b ? "참" : "거짓");
printf("%s", !a ? "참" : "거짓");
return 0;
}
삼항 연산자 ? :을 이용해서 풀었다. 먼저 입력 값을 담을 변수 a, b를 선언하고 scanf로 입력 값을 담았다. 그리고 맨 처음 printf는 첫 번째 조건인 a && b, And 연산. 두 번째 printf는 a ||b, or 연산. 세 번째 printf는 !a, 첫 번째 정수의 not 연산을 하도록 작성했다.
-bool-
c언어에서 0을 거짓, 1을 참으로 사용했지만 stdbool.h 헤더 파일을 include하면 bool 자료형을 사용할 수 있다.
이 bool 자료형은 파이썬과 똑같이 참과 거짓을 나타내주는 자료형이다. 다만 파이썬과 다르게 참은 true, 거짓을 false로 쓰인다.
참 : 파이썬 - True, C언어 - true
거짓 : 파이썬 - False, C언어 - false
위처럼 stdbool.h를 include하면 bool과 false, true를 사용할 수 있다. 위 코드는 삼항 연산자로 a가 true라면 "true" 아니라면 "false"를 출력해준다.
위처럼 if문 조건식에도 사용할 수 있으며 논리 연산자와도 함께 사용할 수 있는 것을 볼 수 있다. 또한 비교 연산자 없이 a, b만 써줘도 if (1) if(0), 이런식으로 되서 결과가 잘 나오는 것을 볼 수 있다. 참고로 true와 false는 각각 1과 0의 값을 갖는다.
위처럼 삼항 연산자에도 역시 쓰일 수 있다. 또한 bool형 변수를 %d 서식 지정자로 출력하면 true : 1, false : 0으로 출력됨을 알 수 있다.
이 bool형의 크기는 sizeof를 사용해서 확인하면 1인 것을 알 수 있다. 크기가 작은 이유는 0과 1, 즉 true와 false만 표현하기 때문이다.
bool, true, false가 정의된 헤더파일은 stdbool.h이다.
답 : d
bool 자료형의 크기는 위에서 sizeof로 확인해 봤듯이 1이다.
답 : a
빈칸으로 주어진 부분이 헤더 include 부분이랑 if 조건식 그리고 printf의 삼항 연산자 부분이다. 참, 거짓이 출력되는 것이 목적이므로 맨 처음에는 bool, true, false를 사용하게 해주는 헤더파일인 stdbool.h를 include하고 조건식은 참이 나오도록 하는 값, 삼항 연산자 부분은 거짓이 나오도록하는 값을 넣어주면 될 것 같다.
#include <stdio.h>
#include <stdbool.h>
int main()
{
bool b1 = true;
bool b2 = false;
if (b1 && !b2)
printf("참\n");
else
printf("거짓\n");
printf("%s\n", b2 || !b1 ? "참" : "거짓");
return 0;
}
일단 stdbool.h를 #include로 include했다. if 조건식 부분은 단순히 true나 b1을 써줘도 됐지만 !를 사용하고 싶어서 !b2를 넣어줬다. 삼항 연산자 부분 역시 !b2로 거짓이 출력 되도록 작성했다.
주어진 코드를 완성하여 참, 거짓을 출력하는 것이 목적이다. 맨 처음 조건식에서 b1 != true일시 참이 출력되므로 bool형 변수 b1을 선언하고 false로 초기화 시켜야될 것 같다. 그리고 삼항 연산자로 두 번째 거짓을 출력해야하는데, b2가 false가 아닐 시 거짓이 출력되므로 b2는 true로 초기화 시키면 될 것 같다.
#include <stdio.h>
#include <stdbool.h>
int main()
{
bool b1 = false;
bool b2 = true;
if (b1 != true)
printf("참\n");
else
printf("거짓\n");
printf("%s\n", b2 == false ? "참" : "거짓");
return 0;
}
b1에는 false, b2에는 true를 줘서 풀었다.
-비트 연산자-
비트 연산자는 비트 단위로 연산해주는 연산자다. 비트 연산자의 종류로는 &, |, ^, ~, <<, >> 등이 있다.
위는 코딩도장에 나와있는 c언어의 비트 연산자의 종류와 기능이다. 이 비트 단위 연산은 리버싱에서 많이 해봐서 좀 익숙하다. 비트 연산은 2진수로 상태에서 연산을 하는 것이다.
-&, |, ^
&, |, ^ 비트 연산자를 이용하여 1과 2를 연산했다.
먼저 1은 2진수로 0000 0001이고 2는 2진수로 0000 0010인데 이를 and 연산한다면 0000 0000이 나온다. 즉 0이다. (비트 단위기 때문에 해당 자리가 둘 다 1이면 해당 자리의 결과는 1이 된다.) 그다음 or 연산을 한다면 0000 0011, 즉 3이다.(둘 중 하나라도 1이면 해당 자리의 결과는 1이 된다.). 마지막으로 xor 연산(둘 중 하나만 참이면 참)으로 연산하면 0000 0011이 되서 3이 나온다.
결과를 보면 제대로 연산되고 있음을 알 수 있다.
-~
~ 비트 연산자로 2를 연산했다.
2는 2진수로 0000 0010이므로 이를 not 연산한다면 1111 1101이 된다.(0 -> 1, 1 -> 0) 10진수로 바꾸면 253이다. 결과를 보면 제대로 연산된 것을 알 수 있다.
->>, <<
>>, <<은 비트 단위 시프트 연산을 해준다. >>은 오른쪽으로, <<은 왼쪽으로 시프트를 해준다. 시프트를 시키면서 모자라는 공간은 0으로 채워준다.
2를 각각 >> 2, << 2 로시프트 연산해보면 0과 8이 나옴을 알 수 있다.
이유는 2는 2진수로 0000 0010인데 오른쪽으로 2만큼 시프트를 시킨다면
1. 0000 0001(0)
2. 0000 0000(10)
이런식으로 0만 남게되므로 0이 결과로 나오는 것이다.
왼쪽으로 2만큼 시프트를 시킨다면
1. (0)0000 0100
2. (00)0000 1000
이렇게 0000 1000이되는데 0000 1000은 10진수로 8이므로 결과가 8로 나오는 것이다.
참고로 <<은 2의 거듭제곱을 곱하기, >>은 2의 거듭제곱을 나누기와 같다고 한다.
2 >> 2 같은 경우 2 / 4(2^2) = 0
2 << 2 같은 경우 2 * 4(2^2) = 8
-&=, |=, ^=, <<=, >>=
+=, -= 등과 같이 연산을 함과 동시에 할당을 해줄 수도 있다.
마찬가지로 <변수> = <변수> <비트 연산자> <값> 을 줄인 것이다.
대표로 &=을 사용해보았다. 2값이 들어간 char형 변수 a를 1과 and 연산한 후 그 값을 a에 저장하는 &=를 사용하니(0000 0010 and 0000 0001) 결과는 0으로 잘 나오는 것을 볼 수 있다.
4 & 2는 4와 2를 비트 단위로 and 연산한 것이다. 4가 0000 0100고, 2가 0000 0010이므로 and 연산하면 0000 0000이다.
답 : a
8 | 3은 8과 3을 비트 단위로 or 연산한 것이다. 8은 0000 1000이고, 3은 0000 0011이므로 or 연산한다면 0000 1011이 된다.
답 : e
7 ^ 10은 7과 10을 비트 단위로 xor한 것과 같다. 7은 0000 0111이고, 10은 0000 1010이므로 xor 연산한다면 0000 1101이 된다.
답 : c
~15는 15를 비트 단위로 not 연산한 것과 같다. 15는 0000 1111와 같으므로 not 연산을 하면 1111 0000가 된다.
답 : d
2 << 3 >> 1은 2를 왼쪽으로 3만큼 시프트 연산을 하고, 오른쪽으로 1만큼 시프트 연산을 하라는 것 같다. 2는 0000 0010이므로 왼쪽으로 3만큼 쉬프트 연산을 하면 0001 0000이 된다. 그 후 오른쪽으로 1만큼 시프트 연산을 하면 0000 1000이 된다. (사실상 2<<3>>1은 2<<2와 같은 것 같다.)
답 : b
빈칸을 채워서 5, 4, 1, 250이 각줄에 출력되게끔 만드는 것이 목적이다. 비트 단위 논리 연산자를 적절히 사용하면 될 것 같다.
#include <stdio.h>
int main()
{
unsigned char num1 = 1;
unsigned char num2 = 5;
printf("%u\n", num1 | num2);
printf("%u\n", num1 ^ num2);
printf("%u\n", num1 & num2);
num1 = ~num2;
printf("%u\n", num1);
return 0;
}
대략적으로 출력값을 보고 암산과 예측으로 풀었다. num1은 0000 0001, num2는 0000 0101이다.
맨 처음 printf에서는 5가 출력되야하므로 or 연산으로 num2의 값 그대로 결과가 되도록 했다.
두 번째 printf는 4가 되야하므로 맨 끝의 1이 없어야하는데 둘 다 맨 끝에 1이 존재하므로 xor 연산을 해줘서 0000 0100만 남도록 했다.
세 번째 printf는 1을 출력해야한다. 1은 자릿수 맨끝인데 보면 num1, num2 둘다 끝에 값이 1이므로 and 연산을 해주면 0000 0001이 된다.
num1 = ___num2; 부분은 연산 대상이 1개 밖에 없는 단항이므로 ~만 사용가능해서 ~를 써주니 맞았다.
32 >> 4가 된 상태에서 적절한 값을 << 시프트 값으로 넣어 값이 4가 되게 하는 것이 목적이다.
32는 2진수로 0010 0000이다. >> 4를 수행하면 0000 0010이 되므로 값이 2가 된다. 여기서 왼쪽으로 1만큼 시프트 연산을 수행하면 값이 4가 되므로 빈칸에 1을 넣으면 될 것 같다.
#include <stdio.h>
int main()
{
unsigned char num1 = 32;
num1 = num1 >> 4 << 1;
printf("%u\n", num1);
return 0;
}
num1 >> 4 연산 후 << 1만큼 왼쪽으로 시프트 연산을 수행해서 풀었다.
두 정수가 입력되는데, 입력된 두 값을 각각 비트 단위로 xor, or, and, not(첫 번째 값만) 연산을해서 서식 지정자 %u로 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
unsigned int a = 0, b = 0;
scanf("%d %d", &a, &b);
printf("%u\n", a^b);
printf("%u\n", a|b);
printf("%u\n", a&b);
printf("%u", ~a);
return 0;
}
출력 값을 보니 char형으로는 범위가 벗어날 것 같아 char 대신 unsigned int형으로 a와 b를 선언했다.(문제를 다시보니 unsigned int형으로 입력된다고 적혀있었다...;;)
scanf를 통해 a와 b에 각각 입력 값을 넣어주고 첫 printf문은 a^b, 두 번째는 a|b 세 번째는 a&b 네 번째는 ~a를 넣어줌으로써 각각 xor, or, and, not 연산 결과를 출력했다.
정수 하나가 입력되는데, 이 입력된 정수를 왼쪽으로 20번, 오른쪽으로 4번 시프트 연산한 결과를 출력하는 것이 목적이다. 변수는 long long으로 선언하고, 출력은 서식 지정자 %llu를 사용하라 한다. 윈쪽으로 20번, 오른쪽으로 4번 시프트한 연산 결과는 결국 왼쪽으로 16번 시프트한 값과 같으므로 입력 값을 왼쪽으로 16번 시프트한 값을 출력해주면 될 것 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
unsigned long long a = 0;
scanf("%llu", &a);
printf("%llu", a << 16);
return 0;
}
unsigned long long 형으로 변수 a를 선언한 후 scanf로 입력 값을 a에 넣어준 후 a << 16으로 a를 왼쪽으로 16만큼 시프트한 값을 출력했다.
'Old (2021.01 ~ 2021.12) > Programming' 카테고리의 다른 글
c언어 코딩도장 Unit 34 ~ Unit 35 (0) | 2021.03.01 |
---|---|
c언어 코딩도장 Unit 24 ~ 33 (0) | 2021.02.21 |
c언어 코딩도장 Unit 1 ~ 11 (0) | 2021.02.16 |
파이썬 코딩도장 Unit 38, 39, 43 (0) | 2021.02.14 |
생활코딩 HTML 의미론적 태그 ~ 검색엔진 최적화 (0) | 2021.02.11 |