[ C 언어 스터디 ]

 

자료출처 : 핵심 길잡이 C 프로그래밍 언어

도서풀판 : 성안당

 

5. 연산자 ( Operators )

★ 연산자의 종류 ★

C 언어는 다른 언어들과는 달리 다양한 연산자를 제공한다. 연산자 ( operator )는 자
료 처리를 위한 수식들을 결합하여 연산 동작을 수행하도록 하는 기호이다. 이때 연산
작용에 사용되는 자료 값들을 오퍼랜드 ( operand )라 한다. 따라서 연산자는 이 오퍼랜
드를 가지고 원하는 연산 동작을 수행하게 된다. 그리고 연산자는 각 연산자가 가지는
오퍼랜드의 개수에 따라 그 개수가 하나이면 단항 연산자 ( unary operator ), 2개이면
이항 연산자 ( binary operator )라 하고, 3개이면 삼항 연산자 ( ternary operator )라 한다.

[ 그림 5 - 1 ]은 C 언어에서 사용하는 연산자를 나타낸 것이다.

연산자 오퍼랜드 개수에 따른 분류 단항 연산자 : ++, -- , +(부호) , -(부호) 등
이항 연산자 : + , - , * , / , % , << , >> 등
삼항 연산자 : ?  :
   
연산자 기능에 따른 분류 산술 연산자 : + , - , * , / , %
관계 연산자 : < , <= , == , != , => , >
논리 연산자 : && , | | , !
증감 연산자 : ++ , --
비트 연산자 : & , | , ∧ , ~ , <<, >>
대입 연산자 : = , += , -= , *= , /= 등
기타 연산자 :  ?  : ,  ,(콤마) , sizeof , pointer ( * , & ) ,  ->

[ 그림 5 - 1 ] 연산자의 종류

★ 연산자의 우선 순위 ★

C 언어에서 사용되는 연산자의 우선 순위와 결합 규칙은 [ 표 5 - 1 ]과 같다.
[ 표 5 - 1 ] 에서도 볼 수 있듯이 상위 칸에서 하위 칸으로 내려오면서 연산자의 우선
순위는 낮고, 같은 칸 안의 연산자들은 우선 순위가 동일하다. 단 , 결합 규칙에서 같은
우선 순위의 연산인 경우에는 그 식 ( expression )이 왼쪽에서 오른쪽으로 , 혹은 오른쪽
에서 왼쪽의 방향으로 평가되며, 이것은 연산이 행해져 가는 방향을 나타낸다. 예를 들
어, < ,  <= ,  > ,  >= 는 같은 우선 순위를 가지며 이들을 포함하는 식은 왼쪽에서 오른쪽
으로 차례대로 연산자를 평가하게 된다.

[ 표 5 - 1 ] 연산자의 우선 순위와 결합 규칙

우선 순위 연산자의 종류 연산자 결합 방향

1

함수, 배열, 구조체 ( ) [ ] ->  : :  . 왼쪽 -> 오른쪽

2

3

단항 연산자

!  ~  +  -  ++  --  &  *  (typecast)

sizeof  new  delete

오른쪽 -> 왼쪽

4

산술 연산자  *  /  %  +  - 왼쪽 -> 오른쪽

5

이동 연산자 <<  >>

6

관계 연산자 <  <=  >  >=  ==  !=

7

비트 논리 연산자 &  ∧  |

8

논리 연산자 &&  | |

9

조건 연산자 ?   : 오른쪽 -> 왼쪽

10

복합 대입 연산자 =  *=  /=  %=  +=  -=  &=

∧=  |=  <<=  >>=

오른쪽 -> 왼쪽

11

콤마 연산자  , 왼쪽 -> 오른쪽

 

★ 산술 연산자 ( Arithmetic operators ) ★

C 언어에서 산술 연산을 수행하기 위한 연산자는 더셈 ( + ), 뺄샘 ( - ), 곱셈 ( * ), 나눗
셈 ( / ), 나머지 연산자 ( % ) 등이 있다. 산술 연산자는 연산의 대상이 되는 오퍼랜드
( operand )가 2개이므로 이항 연산자 ( binary operator )라 한다. 산술 연산자의 일반 형
식은 다음과 같다.

형 식

식 1   연산자    식 2
또는
오퍼랜드 1   연산자   오퍼랜드 2

여기서, 식 1과 식 2는 상수, 변수, 수식 등이 사용된다. [ 표 5 - 2 ]는 산술 연산자의 종
류를 나타낸 것이다.

[ 표 5 - 2 ] 산술 연산자의 종류

연산자 기 능 의 미

+

a + b

a와 b를 더한다.

-

a - b

a와 b를 뺀다.

*

a * b

a와 b를 곱한다.

/

a / b

a에서 b를 나눈 몫을 구한다.

%

a % b

a에서 b를 나누었을 때 나머지를 구한다.

단, 나머지 연산자 ( % )는 int 형이나 char 형에 대해서는 허용이 되지만 float 형이나
double 형에 대해서는 사용할 수 없다. 그리고 나눗셈 연산자 ( / )는 정수 나눗셈과 실수
나눗셈의 결과가 다르다. 따라서 프로그램 작성 시 유의해야 한다. 이들의 관계를 나타
내면 다음과 같다.

연산식 연산 결과 사용 예

정수 / 정수

정수

1/5 = 0

정수 / 실수

실수

1/5.0 = 0.2

실수 / 정수

실수

1/5.0 = 0.2

실수 / 실수

실수

1. / 5. = 0.2

C 언어에는 제곱을 계산하는 연산자가 따로 없기 때문에 2의 제곱을 계산하려면 2 * 2를 사
용하고, 2의 세제곱을 계산하려면 2 * 2 * 2를 사용한다.

다음과 같이 두 수를 입력받아 사칙 연산의 결과를 나타내는 프로그램을 작성해 보자.

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int a = 5, b = 7 ;
printf ( " %d + %d = %d \n " , a , b , a + b ) ;
printf ( " %d - %d = %d \n " , a , b , a - b ) ;
printf ( " %d * %d = %d \n " , a , b , a * b ) ;
printf ( " %d / %d = %d \n " , a , b , a / b ) ;
printf ( " %d  %%  %d = %d \n " , a , b , a % b ) ;

}

▶ 실행 결과
5 + 7 = 12
5 - 7 = -2
5 * 7 = 35
5 / 7 = 0
5 % 7 = 5

 

★ 대입 연산자 ( Assignment operators ) ★

대입 연산자는 수학에서처럼 좌변과 우변의 식이 동일하다는 것을 의미하는 것이 아
니라 우변의 수식의 값을 좌변의 변수에 대입하라는 것을 의미한다. 양변의 값이 같음
을 나타내기 위해서 C 언어에서는 비교 연산자 ( == )를 별도로 사용하고 있다.
대입 연산자는 오른쪽에서 왼쪽으로 결합하여, 이 연산자의 종류와 의미는 [ 표 5 - 3 ]
과 같다.
C 언어에서는 [ 표 5 - 3 ]에 나타낸 바와 같이 a = a + b나 c = c - d처럼 자기 자신 ( 변수
a 와 c )에 어떤 연산의 결과 값을 대입하고자 할 때 복합 대입 연산자를 사용한다. 복합
대입 연산자는 = 와 연산을 하고자 하는 산술 연산자가 결합된 형태로 이루어져 있다.
이와 같은 연산자는 많이 사용되고, 있으므로 반드시 기억하여 두기 바란다.

[ 표 5 - 3 ] 대입 연산자의 종류

연산자 의 미 사용법 산술식
 = 우변의 값이 좌변으로 대입된다. a = b ;  
 += 좌변의 변수와 우변의 변수를 더한 후 좌변에 대입한다. a += b ; a = a + b ;
 -= 좌변의 변수에서 우변의 변수를 뺀 후 좌변에 대입한다. a -= b ; a = a - b;
 *= 좌변의 변수와 우변의 변수를 곱한 후 좌변에 대입한다. a *= b ; a = a * b ;
 /=

좌변의 변수를 우변의 변수로 나눈 후 몫을 좌변에 대입

한다.

a /= b ; a = a / b ;
 %=

좌변의 변수를 우변의 변수로 나눈 후 나머지를 좌변에

대입한다.

a %= b ; a = a % b ;
 <<=

좌변의 변수를 우변의 수만큼 좌측으로 이동한 것을 좌변

에대입한다.

a <<= b ; a = a << b ;
 >>=

좌변의 변수를 우변의 수만큼 우측으로 이동한 것을 좌변

에대입한다.

a >>= b ; a = a >> b ;
&=

좌변의 변수와 우변의 변수를 비트별로 AND하여 좌변

에 대입한다.

a &= b ; a = a & b ;
 ∧=

좌변의 변수와 우변의 변수를 비트별로 배타적 OR하여

좌변에 대입한다.

a ∧= b ; a = a ∧ b ;
 |=

좌변의 변수와 우변의 변수를 비트별로 OR하여 좌변에

대입한다.

a |= b ; a = a | b ;

 

다음 프로그램의 실행 결과를 나타내시오.

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int a , b , c , d ;
a = 2 ;
b = 5 ;
c = 6 ;
d = 10 ;
a += b ;   // a = a + b ; 와 동일
printf ( " %d " , a ) ;
b -= c ;
c *= b ;
d /= a ;
a %= c ;
printf ( " %d  %d  %d \n " , b , c , d , a ) ;

}

▶ 실행 결과
7   -1   -6    1   1

 

★ 증감 연산자 ★

증감 연산자의 종류에는 증가 연산자 ( ++ )와 감소 연산자 ( -- )의 두 가지 형태가 있
는데, 1씩 증가와 1씩 감소를 간단하게 표현하는 C 언어만이 가지고 있는 연산자이다.
연산자가 변수의 앞에 있는가 뒤에 있는가에 따라 전위형 ( prefix )과 후위형 ( postfix )으
로 나뉘어진다. 전위혀은 ++a , --a 의 형태이고, 후위형은 a++ , a-- 의 형태인데, 이들
의 연산 결과는 다르기 때문에 주의하여 사용하여야 한다.

[ 표 5 - 4 ] 증간 연산자의 종류

연산자 의 미 사용법
++ 1 증가 ( a = a + 1 ) ++a 또는 a++
 -- 1 감소 ( a = a - 1 )  --a 또는 a--

< 증가 연산자 ( increment operator ) : ++>

단항 연산자로서 하나의 오퍼랜드의 값을 1 만큼 증가시키는 연산자이며 , 사용 형식
은 다음과 같다 .

형 식 1 전위형 ( prefix )
++ 오퍼랜드

오퍼랜드의 값을 먼저 1 증가시킨 후 변수의 최종값을 수식에 적용시키는 연산이다.

형 식 2 후위형 ( postfix )
오퍼랜드 ++

오퍼랜드의 값을 먼저 연산에 적용시킨 후 최종 변수의 값을 1 증가시키는 연산이다.

< 감소 연산자 ( decrement operator ) : -- >

단항 연산자로서 하나의 오퍼랜드의 값을 1 만큼 감소시키는 연산자이며 , 사용 형식
은 다음과 같다.

형 식 1 전위형 ( prefix )
 -- 오퍼랜드

오퍼랜드의 값을 먼저 1 감소시킨 후 변수의 최종값을 수식에 적용시키는 연산이다.

형 식 2 후위형 ( postfix )
 오퍼랜드 --

오퍼랜드의 값을 먼저 연산에 적용시킨 후 최종 변수의 값을 1 감소시키는 연산이다.
예를 들어 , a = b = 10일 때 단항 연산자의 및 실행 결과는 다음과 같다.

연산식 실행 절차 실행 결과

b = ++a

b = --a

b = a++

b = a--

a에 1을 더한 후 그 값을 b에 대입한다.

a에서 1을 뺀 후 그 값을 b에 대입한다.

a를 b에 대입한 후 a에 1을 더한다.

a를 b에 대입한 후 a에서 1을 뺀다.

a = 11 , b = 11

a = 9 , b = 9

a = 11 , b = 10

a = 9 , b = 10

 

증감 연산자의 전위형과 후위형의 차이를 살펴보기 위해 다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int a = 10 , b = 10 ;
b = ++a ;
printf ( a = %d  b = %d \n " , a , b ) ;
b = --a ;
printf ( " a = %d  b= %d \n " , a , b ) ;
b = a++ ;
printf ( " a = %d   b = %d \n " , a , b ) ;
b = a-- ;
printf ( " a = %d   b = %d \n " , a , b ) ;

}

▶ 실행 결과

a = 11 b = 11
a = 10 b = 10
a = 11 b = 10
a = 10 b = 11

 

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main (  void )
{

int  a ,  b = 5 , c = 10 ;
a = b + c ;
printf ( " a = %d  b = %d  c = %d \n " , a , b , c ) ;
a = ++b  +  ++c ;
printf ( " a = %d  b = %d  c = %d \n " , a , b , c ) ;
a = b++  +  c++ ;
printf ( " a = %d  b = %d  c = %d \n " , a , b , c ) ;
a = --b  +  c-- ;
printf ( " a = %d  b = %d  c = %d \n " , a , b , c ) ;
a = b--  +  --c ;
printf ( " a = %d  b = %d  c = %d \n " , a , b , c ) ;

}

▶ 실행 결과

a = 15 b = 15 c = 10
a =17 b = 6 c = 11
a = 17 b = 7 c = 12
a = 18 b = 6 c = 11
a = 16 b = 5 c = 10

 

 

★ 관계 연산자 ( Relational operators ) ★

관계 연산자는 2개의 오퍼랜드들간의 대소 관계를 나타내는 연산자이다. 주로 두 수
의 대소 비교나 문자형 자료의 대소 ( ASCII 코드 값 ) 비교에 사용된다. 관계 연산자의
종류는 [ 표 5 - 5 ]와 같다.

[ 표 5 - 5 ] 관계 연산자의 종류

연산자 형 식 의 미
 < 식1  <  식2 식1 이 식2 보다 작다
 <= 식1  <=  식2 식1 이 식2 보다 작거나 같다.
 > 식1  >  식2 식1 이 식2 보다 크다.
 >= 식1  >=  식2 식1 이 식2 보다 크거나 같다.
 == 식1  ==  식2 식1 이 식2 와 같다.
 != 식1  !=  식2 식1 이 식2 와 같지 않다.

여기서 2개의 오퍼랜드들간의 대소 관계를 비교해서 참 ( true )인 경우에는 1 , 거짓
( false )인 경우에는 0 값을 갖는다.
모든 관계 연산자는 같은 우선 순위를 가지며 , 왼쪽에서 오른쪽으로 연산이 이루어
진다. 따라서 관계 연산자는 프로그램이 수행되는 도중에 데이터나 계산 결과 등이 어
떤 조건에 맞는지 판단하여 그 결과에 따라 실행할 명령문을 선택하는 데 이용된다.

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  a = 30 ,  b = 20 ,  c = 10 ,  d ;
d = a + b > c ;
printf ( " d의 결과 값은 = %d \n " , d ) ;
d = a > b > c ;
printf ( " d의 결과 값은 = %d \n " , d ) ;

}

▶ 실행 결과
d의 결과 값은 = 1
d의 결과 값은 = 0

 

★ 논리 연산자 ( Logical operators ) ★

여러 개의 조건을 동시에 결합하여 판정하는 연산자로 AND , OR , NOT의 논리 연
산을 수행한다. 관계 연산자와 마찬가지로 참 ( true ) 일 때에는 " 1 "로 , 거짓 ( false ) 일 때
에는 " 0 " 으로 표시한다.

[ 표 5 - 6 ] 논리 연산자의 종류

연산자 형 식 의 미

&& ( 논리곱 , AND )

식1 && 식2

식1과 식2를 논리적으로 곱한다.

| | ( 논리합 , OR )

식1 | | 식2

식1과 식2를 논리적으로 더한다.

! ( 논리부정 , NOT )

! 식1

식1을 논리적으로 부정한다.

 

a = b && c ;   // b 와 c 가 모두 참이면 a 는 1 , 그 이외에는 0
a = b | | c ;   // b와 c 가 모두 거짓이면 a 는 0 , 그 이외에는 1
a = !b ;   // b가 참이면 a 는 0 , b 가 거짓이면 a 는 1

논리 연산의 결과 값인 0이나 1은 그대로 산술 연산에 사용할 수 있으며 산술 연산
에서 나오는 결과 값 역시 논리 연산과 혼합하여 사용할 수 있다. 또한 , 산술 연산의
결과가 0 이외의 값이면 모두 " 참 ( true ) " 으로 취급한다.
산술 연산과 논리 연산의 조합은 다음과 같이 나타낼 수 있다.

if ( ! ( a / b ) )
printf ( " yes " ) ;

산술 연사의 결과에 NOT을 취한다.
산술 연산의 결과가 " 0 " 이 아니면 " 1 " 로 취급한다.
/ * a 를 b 로 나눈 결과가 0 이면  " yes " 를 출력한다 * /

논리 연산자는 왼쪽에서 오른쪽으로 결합하여 산술 연산자나 관계 연산자보다 우선
순위가 낮다.

논리 연산자는 NOT , AND , OR의 순서로 결합한다.

 

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  x = 10 , y = 0 ;
printf ( " x | | y = %d \n " , x | | y ) ;
printf ( " x && y = %d \n " , x && y ) ;

}

▶ 실행 결과
x | | y = 1
x && y = 0

 

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  a , b , c ;
a = 3 ;
b = 11 ;
c = 0 ;
printf ( " %d && %d = %d \n " , a , b , a && b ) ;
printf ( " %d | | %d = %d \n " , a , b , a | | b ) ;
printf ( " %d && %d = %d \n " , a , c , a && c ) ;
printf ( " ! %d = %d \n " , a , !a ) ;
printf ( " ! %d = %d \n " , c , !c ) ;

}

▶ 실행 결과
3 && 11 = 1
3 | | 11 = 1
3 && 0 = 0
!3 = 0
!0 = 1

 

★ 비트 논리 연산자 ( Bitwise logical operators ) ★

비트 논리 연산자는 컴퓨터 자료의 최소 단위인 비트 ( bit ) 단위로 연산을 할 수 있
는 연산자로 AND , OR , NOT의 기본 회로에 의해 모든 작업이 이루어지고 있다. 또한,
비트 논리 연산자를 사용한 연산자를 비트 조작 연산자라 한다. 이때 연산 대상이 되는
오퍼랜드는 정수형이다. 즉, char , short , int , unsigned 형에 대해서만 비트 논리 연산이
가능하며 연산 결과는 다시 정수형이 된다. 비트 논리 연산자는 비트 배열과 관련된 연
산을 할 때 많이 이용된다.
비트 논리 연산자의 종류는 다음과 같다.

[ 표 5 - 7 ] 비트 논리 연산자의 종류

연산자 형 식 의 미
 & ( 논리곱 ) 식1  &  식2 식1과 식2의 비트 단위 논리곱을 구한다.
 | ( 논리합 ) 식1  |  식2 식1과 식2의 비트 단위 논리합을 구한다.
  ∧ ( 배타적 논리합 , XOR ) 식1  ∧  식2 식1과 식2의 비트 단위 배타적 논리합을 구한다.
 ~ ( 보 수 ) ~ 식1 식1의 1의 보수 ( 1's complement )를 구한다.

x , y 두 비트의 조합이 다음과 같을 때 각 연산에 의해 나올 수 있는 값을 정리하면 다음과 같다.

x   y x  &  y x  |  y x  ∧  y ~ x ~ y

0   0

0

0

0

1

1

0   1

0

1

1

1

0

1   0

0

1

1

0

1

1   1

1

1

0

0

0

 

a = b & c ;   // b 와 c 를 비트 AND 하여 a 에 대입한다.
a = b | c ;   // b 와 c 를 비트 OR 하여 a 에 대입한다.
a = b ∧ c ;   // b 와 c 를 비트 XOR 하여 a 에 대입한다.
a = ~ c ;   // b 의 각 비트를 반전하여 a 에 대입한다.

 

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main (  void)
{

int  x = 10 ;
int  y = 7 ;
int  a , b , c , d ;
a = x & y ;
b = x | y ;
c = x ∧ y ;
d = ~ x ;
printf ( " %d \n " , a ) ;
printf ( " %d \n " , b ) ;
printf ( " %d \n " , c ) ;
printf ( " %d \n " , d ) ;

}

▶ 실행 결과
2
15
13
-11

위의 프로그램을 2 바이트 ( 16 bit ) 정수형 자료를 AND , OR , XOR 형태로 나타내면 다음과 같다.

x = ( 10 )10 =      0000 0000 0000 1010

y = ( 7 )10 =       0000 0000 0000 0111

x & y = ( 2 )10 = 0000 0000 0000 0010

 

x = ( 10 )10 =      0000 0000 0000 1010

y = ( 7 )10 =       0000 0000 0000 0111

x | y = ( 15 )10 = 0000 0000 0000 1111

 

x = ( 10 )10 =      0000 0000 0000 1010

y = ( 7 )10 =       0000 0000 0000 0111

x ∧ y = ( 13 )10 = 0000 0000 0000 1101

 

x = ( 10 )10 =           0000 0000 0000 1010

 

~ x ∧ y = ( -11 )10 = 0000 0000 0000 0101

 

★ 이동 연산자 ( Shift operators ) ★

이동 연산자는 비트를 왼쪽 또는 오른쪽으로 이동시키는 연산자로 정수형 자료에서
만 사용되며, 오른쪽으로 비트가 이동할 때 부호부의 취급에 주의해야 한다. 즉 부호가
있는 정수형 자료를 오른쪽으로 지정된 비트만큼 이동할 경우 ( 산술 비트 이동 )에 오른
쪽으로 이동 후 생기는 빈 비트는 부호로 채워진다. 부호가 없는 정수형 자료를 이동할
경우 ( 논리 비트 이동 )에는 0 ( zero )로 채워진다. 이동 연산자의 연산 우선 순위는 산술
연산자보다 낮고 논리 연산자보다 높다.

[ 표 5 - 8 ] 이동 연산자의 종류

연산자 의 미 사용법
<< 비트를 왼쪽으로 이동 a = b << 3 ; b를 3비트 왼쪽으로 이동하여 a 에 대입
>> 비트를 오른쪽으로 이동 a = b >> 3 ; b를 3비트 오른쪽으로 이동하여 a 에 대입

16진수 0xf8 을 이용한 다음의 몇 가지 예를 살펴보기로 하자.

a
1 1 1 1 1 0 0 0
MSB ->  부호비트  LSB


a = 1111 1000  ( 2 진수 표현 )
a = 1111 1000  ( 16진수 표현 )
a = -8    ( 10진수 표현 : a 가 부호와 함께 선언되어 있는 경우 )
a = 248  ( 10진수 표현 : a 가 부호 없이 선언되어 있는 경우 )


1. a << 2   : 왼쪽으로 2비트 이동

해당 변수의 값이 왼쪽으로 이동할 때 이동으로 발생되는 공백이 " 0 " 으로 채워진다.

a
1 1 1 0 0 0 0 0

파란 부분의 공백인 비트에 0 이 채워진다.

a = 1110 0000  ( 2 진수 표현 )
a = 0xe0  ( 16 진수 표현 )
a = -32  ( 10 진수 표현 : a 가 부호와 함께 선언되어 있는 경우 )
a = 224  ( 10진수 표현 : a 가 부호 없이 선언되어 있는 경우 )

2.  a >> 2   : 오른쪽으로 2비트 이동

▶ 산술 비트 이동일 때 ( 부호가 있는 정수형 자료를 이동할 경우 )

a
1 1 1 0 0 0 0 0

파란 부분의 공백 비트에 부호 비트와 동일한 것이 들어간다.
부호

a = 1111 1000  ( 2 진수 표현 )    -------- 이동하기 전의 a 값
a = 0xfe  ( 16 진수 표현 )  --------- 이동 후의 값

▶ 논리 비트 이동일 때 ( 부호가 없는 정수형 자료를 이동할 경우 )

a
1 1 1 0 0 0 0 0

파란 부분 공백 비트에 0 이 들어간다.
부호

a = 1111 1000  ( 2 진수 표현 )  ------- 이동하기 전의 a 값
a = 0x3e  ( 16 진수 표현 )   ------- 이동 후의 a 값
a = 62    ( 10 진수 표현 )  

 

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  a = 10 , b ;
b = a << 2 ;
printf ( " a << 2 = %d \n " , b ) ;
b = a >> 2 ;
printf ( " a >> 2 = %d \n " , b ) ;

}

▶ 실행 결과
a << 2 = 40
a >> 2 = 2

위 예제를 예로 들어 보자 첫 번재 식에서 a 가 10진수 10(10) 이므로 이를 2진수
로 표현하면 0000 1010(2)이 되고 이를 2비트 왼쪽으로 이동시키면 다음과 같은 상태가
되어 그 결과는 0010 1000(2)가 된다.
a << 2

0 0 0 0 1 0 1 0

 

0 0
 제거된 비트

 

0 0 1 0 1 0 0 0
삽입된 비트

a 를 오른쪽으로 2비트 이동시키면 다음과 같은 상태가 되어 , 그 결과 0000 0010(2)이
된다. 이때 제거되는 비트로 10(2)이 있는데 이는 정수 연산 즉 , 정수의 나눗셈에서 소
수 이하 자릿수가 제거되는 현상과 같다.

a >> 2

0 0 0 0 1 0 1 0

 

0 0 0 0 0 0 1 0
  삽입된 비트

 

1 0
  제거된 비트  

다음 예와 같이 -2를 2진수화하면 1111 1110(2)이 된다. 이를 2비트 오른쪽으로 이동
시키면 다음과 같은 상태가 되어 그 결과는 1111 1111(2) = -1 이 된다.
a = -2
b = a >> 2

a >> 2

1 1 1 1 1 1 1 0

 

1 1 1 1 1 1 1 1
  삽입된 비트

 

1 0

제거된 비트  

 

★ 기타 연산자 ★

< 조건 연산자 ( Conditional operator ) >

조건 연산자는 삼항 연산자 ( ternary operator ) 로 if ~ then ~ else 문과 유사한 구조를
갖는 C 언어에서만 볼 수 있는 연산자이다. 일반적인 사용 형식은 다음과 같다.

형 식
조건식  ?  명령문1  :  명령문2 ;

먼저 조건식을 비교한 후 조건식이 참 ( true )인 경우에는 명령문 1을 수행하고 , 거짓
( false )인 경우에는 명령문 2을 수행한다.
이것을 if 문의 형식으로 표시하면 다음과 같다.

형 식

if  ( 조건식 )
     명령문 1 ;
 else
     명령문 2 ;

 

a = ( b ? ( c = d ) : ( c = e ) ) ;
b 가 참일 때 ( c = d ) 실행
b 가 거짓일 때 ( c = e ) 실행

 

두 개의 정수를 입력받아 큰 수를 출력하는 프로그램이다. 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  a , b , c ;
printf ( " 두 개의 정수를 입력하시오 : " ) ;
scanf ( " %d   %d " , &a , &b ) ;
c = ( a > b ) ? a : b ;
printf ( " a = %d , b = %d 일 때 큰수는 %d \n " , a , b , c ) ;

}

▶ 실행 결과
두 개의 정수를 입력하시오 : 2   5   Enter Button Push
a = 2 , b = 5일 때 큰 수는 5

 

 

< 콤마 연산자 ( Comma operator )>

콤마 연산자는 각 변수가 동일한 형태를 취하고 있을 때 동등 성격 또는 동등 자격
의 오퍼랜드를 열거하는 연산자이다. 콤마를 기준으로 왼쪽에서 오른쪽으로 순차적인
명령의 수행이 이루어진다. 예를 들어

int  i = 5 ;
int  j = 7 ;
int  k = 9 ;

에서 각 변수 i , j , k는 초기값으로 5 , 7 , 9의 값을 선언하고 있음을 알 수 있다. 이 세
변수는 동일한 형태를 취하고 있어 콤마 연산자를 이용하여 다음과 같이 나타낼 수 있다.
int i = 5 , j =7 , k =9 ;
또한 , 콤마 연산자는 두 개의 대입식을 하나의 수식으로 압축할 때나 for 문의 루프
제어 변수가 두 개 이상일 때에도 사용된다.

두 수 2와 3을 입력받았을 때 콤마 연산자를 이용한 다음의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  x , y , tot ;
scanf ( " %d   %d " , &x , &y ) ;
tot = ( x +=2 , y <<=2 , x+=y ) ;
printf ( " tot = %3d \n " , tot ) ;
printf ( " y = %3d \n" , y = ( y=0 , x+y , x+4 ) ) ;

}

▶ 실행 결과
2 Enter Button Push
3 Enter Button Push
tot = 16
y = 20

 

< cast 연산자 ( Cast operator ) >

이미 지정된 데이터형을 다른 데이터형으로 강제로 바꾸고자 할 때 사용하는 연산자
로 일반 형식은 다음과 같다.

형 식
( 데이터 형 ) 변수 ;

이 때 cast 연산자는 해당되는 줄에서만 일시적으로 변수를 지정된 형태의 데이터형
으로 바꾼다. 이 연산자는 단항 연산자보다는 우선 순위가 높고 오른쪽에서 왼쪽으로
결합이 이루어진다.

int  a ;

b = ( char ) a ;

위의 예는 정수형 변수 a 의 자료형을 강제로 문자형으로 변환시키는 과정을 보여 주
고 있다.

다음 프로그램 실행 결과를 나타내시오.

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  a ;
float  b , c ;
b = 3.123 ;
c = 9.987 ;
a = ( int )b + ( int )c ;
printf ( " a = %d \n " , a ) ;

}

▶ 실행 결과
a = 12

 

< sizeof 연산자 ( sizeof operator ) >

sizeof 연산자는 변수나 수식 또는 데이터형 , 배열 , 문자열 , 구조체와 공용체 등 어떤
대상의 값을 기억 장소에 기억시키는 데 필요한 크기를 바이트 ( byte ) 수로 나타내 주
는 연산자로서 일반 형식은 다음과 같다.

형 식
sizeof ( 식 1 ) ;

이때 식1 은 변수 , 데이터형 , 수식 등을 의미한다.
예들 들어 , int 형은 2 바이트 또는 4 바이트 , float 형은 4 바이트 등의 길이를 가지고 있
다. 그러면 int , char , float , long , double 형에 대하여 sizeof 연산자를 사용하여 현재 사
용 중인 시스템에서 표현되는 바이트 수를 확인해 보자.

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

printf ( " 데이터형이 int 인 경우 = %d  Byte \n " , sizeof ( int ) ) ;
printf ( " 데이터형이 char 인 경우 = %d  Byte \n " , sizeof ( char ) ) ;
printf ( " 데이터형이  float 인 경우 = %d  Byte \n " , sizeof ( float ) ) ;
printf ( " 데이터형이 long 인 경우 = %d  Byte \n " , sizeof ( long ) ) ;
printf ( " 데이터형이 double 인 경우 = %d  Byte \n " , sizeof ( double ) ) ;

}

▶ 실행 결과
데이터형이 int 인 경우 = 4 Byte   //  시스템에 따라 다르다.
데이터형이 char 인 경우 = 1 Byte
데이터형이 float 인 경우 = 4 Byte
데이터형이 long 인 경우 = 4 Byte
데이터형이 double 인 경우 = 8 Byte

 

< 주소 연산자와 간접 연산자 >

1. 주소 연산자 ( & )

주소 연산자 ( address operator : & ) 는 단항 연산자로서 변수의 바로 앞에 붙어서
그 변수가 메모리 내에 위치하고 있는 주소 ( address ) 를 나타낸다. 결합은 오른쪽에서
왼쪽으로 이루어지며 일반 형식은 다음과 같다.

형 식
& 변수명

예를 들어 변수 a 와 c 가 프로그램에서
int  a = 5 ;
char  c = ' A ' ;
와 같이 선언되었다면 메모리 내에 정수형 변수인 a 는 2 바이트 길이로 , 문자형 변수
c 는 1 바이트 길이로 값이 기억되어 있을 것이다. 이것을 다음과 같이 그림으로 나타
내었다.


1000  1001  1002     1010   1011 1012 1013    1014  
                 
        A      
 변수 a     변수 c   변수명 

여기서  &a 는 변수 a 의 주소 즉 1000번지를 나타내고 , &c 는 변수 c 의 주소 1011 번
지를 나타내는 수조 상수들이다.

2. 간접 연산자 ( * )

간접 연산자 ( indirection operator : * )는 당항 연산자로 포인터 ( pointer ) 앞에 붙어
서 포인터가 가리키는 주소에 기억되어 있는 내용 즉 , 데이터 값을 나타낸다. 결합은
오른쪽에서 왼쪽으로 이루어진다. 간접 연산자의 일반 형식은 다음과 같다.

형 식
 * 포인터

포인터 변수는 일반적인 데이터 값을 기억하는 것이 아니라 변수들의 주소를 기억하
는 것읻. 포인터 변수의 선언 형식은 다음과 같다.

형 식
데이터형 * 포인터변수 ;

예를 들어
int  num = 10 ;
int  *ptr ;
ptr  = &num ;

과 같이 포인터 변수를 선언하였을 경우에 , 포인터 변수 ptr 에 기억되어 있는 주소가
가리키는 곳에는 정수형 데이터가 있다는 것을 의미한다. 즉 , 포인터 변수 ptr 은 정수
형 변수의 주소들만 기억시킬 수 있는 포인터 변수임을 의미한다. ptr = &num ; 은 포
인터 변수 ptr 에 변수 num 의 주소인 &num 이 기억되어 있다는 것을 의미한다. *ptr
은 포인터 변수 ptr 에 기억되어 있는 주소가 가리키는 곳에 기억된 데이터의 값, 즉 변
수 num에 기억된 값 10을 간접 연산자를 이용하여 나타낸 것이다. 이것을 그림으로
나타내면 다음과 같다.

1000  1001
       
1000   5

 

다음 프로그램의 실행 결과를 나타내시오

▶ 프로그램

# include  < stdio.h >

void main ( void )
{

int  i , j , *ptr ;
i = 10 ;
ptr = &i ;
j = *ptr ;
printf ( " = %d \n j = %d \n " , i , j ) ;

}

▶ 실행 결과
i = 10
j = 10

위의 프로그램에서 포인터 변수 ptr 은 i 의 주소를 기억하게 되며 , *ptr 은 i 의 주소에
기억되어 있는 값 즉 , 변수 i 의 값인 10을 의미한다.