티스토리 뷰

 

 본 강좌는 아래 동영상 강좌와 같이 진행됩니다. 되도록이면 동영상과 같이 보시는 것을 추천합니다.

 

 유튜브 채널 가기

 

 강좌 18편 동영상 보기

 


 

 이번시간에는 변수의 사용 범위와 형태에 대해 알아보도록 하겠습니다.

 

 

 

 1. 전역변수와 지역변수

 

 ◆ 지역 변수

 지금까지 우리가 사용한 변수들은 메인 함수의 중괄호 첫부분에 선언하여 사용해왔습니다. 이렇게 선언된 변수는 메인 함수의 마지막 부분, 그러니까 메인 함수의 중괄호가 끝나는 부분에서 소멸하게 됩니다.

 

#include <stdio.h>

 

void main()

{

int a = 0;     // int형 변수 a를 선언

...

}                  // 변수 a 소멸

 

 이렇게 중괄호로 묶인 블럭 안에서 선언된 변수는 블럭의 끝, 그러니까 중괄호가 닫히는 부분에서 소멸하게 되는데 이런 변수를 '지역 변수' 라고 합니다. 전체가 아닌 지역에서만 사용할 수 있다는 의미입니다.

 

 다음의 예를 봅시다.

 

void main()

{

int a = 100;

 

{

int a = 200;

 

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

}

 

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

}

 

실행 결과

 

200

100

 

 간단하게 변수 a를 선언하여 출력해 보았습니다. 중간에 중괄호를 하나 만들어서 이름이 같은 a라는 변수를 만들어주고 그 안에 200을 넣어주었습니다. 보통의 경우 이름이 같은 변수를 선언할 수 없지만, 중괄호로 묶인 블럭 내부에는 같은 이름으로 선언이 가능합니다. (프로그래밍을 하는 과정에서 혼동이 올 수 있으므로 가급적 이렇게 사용하는 것을 권장하지는 않습니다.) 이렇게 같은 이름으로 선언된 a가 있으면 중괄호 밖에서 선언한 100을 초기값으로 갖는 변수 a는 무시하고, 중괄호 내에서 선언한 200을 초기값으로 갖는 변수 a를 사용하게 됩니다.

 

 중괄호를 빠져나간 다음에는 블럭 안의 200을 초기값으로 갖는 변수 a는 소멸하고, 위에서 선언한 100을 초기값으로 갖는 변수 a를 사용하게 되므로 마지막 printf()문은 100을 출력하게 됩니다.

 

 이렇게 '지역 변수'는 중괄호로 묶인 블럭 단위로 사용되며 소멸한다는 것을 기억하시기 바랍니다.

 

 ◆ 전역 변수

 다음의 예를 봅시다.

 

#include <stdio.h>

 

void func()

{

 

}

 

void main()

{

 

}

 

 메인 함수 이외에 func()라는 함수가 있습니다. 이 두 함수가 어떤 변수를 같이 사용하고자 할때는 위에서 설명한 지역변수로는 불가능합니다. 왜냐하면 메인 함수에서 선언한 변수는 메인 함수 내에서만 사용이 가능하고 그 반대의 경우도 마찬가지이기 때문입니다.

 

 이럴때는 다음과 같이

 

#include <stdio.h>

 

int a = 0;

 

void func()

{

 

}

 

void main()

{

 

}

 

 어느 중괄호 안에도 속하지 않은 맨 위에 변수를 선언할 수 있습니다. 이럴 경우 위의 int형 변수 a는 메인 함수 뿐만 아니라 func() 안에서도 같이 사용할 수 있습니다. 이렇게 선언할 경우 변수 a는 프로그램이 완전히 종료가 되는 시점에 소멸하며, 지역 변수처럼 프로그램 실행 중간에 소멸하지 않습니다. 이렇게 선언한 변수는 전체에서 사용할 수 있다고 해서 '전역 변수' 라고 합니다.

 

int a = 0;

 

void func()

{

a++;

}

 

void main()

{

func();

 

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

}

 

실행 결과

 

1

 

 변수 a를 func()안에서 하나 증가시켜 주었고, 메인 함수에서 출력을 했습니다. 이처럼 전역 변수는 어느곳에서나 값을 변경할 수 있고, 읽을 수 있습니다.

 

 지역 변수는 선언했을때 어떤 값이 들어있을지 모르기 때문에 반드시 초기화를 해주었지만, 전역 변수는 자동으로 0의 값으로 초기화가 됩니다.

 

#include <stdio.h>

 

char str[20]

char str[20];

 

void main()

{

printf("%d, %s\n", a, str);

}

 

실행 결과

 

0,

 

 위의 예처럼 전역 변수는 자동으로 '0'으로 선언과 동시에 초기화가 됩니다. 문자열 곁은 경우에도 널문자가 아스키코드상 '0'이므로 널문자로 초기화한 것과 같은 결과가 나옵니다.

 

 정리하자면

 

지역 변수

블럭 안에 선언하여, 블럭 안에서만 사용한다.

블럭이 끝나면 변수도 사라진다.

선언시의 초기값은 어떤 값일지 모른다.

 

전역 변수

블럭 밖에 선언하여 전체 함수에서 사용한다.

프로그램이 종료될때 사라진다.

선언시의 초기값은 0 이다.

 

 이렇게 정리할 수 있습니다.

 

 처음 배우는 분들 중에 간혹 모든 변수를 전역 변수로 선언하여 사용하는 경우도 심심찮게 볼 수 있는데 이것은 바람직하지 않습니다. 함수내에서 혹은 블럭 내에서만 쓰고 버릴 것은 지역 변수로 선언하고, 전체가 공유해야 하는 변수들은 전역 변수로 선언하여 사용하는 연습이 필요합니다.

 

 

 

 2. 정적 변수

 

 변수의 형태 중에는 '정적 변수' 라는 것이 있습니다. 선언은

 

static 자료형 변수명;

 

 일반적인 변수의 선언 앞에 'static'을 붙여주면 됩니다. 그 특징으로는

 

변수의 선언은 단 한번만 실행된다.

블럭이 끝나도 사라지지 않는다.

초기값을 넣어주지 않아도 0으로 초기화된다.

블럭 밖에서는 이 변수를 사용할 수 없다.

 

 지역 변수와 전역 변수의 특징을 모두 갖고 있습니다. 우선 아래 예를 봅시다.

 

void output()

{

int a = 0;

a++;

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

}

 

void main()

{

int i = 0;

 

for (i = 0; i < 5; i++)

output();

}

 

실행 결과

 

1

1

1

1

1

 

 다음과 같이 output() 함수를 만들어주었고, 메인 함수에서 다섯번만큼 반복하여 실행하였습니다. 매번 함수가 실행될 때마다 int형 변수 a를 생성하기 때문에 결과는 모두 1입니다. 그런데 output() 안의 변수 a를 '정적 변수'로 선언하면 결과가 달라집니다.

 

void output()

{

static int a = 0;

a++;

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

}

 

void main()

{

int i = 0;

 

for (i = 0; i < 5; i++)

output();

}

 

실행 결과

 

1

2

3

4

5

 

 일반 변수와는 달리 정적으로 선언된 변수 a는 선언하는 부분이 단 한번만 실행이 되며, 함수가 끝나도 사라지지 않습니다. 그래서 반복적으로 output()을 호출했어도 이전에 증가한 변수의 값이 남아있기 때문에 하나씩 증가한 결과가 나오게 됩니다.

 

 위에서 일반 변수라고 이야기한것은 사실은 '자동 변수' 라고 해서

 

auto int a = 0;

 

 와 같이 변수를 선언할때 앞에 'auto'를 붙여주는 것을, 굉장히 많이 쓰기 때문에 생략한 것입니다. 이것은 자동으로 변수를 생성하고 블럭의 끝에서 소멸시키라는 의미입니다. 한마디로 일반 지역 변수는 자동 변수인 것입니다.

 

 

 

 

 3. 성적관리 프로그램에 적용

 

 그러면 지난시간에 알아본 '함수'와 이번시간에 알아본 '전역 변수'를 성적관리 프로그램에 사용해 봅시다. 기본적으로 이 프로그램은 다음과 같은 구조를 가집니다.

 

입력

계산

출력

 

 이 구조에 맞게 각각 함수를 만들어 볼 것입니다. 그 전에 지역 변수로 선언된 것들 중에서 전역 변수로 선언할 만한 것들을 먼저 추려 선언해 보겠습니다.

 

char name[20][20] = {'\0'};   // 이름

int scoreKOR[20] = {0};       // 국어점수

int scoreMAT[20] = {0};      // 수학점수

int scoreENG[20] = {0};      // 영어점수

int scoreSCI[20] = {0};      // 과학점수

char *comment[20] = {NULL};     // 평가

 

 이것들은 프로그램 전반에 걸쳐 사용하는 학생 성적처리의 중요한 데이터이기 때문에 전역 변수로 선언해 주었습니다. 다음은 '입력 함수'를 만들어 보겠습니다.

 

int inputGrade(int index)

{

char temp[1024] = "\0";   // 임시 저장
int len = 0;                     // 문자열 길이

 

do

{

printf("이름을 입력하세요 : ");

scanf_s("%s", temp, sizeof(temp));

len = strlen(temp) + 1;

 

if (len > sizeof(name[index]))

printf("너무 긴 이름을 입력하셨습니다.\n");

else

strcpy_s(name[index], sizeof(name[index], temp);

} while (len > sizeof(name[index]));

 

printf("국어점수를 입력하세요 : ");

scanf_s("%d", &scoreKOR[index]);

printf("수학점수를 입력하세요 : ");

scanf_s("%d", &scoreMAT[index]);

printf("영어점수를 입력하세요 : ");

scanf_s("%d", &scoreENG[index]);

printf("과학점수를 입력하세요 : ");

scanf_s("%d", &scoreSCI[index]);

 

getchar();

 

printf("평가를 입력하세요 : ");

gets_s(temp, sizeof(temp);

len = strlen(temp) + 1;

comment[index] = (char*) malloc(len);

strcpy_s(comment[index], len, temp);

 

return 0;

}

 

 원래 만들어둔 입력 부분을 그대로 복사해 넣어주었습니다. 다음은 '계산 함수'를 만들어보겠습니다.

 

int calcGrade(int index, int *scoreTotal, float *scoreAverage, char *grade)

{

// 총점 계산

*scoreTotal = scoreKOR[index] + scoreMAT[index] + scoreENG[index] + scoreSCI[index];

// 평균 계산

*scoreAverage = (float) *scoreTotal / 4;

 

// 평균값에 대응하는 등급 구하기

if (*scoreAverage >= 90)

*grade = 'A';

if (*scoreAverage >= 80)

*grade = 'B';

if (*scoreAverage >= 70)

*grade = 'C';

if (*scoreAverage >= 60)

*grade = 'D';

else

*grade = 'F';

 

return 0;

}

 

 역시 계산하는 부분을 그대로 복사해 넣었습니다. 계산된 값을 다른 함수에서 사용할 수 있도록 인자를 포인터로 선언하였고, 수정된 곳은 빨간색으로 표시해 두었습니다.

 

 마지막으로 '출력 함수'를 만들어 봅시다.

 

int outputGrade(int index)

{

char grade = 0;

int scoreTotal = 0;

float scoreAverage = 0.0F;

 

calcGrade(index, &scoreTotal, &scoreAverage, &grade);

 

// 화면 출력

printf("%s\t\t",name[index]);

printf("%c\t", grade);

printf("%d\t", scoreKOR[index]);

printf("%d\t", scoreMAT[index]);

printf("%d\t", scoreENG[index]);

printf("%d\t", scoreSCI[index]);

printf("%d\t%.1f\t", scoreTotal, scoreAverage);

printf("%s\n", comment[index]);

 

return 0;

}

 

 역시 출력부분을 그냥 붙여넣었고, 그 전에 만들어놓은 calcGrade()를 사용하여 계산을 해 주었습니다. 이제 메인 함수를 수정해 봅시다.

 

void main()

{

int index = 0;            // 입력받을 배열위치

char menuChoice = '\0';        // 메뉴 선택

 

do

{

// 메뉴 출력

printf("*** 성적관리 프로그램 ***\n");

printf("\n");

printf("1. 학생 성적 입력\n");

printf("2. 성적 확인\n");

printf("\n");

printf("Q. 프로그램 종료\n");

printf("\n");

printf("작업할 번호를 입력하세요 : ");

 

// 메뉴 선택

menuChoice = getchar();

 

switch (menuChoice)

{

case '1':

{

inputGrade(index);

 

index++;

}

break;

 

case '2':

{

int i = 0;

 

// 상단 출력

printf("이름\t\t등급\t국어\t수학\t영어\t과학\t총점\t평균\t평가\n");

printf("----------------------------------------------------------\n");

 

for (i = 0; i < index; i++)

outputGrade(i);

 

getchar();

}

break;

 

case 'Q':

case 'q':

break;

 

default:

{

printf("잘못 입력하셨습니다.\n\n");

getchar();

}

}

} while (menuChoice != 'Q' && menuChoice != 'q');

 

while(index)

{

index--;

free(comment[index]);

}

}

 

 이렇게 각각의 기능별 함수로 코드가 분리 되어 메인 함수가 간단해졌습니다. 그리고 각 기능을 수정하기 위해서는 이제 해당 함수만 고치면 되기 때문에 프로그래밍을 하는데 있어 더욱 편리해졌습니다.

 

 이번시간에는 전역변수와 지역변수, 정적변수와 자동변수에 대해 알아보았습니다. 다음시간에는 여러 변수들을 묶어 하나처럼 사용할 수 있는 구조체에 대해 알아보도록 하겠습니다.

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31