[C] 가변 배열 (malloc)
(update) 2022.03.10 코드에 오타가 많아 수정했습니다.
그동안 배웠던 배열은 크기가 고정이었다.
int arr[10] = {}; // 크기 10개 짜리 배열.
이건 가능할까?
//1번 경우
int a=100;
int arr[a] = {};
//2번 경우
int iInput = 0;
scanf_s("%d", &a);
int arr[a] = {}; // 지역변수인데 실행이전 컴파일러가 값을 확정할 수 없다.
// 프로그램을 실행시켜봐야 아는 자료형이 어디 있겠느냐~
배열 개수를 선언할 때에는 변수를 사용할 수 없다.
가변 배열을 만들기 위해서는 힙 메모리 영역을 사용할 수밖에 없다.
- 가변 배열 만들기
가변 배열을 할 수 있는 자료형을 분할 구현을 해서 만든다.
헤더 파일을 만든다.
현재 <Arr.h>, <Arr.cpp>, <main.cpp> 파일이 있다.
각자 3개의 파일을 만들어보자.
<Arr.h>는 구조체 선언, 가변 배열에 대한 함수를 선언만 해두었다.
<Arr.cpp>에서는 #include로 Arr.h를 받아 실질적 함수 구현을 해두었다.
<main.cpp>는 실질적으로 가변 배열을 만들어 사용하는 곳이다.
- 코드 구현
<Arr.h>
#pragma once
typedef struct _tabArr
{
// 가변 배열의 기능을 하기 위해서 이 세가지 포인터를 필요로 한다.
int* pInt;
int iCount;
int iMaxCount;
}tArr;
// 단축키 ctrl + '+', '.' 함수 생성하는 기능
// 배열 초기화 함수
void InitArr(tArr* _pArr); // 함수 선언만 하고 구현은 Arr.cpp에 한다. 이유는 맨아래.
// 데이터 추가 함수
void PushBack(tArr* _pArr, int _iData); //어떤 객체에 넣어줄지 주소, 넣을 데이터
// 공간 추가 확장
// void Reallocate(tArr* _pArr); //외부에서 쓸 수 없도록 숨김.
// 배열 메모리 해제 함수
void ReleaseArr(tArr* _pArr);
<Arr.cpp>
#include "Arr.h"
#include <iostream>
#include<stdlib.h> //malloc, free 선언된 헤더파일
void InitArr(tArr* _pArr) // 초기화
{
_pArr -> pInt = (int*)malloc(sizeof(int)*2);
// sizeof(int)*2 = 8 byte이다.
// int(4byte) 2개를 집어놓은거랑 똑같은데 쉬운 문맥 이해를 위해 이렇게 표현한다.
_pArr -> iCount = 0;
_pArr -> iMaxCount = 2; //sizeof(int)*2 여서 max도 2
}
void Reallocate(tArr* _pArr)
{
// 1. 2배 더 큰 공간을 동적할당한다.
int* pNew = (int*)malloc( _pArr->iMaxCount* 2 * sizeof(int)); //기존값*2 크기
// 2. 기존 공간에 있던 데이터들을 새로 할당한 공간으로 복사시킨다. (큰집으로 이사)
for(int i=0; i<_pArr->iCount; ++i)
{
pNew[i] = _pArr->pInt[i];
}
// 3. 기존 공간은 메모리 해제.
free(_pArr->pInt);
// 4. 가변 배열이 새로 할당된 공간을 가리키게 한다.
_pArr->pInt = pNew;
// 5. MaxCount 변경점 적용
_pArr -> iMaxCount *=2;
}
void PushBack(tArr* _pArr, int _iData)
{
// 데이터를 넣기 전 현재 개수와 최대 개수가 같은 지 비교한다.
if(_pArr->iMaxCount <= _pArr->iCount)
{
// 재할당, 공간이 모자라면 추가 할당 해줘야 한다.
Reallocate(_pArr);
}
// 데이터를 추가
// 가변 배열을 두고 있는 주소 변수로 가서, 거기 인덱스가 본인이 사용할 카운트값
_pArr->pInt[_pArr->iCount++] = _iData;
}
void ReleaseArr(tArr* _pArr)
{
free(_pArr->pInt);
_pArr->iCount =0;
_pArr->iMaxCount =0;
}
<main.cpp>
#include <iostream>
#include "Arr.h"
int main()
{
/*
tArr s;
s.pInt = (int*)malloc(40);
s.iCount = 0;
s.iMaxCount = 10;
-> 이 초기화 코드는 자주 사용된다 -> 초기화 함수로 만들어준다. -> Arr.h에 만듦
*/
tArr s1 = { };
InitArr(&s1);
// 본인이 가지고 있는 데이터 만큼 반복문을 돌며 값 출력.
for(int i=0; i< s1.iCount; ++i)
{
printf("%d\n", sl.pInt[i]);
}
return 0;
}
- 헤더 파일에 Reallocate 를 넣지 않은 이유
헤더 파일에 Reallocate 함수를 선언할 경우 main 함수에서도 직접적으로 Reallocate 함수를 사용할 수 있다.
딱히 문제가 되는 건 아니지만 내가 원하지 않을 때 함수를 사용할 수 있게 되는 것이니 본래 용도와 어긋난다.
그렇기 때문에 헤더 파일에 Reallocate 함수를 선언하지 않고 Arr.cpp 파일 안에 정의와 구현이 다 되어 있게 해 보호한다.
외부에 공개하지 않는 것은 헤더 파일에 적지 않고 내부적으로 구현과 정의를 다 해두어 사용한다.
이 가변 배열은 구현 순서를 되짚으면서 혼자 공부하며 복습하자.
'공부 > C, C++' 카테고리의 다른 글
[C] 함수 포인터 (0) | 2022.03.12 |
---|---|
[C] Bubble sort (0) | 2022.03.11 |
[C] 동적 할당 malloc( ); (0) | 2022.01.10 |
[C] 구조체 포인터 (0) | 2022.01.10 |
[C] wchar_t 함수 ( wcslen( ), wcscat_s( ) ) (0) | 2022.01.09 |
댓글