본문 바로가기
공부/C, C++

[C] 가변 배열 (malloc)

by 김샤랑 2022. 1. 10.

[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

댓글