[ C 언어 스터디 ]

자료출처 : 핵심 길잡이 C 프로그래밍 언어
도서출판 : 성안당

8. 기억 클래스 ( Storage class )

C 언어에서는 메모리의 효율성을 높이기 위해 기억 장소를 메모리에 확보할 대 해당
변수의 크기뿐만 아니라 데이터를 저장하는 장소를 메모리 ( memory )와 레지스터
( register )중 어느 곳에 저장시킬 것인가를 결정할 수 있다. 그 변수의 유효 범위
( scope )를 기억 클래스( storage class )라 한다. 지금까지는 변수를 선언할 때,

int number ;
float tex ;

와 같이 데이터형만 선언해 주었으나, 변수를 선언하는 일반적인 형태는 다음과 같이
기억 클래스를 함께 선언해 주는 것이다.

형 식
기억클래스 데이터형 변수명 ;

기억 클래스는 auto, static, extern, register의 4가지 중 하나를 사용할 수 있으며,
기억 클래스가 auto인 경우에는 생략할 수 있다.

★ 자동 변수 ( Automatic variable ) ★

자동 변수는 함수나 그 함수 내의 블록 안에서 선언되는 변수이다. 자동 변수는 유효
범위가 그 함수 내부 또는 그 블록 안에만 국한되는 지역적인 변수( local variable ) 이
다. 즉 자동 변수는 그것이 선언된 함수나 블록이 실행되는 동안에만 기억 장소에 존
재하다가 제어가 그 함수나 블록을 벗어나면 소멸된다. 자동 변수의 선언 형식은 다음
과 같다.

형 식
auto 데이터형 변수명 ;

C 프로그램에서 사용하는 변수는 대부분 자동 변수이다. 기억 클래스를 선언하지 않
으면 auto가 생략된 것으로 간주한다. 자동 변수는 초기값을 주지 않으면 쓰레기 값을
가지며, 함수 외부에서 선언된 변수와 함수 내부에서 선언된 자동 변수가 이름이 같을
경우에는 함수 내부의 자동 변수가 우선한다.

자동 변수를 사용함으로써 얻을 수 있는 장점은 해당 내용이 스택 메모리 상에 일시
적으로 기억되기 때문에 메모리 공간을 절약할 수 있다는 것이다.

void main ( void )
{

int a ; // 변수 a 의 유효 범위
{

int b ; // 변수 b 의 유효 범위
{

int c ; // 변수 c 의 유효 범위

} // 변수 b 의 유효 범위

} // 변수 a 의 유효 범위

}


[ 그림 8 - 1 ] 자동 변수의 유효 범위

자동 변수의 유효 범위는 해당 변수가 선언된 블록뿐만 아니라 그 내부의 블록까지
포함한다.

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

▶ 프로그램
# include < stdio.h >
void main ( void )
{

int a = 1 ;
{

int a = 2 ;
{

int a = 3;
printf ( " a = %d \n " , a ) ;

}
printf ( " a = %d \n " , a ) ;

}

printf ( " a = %d \n " , a ) ;

}
▶ 실행 결과

a = 1
a = 2
a = 1

 


위의 프로그램은 main ( ) 함수 내에 3개의 블록이 있고, 각각의 블록에 a 라는 자동
변수가 하나씩 선언되어 있다. 이들은 변수명은 동일하지만 서로 독립적이어서 각 블록
내에서만 유효하다.

★ 정적 변수 ( Static variable ) ★

정적 변수 역시 자동 변수와 마찬가지로 그것이 선언된 함수 또는 해당 블록 내에서
만 사용 가능하다. 단, 프로그램이 실행되면 프로그램이 종료할 때까지 선언된 변수의
기억 장소가 확보되기 때문에 그 함수가 종료되더라도 변수는 소멸되지 않고 그 값이
기억 장소에 계속 존재한다.

함수나 블록의 내부에서 선언되어 유효 범위가 그 변수가 선언된 함수나 블록 내에
국한되는 내부 정적 변수 ( internal static variable )와, 함수의 외부에서 선언되어 유효
범위가 그 변수가 선언된 이후부터 그 파일의 끝 ( end of file )까지 영향을 미치는 외부
정적 변수 ( external static variable )가 있다.

정적 변수는 유효 범위가 제한되어 있지만 프로그램이 종료될 때까지 계속해서 기억
장소에 존재하므로 함수나 블록이 다시 호출될 경우에도 그 이전의 값을 보존하고 있
다. 정적 변수의 선언 형식은 다음과 같다.

형 식
static 데이터형 변수명 ;

자동 변수는 프로그램이 실행될 때마다 초기값이 새롭게 부여되지만, 정적 변수는
컴파일 시에 한 번만 초기값이 부여된다. 초기값을 부여하지 않으면 char 형 변수는 널
문자 ( '\0', null character ), int형 변수는 0(zero), float형 변수는 0.0과 같이 데이터형
에 따라 초기값이 자동으로 부여된다.

정적 변수의 유효 범위는 다음과 같다.

static int a ; // 변수 a 의 유효 범위 시작
void main ( void )
{

sub1 ( ) ;

} // 변수 a 의 유효 범위 끝

sub1 ( )
{

static int b ; // 변수 b 의 유효 범위 시작

}


[ 그림 8 - 2 ] 정적 변수의 유효 범위

여기서 외부 정적 변수 a 는 main ( ) 함수와 sub1 ( ) 함수에 모두 통용되는 변수이다.
그러므로 main ( ) 함수와 sub1 ( ) 함수간의 데이터 전달은 인수를 통하지 않고 외부 정
적 변수를 사용하여 전달할 수도 있다. 그러나 이와 같은 방법은 함수간의 독립성을 떨
어뜨려 부작용의 원인이 되기 쉬워 사용하지 않는 것이 좋다.

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

▶ 프로그램
# include < stdio.h >
void sum ( int x ) ;
void main ( )
{

int a ;
for ( a = 1 ; a <= 4 ; a++ )
sum ( a ) ;

}

void sum ( int x )
{

static int y = 0 ;
y += x ;
printf ( " y = %d \n " , y ) ;

}

▶ 실행 결과

y = 1
y = 3
y = 6
y = 10

 


sum ( ) 함수가 호출될 때마다 y에 매개변수의 값 ( 즉 가인수 x 의 값 )이 더해진다.

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

▶ 프로그램
# include < stdio.h >
void sub ( )
{

static int i = 1 ;
auto int j = 1 ;
printf ( " i = %d  j = %d \n " , i , j ) ;
i++ ;
j++ ;

}
void main ( void )
{

int k ;
printf ( " static    auto \n" ) ;
printf ( " --------------- \n " ) ;
for ( k = 0 ; k < 3 ; k++ )
sub ( ) ;

}

▶ 실행 결과

static    auto
---------------
i = 1 j = 1
i = 2 j = 1
i = 3 j = 1


★ 외부 변수 ( External variable ) ★

외부 변수는 함수의 외부에 기억 클래스 없이 정의되고 어떤 함수라도 참조할 수 있
는 전역 변수 ( global variable )이다. 이 변수는 프로그램이 실행되면 기억 장소가 확보
되고 그 함수의 처리가 종료되어도 변수가 소멸되지 않고 그 값을 영구적으로 기억한
다. 외부 변수가 정의되었을 때 그 외부 변수를 사용하기 위해서는 외부 변수를 선언하
여야 한다. 외부 변수의 선언 형식은 다음과 같다.

형 식
extern 데이터형 변수명 ;

외부 변수가 그 변수를 사용하는 함수 이전에 정의되면 외부 변수 선언을 생략할 수
있다. 그러나 외부 변수가 그 변수를 사용하는 함수 이후에 정의되어 있거나 다른 파일
안에 정의되어 있는 경우에는 외부 변수를 선언하여야 한다. 외부 변수는 프로그램에서
단 한 번 정의되어야 하며, 그 외부 변수를 참조하기 위한 외부 변수의 선언은 여러 곳
에서 사용될 수 있다. 즉 정적 변수 ( static variable )는 선언된 함수 내에서만 사용이
가능한 반면에 외부 변수 ( extern variable )는 어떤 함수 내에서도 참조가 가능하다.

외부 변수를 정의할 때 초기값을 부여할 수도 있다. 이때 초기값을 생략하면 정적 변
수와 동일하게 데이터형 따라 초기값이 자동으로 부여된다.

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

▶ 프로그램
# include < stdio.h >
int a = 100 ;
void main ( void )
{

extern int a ;
extern int b ;
printf ( " a = %d   b = %d \n " , a ,b ) ;

}
int b = 200
▶ 실행 결과

a = 100   b = 200

 



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

▶ 프로그램
# include < stdio.h >
void chage ( ) ;
int a , b ;
void main ( )
{

printf ( " 두 수를 입력하시오 => " ) ;
scanf ( " %d %d " , &a , &b ) ;

change ( ) ;

printf ( " 교환된 값 => %d %d \n " , a , b ) ;

}
void change ( )
{

int temp ;
temp = a ;
a = b ;
b = temp ;

}
▶ 실행 결과
두 수를 입력하시오 => 5  7 Enter Button Push
교환된 값 => 7  5



다음 프로그램의 실행 결과를 나타내시오
▶ 프로그램
# include < stdio.h >
int x = 1 ;
void sub1 ( )
{

x++ ;
printf ( " sub1 -> x = %d \n " , x ) ;

}
void sub2 ( )
{

x++ ;
printf ( " sub2 -> x = %d \n " , x ) ;

}
void sub3 ( )
{

extern int x ;
x++ ;
printf ( " sub3 -> x = %d \n " , x ) ;

}
void main ( )
{

int x = 1 ;
sub1 ( ) ;
sub2 ( ) ;
sub3 ( ) ;
printf ( " main ( ) -> x = %d \n " , x ) ;

}
▶ 실행 결과

sub1 -> x = 2
sub2 -> x = 3
sub3 -> x = 4
main ( ) -> x = 1

 

★ 레지스터 변수 ( Register variable ) ★

레지스터 변수는 함수 내에서 정의되고 해당 함수 내에서만 사용이 가능한 변수이
다. 레지스터 변수가 선언된 함수가 호출되면 레지스터가 할당되고, 함수가 종료되면
자동 변수와 같이 소멸되므로 자동 변수와 비슷하나 기억 장소가 레지스터라는 점이
다르다.

레지스터 변수는 항상 int 로 선언되어야 하며, 레지스터의 사용 개수는 한정되어 있다.
따라서 변수를 레지스터 변수로 선언하였다. 하더라도 레지스터를 할당할 수 없는 경우에
는 자동 변수로 취급되어 메모리에 할당된다. 레지스터 변수의 선언 형식은 다음과 같다.

형 식
register 데이터형 변수명 ;

레지스터 변수의 초기화는 자동 변수와 같이 호출할 때마다 행해지며 초기화가 행해
지지 않으면 쓰레기 값이 할당된다. 프로그램이 자주 사용되는 변수를 레지스터 변수
로 선언하면 수행 속도를 높일 수 있다.

다음 프로그램의 실행 결과를 나타내시오
▶ 프로그램
# include < stdio.h >
void main ( void )
{

register int i , sum ;
for ( i=sum=0 ; i <= 100 ; i++ )
sum += 1 ;

printf ( " 합계 = %d \n" , sum ) ;

}
▶ 실행 결과
합계 = 5050


다음 프로그램의 실행 결과를 나타내시오
▶ 프로그램
# include < stdio.h >
static int x ;
void main ( void )
{

extern int y ;
static int z ;
auto int m = 0 ;
register int n = 0 ;
printf ( " x=%d \t y=%d \t z=%d \t m=%d \t n=%d \n " , x , y , z , m , n ) ;

}
int y ;
▶ 실행 결과

x=0 y=0 z=0 m=0 n=0

 


정적 변수와 외부 변수는 초기화하지 않을 경우 자동으로 초기값이 부여된다. 그러
나 자동 변수와 레지스터 변수는 초기화하지 않을 경우 쓰레기값을 가진다.