Category (Click)
개발보드 덕질하기
📦

[변수] 박스 그 자체

이전까지 변수의 종류인 자료형에 대해 알아보았으니 이제는 이걸 사용할 차례입니다.
우선 변수는 아래와 같은 방식으로 선언(declaration)합니다.
앞선 [자료형] C언어의 기본!자료형의 이름을 먼저 작성하고 그 뒤에는 변수의 이름을, 그 뒤에는 코드 한 줄 이 끝났음을 의미하는 세미클론(;)을 입력합니다.
이렇게 변수를 생성하게 되면 메모리에는 자료형의 크기 만큼의 공간이 생기고 그 공간이 변수의 이름인 foo와 연결되는데요, 처음 변수를 생성하면 그 공간 안에는 소위 “쓰레기 데이터”라 부르는 일정하지 않은 값이 들어있게 됩니다. 변수를 선언한 후 처음 값을 설정하는 행위를 init(initialization, 초기화) 과정이라 합니다.
쓰레기 데이터(garbage value)는 이전에 사용하던 프로그램에서 메모리를 사용하다가 반환한 공간의 데이터입니다. 새 프로그램에서 변수를 생성해 메모리를 할당받게 되면 그 위치가 이전 프로그램에서 할당한 위치와 반드시 동일하고 겹치는 것은 아니기 때문에 알 수 없는 데이터, 즉 쓰레기 데이터가 출력되는 것입니다. 만약 정말 우연으로 동일한 위치가 겹쳐버리면 유효한 데이터가 나오겠죠?
변수의 init을 위해서는 변수에 데이터를 저장하기 위해서는 변수의 이름과 대입 연산자 기호인 =, 변수에 넣을 데이터(숫자)를 입력하고 마찬가지로 끝에는 세미클론을 입력합니다.
물론 변수를 선언하며 init 과정을 거칠수도 있습니다. 위와 같이 변수 선언 과정에서 대입 연산자를 사용하면 변수를 선언하며 동시에 init을 진행합니다.
앞서 배운 자료형을 모두 변수로 선언하면 아래와 같습니다.

변수의 저장

앞서 [자료형] C언어의 기본! 에서 언급한것과 같이 모든 프로그램은 컴퓨터 메모리에 저장됩니다. 메모리의 구조를 그림으로 그리자면 아래와 같이 그릴 수 있습니다.
컴퓨터에서 어떤 숫자를 표현할 때에는 2진수를 사용하는데요, 0과 1의 상태를 나타낼 수 있는 가상의 스위치가 하나의 메모리 공간에 8개씩 존재합니다. 즉, 하나의 메모리 공간은 8개의 비트로 구성되어 있고 이 하나의 공간은 1 byte라는 크기를 가집니다.
왜 하필 1 byte = 8 bit 일까요?
이는 컴퓨터를 개발한 국가가 영어를 사용하는 미국이기 때문입니다. 뒤에서 설명하겠지만 컴퓨터에서 영문자를 표현하기 위해서는 ASCII 코드를 이용하는데요, 이 때 ASCII 코드표의 내용이 7 bit 로 나타낼 수 있는 128가지이며 문자를 전송할 때 오류를 검출하기 위해 하나의 패리티 비트를 사용합니다. 이때문에 하나의 영문자 당 8 bit를 사용하게 되었고 메모리의 단위로 정해지게 되었습니다.
8 bit를 표현할 수 있는 각 공간은 아파트의 호수와 같이 고유한 주소지를 가집니다. 이때 이 주소지는 16진수를 이용하며 0부터 시작해 메모리의 공간의 끝까지 부여되어 있습니다. 즉, 1번째 방은 0x0000이고 6번째 방은 0x000F, 17번째 방은 0x0010이 되겠죠.
다시 돌아와 메모리에 4라는 데이터를 저장한다면 위 그림과 같이 메모리에 저장되는데요, 그 과정을 사람한테 친숙하도록 대략적으로 설명하면 아래와 같습니다.
1.
10진수인 4를 2진수로 변환
4 ⇒ 100
2.
메모리는 8 bit이기 때문에 앞에 0을 5개 추가해 8비트짜리 2진수로 고침
100 ⇒ 00000100
3.
메모리의 비어있는 공간을 찾은 후 각 비트를 앞서 변환한 비트로 변경
0x0003의 첫번째 비트: 0
0x0003의 두번째 비트: 0
0x0003의 세번째 비트: 1
0x0003의 네번째 비트: 0
0x0003의 다섯번째 비트: 0
0x0003의 여섯번째 비트: 0
0x0003의 일곱번째 비트: 0
0x0003의 여덟번째 비트: 0
이때 메모리의 8개 비트를 모두 1로 설정한 것이 메모리의 한 공간에서 표현할 수 있는 가장 큰 숫자가 됩니다. 예를 들어 0x0002에 저장된 2진수 11111111를 10진수로 변환하면 255입니다.
앞에서 언급한 char형이 바로 1 byte의 공간을 가진다고 했었죠? char형은 위 사진에서 하나의 방 만큼의 크기를 가지고 이때문에 0~255, 또는 -127~126의 총 255단계를 저장할 수 있는 것입니다.
그렇다면 더 큰 데이터를 표현하기 위해서는 어떻게 해야할까요?
간단합니다. 옆의 벽을 허물어버린다고 생각하면 되는데요, 바로 옆에 있는 공간을 이어붙여 표현할 수 있는 숫자의 크기를 확장합니다. 위와 같이 0x0002과 0x0003을 함께 사용하면 0~65535까지, 총 65537단계를 표현할 수 있으며, 이는 short 자료형에 해당합니다.
마찬가지로 방을 4개 사용하면 4 byte의 int형, 8개 사용하면 8 btye의 long형이 되는것이죠.

전역 변수, 지역 변수

그럼 변수는 언제 메모리에 할당될까요? 그리고 언제 메모리에서 사라질까요? 우선 변수를 선언하는 위치에 따라 두 가지로 분류해 알아보겠습니다.

전역 변수

전역 변수는 main() 함수 밖에 선언되는 변수를 뜻합니다. 이렇게 선언된 변수는 프로그램의 실행과 동시에 메모리에 할당되고 프로그램이 종료될 때 메모리에서 삭제됩니다. 또한 전역 변수는 프로그램 안의 모든 위치에서 사용할 수 있습니다.
전역 변수는 생성과 동시에 init를 진행해야 하며, 만약 사용자가 init하지 않는다면 자동으로 0으로 init됩니다.
일반 전역 변수
자료형 앞에 아무런 키워드를 붙이지 않은 변수는 파일 안의 모든 위치는 물론, 파일이 전처리기인 #include로 include된 모든 파일에서 사용할 수 있습니다.
이는 매우 위험한데요, include한 다른 라이브러리의 전역변수를 수정해 의도치 않은 오류를 발생시킬 수 있습니다. 이러한 이유로 일반 전역 변수 대신 아래 설명할 정적 전역 변수를 사용하는것을 권장합니다.
외부 변수 (external variable)
외부 변수는 다른 파일에 선언된 일반 전역 변수외부 변수가 사용된 파일에서 참조(사용)하기 위한 변수입니다. 이를 위해서는 변수의 자료형 앞에 extern 키워드를 붙이고 참조할 다른 파일의 일반 전역 변수와 변수의 이름이 동일해야 합니다.
위 사진에서 test_function()함수를 실행하게 되면 test.c파일에서 만들어진 외부 변수를 통해 main.c의 변수를 수정하게 됩니다.
정적 전역 변수 (static variable)
전역변수를 선언할 때 자료형 앞에 static 키워드를 붙이면 정적 전역 변수로 선언됩니다. 이렇게 선언된 변수는 변수가 작성된 파일 안에서만 사용할 수 있고 다른 파일에서 외부 변수로 사용할 수도 없습니다.
정적 전역 변수를 사용하는 가장 큰 이유는 다른 파일의 전역 변수와 의도치 않게 겹치는 상황을 방지하기 위해서인데요, 아래 예시를 보겠습니다.
C언어에서는 모든 전역 변수를 extern으로 생성하는 성질이 있어 extern 키워드를 사용하지 않았다 하더라도 다른 파일의 이름과 겹치게 되면 의도치 않게 외부 변수로 작동할 수 있습니다.
여기서 main.c의 전역 변수를 static 키워드를 붙여 정적 전역 변수로 만들게 되면 test.c에서 만들어진 전역 변수는 test.c의 전역 변수로 생성되어 main.c에서 생성한 변수가 변하지 않게 됩니다.
만약 이 상태에서 test.c의 변수에 extern 키워드를 붙이면 test.c에서 main.c의 global_variable을 참조하려 하더라도 오류가 발생하게 됩니다.

지역 변수

지역 변수는 중괄호({}) 속에서 선언되는 변수를 뜻합니다. 지역변수는 중괄호 안에서만 사용할 수 있으며, 중괄호 밖에서는 사용할 수 없습니다.
지역 변수는 종류에 따라 크게 3가지로 분류할 수 있습니다.
자동 변수 (auto variable)
일반적으로 지역변수라 하면 자동 변수를 의미합니다. 자동 변수는 변수의 선언문에서 메모리에 할당되고, 선언문이 위치한 중괄호가 끝날 때 메모리 할당이 해제됩니다. 이러한 이유로 자동 변수는 메모리에서 해제된 이후에는 어떠한 방법으로도 다시 되살릴 수 없습니다.
정적 변수 (static variable)
정적 변수는 자동 변수와 동일하게 변수의 선언문에서 메모리에 할당되지만, 중괄호가 끝난다 하더라도 프로그램이 종료될 때 까지 메모리의 할당이 해제되지 않습니다. 또한 한 번 선언되면 반복문 등을 이용해 다시 한번 선언문이 실행된다 하더라도 선언되지 않고 무시됩니다.
정적 변수 또한 지역 변수의 일종이기 때문에 중괄호 밖으로 나가게 되면 변수의 이름으로는 참조할 수 없게 됩니다. 하지만 중괄호 밖으로 나갔다 하더라도 프로그램이 종료되기 전까지는 메모리에 존재하기 때문에 포인터 등을 활용하면 언제든지 참조할 수 있습니다.
이러한 정적 변수의 특성은 반복문 섹션과 포인터 섹션에서 다룰 예정입니다.
동적 변수 (dynamic variable)
메모장과 같은 텍스트 에디터를 켰을 때 작성한 모든 글씨는 메모리에 저장됩니다. 당연하게도 메모리가 부족하면 글을 더 이상 쓸 수 없겠죠. 그런데, 메모장이 켜졌을 때 사용자가 글씨를 얼마나 입력하는지 어떻게 알고 메모리를 할당받는것일까요?
이러한 상황에서 사용되는것이 바로 동적 변수입니다. 동적 변수는 상황에 따라 필요할 때 변수에 메모리를 할당하고, 필요하다면 할당된 용량을 즉흥적으로 확장할 수도 있습니다. 반대로 필요하지 않다면 사용하고 있는 메모리를 일부 해제할 수도 있습니다.
동적 변수를 사용하는 것을 동적 메모리 할당이라 하며 이후 동적 메모리 할당 섹션에서 다룹니다.
동적 변수는 프로그램이 실행되는 동안에도 메모리가 할당되거나 해제될 수 있습니다. 이는 메모리를 동적으로 할당하는 변수로, malloc() 함수를 이용하여 메모리를 할당받습니다.
이 변수는 다른 변수들과 달리, 프로그래머가 메모리를 할당하고 해제하는 작업을 직접 해야 합니다. 이러한 변수는 동적 할당 변수라고도 불립니다.