어떤 변수가 함수 내에서 선언되는 경우, 그 변수는 지역변수라고 불린다. 지역변수는 기본적으로 다음과 같은 특징을 가진다.
첫 번쨰는 자동저장기간(auto storage duration)이다. 변수는 저장되어 존재하는 동안, 프로그램의 한 부분이다. 지역변수는 함수가 실행 될 때, 자동적으로 저장공간이 할당되고, 함수가 종료될 때, 자동적으로 할당이 사라진다. 즉 함수가 다시 호출되었을 때, 해당 변수는 이전에 가지고 있던 값을 더이상 가지고 있지 않는다.
두 번째는 블록 스코프(Block scope) 다. 변수의 스코프는 변수가 참조될 수 있는 프로그램 텍스트 내의 부분을 의미한다. 지역변수는 블록 스코프를 가진다. 그렇기때문에, 지역변수는 함수 바깥에서 참조될 수 없다.
C99에서는 변수가 함수의 시작부분에서 선언될 것을 요구하지 않는다. 즉 만약 함수 후단에서 변수가 선언된다면, 그만큼 변수는 좀은 스코프를 가지게 되는 것이다.
지역변수는 자동저장기간을 가지고 있으나 static을 변수 자료형 앞에 붙여서 사용하면, 저장 기간을 항구적으로 만들 수 있다. 즉 함수가 종료되더라도 메모리에 해당 변수의 값이 계속 존재하는 것이다.
물론 지역변수는 블록스코프를 가지고 있기 때문에 함수 바깥에서 참조할 수는 없다. 하지만 훗날 다시 같은 함수가 호출 될 때 사용될 수 있다.
입력변수를 전달하는 것은 함수에게 정보를 전달하는 방법 중 하나다. 그 밖에도 함수는 전역변수를 통해 정보를 주고받을 수 있다. 이 전역변수는 함수 바깥에서 선언되며, 다음과 같은 특징을 가진다.
첫 번째, 정적저장기간(static storage duration). 이는 지역변수에 static이 사용된 것과 같은 효과를 가진다.
두 번째, 파일 스코프(File scope) 전역변수는 파일 스코프를 가진다. 즉 전역변수는 프로그램 내 어디서든 참조가 가능하다.
거의 단점만 이야기한 것 같은데, 그만큼 전역변수 사용은 조심해야한다. 전역변수의 선언은, 코드를 읽는 사람으로 하여금 특정한 목적을 가지고 있다고 오해하게 만들 수 있다.(그러려는 목적이 작성자에게 없었음에도 불구하고!). 따라서 전역변수의 작명을 할 때에는, 의미있는 이름을 가지도록 해야한다. 그러니까 전역변수에 i나 temp같은거 쓰지 말라고. 다음은 전역변수로 인해 버그가 발생하는 코드다.
int i;
void print_one_row(void)
{
for (i = 1; i <= 10; i++)
printf ("*") ;
}
void print_all_rows(void)
{
for (i = 1; i <= 10; i++) {
print_one_row(); printf("\n");
}
}
우리는 이미 앞서서 {}을 활용한 복합구문, 즉 블록을 살펴봤다. 기본적으로 이 블록 안에서 선언되는 함수는 자동저장기간을 가지며, 블록 바깥에서 참조될 수 없다. 즉 함수 내부는 블록이다. 이렇게 블록 내에서 변수를 선언하는데에는 두 가지 이점이 있다. 1: 잠깐 이용할 변수를 번복적으로 선언하는 것을 방지해준다. 2: 식별자, 즉 이름 충돌을 방지해준다.
같은 식별자라고 하더라도, 여러가지의 의미를 가질 수 있다. C언어의 스코프 룰은 식별자가 나타나는 위치에 따라 다른 값을 가질 수 있게 만든다. 이렇게 코드를 짜면 안되겠지만 극한의 예시를 보여주겠다.
int i;
void f(int i)
{
i = 1;
}
void g(void)
{
int i = 2;
if(i > 0) {
int i;
i = 3;
}
i = 4;
}
void h(void)
{
i = 5;
}
프로그램의 구성은 일반적으로 다음과 같다.
- #include, #define 과 같은 지시자들에 대한 전처리
- 형정의
- 전역변수의 선언
- 함수 프로토타입 / 함수 선언
- 함수 정의
함수를 정의할 때에는 main함수를 먼저 해주는 것이 일반적이다. 반드시 함수 선언 혹은 정의는 해당 함수의 호출 이전에 이뤄져야만 한다.