-
[C언어] 변수를 처리하는 다양한 방식 (소스코드, 전역변수, 지역변수, 동적할당변수, 매개변수)CS & Algorithm & Data Structure & C 2021. 11. 5. 16:03반응형
기본적으로 프로그램을 돌리기 위해서는 메모리 상에 프로그램이 적재 되어야한다.
이 후에 프로그램을 읽게 되는 것이다.
즉, 메모리에 프로그램을 돌릴만한 공간이 있어야 한다는 것이다.
이러한 메모리는 아래와 같이 크게 네 가지로 구분 해서 관리를 할 수 있으며, 각각은 그 아래 칸과 같은 변수를 관리하고 있다.
코드(Code) 영역 데이터(Data) 영역 힙(Heap) 영역 스택(Stack) 영역 소스 코드 전역 변수
정적 변수동적 할당 변수 지역 변수
매개 변수그렇다면 각각의 영역에서 관리하고 있는 변수에 대해서 무슨 말인지 알아보자.
우선 소스 코드(Source Code) 라는 것은 말 그대로 한 줄, 한 줄 씩 실행 시킬 수 있는 소스 코드를 말한다.
이 후 컴퓨터가 이를 이해하기 위해서는 이 소스 코드를 기계어로 번역해야 할 것이다.
전역변수(Global Variable)는 프로그램의 어디서든 접근 간으한 변수를 말한다.
main 함수가 실행 되기도 전에 프로그램의 시작과 함께 메모리에 할당이 되며, 이로 인해서 프로그램이 복잡해질 수 있다.
이는 앞선 표에서 처럼 데이터영역에 적재(Load) 된다.
아래는 전역변수의 예를 C 언어로 작성한 것이다.
#include <iostream> #include <stdio.h> int a = 5; void changeValue() { a = 10; } int main(void) { printf("%d\n", a); // 5 changeValue(); printf("%d\n", a); // 10 return 0; }
이 처럼 changeValue에서 전역변수를 사용 할 수 있으며 main에서도 사용 할 수 있다.
즉, 어디서든 사용이 가능한 것이다.
지역변수(Local Variable)는 특정 블록(Block)에서만 접근 할 수 있는 변수를 말한다.
마치 Javascript의 Block scope와 같은 것이 아닐까.
이는 함수가 실행 될 때 마다 메모리에 할당이 되고, 함수가 종료됨녀 메모리에서 해제가 된다.
메모리 상의 Stack에 저장이 된다.
그 예시는 아래와 같다.
#include <iostream> #include <stdio.h> int main(void) { int a = 10; if(1) { int a = 5; printf("%d\n", a); // 5 } printf("%d\n", a); // 10 return 0; }
main 블록이 있고, if 블록이 있다.
그리고 둘 다 같은 변수 a를 가지고 있다.
그러나 블록 단위로 움직이기 때문에 if 블록 안에서는 if 블록 안의 a 값이 출력되고, main 안에서는 main에서의 a값이 출력된다.
정적변수(Static variable)는 특정한 블록에서만 접근 할 수 있는 변수이다.
이는 프로그램이 실행 될 때 메모리에 할당 되고, 프로그램이 종료되면 메모리에서 해제 된다.
즉, 전역변수와 지역변수의 특징을 모두 가진다고 할 수 있다.
메모리 상에서는 데이터 영역에 전역변수와 함께 적재된다.
그 예시는 아래와 같다.
#include <iostream> #include <stdio.h> void process() { static int a = 10; a++; printf("%d\n", a); } int main(void) { process(); // 11 process(); // 12 process(); // 13 process(); // 14 process(); // 15 return 0; }
위와 같이 하나씩 숫자가 증가하는 것을 볼 수 있다.
이는 초기에 static int a = 10을 적재하고, 다시 호출 할 때는 그 부분을 무시하고 바로 더해서 출력시키고, 또 다시 호출 될 때 static 부분이 무시되고 더해진 값에 숫자가 더해지면서 출력이 된다.
레지스터 변수(Register variable)는 Main memory 대신 CPU의 레지스터를 사용하는 변수이다.
Main memory보다는 Register가 CPU 가까이에 붙어있으므로 처리 속도가 빠르다고 할 수 있다.
하지만 레지스터는 한정적이므로 실제로 레지스터에서 처리 되는 것은 컴파일러가 담당하는 것이므로 우리가 레지스터 변수를 활용해서 코딩한다고 해도 항상 레지스터에서 처리 될지는 장담 할 수 없다.
레지스터 변수에 대한 예는 아래와 같다.
#include <iostream> #include <stdio.h> int main(void) { register int a = 10; for(int i = 0; i < a; i++) { printf("%d", i); // 0123456789 } return 0; }
이렇게 레지스터 변수를 사용했으므로 일반적인 변수처리보다는 더 빨리 처리가 될 것이라는 기대를 할 수 있는 것이다.
함수에서의 매개변수의 처리는 어떻게 될까?
일반적으로 함수를 호출 할 때 함수에 필요한 데이터를 매개변수로 전달하게 될 것이다.
전달 방식은 "값에 의한 전달" 그리고 "참조에 의한 전달" 방식이 있으며, 값에 의한 전달 방식의 경우 단순히 "값"을 전달하므로 함수 내에서 변수가 새롭게 생성된다.
참조에 의한 전달방식은 주소를 전달하므로 원래 변수 자체에 접근 할 수 있다.
우선 값에 의한 전달방식을 보자!
그 예시는 아래와 같다.
#include <iostream> #include <stdio.h> void add(int a, int b) { a = a + b; } int main(void) { int a = 7; add(a, 10); printf("%d\n", a); // 7 return 0; }
add함수에 두 개의 값을 넣으면 새롭게 두 변수가 메모리 내에 할당되어 처리 된다.
main 안에서 사용 되는 add 함수의 매개변수는 add함수만을 위한 전용 변수이다.
즉, 원래 변수(main 안의 int a = 7)의 값에는 영향을 미치지 못한다는 것이다.
add함수 안에서만 17이라는 것이 출력 될 것이다.
그렇다면 main 안의 int a = 7 값을 바꾸려면 어떻게 해야할까?
이런 경우 참조에 의한 방식을 사용해볼 수 있다.
참조에 의한 방식은 값을 전달 하는 것이 아니라 변수의 주소(포인터 값)를 전달하게 된다.
그래서 변수 값에 접근하여 값을 변경 할 수 있는 것이다.
#include <iostream> #include <stdio.h> void add(int *a) { *a = (*a) + 10; } int main(void) { int a = 7; add(&a); printf("%d\n", a); // 17 return 0; }
반응형'CS & Algorithm & Data Structure & C' 카테고리의 다른 글
[C언어] 다차원 배열 그리고 포인터 배열 (0) 2021.11.05 컴퓨터 과학과 2진법 (0) 2021.07.12