변수
변수란 변경이 가능한 수를 말하며 변수에는 어떠한 값(문자열, 숫자, 객체, 배열 등등)이 들어갈지 알 수 없습니다. 그렇다면 왜 변수를 사용하는 것일까요? 변수는 메모리에 저장된 데이터들 중에 메모리 위치 즉, 주소값을 기억하는게 아니라 변수라는 이름으로 기억을 하는것입니다.
예시 )
너 어제 서울특별시 OO구 OO로 XXX동 XXX호 갔어? -> 너 어제 홍길동네 갔어?
주소값 : 서울특별시 OO구 OO로 XXX동 XXX호
변수 : 홍길동네
상수
상수는 변수와 다르게 값을 변경할 수 없는데요. 때문에 상수는 변하지 않는 수라고 합니다. 상수는 꼭 선언과 동시에 초기 값을 설정을 해줘야 합니다.
var a; // 가능
let b; // 가능
const c; // 불가능 > const c = 10 이와같이 값을 입력해줘야한다.
변수의 범위
변수는 크게 지역변수와 전역변수로 나뉩니다.
지역변수
지역변수는 말그대로 지역에서만 사용이 되는 변수를 말하며 보통 함수를 포함하여 {}(중괄호)안에서만 존재하는 변수를 말합니다. 중괄호 밖에서는 변수값을 받아올 수 없습니다. 아래 코드처럼 val이라는 변수명은 다 같지만 main에서의 val과 func1, func2에 존재하는 val은 각각 다른값을 가지고 절대 중괄호 밖에서 사용할수 없습니다.
void main (){
int val = 10;
func1();
printf("%d", val); // 10
}
void func1(){
int val = 20;
func2();
printf("%d", val); // 20
}
void func2(){
int val = 30;
printf("%d", val); // 30
}
그렇다면 어떻게 해야 다른 함수의 값을 받아 올 수 있을까요? 그건 바로 아래 코드처럼 변수 특성을 이용하여 자료형을 제대로 입력하고 해당 값을 return하여 main에서 val 값을 다시 할당하게 만드는 방법으로 해결할수 있습니다. 즉, 이 방식은 상수에서는 사용할 수 없고 변수에서만 사용이 가능합니다.
void main () {
int val = 10;
val = func1();
printf("%d", val); // 20
}
int func1(){
int val = 20;
return val;
}
전역변수
전역 변수는 함수 바깥쪽에 선언된 변수를 말하며 어떤 함수에서 호출을 하더라도 해당 값을 불러올 수 있습니다.
전역 변수와 지역 변수에대해서 들었을때 전역변수가 더 편해보여서 많이 사용을 하는 경우도 많이 보았는데요. 사실 전역변수는 사용하는 함수가 많아지고 전역변수 자체가 양이 많아지면서 어디에서 어떤 값으로 변경이 되는지 알지 못한다면 결국에는 디버깅하다가 문제가 발생할 수 있습니다. 때문에 전역변수를 정말 필요한 곳에 사용을 하고, 필요에 의할때에만 전역변수로 설정을 하고 최대한 지역변수를 사용하는것을 권장드립니다.
int val = 10;
void main (){
func1();
printf("%d", val); // 10
}
void func1(){
func2();
printf("%d", val); // 10
}
void func2(){
printf("%d", val); // 10
}
static 변수
static 변수는 지역변수처럼 중괄호 안에서 선언이 되지만 중괄호를 벗어나더라도 메모리에 고정되어 소멸하지 않기 때문에 중괄호 밖에서도 사용이 가능한 변수입니다.
void main () {
int val = 0 ;
while(val < 5){
func1();
val++;
}
}
void func1 (){
static int total = 0;
int notStatic = 0;
total++;
notStatic++;
printf("total 값 : %d, notStatic 값 : %d\n", total, notStatic);
}
func1 함수에서 선언된 notStatic값은 while이 돌면서 0으로 초기값을 설정하기 때문에 계속 1이라는 숫자만 나오게 되고, static 변수로 생성된 total 값은 while 돌더라도 메모리에 남아 있어 초기값으로 변경되지 않아 1,2,3,4,5 로 점점 증가하게 됩니다.
메모리 영역 🔻
메모리 영역이란?
메모리 영역은 코드 영역, 스택 영역, 힙 영역, 데이터 영역 이렇게 4가지로 구분이 됩니다.
코드 영역 : 실행 명령어들을 저장합니다
스택 영역 : 지역변수 및 매개 변수를 저장합니다.
힙(큐) 영역 : 프로그래머가 직접 할당하여 저장합니다.
데이터 영역 : 전역변수나 static 변수를 저장합니다.
스택과 힙에 저장되는 메모리들은 대게 원시타입 데이터와 참조타입 데이터로 나뉘는데 원시데이터는 대게 정수, 실수, 문자와 같은 기본타입을 말합니다. 참조데이터는 힙에 저장된 데이터들을 참조하는 데이터를 말하며 대게 배열, 객체, 함수 등을 말합니다.
위 표를 보면 원시 데이터는 스택에 값을 그대로 저장을 합니다.
스택 힙 주소 값 주소 값 변수 A ( 원시 타입 ) x.0001 10 변수 B ( 참조 타입 ) x.0010 y.0000 y.0000 [1,2,3,4,5]
하지만 참조 타입은 메모리 힙에서 참조하여 필요한 값의 참조하는 주소를 값으로 가지게 됩니다.
그렇다면 우리가 데이터 값을 변경하게 되면 스택에서는 어떤일이 일어나는걸까요?
원시 타입의 경우
A변수는 x.0001라는 주소에 10이라는 값을 저장하고있고
B 변수에는 x.0010라는 주소에 20이라는 값을 저장하고있다는 가정하에
A변수의 값을 20으로 변경하면 x.0001라는 주소의 값이 20이 되는게 아니라 20이라는 값을 가지고 있는 x.0010주소를 A 변수의 주소값으로 연결을 해주는것입니다. 만약에 기존의 값이 없다면 새로운 메모리 주소에 30을 넣어 새로운 주소값이랑 연결해 주는것입니다.
자료형
자료형은 선언을 할 변수가 어떤 자료형이냐에 따라 메모리 공간을 할당받는 양이 결정이 됩니다.
기본 자료형에는 정수형*과 실수형*으로 나뉘는데요. 이때 이 데이터 타입에 따라 크기(byte)가 정해지게됩니다. 이렇게 다영한 자료형을 사용하는 이유는 효율적으로 메모리의 공간을 활용하기 위해서입니다.
자료형 | 크기 | 표현범휘 | |
정수형 | char | 1 byte | -128 ~ +127 |
short | 2 byte | -32768 ~ + 32767 | |
int | 4 byte | -2147483648 ~ +2147483647 | |
long | 4 byte | -2147483648 ~ +2147483647 | |
실수형 | float | 4 byte | 3.4*10-38 ~3.4*1038 |
double | 8 byte | 1.7*10-308~1.7*10308 | |
long double | 10~16 byte | 1.2*10-4932~3.4*104932 |
문자형은 숫자만 인식하기 때문에 문자를 특정 숫자와 특정 문자를 대응 시키는 방법을 이용하는데 이때 아스키 코드를 표준으로 사용합니다.
아스키 코드 표
10진수 | 아스키코드 | 10진수 | 아스키코드 | 10진수 | 아스키코드 | 10진수 | 아스키코드 |
0 | NULL | 32 | SP | 64 | @ | 96 | ` |
1 | SOH | 33 | ! | 65 | A | 97 | a |
2 | STX | 34 | " | 66 | B | 98 | b |
3 | ETX | 35 | # | 67 | C | 99 | c |
4 | EOT | 36 | $ | 68 | D | 100 | d |
5 | ENQ | 37 | % | 69 | E | 101 | e |
6 | ACK | 38 | & | 70 | F | 102 | f |
7 | BEL | 39 | ' | 71 | G | 103 | g |
8 | BS | 40 | ( | 72 | H | 104 | h |
9 | HT | 41 | ) | 73 | I | 105 | i |
10 | LF | 42 | * | 74 | J | 106 | j |
11 | VT | 43 | + | 75 | K | 107 | k |
12 | FF | 44 | , | 76 | L | 108 | l |
13 | CR | 45 | - | 77 | M | 109 | m |
14 | SO | 46 | . | 78 | N | 110 | n |
15 | SI | 47 | / | 79 | O | 111 | o |
16 | DLE | 48 | 0 | 80 | P | 112 | p |
17 | DC1 | 49 | 1 | 81 | Q | 113 | q |
18 | DC2 | 50 | 2 | 82 | R | 114 | r |
19 | DC3 | 51 | 3 | 83 | S | 115 | s |
20 | DC4 | 52 | 4 | 84 | T | 116 | t |
21 | NAK | 53 | 5 | 85 | U | 117 | u |
22 | SYN | 54 | 6 | 86 | V | 118 | v |
23 | ETB | 55 | 7 | 87 | W | 119 | w |
24 | CAN | 56 | 8 | 88 | X | 120 | x |
25 | EM | 57 | 9 | 89 | Y | 121 | y |
26 | SUB | 58 | : | 90 | Z | 122 | z |
27 | ESC | 59 | ; | 91 | [ | 123 | { |
28 | FS | 60 | < | 92 | \ | 124 | | |
29 | GS | 61 | = | 93 | ] | 125 | } |
30 | RS | 62 | > | 94 | ^ | 126 | ~ |
31 | US | 63 | ? | 95 | _ | 127 | DEL |
* 정수형 : 0을 포함한 부호가 있는 수
* 실수형 : 소수점 이하를 가지는 수
'프로그래밍📚' 카테고리의 다른 글
사용자 정의 타입이란? - 공용체와 enum (0) | 2024.02.05 |
---|---|
사용자 정의 타입이란? - 구조체 (0) | 2024.02.05 |
함수포인터란? (0) | 2024.02.04 |
함수와 배열, 포인터 개념알기 (0) | 2024.01.29 |
연산자와 조건문, 반복문 (0) | 2024.01.28 |