-> 가변 배열은 지역 변수로 만들 수 없다.
👉 가변 배열은 힙 메모리 영역을 이용해 만들 수 있다.
구조체 는 될까?
: 사용자가 만든 자료형이라는 특징을 제외하고는 일반적인 자료형이랑 똑같기 때문에, 규칙이 그대로 적용되어서 배열 크기 선언에 변수를 사용할 수 없다.
객체(Instance)
: 구조체의 실질적인 데이터를 말한다.
(자료형이라는 틀로 찍어낸 결과물이 객체)
int a;
-> a : 객체
창고 주인 <-> 창고
배열 객체 <-> 힙 메모리
: 창고 주인은 물건(데이터)을 받아 창고에 저장한다.
예시
typedef struct _tagArr
{
int arr[100];
}tArr;
tArr s;
for (int i = 0; i < 100; ++i)
{
s.arr[0] = i;
}
👉 동적 할당이 가능한 힙 메모리를 사용해야 함.
구현
typedef struct _tagArr
{
int* pInt; //메모리 주소
int iCount; //데이터 개수
int iMaxCount; //최대치
}
1) 메모리 시작 주소
2) 데이터 개수
3) 데이터 최대치
객체 생성할 때마다 일일이 초기화하기가 번거롭다.
tArr s; s.pInt = (int*)malloc(40); s.iCount = 0; s.iMaxCount = 10;-> 초기화 함수를 만들자.
InitArr(s); 처럼 객체를 그대로 넘긴다고 초기화 되지 않음.선언
void InitArr(tArr* _pArr);
정의
void InitArr(tArr* _pArr)
{
_pArr->pInt = (int*)malloc(sizeof(int) * 2);
_pArr->iCount = 0;
_pArr->iMaxCount = 2;
}
선언
void ReleaseArr(tArr* _pArr);
정의
void ReleaseArr(tArr* _pArr)
{
free(_pArr->pInt);
_pArr->iCount = 0;
_pArr->iMaxCount = 0;
}
-> free(_pArr->pInt); 이후, 가리키던 힙 공간이 해제되어서 객체가 텅 비었다. 따라서 데이터 한계치, 최대치 모두 0이 됨
선언
void PushBack(tArr* _pArr, int _iData);
정의
void PushBack(tArr* _pArr, int _iData)
{
//힙 영역에 할당한 공간이 다 찬 경우
if (_pArr->iMaxCount <= _pArr->iCount)
{
//재할당
Reallocate(_pArr);
}
//데이터 추가한 뒤, 후위 연산자로 한계치 1 증가
_pArr->pInt[_pArr->iCount++] = _iData;
}
malloc()으로 메모리를 동적할당 받을 때, 원하는 위치의 주소를 할당받을 수는 없었다.
할당받은 공간 이외의 공간을 침범하면 문제가 발생할 수 있다.
(힙손상 오류 등)
-> 가변배열의 공간이 부족할 때, 메모리 확장은 어떻게 가능할까?
👉 만약 int형 2칸(8byte)을 사용하는데, 2칸이 더 필요하다면 2칸을 뒤에 이어붙이는 게 아니라, 한꺼번에 4칸을 새로 할당받아야 한다.
+💡 처음에 동적할당 받을 때 충분히 넉넉한 공간을 할당하는 게 좋음.
순서 )
선언
void Reallocate(tArr* _pArr);
정의
void Reallocate(tArr* _pArr)
{
//간단하게 2배씩 늘려서 재할당해보기
int* pNew = (int*)malloc(_pArr->iMaxCount * 2 * sizeof(int));
// 기존 공간 -> 새로운 공간 으로 데이터 복사
for (int i = 0; i < _pArr->iCount; ++i)
{
pNew[i] = _pArr->pInt[i];
}
free(_pArr->pInt);
_pArr->pInt = pNew;
_pArr->iMaxCount *= 2;
}
-> 가변배열 객체의 pInt 멤버로 새로 할당한 주소를 넣으면 기존에 있던 메모리 주소는 알 수 없게 되어버리는 문제가 생긴다.
💡 추가
-> 방지하려면?
: 헤더 파일에 선언해 두지 않는다. 어차피 가변배열 cpp 파일 안에 구현이 되어 있으므로 문법적으로 문제 없다.
최종 코드
//[Arr.h]
#pragma once
typedef struct _tagArr
{
int* pInt; //메모리 주소
int iCount; //한계치
int iMaxCount; //최대치
}tArr;
//배열 초기화 함수
void InitArr(tArr* _pArr);
//데이터 추가 함수
void PushBack(tArr* _pArr, int _iData);
////메모리 재할당 함수
//void Reallocate(tArr* _pArr);
//배열 메모리 해제 함수
void ReleaseArr(tArr* _pArr);
//[Arr.cpp]
#include "Arr.h"
#include <iostream>
void InitArr(tArr* _pArr)
{
_pArr->pInt = (int*)malloc(sizeof(int) * 2);
_pArr->iCount = 0;
_pArr->iMaxCount = 2;
}
void ReleaseArr(tArr* _pArr)
{
free(_pArr->pInt);
_pArr->iCount = 0;
_pArr->iMaxCount = 0;
}
//메모리 재할당
void Reallocate(tArr* _pArr)
{
//간단하게 2배씩 늘려서 재할당해보기
int* pNew = (int*)malloc(_pArr->iMaxCount * 2 * sizeof(int));
// 기존 공간 -> 새로운 공간 으로 데이터 복사
for (int i = 0; i < _pArr->iCount; ++i)
{
pNew[i] = _pArr->pInt[i];
}
free(_pArr->pInt);
_pArr->pInt = pNew;
_pArr->iMaxCount *= 2;
}
void PushBack(tArr* _pArr, int _iData)
{
if (_pArr->iMaxCount <= _pArr->iCount)
{
//메모리 재할당
Reallocate(_pArr);
}
_pArr->pInt[_pArr->iCount++] = _iData;
}
//[main.cpp]
#include <iostream>
#include "Arr.h"
int main()
{
tArr s = {};
InitArr(&s);
for (int i = 0; i < 10; ++i)
{
PushBack(&s, i);
}
for (int i = 0; i < s.iCount; ++i)
{
printf("%d\n", s.pInt[i]);
}
ReleaseArr(&s);
return 0;
}
[출력]
0
1
2
3
4
5
6
7
8
9
가변 배열의 데이터를 버블 정렬을 사용해 정렬하는 동작을 구현할 것
구현
void BubbleSort(tArr* _pArr)
{
while (true)
{
bool bFinish = true;
for (int i = 0; i < _pArr->iCount-1; i++)
{
//왼쪽 요소가 오른쪽 요소보다 크면 서로 교환
if (_pArr->pInt[i] > _pArr->pInt[i + 1])
{
int temp = _pArr->pInt[i];
_pArr->pInt[i] = _pArr->pInt[i + 1];
_pArr->pInt[i + 1] = temp;
bFinish = false;
}
}
//for문 마친 후, 왼쪽 요소가 오른쪽 요소보다 크지 않은 상태면 break
if (bFinish)
break;
}
}
-> for (int j = 0; j < _pArr->iCount-1-i; j++)
: 버블 정렬 할 때마다 데이터 개수-1 만큼 비교하기 때문에 j < _pArr->iCount-1-i;
<time.h> rand() : 난수 페이지 참조, but 페이지 순서를 따르기 때문에 완벽한 난수가 아님srand() : 여러 난수 페이지를 참조, rand()보단 보완됨rand() 활용하여 구현함수 구현main.cpp
#include <iostream>
#include "Arr.h"
#include <time.h>
int main()
{
tArr s = {};
InitArr(&s);
for (int i = 0; i < 10; ++i)
{
int iRand = rand() % 100 + 1;
PushBack(&s, iRand);
}
printf("정렬 전\n");
for (int i = 0; i < s.iCount;++ i)
{
printf("%d\n", s.pInt[i]);
}
printf("\n정렬 후\n");
BubbleSort(&s);
for (int i = 0; i < s.iCount; ++i)
{
printf("%d\n", s.pInt[i]);
}
ReleaseArr(&s);
return 0;
}
출력
💡 팁
- 함수 바로 정의할 수 있는 단축키
Ctrl+++.- srand() 함수
[참고]
https://youtu.be/osL_ngXRmA4
https://youtu.be/UV30FZqQsAM
https://syrang.tistory.com/51