오늘의 TIL 목차 (22.08. 11)
- 열거체 ( enum )
- 동적 할당 ( C언어 : malloc(), calloc(), free() )
- 동적 할당 ( C++ : new , delete() )
열거체
[ 열거체 ( enum ) ]
: 상수를 사용자가 정의한 이름으로 열거하는 것
enum 열거형이름
{
열거체0
열거체1
...
};
■ 기능 / 주의
- 열거체는 원소의 개수와 상관없이 4byte 크기를 갖는다.
- 열거체는 초깃값을 할당할 수 있다.
- 열거체는 상수로, 사용자 정의한 이름의 상수이다.
- 열거체는 0부터 순서대로 +1씩 증가하며, 초기화 시 초기화된 값에 이어서 +1이 된다.
- switch문 등에서 상수를 사용할 때 무엇을 뜻하는지 명확히 표기하고 싶을 때 주로 사용된다.
- 오류를 표기하기 위해서도 주로 사용된다.
- 열거체는 사용할 함수 안에 따로 정의하지 않고 바로 사용 가능하다.
- 열거형이 여러 개일 경우 스코프연산자로 지정해서 사용
■ 예시
enum STATE
{
IDLE, // 열거체는 초기화를 안한다면 0부터 시작하여 차례로 1씩 증가한다.
WALK = 10, // 선언과 동시에 초기화가 가능
ATTACK,
DEAD = 20,
RUN,
END
};
void main(void)
{
cout << sizeof(STATE) << endl; // 열거체는 원소의 개수와 무관하게 무조건 4byte의 크기를 갖는다.
STATE eState = END; // eState == 22
cout << eState << endl;
cout << STATE::IDLE << endl;
cout << ATTACK << endl;
cout << RUN << endl;
cout << ATTACK + RUN << endl; // 11 + 21 상수끼리 연산 가능하므로 32
int iResult = ATTACK + RUN;
}
출력 결과:
4
22
0
11
21
32
※ 스코프연산자 ( :: ) 로 소속 위치를 지정하여 가져올 수 있음
C언어 동적할당 ( feat. Heap )
[ Heap ]
: 메모리 저장 장치 ( Code(ROM), Data, Stack, Heap ) 중 하나로 동적할당에 사용되는 메모리 공간
- 정적변수로 선언 시 프로그램 종료 시까지 해당 변수를 사용하지 않아도 컴파일 때 이미 정의되어 메모리 공간 사용
이로 인한 메모리 낭비를 줄이기 위해 동적할당을 통해 원할 때 해당 메모리 공간을 사용하고 해제 - 힙 메모리는 정의한 byte만큼 메모리 공간을 할당해줄뿐 기능 X
- 포인터를 이용하여 사용자가 원하는 타입으로 힙 메모리 주소에 접근 및 기록
- 메모리 공간 해제 필수 ( 힙 메모리는 재부팅 전까지 해당 메모리를 계속 할당해놓기 때문에 낭비 발생 )
C언어 | 1. malloc() 2. calloc() 3. free()
[ malloc ]
: 메모리 할당 함수, 사용자가 프로그램이 실행 도중(런타임) 원하는 메모리의 크기를 할당하여 사용하는 것

포인터타입* 포인터명 = (void*)malloc(메모리크기);
// void*인 이유는 포인터 타입에 따라서 할당된 메모리 크기를 몇byte 단위로 잘라 사용할 것인지 정해지기 때문
■ 기능 / 주의
- free(힙메모리주소 = 포인터)를 통해 메모리 공간 해제 필수 ( 미해제 시 메모리 누수 발생 )
- malloc의 초기화 값은 쓰레기 값
- 힙 메모리 공간 부족으로 할당 실패 시 NULL 반환
■ 예시
- 같은 힙 메모리 공간을 여러 타입의 포인터가 같이 쓰는 경우
int* pI = (int*)malloc(sizeof(int));
// 힙 메모리에 4byte만큼 할당, int형 포인터 pA는 힙 메모리의 주소를 저장하여 int형으로 접근 및 기록
// (int*)malloc(sizeof(int)) 자체가 힙 메모리의 시작 주소를 가짐
float* pF = (float*)pA;
// pA는 4byte만큼 할당된 힙 메모리 주소, 이를 fA포인터는 float형 단위로 접근 및 기록
*pF = 2.4f; // 4바이트 할당된 힙 메모리 주소에 2.4f 저장 (부동소수점 형태로 저장됨)
cout << *pI << endl; // pF가 가리키는 힙 메모리 주소와 같은 주소를 가리키므로 값 2.4f를 int형으로 받아옴
출력 결과:
1075419546 // 2.4f가 부동소수점 형태로 저장됐기 때문에 int로 받아왔을 때 저 값이 됨
- 동적 배열 할당
// 동적 배열 할당
unsigned int* pUi = (unsigned int*)malloc(sizeof(unsigned int)*3); // 4byte 크기만큼 3개 할당됨
cin >> pUi[1] >> pUi[0]; // 입력은 2번 받지만 pszName[0]이 [1]에 넘겨지고 cin에 넘겨지면서 0것만 입력됨
cin >> pUi[2];
cout << "0번째 동적할당과 2번째 동적할당 출력" << endl;
cout << *pUi << "\t" << pUi[2] << endl; // [인덱스]를 지정하지 않으면 [0] 번째꺼 출력
//cout << sizeof(325425) << endl << sizeof("안녕") << endl << sizeof("dainn") << endl;
// 숫자는 42543가 한묶음 4byte, 문자열 상수 dainn은 영어 한 글자당 1byte + '\0' 1byte = 6byte
// "안녕"은 한글 한 글자당 2byte + '\0' 1byte = 5byte
출력 결과:
입력받은 pUi[0] 입력받은 pUi[2]
[ calloc ]
: 메모리 할당 함수, malloc과 거의 동일하며 매개변수가 하나 추가되어 배열처럼 개수를 지정할 수 있는 함수
포인터타입* 포인터명 = (void*)calloc(할당할 메모리 개수, 메모리크기);
/* malloc은 배열로 사용하고 싶으면 (메모리크기 * n) 해줬어야했는데
calloc은 (메모리 개수, 메모리크기) 로 지정 */
■ 기능 / 주의
- calloc은 동적할당 시 heap 공간을 자동 0으로 초기화
- 힙 메모리 공간 부족으로 할당 실패 시 NULL 반환
■ 예시
int* iC = (int*)calloc(2, sizeof(int)); // 4byte 크기의 힙 메모리 공간을 2개 할당
cin >> *iC; // [0]번째 iC에 값 입력
cin >> iC[1];
cout << endl << iC[0] << endl << iC[1] << endl << iC[4]; // iC[4]는 쓰레기값 출력
[ free ]
: 메모리 해제(반환) 함수, 힙 메모리 할당 시 해제 필수 ( 미해제시 메모리 누수 (=메모리 릭) 발생 )
free(힙메모리주소); // 힙 메모리 주소를 담고 있는 포인터를 주로 매개변수
■ 예시
char* pName = (char*)calloc(3,sizeof(char));
if(nullptr == pName) // nullptr 반환 시 ( 메모리 할당 실패 시 nullptr 반환함 )
cout << "힙 메모리 공간이 부족합니다. 할당 불가 " << endl;
free(pName); // 메모리 해제
pName = nullptr; // 메모리 해제해준 뒤 nullptr 넣어주는 것이 관습
C++ 동적할당
C++ | 1. new 2. delete()
[ new ] & [ delete ]
: 메모리 할당 함수, C++에서만 사용 가능하며 malloc, calloc, realloc의 기능을 합친 버전
자료형* 변수 = new 자료형; // 동적할당
자료형* 변수 = new 자료형(초기값); // 동적할당 및 초기화
delete 포인터명; // 메모리 해제(반환)
포인터명 = nullptr;
// 동적 배열 할당
자료형* 변수 = new 자료형[배열의 개수]; // 배열 동적 할당
자료형* 변수 = new 자료형[배열의 개수]{초기화값}; // 배열 동적 할당 및 초기화
delete []포인터명; // 동적 배열 메모리 해제(반환)
포인터명 = nullptr;
→ new 뒤의 자료형은 메모리 크기를 의미
■ 예시
char* szA = new char[3]{ "" }; // 길이 3인 문자열 동적 할당
cin >> szA; // imhome 길이 3 넘어가도 입력 잘되지만 X
cin >> szA[1]; // dainn 입력 시 2번째 원소에 단문자 d만 입력됨
cout << szA << endl; // idhome 출력
cout << szA[1] << endl; // a, 배열 인덱스는 0부터 시작
int* szInt = new int(100);
int* szArray = new int[3]{1, 2, 3};
*szInt = 300; // szInt는 포인터(=주소)이므로 *포인터로 만들어줘야함
*szArray = 300; // szArray는 배열로 주소이기 때문에 *배열명으로 해줘야함 (0번째에 값 들어감)
szArray[1] = 200; // szArray 1번째에 200 입력됨
cout << *szInt << endl;
for(int i=0; 3 > i ; ++i) // 배열의 경우 '\0' != i 불가능
cout << szArray[i] << "\t";
출력 결과:
300
300 200 3
→ char형의 동적 배열은 문자열 상수 배열이 아닌 문자 배열 ( 문자열 하나 )
■ 기능 / 주의
- 문자열 상수 ( 여러 개 ) 배열
char* szA = new char[3]{ "" }; // 문자 배열
char** szP = new char*[3]{}; // 문자열 배열
- 포인터 배열과 동적 배열 구분
// 포인터 배열과 동적 배열을 구분하여 이해할 것!
int iA = 0, iB = 10, iC = 20;
int* p[3] = { new int, new int, new int }; // 포인터 배열
for (int i = 0; i < 3; ++i)
{
cout << p[i] << endl;
delete p[i];
p[i] = nullptr;
}
int* p = new int[3]; // 동적 배열
delete[]p;
p = nullptr;
- 메모리 누수
메모리 누수의 예
int iA = 100;
int* p = new int;
*p = iA;
p = &iA; // 힙 메모리가 저장된 p에 iA의 주소값을 넣음 - 힙메모리 주소 잃어버림
*p = 200; // iA = 200;
cout << iA << endl;
-> 힙 메모리 주소를 잃어버려 영영 반환할 수 없게 됨 - 메모리 누수'C++' 카테고리의 다른 글
| [TIL 15장] 파일 입출력(feat. errno_t, 경로) 및 지원함수 텍스트 모드(.txt) & 바이너리 모드(.dat) (0) | 2022.08.16 |
|---|---|
| [TIL 14장] 메모리 함수, 콘솔/파일 입출력 함수[text] (0) | 2022.08.12 |
| [TIL 12장] 문자열 함수, 구조체(feat. 포인터 사용), 공용체 (0) | 2022.08.10 |
| [TIL 11장] 문자열, 함수 포인터 (0) | 2022.08.08 |
| [TIL 10장] 2차원 배열 (0) | 2022.08.05 |