오늘은 상수와 연산자를 집중적으로 공부할 예정이다.
그럼 상수부터 알아보자.
목차
1. 상수
2. 연산자
1. 상수
상수와 변수는 둘 다 Data를 저장하는 메모리(RAM) 공간이다.
그럼 이 둘의 차이는 뭘까?
변수 : Data를 저장하는 메모리(RAM) 공간, 값을 변경할 수 있음
상수 : Data를 저장하는 메모리(RAM) 공간, 값이 고정되어 있음
상수의 종류
1. Literal
2. 매크로(심볼릭)
3. 상수화된 변수(const 상수)
1. Literal
우리가 기존에 사용했던 printf의 2번째 형식을 기억하는가?
printf(" %d ", 10); 이런 형식 말이다. 여기서 10은 값(value)이다.
이런 값을 Literal이라고 하며, RAM에도 저장되는 값이다.
또한 a = 10; 에서
a는 변수라면, 10은 상수이다.
(int a =10;이라고 선언하는 것은 메모리를 초기화하는 것이다. 대입이 아니다)
10 - 정수 상수 - int형(4byte)
3.14 - 실수 상수 - double형(8byte)
'A' - 문자 상수 - int형(4byte)
"Hello" - 문자열 상수 - 글자수*1byte(실제로 6byte)
2. 매크로(심볼릭, c언어에만 존재)
원래라면 MAX는 정의되어 있는 것이 아니기 때문에 에러가 나야 한다.
하지만 #include <stdio.h> 밑에
#define MAX 100로 MAX를 정의해 두었다.
즉, 글자바꿔치기이다.
이걸 이용하자면,
printf를 줄여서 pr로도 사용이 가능하다.
다시 한번 이야기하자면 c언어에서만 사용가능하다.
3. 상수화된 변수 (const 상수)
int a 앞에 const를 붙여주면, 상수화를 시킨다.
이렇게 되면 그다음에 변수 값을 바꾸려 하면 에러가 난다.
또 상수화를 시키고 그 뒤에 변수에 값을 넣어줘도 에러가 난다.
이 경우 a에는 쓰레기 값이 저장되게 된다.
이때 상수의 표기법이 있다.
<Snake 표기법>이라고 불리는데,
예를 들자면
회사명이라면 'COMPANY_NAME'과 같은 방식이다.
다시 한번 정리해 보자면
변수는 Camel표기법 (ex- companyName)이며
상수는 Snake표기법 (ex- COMPANY_NAME)이다.
2. 연산자
연산자의 종류(카테고리)는 8개다.
1. 산술연산자 : +, -, *, /, %, -(단항)
2. 비교연산자 : <, >, <=, >=, ==, !=(같지 않다.)
3. 논리연산자 : &&(and), ||(or,원표시 위에 있는거), !(not)
4. 비트연산자 : &(and), |(or), ~(not, 단항), ^(exclusive or), <<, >>
5. 증감연산자 : ++(단항), --(단항)
6. (복합)대입연산자 : =, +=, -=, *=, /=, %=
7. 삼항(조건)연산자 : 조건?x:y
8. 형변환연산자
단항연산자는 하나의 숫자만 있어도 된다는 것이다.
예를 들어 4가 있으면, - 단항연산자를 사용하면 -4가 된다.(즉 부호를 바꿔준다.)
나머지 연산자들은 이항 연산자이다.
즉 두 개의 숫자가 있어야 하는 것이다.(그래야 계산이 가능하니까) ex) 3 * 7
1. 산술연산자 : +, -, *, /, %, -(단항)
문제는 /(나눗셈)에서 발생한다.
10 / 4를 하면 우리는 2.5라고 계산을 할 것이다.
이런 상황이 발생한 이유는
우선 %d를 서식문자로 사용하였고,
c 역시 int이기 때문에 이런 상황이 발생한다.
?????
하지만 이를 수정해도 우리가 원하는 답은 나오지 않는다.
그 이유는 우리가 앞에서 a와 b를 이미 int형이라고 선언했기 때문이다.
컴퓨터의 계산 과정을 설명해 보자면
RAM에서 저장된 값들을 CPU가
레지스터로 가져온다.
그 레지스터를 사용해 CPU에서 계산을 하고
결과값을 ACC(누산기)에 저장한다.
이때 결과 값이 2.5로 저장이 될 것이다.
그러나 문제는 이 결과값을 바로 c에 넣는 것이 아니라
메모리(RAM)에 넣어버리는 것이다.
대입 연산자는 오른쪽에 쓰여 있는 메모리의 값을 카피해서 왼쪽에 넣는 것이다.
다시 말해, ACC는 메모리가 아니기 때문에 컴퓨터는
새로운 메모리 주소에 결과값을 넣어버린다.
이때 결과값을 처음 저장되어 있던 a, b의 값에 맞게 변환시킨다.(2.5 -> 2)
그래서 계산은 제대로 2.5로 되었지만, 연산에 사용했던 것이 int였기 때문에
메모리로 가면서 int형으로 변환되어 2로 저장되는 것이다.
이때 c는 double형이라 8byte이고 계산 값은 int형으로 4byte이다.
c언어는 이를 맞추기 위해 자동으로 형변환하여 8byte로 바꾼다.
(이를 자동형 변환, 묵시적형변환이라고 한다.)
그러면 2는 2.000000이 되고, 이를 c에 넣게 되는 것이다.
하지만 누가 과연 이런 것을 다 계산하여 쓸까?
이런 문제를 해결하기 위해서 형변환연산자를 사용한다.
c의 대입할 값에 (double)를 추가하여
임시로 형변환한 수를 메모리에 저장하고 그 형태로 계산하게 하는 것이다.
연산자는 양쪽의 자료형이 같아야 사용할 수 있다.(대입연산자도 마찬가지)
그러니 c언어는 자료형을 작을 것을 큰 것에 맞춰줘야 한다.
3 + 3.14가 있다고 예를 들면,
int와 double형이 있는 것이다.
어제 말한 것과 같이
char
short
int
long
float
double
순으로 크다.
그러니 int를 double형으로 형변환해줘야 한다.
근데 float은 4byte이다.
우리가 상수 3.14를 입력하면 컴퓨터는 이를 8byte로 인식한다.
그러나 우린 분명 float으로 사용하고 싶을 경우도 있을 것이다.
이럴 때 간단하게 숫자 뒤에 f를 붙여주면 float 값에 맞는 상수 값을 넣어줄 수 있다.
<알아야 할 것>
c언어는 형변환하지 않아도 알아서 형변환하여 계산을 한다.
그러나, 다른 언어는 이를 위험하게 생각하여 에러가 발생한다.
그래서 이런 형변환을 꼭 알아둬야 한다.
% 연산자는 나눗셈에서 나머지를 구하는 연산자이다.
사진에서는 10을 3으로 나누었을 때, 나머지를 구하는 출력이다.
(나머지를 구하는 연산자는 엄청 많이 사용하는 연산자이다.)
-(단항) 연산자이다.
-를 상수나 변수 앞에 붙여주기만 하면 되고, 음수 값에 붙여주면 양수가 된다.
2. 비교연산자 : <, >, <=, >=, ==, !=(같지 않다.)
비교연산자의 결과는 참과 거짓이다.
ex)
5<8 → 참 → true → 1
5<3 →거짓 → false → 0
간단한 표기로 남기기 위해
true를 1로
false를 0으로 표기하였다.
3. 논리연산자 : &&(and), ||(or,원표시 위에 있는거), !(not)
논리연산자는
오직 2진법을 위해서 만들어진 연산자이다.
우선 &&(and)
A | B | 결과 |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
오직 A와 B 둘 다 1이여야지 결과값이 1이 되는 연산자이다.
이게 왜 필요하냐면
만약 클럽이 있다고 가정해 보자.
클럽은 분위기를 위해서
나이제한을 두고 있는데
20살 초과 40살 미만의 고객만 입장을 허가한다.
age > 20 and age < 40
라고 한다면
int age = 15;
일 때 이것은 참이겠는가?
계산해 보면
우선 20살보다 작아서 이것은 거짓(0)
40살보다 어려서 참(1)이다.
그러나 and 연산자에 의해서 둘 다 만족을 하지 않으므로 거짓(0)이 되는 것이다.
위에 작성한 표는 이런 식으로 이해가 가능하다.
만일 프로그래밍 언어에서
조건을 연달아 쓰면
ex) 20 < age < 40
원하는 값을 얻을 수 없다.
그 이유는 컴퓨터의 특성에 있다.
컴퓨터는 분명 하나하나 차례대로 작동하는 기계이다.
여기서 차례대로 계산하면
20 < age는 참이든 거짓이든 0,1이고
0,1은 40보다 작으므로 언제나 참이 된다!
||(or) 연산자
A | B | 결과 |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
둘 중에 하나만 참이어도 참(1)의 결과값을 갖는 연산자이다.
!(not) 연산자
이 연산자는 그 값을 부정하는 조건문으로
0을 1로
1을 0으로
바꾸는 연산자이다.
어떤 조건에 반대상황을 물어볼 때 많이 사용하는 연산자이다.(꽤나 많이 사용)
4. 비트연산자 : &(and), |(or), ~(not, 단항), ^(exclusive or), <<, >>
거의 쓰지 않는 연산자로 간단하게 설명하고 넘어가겠다.
비트연산자는 비트마다 저 연산자로 계산하는 연산자이다.
ex) 5 & 7 는
2진법으로 바꿔서 계산해 보면
101 & 111 이고
각 자리별로 계산해 보면
(제일 첫자리는 둘 다 1이어서 1, 둘째자리는 하나만1이여서 0, 셋째는 둘다 1이여서 1)
101이 된다. 101이라는 2진법은 10진법으로 5가 된다.(결괏값 5)
^(exclusive or)은
서로 다를 때 1이 되는 연산자이다.
A | B | 결과 |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
^ 9를 하면
2진법 1001에서 0과 1이 역전되어
0110이 된다. 그럼 이를 10진수로 바꾸면 6이다.
그러나 실제 결과값은 -10이다.
그 이유는 9가 int형이기 때문이다.
int형은 4byte여서 나머지 앞에 0들까지도 고려해야 한다.
즉 9는 00000000000000000000000000001001이다.
여기서 0을 다 1로, 1을 0으로 바꿔줘야 한다.
>>, << 연산자는
2진수의 값에서 화살표의 방향으로 밀라는 뜻이다.
즉 0010이 있다면 이를 <<1 해보자.
그러면 0100이 되고
10진수로는 4가 된다.
5. 증감연산자 : ++(단항), --(단항)
컴퓨터는 본인의 값을 1 증가시킬 때
a = a + 1; 로 할 수 있다.
그러나 변수이름이 a가 아니라 엄청 긴 이름이었을 때,
이를 간편하게 사용하려고
a++; 을
(++a; 도 가능)
사용한다.
a++과 ++a의 차이점은
연산을 먼저 하느냐 나중에 하냐의 차이이다.
따라서 a++을 출력하는 printf에선
a를 먼저 출력한 뒤에 +1을 한 것이기 때문에 출력은 11이 되는 것이다.
같은 로직으로
b엔 a값이 들어가고 그다음에 a에 +1이 돼서
a와 b의 값이 다른 것이다.
6. (복합) 대입연산자 : =, +=, -=, *=, /=, %=
a++;이 1을 증가시킬 때
a를 7 증가시키고 싶다면 어떻게 해야 할까?
원래 줄인 식 말고
a = a +7;을 작성하면 된다.
그러나 아까도 말했듯 변수이름이 너무 길다면?
이때 사용하는 게 복합대입연산자이다.
a += 7;
이런 수식을 사용하면 된다.
즉 산술연산자와 대입연산자를 섞은 표현으로
생각하면 이해하기 쉽다.
7. 삼항(조건)연산자 : 조건?x:y
if문과 같은 역할을 하는 연산자이다.
만일 내가 b의 값을 어떨 땐 50, 어떨 땐 100으로 설정하고 싶을 때
앞에 조건을 적고,
(조건은 비교연산만)
맞으면 2번째 값, 틀리면 3번째 값이 적용되는 연산자이다.
이렇게 그 안에 한 번 더 삼항연산을 넣어 세분화도 가능하다.
강사님의 조언
우리는 '앱 개발자'이다. '언어 개발자'가 아니다.
문법을 외우는 것에 치중하는 것이 아니라, 어떻게 이 문제를 해결할지 생각하는 게 중요하다.
'코더'가 되지 말고 '개발자'가 되자.
'# 개발 > C언어' 카테고리의 다른 글
c언어 #5 - 제어문(if, switch,for,while,break,continue) (국비6일차) (0) | 2023.01.06 |
---|---|
c언어 연습문제 #3 (국비5일차) (0) | 2023.01.05 |
c언어 연습문제 #2 (국비4일차) (0) | 2023.01.04 |
c언어 #3 - 변수, scanf (국비4일차) (0) | 2023.01.04 |
c언어 연습문제 #1 (국비3일차) (0) | 2023.01.03 |