변수(Variable)

이인혁·2024년 5월 8일

C

목록 보기
11/23

1. 변수란?

C언어에서 바뀔 수 있는 어떤 값을 보관하는 곳을 변수 라고 합니다. 영어로는 Variable 이라 하는데, 말 그대로 바뀔 수 있는 것들 이라는 뜻입니다.

하지만 변수에도 다양한 종류의 변수가 존재합니다. 접근 범위, 존속 기간으로 변수를 구분하기도 합니다. 변수를 만드는 위치, 사용하는 키워드에 따라서 성격이 달라집니다. 이제부터 C언어에 존재하는 변수들에 대해서 소개해보려고 합니다.

2. 메모리

변수의 접근 범위, 존속 기간으로 변수를 구분한다고 했습니다. 놀랍게도 메모리에서 변수를 구분해서 각각의 영역에 공간을 할당해 줍니다.
간단하게 영역별로 어떤 변수들이 저장이 되는지 알아보겠습니다.

  • Stack영역 : 지역변수
  • Heap영역 : 동적변수
  • Code영역 : 함수
  • Data영역 : 전역변수 정적변수 상수형변수

저희가 알아볼 것은 Stack영역과 Data영역에 할당되는 지역변수, 전역변수, 정적변수에 대해서 알아보겠습니다.

3. 지역변수(로컬변수, 자동변수)

함수안에서 선언되는 변수입니다. 메모리 안에서 Stack영역에 공간을 할당받습니다. 중괄호 내에 선언된 변수로 닫는 중괄호를 만나 함수가 종료되면, 자연스럽게 없어집니다.
ex)

int add(int n1, int n2) {
    ...
    int n;// <-중괄호 내 범위에서만 n이 존재!
    ...           
    return 0;
}

4. 전역변수(외부변수)

메모리 내에서 Data영역에 공간을 할당받는 변수입니다. 프로그램 어디서나 접근이 가능합니다. 심지어 다른 파일에서도 접근이 가능합니다. 다른파일에서 전역변수에 접근할 때 외부에 있다는 선언을 해야합니다.(ex. extern int global;)

번외로 다른파일에서의 함수도 사용 가능합니다. 첫번째로 함수 선언을 그냥 하고 쓰거나 두번째로 헤더파일에 선언한 후 #include" " 로 선언한 후 씁니다.

전역 변수는 프로그램이 실행될 때 만들어지고 프로그램이 종료될 때 없어집니다. 전역변수는 될 수 있으면 사용하지 않는게 좋습니다.(권고) 만약 전역변수를 남용하게 된다면 나도 모르는 새에 다른파일에서 전역변수의 값을 바꿔버리는 참사가 발생할 수 있습니다. 해결하기 위해선 전역변수에 접근하는 모든파일을 다 훑어봐야 하기 때문에 오류찾기가 힘들어집니다.

그래서 다른파일에서 접근하는 것을 막는 static변수로 선언하는 방법이 있습니다. 그건 밑에서 다시 설명해드리겠습니다. 따라서 전역변수는 정의된 파일에서만 접근하도록 하는 것이 좋습니다.

지역변수와 전역변수의 이해를 위한 간단한 코드를 설명해드리겠습니다.
ex)
global.h

void PrintGlobal2();
void SetGlobal2(int value);

global.c

#include <stdio.h>

extern int global;//global이라는 변수가 외부에 있어라는 정보를 제공

void PrintGlobal2() {
	printf("PrintGlobal2 global = %d\n", global);
}

void SetGlobal2(int value) {
	global = value;
}

main.c

#include "global.h"
int global = 0; 

void PrintGlobal() {
    printf("PrintGlobal Function global = %d\n", global);
}

int main() {
    int a;//지역변수(로컬변수), 자동변수
    a = 20;

    int b = 20;
    {
        int a;//지역변수(로컬변수), 자동변수
        a = 200;

        int c = 1000;

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

    //c = 2000; c변수는 자신이 정의된 범위가 닫혔기 때문에 없어졌습니다.

    global = 200000;//전역변수는 프로그램 어디서나 접근이 가능합니다.

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

    SetGlobal2(40000);
    PrintGlobal2();

    return 0;
}

결과

a = 200, b = 20, c = 1000
global = 200000
PrintGlobal2 global = 40000

5. 매개변수(지역변수)

함수를 호출할 때 인자값을 받는 매개변수는 메모리 내에서 Stack영역에 공간을 할당받는 지역변수입니다. 매개변수도 지역변수와 동일한 함수를 반복할 때마다 할당받았다 지워졌다 합니다. 매개변수도 지역변수와 동일한 성질을 가지고 있습니다.

#include <stdio.h>

void func3(int a) {
    int temp = 100;
}

void func2(int a) {
    int temp = 20;
    func3(a);
    int temp2 = 30;
}

void func(int a) {
    int temp = 100;
    func2(a);
    int temp2 = 200;
}

int main() {
    int a = 1000;

    func(a);
    int b = 2000;
    return 0;
}

이런 코드가 있다고 생각하겠습니다. 일단 main함수가 entry point(진입점)이므로 main함수부터 실행이 됩니다. 할당받는 순서를 알면 이해하기가 쉬워집니다.
1. Stack에 main함수의 지역변수 a가 할당받는다.
2. Stack에 func함수의 매개변수 a가 할당받는다.
3. Stack에 func함수의 지역변수 temp가 할당받는다.
4. Stack에 func2함수의 매개변수 a가 할당받는다.
5. Stack에 func2함수의 지역변수 temp가 할당받는다.
6. Stack에 func3함수의 매개변수 a가 할당받는다.
7. Stack에 func3함수의 지역변수 temp가 할당받는다.
8. func3함수의 지역변수 temp가 소멸하고, 매개변수 a가 소멸한다.
9. Stack에 func2함수의 지역변수 temp2가 할당받는다.
10. func2함수의 지연변수 temp2가 소멸하고, temp가 소멸하고, 매개변수 a가 소멸한다.
11. Stack에 func함수의 지역변수 temp2가 할당받느다.
12. func함수의 지역변수 temp2가 소멸하고, temp가 소멸하고, 매개변수 a가 소멸한다.
12. Stack에 main함수의 지역변수 b가 할당받는다.
13. main함수가 종료되면서 b a순으로 소멸한다.

6. static 변수(정적변수)

변수앞에 static이 붙으면 전역변수는 다른 파일에서 접근하지 못하고, 지역변수는 다른 함수에서 접근하지 못합니다.

프로그램이 실행되고 선언되면, 프로그램이 종료할 때까지 메모리(Data영역)에 남아있습니다.(정적변수의 주소값을 하수 외부로 전달해서 사용하는 것은 괜찮습니다.)

지역변수의 주소값을 함수의 외부로 전달해서 사용하시면 안됩니다. 전달받은 주소값의 공간에 있는 값이 유지된다고 보장할 수 없습니다.

정적변수의 주소값을 함수 외부로 전달해서 사용하는 것은 괜찮습니다. 정적변수의 메모리공간은 프로그램 생명주기 내내 없어지지않고 공간의 값이 유지가 됩니다.
예시

#include <stdio.h>

int* SetScore(int value) {
	int sum = 0;//지역변수

	sum += value;

	return &sum; //지역변수의 주소값을 리턴함
}

int* PSetScore(int value) {
	static int sum = 0;//지역변수, 정적변수

	sum += value;

	return &sum; //정적변수의 주소값을 리턴함
}

int main() {
	
	printf("\nSetScore\n");
	int* pa = SetScore(100);

	printf("*pa = %d\n", *pa);
	printf("*pa = %d\n", *pa);
	printf("*pa = %d\n", *pa);

	
	printf("\nPSetScore\n");
	pa = PSetScore(100);
	
	printf("*pa = %d\n", *pa);
	printf("*pa = %d\n", *pa);
	printf("*pa = %d\n", *pa);
	return 0;
}

결과

    SetScore
*pa = 100
*pa = -858993460
*pa = -858993460

PSetScore
*pa = 100
*pa = 100
*pa = 100

정적변수는 프로그램이 종료될때까지 메모리에 남아있습니다. 그래서 함수를 반복적으로 꺼내서 초기화 시키는것은 불가능합니다. 따라서 위에 함수에서는 2번째 호출을한다고 가정했을때 0으로 초기화가 안됩니다.

profile
게임개발공부블로그

0개의 댓글