포털:컴퓨터공학/C++/동적할당

위키배움터

메모리 구조[편집]

C와 C++에서 메모리는 다음과 같은 모습으로 나타내어집니다.

스택
지역 변수가 쌓입니다. stack은 쌓아 올린 무언가를 뜻합니다.
프로그래머가 운영체제에 요청하여 사용할 수 있는 자유 공간입니다.
BSS(Block Started by Symbol)
정의만 이루어진, 전역변수와 static 변수가 들어갑니다.
BSS와 데이타 영역을 합쳐서 데이타 영역이라고 하기도 합니다.
데이타
정의와 초기화가 동시에 이루어진, 전역변수와 static변수가 들어갑니다.
BSS와 데이타 영역을 합쳐서 데이타 영역이라고 하기도 합니다.
코드
컴파일러에 의해 기계어(바이너리)로 만들어진 코드가 들어갑니다
우리가 쓴 소스가 들어간다고 생각하셔도 됩니다.

이 영역을 text영역이라고도 합니다. 글로 쓰여진 코드가 들어간다는 의미지요.


 주의하세요! 
  위 구조를 메모리 맵이라고 부릅니다. 위의 구조는 단순화, 일반화한 모습입니다.
  실제 메모리 맵은 사용하는 프로그래밍 언어에 따라, cpu에 따라, 동작 환경에 따라 달라질 수 있습니다.

이 중에서 우리가 관심 가져야 할 영역은 힙(heap)입니다. 우선 다음 소스를 봅시다.

6.01 문자열을 입력받아 대소문자를 바꿔줍니다
#include <iostream>

using namespace std;

int main(void)
{
 char input[10]={};
 int index = 0;
 
 cin>>input;

 while(input[index]!='\0')
 {
  if(input[index]>='A' && input[index]<='Z')
   input[index]+=32;
  else if(input[index]>='a' && input[index]<='b')
   input[index]-=32;

  index++;
 }

 cout<<input<<endl;

 return 0;
}
abcDEF!@#
ABCdef!@#

소문자 abc는 대문자인 ABC로 바뀌었고 대문자 DEF는 소문자 def로 바뀌었으며, 특수문자인 !@#는 알파벳이 아니니 입력한 모습 그대로 출력되었습니다.

그런데 학습자 당신에게 이런 불평이 들려왔다고 합시다.

이 프로그램은 겨우 9글자밖에 입력할 수 없어요. 난 더 길게 입력하고 싶어요!

그래서 당신은 흔쾌히 소스를 수정해 더 많이 입력할 수 있는 프로그램을 만들어 주었습니다. 마치 다음 소스처럼요.


6.02 문자열을 입력받아 대소문자를 바꿔줍니다. 99글자까지 지원!
#include <iostream>

using namespace std;

int main(void)
{
 char input[100]={};
 int index = 0;
 
 cin>>input;

 while(input[index]!='\0')
 {
  if(input[index]>='A' && input[index]<='Z')
   input[index]+=32;
  else if(input[index]>='a' && input[index]<='b')
   input[index]-=32;

  index++;
 }

 cout<<input<<endl;

 return 0;
}
abcdefgHIJKLMN!@#$%^&
ABCDEFGhijklmn!@#$%^&

잘 작동 되는 것 같습니다. 하지만 아직도 당신에게 불평할 사람이 있는 것 같습니다.

전 대부분의 99자보다 적게 입력해요. 하지만 어쩌다가 어쩌다가 1,000자, 10,000자, 일년에 한번쯤은 100,000,000자를 입력할 때도 있어요.
이렇게 많은 글자도 입력할 수 있게 해주세요.

어떻게 해야할까요? char input[100000000]={}으로 소스를 변경해야 할까요? 하지만 이 사용자는 대부분의 경우 99자보다 적게 입력한다고 합니다. 일년의 한번을 위해서 항상 프로그램이 sizeof(char)*100000000만큼을 할당 받게 하는 건 엄청난 낭비입니다.

이러한 문제를 해결하기 위해서, C언어는 실행되기 전에 크기를 정하지 않고, 실행 중에 필요에 따라 자유롭게 할당할 장소를 제공해줍니다.

그곳의 이름이 바로 힙입니다.

 T I P 
  C에서는 힙을 위해 malloc함수를 사용합니다.
  C++에서도 <cstdlib>를 include함으로서 malloc함수를 사용할 수 있습니다.
  다만 C++에서는 void*의 암묵적 형변환이 불가능하기 때문에 할당한 공간 주소를 명시적 형변환하여 사용해야 합니다.


new & delete[편집]

C++에서 힙 영역에 원하는 만큼 메모리를 할당받기 위해서는(다시 말해서, 원하는 크기의 변수를 힙에 선언하기 위해서는) new라는 명령어를 사용면 됩니다.

다음과 같이 사용하면 됩니다.

int new_data = new int

배열은 다음과 같이 할당 시키면 됩니다.

int * new_data = new int[10]


사용이 끝난 동적 할당 공간은 다음과 같이 삭제합니다.

delete new_data;

사용이 끝난 동적 할당 배열 공간은 다음과 같이 삭제합니다.

delete[] new_data


주석을 참고하면서 다음 소스를 읽어보세요.

6.03 new맛 보기
#include <iostream>
#include <cstring>

using namespace std;

int main(void)
{
 char *input= new char[5];
 char *new_input;
 int index = 0;
 int max_index = 4; // 배열의 크기를 나타냅니다
 //인덱스는 0부터, 크기는 1부터 시작하니, max_index+1이 실제 크기겠죠?

 while(true)
 {
  cin>>input[index];

  if(index >= max_index) // 만약 배열을 다 썼다면
   {
    new_input = new char[max_index+=1+5]; // 현재보다 5칸을 늘려서 new_input이 가리키게 하고
    strcpy(new_input, input); // 지금까지 내용을 새로운 공간에 복사해 넣고
    delete[] input; // 예전 공간을 지우고
    input = new_input; // input을 이제 새 공간을 가리키게 합니다
   }

  if((int)input[index]==26) // CTRL + Z가 ascii코드로 26입니다
  {input[index]='\0'; break;} // CTRL + Z를 입력하면 널 문자를 집어넣고 while문을 나갑니다
  
  index++:
 }

 cout<<input<<endl;
 
 delete[] input;

 return 0;
}
zxcvsafasfwqerasfasdfxzvxcvzqwasfsafqwer^z
zxcvsafasfwqerasfasdfxzvxcvzqwasfsafqwer

new와 delete는 문법적으론 어렵지 않습니다. 여러번 사용하여 익히도록 합시다.

 예제 6.01번 
  동적할당으로 문자를 입력 받습니다. 소문자는 대문자로, 대문자는 소문자로 바꿔서 출력하도록 합시다.
  CTRL+Z를 입력하면 입력이 종료되도록 합니다.
 연습 문제 6.01번 
  동적 할당으로 문자열을 입력 받습니다. 한 문자열과 다른 문자열은 공백(space)으로 구분됩니다.
  CTRL+Z를 입력받으면 입력이 종료되도록 합니다. 출력 형태는 다음과 같습니다.
[1번 문자열]hello
[2번 문자열]world!
[3번 문자열]hello_world!!!!!!
[4번 문자열]what's
[5번 문자열]your
[6번 문자열]name?
[7번 문자열]axcvzxvasfqwfsadfzxcvzxasdfjhasdkjfhasdkjfasdhfhakjhejh
[8번 문자열]^Z

이 문제는 어려운 문제이고, 여러가지 답변이 가능합니다. 시간을 들이면서 찬찬히 풀어봅시다.

정리[편집]

무엇을 배웠는지 기억해봅시다. 복습은 최고의 공부법!

  1. 메모리 맵의 형태를 생각해봅시다.
  2. 실행 중에 크기를 결정해 마음대로 공간을 할당할 수 있는 곳의 이름은?
  3. 그래서, 그곳에 공간 할당하기 위해서 어떤 명령어를 썼나요.
  4. 지우기 위해서는?
  5. 배열 공간을 만들고, 지울때는 조금 달랐습니다. 어떻게 달랐는지 생각해 보세요.