■배열
 - 배열이란 데이터형이 같은 여러개의 값을 연속적으로 저장할수 있는 데이터 구조이다.
    배열은 선언 명령문을 사용하여 생성한다. 배열 선언 명령문에서는 다음과 같은 세가지를 선언한다.
   ●각 원소에 저장될 값의 데이터형
   ●배열의 이름
   ●배열 원소의 개수

배열원소의 개수를 대괄호안에 넣어서 선언한다.
short months[12];       //12개의 short형 값을 넣을수 있는 배열 생성
배열의 이름이 months이고, 12개의 원소를 가지며, 각 원소에 short 형 값을 저장할수있다는것을 나타낸다.

배열의 일반적인 형식
typeName arrayName[arraySize];

원소개수를 나타내는 arraySize는 값 10 또는 const기호 상수와 같은 정수 상수이거나, 또는 컴파일 할때 값이 결정되는 8*sizeof(int)
와 같은 상수 수식이어야한다.
배열이 여러가지 용도로 유용한 것은 각각의 배열 원소에 개별적으로 접근할수 있기때문이다.
개별적인 접근을 허용하기 위해 첨자또는 인덱스를 사용하여 배열 원소에 차례로 번호가 매겨진다.
C++의 배열 첨자는 항상 0부터 시작한다. 그리고 C++는 대괄호 안에 첨자를 넣어 배열원소를 지정한다. 예를들어, months[0]은 months 배열의첫번재 원소를 나타낸다. months[11]은 months 배열의 마지막 원소를 나타낸다. 배열의 마지막 원소를 나타내는 첨자는 배열의 크기보다 항상 1만큼 작다.

■배열 초기화 규칙
초기화 형식은 배열을 정의하는 곳에서만 사용할수 있다. 초기화를 나중에 할수는 없다.
그러나 첨자를 사용하여 배열 원소에 개별적으로 값을 대입하는 것은 언제든지 가능하다. 배열을 초기화 할때, 초기화 값의 개수를 배열원소의 개수보다 모자라게 제공할수도있다.
float hotelTips[5] = {5.0,2.5};
배열을 부분적으로 초기화하면, 컴파일러가 나머지 원소들을 모두 0으로 설정한다. 따라서 배열의 모든 원소를 0으로 초기화하는일은 매우 쉽다.
 명시적으로 첫번째 원소만 0으로 초기화 하면 된다. 그러면 컴파일러가 나머지 원소들을 모두 0으로 초기화 시켜준다.
long totals[500]={0};

{0}대신에 {1}로 초기화한다면 첫번째원소를 1로 설정하고, 나머지들은 여전히 0으로 설정한다.
배열을 초기화할때 대괄호([])속을 비워두면, 컴파일러가 초기화 값의 개수를 헤아려 배열원소의 개수를 결정한다.
short things[] = {1,5,3,8};

배열원소의 개수가 4개인 short형의 배열 things 를 생성한다.

■문자열
문자열 이란 메모리에 바이트 단위로 연속적으로 저장되어있는 문자들을 말한다. C++는 두가지 방법으로 문자열을 처리한다.
첫번째 방법은 C로부터 유래한 C스타일의 문자열 처리방법.
두번째 방법은 string클래스 라이브러리에 기반을둔 또다른 문자처리 방법.

문자들이 메모리에 바이트 단위로 연속적으로저장된다는것은, 문자열을 char형의 배열에 저장할수 있다는것을 의미한다.
이때 문자열을 구성하는 각문자들은 배열의 원소에 하나씩 저장된다.
char dog[5] = {'b','e','a','u','x'};
char cat[5] = {'f','a','t','s','\0'};

두배열이 모두 char형의 배열이다. 그러나 두번째 배열만이 문자열이다. 널 문자는 C스타일의 문자열에서 중요한 역할을 한다.
C++는 cout이 사용하는 함수들도 포함하여, 많은 문자열 처리 함수를 가지고있다. 이 함수들은 널 문자를 만날때까지 문자 단위로 문자열을 처리한다. cat문자열을 cout으로 출력하면 , 4개의 문자를 출력하고 나서 널문자를 만나면 출력을 중단한다.
그러나 dog를 cout으로 출력하면, 배열에 들어있는 5개의 문자를 모두 출력한뒤에도 그이후 메모리 내용을 한 바이트 씩 문자로 간주하여 계속해서 출력한다. 출력은 우연히 널 문자를 만날때까지 이어진다.
문자열에 들어있는 각문자들은 일일이 작은 따옴표로 묶어 콤마로 구분하고, 끝에 널 문자를 넣어야 한다.
그러나 이보다 좋은방법은 char형의 배열을 문자열로 초기화 하는 것이다.
다음과 같이 큰 따옴표 안에 문자열을 넣기만 하면 된다. 이렇게 큰 따옴표로 묶인 문자열을 문자상수라고한다.
char bird[10] ="Mr. Cheeps";    // \0을저장한다.
char fish[] ="Bubbles";            //컴파일러가 알아서 처리한다.

큰따옴표로 묶인 문자열은 끝내기 널 문자를 암시적으로 가지고 있다.
키보드 입력에서 문자열을 읽어 char형의 배열에 저장하는 C++의 다양한 입력 기능들은 끝내기 널 문자를 자동으로 추가한다.
문자열을 저장할 char형의 배열은, 그 크기가 끝내기 널 문자까지 포함하여 그문자열에 들어이 있는 모든 문자들을 다 넣을수 있을만큼 충분히 커야한다. char형의 배열을 문자열 상수로 초기화하면 컴파일러가 배열 원소의 개수를 대신 헤아려 주므로 더 안전할 수 있다. 이방법은 전혀 문제를 일으키지않는다. 오히려 배열의 크기를 크게 잡는 바람에 메모리를 낭비하는 일을 막아준다.
C++는 문자열의 길이에 제한을 두지않는다.
(큰따옴표를 사용하는) 문자열 상수와 (작은따옴표를 사용하는) 문자 상수는 서로 바꾸어 쓸수 없다.

■배열에 문자열 사용
배열에 문자열을 넣는 가장 일반적인 방법은 두가지이다.
배열을 문자열 상수로 초기화 하는 방법과 , 키보드 입력이나 파일 입력을 배열에 저장하는 방법이다.
문자열의 길이를 알아내기위한 표준 라이브러리 함수에는 strlen()을 사용하고 cstring표준 헤더파일을 include해준다.

■문자열 입력

 

디저트르르 입력하라는 프롬프트에 응답할 기회도 주지않고 넘어가버린다.
이렇게 되는 이유는 cin이 문자열의 끝을 인식하는 방법 때문이다. 키보드로는 끝내기 널 문자를 입력할수 없기 떄문에,cin에게 문자열의 끝을 알려주는 다른 수단이 필요하다. 그렇기 때문에 cin은 빈칸, 탭,캐리지 리턴과 같은 화이트 스페이스가 있으면 그위치에서문자열이 끝난것으로 간주한다. 즉, char형의 배열에 저장하기 위해 키보드로 부터 입력을 받을때 cin은 하나의 단어만 읽어 그것을 배열에 저장하고 널 문자를 끝에 추가한다.

■한번에 한 행의 문자열 입력읽기
istream 클래스가 행 단위로 문자열을 입력하는 클래스 맴버함수인 getline()과 get()을 제공한다. 둘다 전체 입력 행을 읽는다.
즉, 개행문자가 나올때까지 읽는다. 그러나 getline()은 개행문자를 읽어서 폐기하는 반면에 get()은 입력 큐에 개행문자를 남겨둔다.

 ●getline()을 이용한 행 단위 입력
    getline() 함수는 Enter 키에 의해 전달되는 개행 문자를 입력의 끝으로 간주하여 한 행 전체를 읽는다. cin.getline()을 함수 호출로 
   사용함으로써 이 메서드를 호출할수 있다. 이함수는 두개의 전달인자를 사용한다.
   첫번째 전달인자는 입력한 행을 저장할 배열의 이름이다.
   두번째 전달인자는 입력받을 문자들의 한계이다.
   
   getline()함수로 이름을 읽어 20개의 원소를 가진 name배열에 저장하고 싶다면 다음과 같은 호출을 사용할수 있다.
cin.getline(name,20);
이 명령문은 한행 전체를 읽어 name배열에 저장한다. 이때 그행에 있는 문자들의 개수는 최대 19개 또는 그보다 적어야한다.
getline()함수는 편리하게 한행을 한번에 읽는다. 이함수는 행의 끝을 표시하는 개행문자까지 읽는다.
그러나 개행 문자는 저장하지않는다. 문자열을 배열에 저장할 때 개행문자는 널 문자로 대체된다.

  ●get()을 이용한 행 단위 입력
    istream클래스는 또다른 맴버 함수 get()을 제공한다. 이함수는 여러 변종이있다. 그중의 하나가 getline()처럼 동작한다.
    같은 전달인자를 사용하고, 전달인자를 같은 방식으로 해석하며, 행의 끝까지 읽는다. 그러나 이 함수는 개행문자를
    읽어서 버리지 않고 입력큐에 그대로 남겨둔다. get()을 연달아 두번 호출한다면 문제가 생길것이다.
    첫번째 호출이 입력 큐에 개행문자를 그대로 남겨두기 때문에, 두번째 호출은 그 개행문자를 첫문자로 만나게된다.
    그래서  get()은 읽을 것도 없이 곧바로 행의 끝에 도달했다고 결론을 내린다. 
  
    위와같은 문제는 cin.get()호출로 해결할수 있다. cin.get()호출은 그것이 개행문자이든 아니면 다른 무엇이든 간에 무조건
    하나의  문자로 읽는다. cin.get()을 사용하면 개행 문자를 읽어서 처리하고, 다음 행의 입력으로 넘어가게 할수 있다.
cin.get(name,ArSize);        //첫번째 행을 읽는다.
cin.get();                          // 개행문자를 읽는다.
cin.get(dessert,ArSize);     //두번째행을 읽는다.
get()을 사용하는 또한가지 방법은 두개의 클래스 맴버 함수를 결합하여 사용하는것이다.
cin.get(name,ArSize).get();    //맴버함수들을 결합한다.
이와같이 사용하면 cin.get(name,ArSize)가 cin객체를 리턴한다.
이와 비슷한원리로
cin.getline(name1.ArSize).getline(name2,ArSize);
두행의 입력을 연속해서 읽어 name1과 name2 배열에 각각 저장한다. 이것은 getline()를 2번호출하는것과 같다.
-getline()대신에 get()을사용한 이유는
 첫째, 구식 C++에는 getline()이 없다.
 두번째,get()이 사용자를 다소 신중하게 만들기때문.

●빈행과 문제점
  get()이 빈행을 읽으면 failbit라는것이 설정된다. 이행동이 뜻하는것은 계속되는 입력을막고, 입력을 복원하려면 다음과 같은 명령을
  실행해야한다는것이다.
  cin.clear();
  잠재적으로 발생할수 있는 또 하나의 문제는 입력 문자열이 할당된 공간보다 더 길수 있다는 것이다.
  입력 행이 지정된 문자 수보다 길면, getline()과 get()은 failbit를 설정하고 더이상 입력을 받지않는다.

 ●문자열과 수치의 혼합 입력

cin이 입주 연도를 읽어 들이고, Enter키가 만들어내는 개행문자 를 입력 큐에 남겨두기 때문에 이프로그램은 주소를 입력할 기회를
주지않는다.
cin.getline()은 입력큐에 남겨진 개행문자를 빈행으로 읽어들이고, address배열에 널문자열을 대입한다. 이문제를 해결하는 방법은
주소를 읽기전에 개행문자를 읽어 버리는것이다. 전달인자를 사용하지않는 get()이나, 하나의 char형 전달인자를 사용하는 get()을
호출하는 것을 포함하여, 여러가지 방법으로 이문제를 해결할수 있다.
cin>>year;
cin.get();                 //또는 cin.get(ch);

또는 cin>>year가 cin객체를 리턴한다는 사실을 이용하여, cin>>year에 결합하여 사용할수도있다.
(cin>>year).get();           //또는 (cin>>year).get(ch);

■string 클래스
문자열을 저장하는데 문자 배열을 사용하는 대신, string형 변수를 사용할수 있다.
string클래스를 사용하려면, 프로그램에 string 헤더파일을 포함시켜야한다.
string클래스는 std이름 공간에 속해있으므로, using지시자를 사용하거나 std::string를 사용하여 그 클래스를 참조해야한다.
string객체를 문자 배열과 동일한 방식으로 사용할수 있다.
-C스타일 문자열로 string객체를 초기화 할수 있다.
-cin을 사용하여 string객체에 키보드 입력을 저장할수 있다.
-cout을 사용하여 string 객체를 디스플레이 할수 있다.
-배열 표기를 사용하여 string 객체에 저장되어있는 개별적인 문자들에 접근할수 있다.
string객체를 사용하는것이 배열을 사용하는것보다 편리하고 안전하다. 개념적으로, char형의 배열은 char형 저장 단위의 집합체라고 생각할수 있고, string 클래스 변수는 문자열을 나타내는 하나의 실체라고 생각할수 있다.

 ●대입,결합,추가
char charr1[20];                       //빈배열 생성
char charr2[20]= "jaguar";          //초기화된 배열생성
string str1;                               //빈string객체 생성
string str2="panther";                 //초기화된 string객체생성
charr1=charr2;                         //틀리다. 배열대입 x
str1=str2;                                //맞다. 객체 대입 o

string 클래스는 문자열 결합을 간단하게 처리한다. +연산자를 사용하여 두개의 string객체를 하나로 결합할수도있고, +=연산자를 사용하여 기존의 string객체의 끝에 또 다른 string객체를 덧붙일수있다.

 ●string 클래스의 조작
   cstring 헤더 파일에 strcpy()함수를 사용하여 문자열을 문자 배열에 복사할수있고, strcat()함수를 사용하여 문자열
   문자 배열에  추가할수있다.
strcpy(charr1, charr2);      //charr2를 charr1에 복사한다.
strcat(charr1,charr2);        //charr2의 내용을 charr1에 추가한다.

■구조체
  구조체는 사용자가 정의할수 있는 데이터 형이다. 데이터 형의 특성을 정의하는 구조체 선언이 필요하다. 데이터형을 정의한후에는
  그 데이터형의 변수를 생성할수 있다.
struct inflatable      //구조체선언
{
   char name[20];
   float volume;
   double price;
};

여기서 키워드 struct는 이코드가 구조체 서술을 정의하고 있다는것을 나타낸다. 태그라고도 부르는 식별자 inflatable은 새로
만들어지는 데이터형의 이름으로 사용된다. 중괄호 { } 안에는 이 구조체를 구성하는 데이터형들의 리스트를 넣는다.
이 리스트의 각항목을 맴버라고 부른다. 이 예제에는 문자열을 저장하는 적당한 하나의 char형 배열, 하나의 float형,
하나의 double형을 사용한다.
hat가 inflatable형이라면 , 맴버연산자(.)을 사용하여 그 구조체의 개별적인 맴버에 접근할수 있다.
예를 들어 hat.volume은 hat변수의 volume맴버를나타낸다.
쉽게 말해서, 배열 첨자를 이용하여 배열 원소에 접근할수 있듯이, 맴버 이름을 사용하여 구조체의 맴버에 접근할수 있다.

 

- 초기화 과정에서
inflatable guest=
{
  "Glorious Gloria",       //name값
  1.88,                         //volume값
  29.99,                       //price값
};

배열과 마찬가지로, 한쌍의 중괄호 { } 안에 초기화 값들이 콤마로 구분되는 초기화 리스트를 넣는다. 반드시 초기화 값들은 콤마로 구분해야 한다. 구조체의 각 맴버는 자신의 데이터형에 맞는 값으로 초기화 할수 있다.
name맴버는 char의 배열이므로 , 문자열로 초기화 가능.

  ●구조체의 기타 특성
    사용자가 정의한 데이터형을 내장 데이터형과 동일한 방식으로 다룰수있다. 구조체를 함수에 전달인자로 전달할수 있으며,
    구조체를 리턴값으로 사용할 수도 있다. 대입 연산자(=)를 사용하여 하나의 구조체를 같은 데이터형의 다른 구조체로
    대입할수도 있다. 이때 에는 한 구조체의 맴버값들이 상대방 구조체의 해당 맴버에 각각 대입된다. 
    데이터형 이름이 없는 구조체를 생성할수도 있다. 이것은 태그 이름을 생략하고 템플릿과 변수를 동시에 생성하는 것이다.
 
struct            //태그가없음.
{
   int x;          //두개의 맴버
   int y;
}position;      //구조체변수

이것은 position이라는 구조체 변수를 생성한다. position.x와 같이 맴버 연산자를 사용하여 맴버에 접근할수 있지만,
데이터형 이름이 없기 때문에 이후에 같은 형의 다른 변수를 생성할수 없다.


  ●구조체의 배열
    inflatable 구조체는 배열을 맴버로 포함하고 있다. 또한 원소가 구조체인 배열을 생성할수도 있다. 구조체의 배열을 만드는
    방법은  기본 데이터형의 배열을 만드는것과 같다.
inflatable gifts[100];         //inflatable 형 구조체 100개생성.

구조체의 배열을 초기화 하는 방법은 (각 맴버의 값의 리스트를 콤마로 분리하고 중괄호로 묶는) 구조체 초기화 규칙과
(각원소 값의 리스트를 콤마로 분리하고 중괄호 로 묶는), 배열원소의 각 값의 리스트를 콤마로 다시 분리하고 중괄호로 묶는다.
inflatable guests[2]=                     //구조체 배열을 초기화
 {
    {"Bambi",0.5,21.99},                 //첫번째 배열 원소인 구조체
    {"Godzilla",2000,565.99}            //두번째 배열 원소인 구조체
};
 ●구조체 안의 비트 필드
   구조체 맴버들이 각각 일정 비트수를 차지하도록 지정할수 있다. 이것은 어떤 하드웨어 장치에 들어있는 레지스터에 대응하는  데이터 구조를 만들때 매우 편리하다. 사용할 비트수는 콜론을 찍고 그뒤에 적는다. 이름이 없는 필드를 사용하여 간격을
 줄일수도 있다. 이러한 각 맴버를 비트 필드라 한다.
struct  torgle_register
{
   unsigned int SN:4;     //SN값(4비트)
   unsigned int  :4;        //사용하지않음(4비트)
   bool goodIn:1;          //유효한 입력(1비트)
   bool goodTorgle:1;    //토클에 성공(1비트)
};

■공용체
 공용체는 서로 다른 데이터형을 한번에 한가지만 보관할수 있는 데이터 형식이다. 즉, 구조체는 int형과 long형과 double형을
 한꺼번에 보관할수 있지만, 공용체는 int형이나 long형이나 double형 중에서 한번에 어느 하나만 보관할수 있다.
 구문은 구조체와 같지만 의미가 조금 다르다.
union one4all
{
   int int_val;
   long long_val;
  double double_val;
};

one4all 변수는 int형이나 long형이나 double형을 보관할수 있지만, 어느 한 시점에 어느 한가지만 보관할수 있다.
one4all pail;
pail.int_val =15;       //int형 저장
cout<<pail.int_val;
pail.double_val = 1.38;   //double형을 저장, int형 값은 소실
cout<<pail.double_val;

pail은 어떤 경우에는 int형 변수처럼, 또어떤경우에는 double형 변수처럼 행동.
pail이 어떤 데이터형의 변수로 행동하는지는 맴버이름을 보면 알수 있음.
공용체는 한번에 하나의 값만 보관할수 있으므로, 가장 큰 멤버를 보관할수 있을만큼의 공간이 필요하다. 따라서 공용체의 크기는
가장 큰 맴버의 크기가 된다.
여러가지 데이터형을 사용할수는 있지만 이들을 동시에 사용할수 없을때 공용체를 사용하면 메모리를 절약할수 있다.
struct widget
{
   char brand[20];
   int type;
   union id                               //데이터 형이 부품 종류에 따라 다름
   {
      long id_num;                     //1번 형식의 부품
      char id_char[20];               //다른 형식의 부품
   }id_val;
};
......
widget prize;
......
if(prize.type ==1)
  cin>>prize.id_val.id_num;      //맴버이름으로 모드를 나타낸다.
else
  cin>>prize.id_val.id_char;
익명공용체는 이름이 없다. 본질적으로 익명 공용체의 맴버들은 동일한 주소를 공유하는 변수들이다.
당연히 한번에 한 맴버만 사용할수 있다.
struct widget
{
   char brand[20];
   int type;
   union                        //익명공용체
   {
      long id_num;          //1번형식 부품
      char id_char[20];   //다른 형식의 부품
   };
};
....
widget prize;
....
if(prize.type == 1)
   cin>> prize.id_num;
else
   cin>>prize.id_char;
익명 공용체이므로 id_num과 id_char는 동일한 주소를 공유하는 prize의 두맴버로 취급된다.
따라서 이경우에는 중간에 개입하는 식별자 id_val이 필요하다.

■열거체
 C++의 enum기능은 const를 사용하여 기호 상수를 만드는 것에 대한 또 다른 방편을 제공한다. 그것은 제한적이기는 하지만 새로운 데이터 형을 정의 할수 있게 해준다. enum을 사용하는 구문은 구조체 구문과 비슷하다.
enum spectrum{red,orange,yellow,green,blue,violet,indigo,ultraviolet};
이명령문은 두가지 일을 수행한다.
①spectrum을 새로운 데이터형의 이름으로 만든다. struct형 변수를 구조체라 부르듯이, enum형 변수를 열거체 라 부른다.
②red,orange,yellow...등을 0에서 7까지의 정수 값을 각각 나타내는 기호 상수로 만든다. 이 상수들은 열거자라고 부른다.

기본적으로 첫번째 열거자에는 0이 대입되고, 두번째 열거자에는 1이 대입되는 방식으로 정수값들이 차례로 대입된다. 그러나 열거자에 정수값을 명시적으로 대입하면 이 기본값을 무시할수있다.

spectrum band;  로 선언했을경우 열거체 변수에는 그데이터형을 정의하는데 사용된 열거자 값들만 대입할수 있다.
즉 band = red;, band=blue; 는 사용 할수 있지만 band=200; 은 사용할수 없다.
그리고 열거체는 대입연산자만 사용할수 있고 산술연산자는 사용되지않는다. 예) ++band;  band = red+blue;  (X)
일부 C++에서는 제한을 시키지않는경우도있다. band가 ultraviolet또는 7을 값으로 가지고있다면, ++band를 8로증가시킨다.
그런데 8은 spectrum값이 아니다. 이식성을 최대한 높이기 위해서는 이제한을 지키는것이 좋다.
열거체에 적용 되는 규칙은 매우 제한적이다. 실제로 열거체는 새로운 데이터형을 정의하는 수단이 아니라, 상호 관련이있는 기호 상수들을 정의하는 용도로 주로 사용된다. 예로들면, switch문에 사용할 기호 상수들을 정의하기 위해 열거체를 사용한다.
단지 상수만을 사용할 계획이고 열거체변수를 만들생각이 없다면, 열거체이름을 생략할수도있다.
enum{red,orange,yellow,green,blue,violet,indigo,ultraviolet};

■포인터와 자유저장
포인터는 값자체가 아니라 값의 주소를저장하는 변수이다.
주소연산자(&) 를 변수 앞에 붙이면 그 변수의 주소를 알아낼수 있다.주소 연산자(&)를 변수 앞에 붙이면 그 변수의 주소를 알아낼수있다.
16진수 표기가 메모리를 나타내는 가장 일반적인 방법이기 때문에, 주소값을 출력할때 16진수 표기를 사용한다.
포인터란, 포인터라는 특변한 데이터형의 변수에 어떤값의 주소를 저장한다.
즉, 포인터의 이름이 주소를 나타낸다. 간접값 연산자또는 간접참조연산자라고 부르는 *를 포인터 이름앞에 붙이면 그 주소에
저장되어있는 값이 된다.
예를들어 manly가 포인터라고 가정하였을때, manly는 주소를 나타내고, *manly는 그주소에 저장되어있는 값을 나타낸다.
*manly는 보통의 int형 변수와 동등하게 취급된다.

int형 변수 updates와 포인터 변수 p_updates는 동전의 양면과도 같다. updates변수는 값을 우선적으로 나타내고,
여기에 &연산자를 적용하여 주소를 알아낸다. p_updates 포인터 변수는 주소를 우선적으로 나타내고, 여기에 *연산자를
적용하여 값을 알아낸다. p_updates는 updates를 지시하기때문에 *p_updates와 updates는 완전히 동등하다.
그러므로 *p_updates를 int형 변수처럼 사용할수 있다.

●포인터의 위험
포인터를 생성하면서 컴퓨터는 주소를 저장하기 위한 메모리를 할당한다. 이것은 그포인터가 지시하는 데이터를 저장하기 위한 메모리를 할당하는것이아니다. 데이터를 저장하기 위한 메모리를 할당하는 것은 이와 전혀 다른단계이다.
long *fellow;            //long형을 지시하는 포인터 생성
*fellow =223323;       //어딘지 알수 없는 곳에 값을 저장
여기서 fellow는 포인터다. 그런데 이포인터가 어디를 지시하고 있는지는 알수가 없다. fellow에 주소를 대입하는 단계를
빠트렸기 때문이다.

●포인터와 수
 일반적으로 컴퓨터가 주소를 정수로 다루고 있지만, 포인터는 정수형이아니다.
포인터는 개념적으로 정수형과 다른 데이터형이다. 수행할 수 있는 연산의 관점에서 포인터와 정수형은 서로 다르다.
결론적으로 말해서, 포인터에 정수를 직접 대입할수 없다.
int *pt;
pt = 0xB8000000;    //데이터형 불일치
여기서 좌변은 int형을 지시하는 포인터다. 따라서 주소를 대입할수 있다. 그러나 우변은 단순한 정수이다.
우변의 정수 0xB8000000은 실제로는 세그먼트와 오프셋이 결합된 비디오 메모리의 주소이다.
하지만 이것이 주소라는 것을 알려주는 것이 전혀 없다.
데이터형이 일치하지않을경우 컴파일러는 에러메시지를 내보낸다. 따라서 어떤 주소로 사용하려면 데이터형 변환자를
사용하여 적당한 주소형으로 반드시 변환해주어야한다.
int *pt;
pt = (int *) 0xB8000000;   //데이터형일치
이제 대입 명령문의 좌변과 우변이 모두 정수의 주소를 나타낸다. 따라서 이대입 명령문은 올바른것이다.
int형의 값을 가지고 있다해서 pt를 int형이라고 생각해서는 안된다.

●new를사용한 메모리 할당
C에서는 malloc()이라는 라이브러리 함수를 사용하여 이름이 없는 메모리를 할당하였다.
C++에서도 여전히 그렇게 사용할수 있다. 그러나 C++에서는 new연산자를 사용하는 더좋은 방법을 제공한다.
프로그램을 실행하는 동안 int 형 값을 저장할수 있는 이름이 없는 메모리를 할당하고, 포인터를 사용하여 그메모리의 접근하는 새로운방법에는 new연산자가 중요한 역할을 한다.
어떤 데이터형의 메모리를 원하는지 new연산자에게 알려주면, new연산자는 그에 알맞은 크기의 메모리 블록을 찾아내고,
그블록의 주소를 리턴한다. 이주소를 포인터에 대입하면된다.
int *pn =new int;
new int 부분은 int형 데이터를 저장할 새로운 메모리가 필요하다고 프로그램에게 알린다.
new연산자는 뒤따르는 데이터형을 보고, 몇바이트가 필요한지 파악한다.
그러고나서 적당한 메모리를 찾아 필요한만큼 블록을 할당하고, 그주소를 리턴한다.
리턴되는 주소는 int형을 지시하는 포인터로 선언되어있는 pn에 대입된다. 여기서 pn은 주소이고, *pn은 그주소에 저장되는 값이다.
int higgens;
int *pt =&higgens;
두방식 모두 int형의 주소포인터(pn과 pt)에 대입된다. 두번째 방식에서는 pt를 통하지않고 변수 이름higgens를 통하여 int형
값에 접근할수 있다. 그러나 첫번째 방식에서 포인터pn이 int형 값에 접근할수 있는 유일한 통로이다.
pn은 데이터 객체를 지시하고있기때문에 메모리의 이름이 없어도 접근이 가능하다.
기본데이터형일 수도있는 어떤 단일 데이터 객체를 저장하기 위해 메모리를 확보하고, 그 주소를 포인터에 대입하는 일반적인
형식은 다음과 같다.
typeName *pointer_name = new typeName;
여기서는 데이터형을 두번 사용한다. 한번은 요구하는 메모리의 종류를 지정하기 위해 사용하고,
다른한번은 적당한 포인터를 선언하기 위해 사용한다.
적당한 데이터형을 지시하는 포인터가 이미 선언되어있는 경우에는 포인터를 새로 선언할 필요없이 그 포인터를 사용한다.

●delete 를 사용한 메모리 해제
new로 할당된 메모리는 delete를 사용하여 다시 메모리 풀로 환수해야한다.
이것은 메모리를 가장 효율적으로 사용하기 위한 중요한 절차이다.
delete는 new로 할당한 메모리 블록을 지시하는 포인터와 함께 사용한다.
int *ps = new int;     //new로 메모리할당
....
delete ps;              //delete로 메모리 해제
이렇게 하면 ps가 지시하는 메모리가 해제된다.
그러나 ps자체가 없어지는 것은 아니다. ps는 새로 할당한 메모리를 지시하는데 다시 사용할수 있다. new를 사용한후에는
반드시 delete를 사용해야한다. 그러지않는다면 메모리 누설이 발생할수 있다.
int *ps = new int;         //메모리를 할당하고 첫번째 포인터로 지시
int *pq = ps;                //같은 메모리를 지시하는 두번째 포인터 설정
delete pq;                   //두번째 포인터에 delete사용

●new 를 사용한 동적 배열의 생성
배열, 문자열, 구조체와 같은 커다란 데이터를 다룰 때에는 new를 사용하는것이 훨씬 효율적이다.
선언에 의해 배열을 생성하면, 프로그램이 컴파일 될때 배열을 위한 메모리가 할당된다. 프로그램이 실행될때 이배열은
실행이 되든 안되든 항상 메모리를 차지한다. 이방식을 정적 바인딩이라고 한다. 이것은 배열이 컴파일 시간에
생성된다는것을 뜻한다. 그러나 new를 사용하면 배열 실행 시간에 생성할수 있고, 필요없으면 생성하지 않을수도있다.
또는 프로그램을 실행하는 동안에 배열의 크기를 결정할수있다. 이방식을 동적바인딩이라고 한다.
   ◈new를 사용한 동적 배열의 생성
      10개의 int형 원소를 갖는 배열이 필요하다면, 대괄호 안에 원소의 개수를 넣어 다음과 같은 형식으로 동적배열을 생성.
     
int *psome = new int[10];    //10개의 int형 값을 저장할 블록을 할당.
new 연산자는 그블록의 첫번째 원소의 주소를 리턴한다.포인터 psome에 그주소가 대입된다.
new를 사용하여 생성된 메모리 블록은 , 프로그램이 사용을 끝낸 후에 반드시 delete로 해제해주어야한다.
new를 사용하여 생성된 배열을 해제할때는,
delete [] posme;      //동적 배열을 해제
대괄호 [] 가 사용되었기 때문에 포인터가 지시하는 첫번째 원소가 해제되는것이 아니라 배열 전체가 해제된다. 대괄호는
delete와 포인터사이에 사용된다. new를 대괄호 없이 사용했다면 delete도 대괄호를 넣어 사용해야한다.
▣new와 delete를 사용할때는 다음과 같은 규칙을 지켜야한다.
  ▶new로 할당하지않은 메모리는 delete로 해제하지않는다.
  ▶같은 메모리 블록을 연달아 두번 delete로 해제하지않는다.
  ▶new[]로 메모리를 할당한 경우에는 delete[]로 해제한다.
  ▶new를 대괄호 없이 사용했으면 delete도 대괄호 없이 사용한다.
  ▶널 포인터에는 delete를 사용하는 것이 안전하다.(아무일도 일어나지않음)
동적배열을 위한 메모리를 할당하고, 그 배열의 시작 주소를 포인터에 대입하는 형식은 다음과 같다.
type_name *pointer_name = new type_name[num_elements];


첫번째원소는 p3[0]  즉 0.2이지만
p3= p3+1;
을 만나고 나서 p3[0]이 배열의 두번째 원소를 지시하게 된다. p3에서 다시 1을 빼면 포인터는 원래의
첫번째 원소를 지시하게 된다. 따라서 delete[]로 배열에 할당된 메모리를 정확하게 해제 할수 있다.

■포인터, 배열, 포인터 연산
 정수형 변수에 1을 더하면 값이 1만큼 증가한다. 그러나 포인터 변수에 1을 더하면 값이 그 포인터가 지시하는 데이터형의
바이트 수만큼 증가한다. double형이 8바이트인 시스템에서,double형을 지시하는 포인터에 1을 더하는것은 그 포인터의
수치값에 8을 더하는것과 같다. short형이 2바이트인 시스템에서 short형을 지시하는 포인터에 1을 더하는것은 그포인터의 값에 2를 더하는 것과 같다.

◈포인터에 관한 요약
   ★포인터 선언
      -특정 데이터형을 지시하는 포인터를 선언하려면 다음과 같은 형식을 사용한다.
typeName *pointerName;
ex) double *pn;      //pn은 double형 값을 지시할수 있다.
      char *pc;        //pc는 char형 값을 지시할수 있다.
     ★포인터에 값 대입
        - 포인터에는 메모리 주소를 대입해야 한다. 변수 이름에  &연산자를 적용하면 이름이 있는 메모리의 주소를 얻을수 
           있다. new연산자는 이름이 없는 메모리의 주소를 리턴한다.

     ★포인터의 간접참조
        -포인터의 간접 참조는 포인터가 지시하는 주소에 저장되어 있는 값을 참조한다는 뜻이다. 간접값 연산자 또는
         간접참조 연산자라 부르는 *연산자를 포인터에 적용하면, 그 포인터가 지시하는 주소에 저장되어있는 값을 참조할수
         있다. 배열표기는 포인터를 사용하여 값을 간접적으로 참조하는 또 다른 방법이다. pn[0]은 *pn과 같다. 포인터를 
         적당한 주소로 초기화하지 않은 상태에서 간접 참조에 사용하면 안된다.

    ★포인터와 참조값 구별
      -pt가 int형을 지시하는 포인터라면, *pt는 int형을 지시하는 포인터가 아니라 int형 변수와 완전히 동등한 것이다.

    ★배열이름
      -대부분의 경우에는 C++는 배열 이름을 그 배열의 첫번째 원소의 주소와 동일하게 취급한다.
       한가지예외는 배열 이름에 sizeof연산자를 적용할떄에는 배열의 첫번쨰 원소의 크기가 아니라 배열의 전체 크기가
       바이트 단위로 리턴된다.

   ★포인터연산
     -C++에서는 포인터에 정수를 더할수 있습니다. 포인터에 1을 더하는것은 원래의 주소 값에 그포인터가 지시하는 데이터
       객체의 크기를 더하는 것과 같다. 반대로 포인터에서 정수를 뺄수도있다. 두포인터의 차를 구하는 연산은 두 포인터가
       같은 배열을 지시하고 있을때에만 의미가 있다.
   
   ★배열의 동적 바인딩과 정적바인딩
     -정적 바인딩으로 배열 크기가 고정된 배열을 생성할 때에는 배열 선언 명령문을 사용할수 있다.
      동적 바인딩으로 동적 배열을 생성할 때에는 new연산자를 사용한다. 동적 바인딩에서는 프로그램이 실행될때 배열의
      크기가 정해지고 메모리를 할당받는다. 배열을 사용하는 작업이 끝나면 delete[]로 메모리를 해제해야한다.

    ★배열 표기와 포인터 표기
     -대괄호를 사용하는 배열 표기는 포인터를 사용하는 간접 참조와 의미상 동등하다. 
       tacos[0]은 *tacos와 동등하다. 이들은 tacos주소에 있는 값을 의미한다.
       tacos[3]은 *(tacos +3)과 동등하다. 이들은 tacos+3주소에 있는 값을 의미한다.

■포인터와 문자열
char flower[10] ="rose";
cout<<flower<<" s are red\n";
배열이름은 첫번째 원소의 주소이다. 여기서 cout명령문에 있는 flower는 문자 r이 들어있는 char형 원소의 주소이다.
cout객체는 그 주소를 문자열의 주소라고 간주하여 그 주소에 있는 문자를 출력한후, 널문자(\0)를 만날때까지 계속해서
문자들을 출력한다. 다시 말해, cout에 문자의 주소를 넘겨주면, 그 문자부터 시작해서 널 문자를 만날떄까지 계속해서
출력한다.

●new를 사용한 동적 구조체의 생성
 new연산자를 사용하여 동적 구조체를 생성할수 있다. "동적"이라는 말은 컴파일 시간이 아닌 실행 시간에 메모리를 할당
받는다는것을 뜻한다. new를 구조체에 사용할 떄에는 두가지를 알아야한다.
하나는 구조체를 생성하는것, 또다른 하나는 구조체의 맴버에 접근하는것이다.
구조체를 생성할면 구조체형 앞에다 new를 붙인다.
inflatable *ps =new inflatable;
inflatable형의 구조체를 저장할수 있는 새로운 메모리 블럭을 확보하고, 그것의 주소를 포인터 ps에 대입한다.
맴버에 접근하는 방식은 동적구조체에는 도트(.) 맴버연산자를 사용할수 없다. 그이ㅇ는 구조체에는 이름이없기
때문이다. 우리는 동적 구조체의 주소만 알수있다. 이 문제를 해결하기 위해서는 화살표 맴버 연산자(->)를 제공한다.
화살표 맴버연산자는 하이픈(-)에'보다큰(<)'연산자를 결합한것이다.
도트 맴버 연산자는 구조체이름과 함께 사용하고, 화살표 맴버 연산자는 구조체를 지시하는 포인터와 함께 사용한다.
ps가 inflatable형 구조체를 지시하는 포인터라면 ps->price 는 ps가 지시하는 구조체의 price맴버이다.
또하나의 방법은 ps가 구조체를 지시하는 포인터이면, *ps는 그포인터 지시하는값, 즉 구조체가 된다. *ps가 구조체이기
때문에 (*ps).price는 그 구조체의 price맴버이다.

● new와 delete를 사용하는 예제

포인터를 리턴하는 getname()함수를 정의한다. 이함수는 입력 문자열을 일단 큰 임시배열에 읽어 들인다음, 적당한 크기를
가지고 new[]를 사용하여 그 입력문자열의 길이에 꼭 맞는 크기의 메모리 블록을 할당한다. 그리고 나서, 그 메모리 블록을 지시하는 포인터를 리턴한다. 이러한 접근은 많은 개수의 문자열을 읽어 들여야하는 프로그램에서 메모리를 크게 절약한다.

char형을 지시하는 1000개의 포인터를 원소로 가지는 배열을 만든는것이다. 그런다음, 문자열마다 new를 사용하여 각
문자열의 크기에 맞는 메모리 블록을 할당하고, 각 블록의 주소를 포인터 배열의 각 원소에 대입한다. 이렇게 하면 적어도
수만 바이트를 절약할 수 있다. 문자열 마다 하나씩 커다란 배열을 사용하는 대신에 이방법은 입력 문자열의 크기에 꼭 맞게 메모리를 할당할수있다.

 ●C++에서는 데이터를 저장해두기 위한 메모리를, 할당하는 방법에 따라 자동 공간,정적공간, 동적공간으로 구분한다. 동적 공간은  자유공간 또는 힙이라고 불른다.
   ▶자동공간(Automatic storage)
     자동 공간을 사용하는 함수 안에서 정의되는 보통의 변수들 을 자동변수 라고 한다.
     위의 예제에서 임시배열 temp는 getname()함수가 작동하는 동안에만 존재한다. 프로그램의 제어가 main()으로 다시 
     넘어가면 , temp가 사용하던 메모리는 자동으로 해제된다. 만약에 getname()이 temp의 주소를 리턴했다면, main()
     에있는 name포인터는 곧 다른용도로 사용될 운명을 지닌 메모리 위치를 지시하는꼴이 되었을것이다.
     getname()에서 new를 사용하는것은 바로 그이유때문이다.
     자동변수는 자신들을 포함하고있는 블록안에서만 유효하다(지역변수).블록이란 중괄호로 묶여진 코드의 일정부분을
     말한다.블록들중의 어느 하나 안에서 변수를 선언하면, 그변수는 프로그램이 그 블록안에 있는 명령문들을 실행되는
     동안에만 존재한다.
▶정적공간(Static storage)
     정적 공간은 프로그램이 실행되는 동안에 지속적으로 존재하는 공간이다. 변수를 정적으로 만드는 방법은 두가지이다.
     하나는 외부에서 변수를 정의하는 것이고, 다른하나는 변수를 선언할때 static이라는 키워드를 붙이는것이다.
static double fee= 56.50;
정적변수는 프로그램이 실행되는 동안에 지속적으로 존재하고, 자동 변수는 특정함수나 블록이 실행되는 동안에만 존재한다.

▶동적 공간(Heep)
   new와 delete 연산자는 보다 융통성 있는 방법을 제공한다. 이들은 자유공간이라 부르는 메모리 풀을 관리한다. 이풀은 
   자동변수 와 정적 변수가 사용하는 메모리와 분리되어 있다. new와 delete는 어떤함수에서 메모리를 할당하고, 다른 함수
   에서 그것을 해제할수 있도록 해준다. 따라서 데이터의 수명은 프로그램의 수명이나 함수의 수명에 얽매이지 않는다.
   new와 delete를 함께 사용하면 일반 변수를 사용할 때 보다 메모리에 대한 더 강력한 제어권을 가질수 있다.

================================요약============================================
배열,구조체,포인터는 C++의 세가지 복합 데이터형이다. 배열은 동일한 데이터형의 여러개 값을 하나의 데이터 객체 안에
저장할수 있으며, 첨자를 사용하여 배열 내의 각 원소에 접근할수 있다.
구조체는 데이터형이 다른 여러개의 값을 하나의 데이터 객체 안에 저장한다. 도트(.) 맴버 연산자를 사용하여 개별적인 맴버
에 접근한다. 구조체를 사용하려면 먼저 구조체 템플릿을 생성해야 한다. 구조체 템플릿은 구조체 안에 어떤 맴버를 넣을
것인지 정의한 것이다. 템플릿 이름 또는 태그는 새로운 데이터형을 나타내는 식별자로서, 그 데이터형의 구조체 변수를 생성
할수 있다.
공용체는 여러 가지 데이터형을 저장할수 있으나 오직 하나의 값만 저장한다. 어떤 데이터형이 사용되고 있는지 멤버 이름
으로 판별해야한다.
포인터는 주소를 저장하도록 설계된 변수이다. 포인터는 자신이 저장하고 있는 주소를 지시하고 있다. 포인터를 선언할 때에는 반드시 그 포인터가 어떤 데이터형의 객체를 지시하는지 함께 지정해야한다. 포인터에 간접 참조 연산자(*)를 적용 하면
포인터가 지시하는 주소에 저장되어있는 값을 얻을수 있다.
문자열은 널문자로 끝나는 연속된 문자들이다. 문자열은 큰따옴표로 묶어서 문자열 상수로 나타낼수 있다.이때 끝내기 널문자는 내부적으로 처리 된다. 문자열은 charq배열에 저장할수 있다. 또한 문자열은 char형을 지시하는 포인터를 가지고 나타낼
수도있다. 이때 char형을 지시하는 포인터는 그 문자열의 첫번째 문자의 주소를 지시하도록 초기화 된다. strlen()함수는 널 문자를 빼고 문자열 의 길이를 리턴한다. strcpy()함수는 한위치에서 다른 위치로 문자열을 복사한다. 이러한 문자열 함수들을 사용하려면 cstring또는 string.h 헤더파일을 포함해야한다.
string헤더 파일이 지원하는 C++ string클래스는,문자열을 다루는 좀더 친근한 수단을 대안으로 제공한다. 특별히,string객체들은 문자열을 저장하는데 꼭 알맞은 크기로 자동으로 조절된다. 그리고 대입 연산자를 사용하여 문자열을 복사 할수 있다.
프로그램이 실행되는 동안에 new연산자를 사용하여 데이터 객체를 저장할 수 있는 메모리를 할당할수 있다. new연산자는
할당한 메모리의 주소를 리턴한다. 리턴되는 주소를 포인터에 대입할수 있다. 포인터를 사용하는 것이 그 메모리에 접근할수 있는 유일한 방법이다. 데이터 객체가 간단한 변수라면 간접 참조 연산자를 사용하여 포인터가 지시하는 값을 나타낼수 있다. 데이터 객체가 가 배열인 경우 포인터를 마치 배열이름처럼 사용하여 배열의 원소에 접근할수 있다. 데이터 객체가 구조체일
경우에는 화살표 맴버연산자(->)를 포인터와 함께 사용하여 구조체의 맴버에 접근할수 있다.
포인터와 배열은 가까운 관계이다. ar가 배열이름일때, ar[i]는 *(ar+i)로 해석된다. 이때 배열이름은 그 배열의 첫번째 원소의
주소로 해석된다. 그래서배열 이름은 포인터와 같은 역할을 한다. 반대로 포인터 이름을 배열 표기화 함께 사용하여 new로
할당된 동적 배열의 원소에 접근할수 있다.
new 연산자를 사용하여 데이터 객체를 위한 메모리를 할당하고, delete연산자를 사용하여 할당한 메모리를 해제하여 메모리 풀에 반환하는것을 명시적으로 제어할수 있다. 함수 안에서 선언하는 자동 변수와, 함수 밖에서 선언하거나 static이라는
키워드를 사용하여 선언하는 정적 변수는 융통성이 적다. 자동 변수는 자신이 정의되어있는 블록이나 함수가 실행되는
동안에만 존재한다. 정적변수는 프로그램이 실행되는 동안에 지속적으로 존재한다.

'C++ > C++ PRIMER PLUS' 카테고리의 다른 글

함수 - C++의 프로그래밍 모듈  (0) 2011.11.09
분기 명령문과 논리 연산자.  (0) 2011.11.07
루프와 관계 표현식  (0) 2011.10.27
데이터처리  (0) 2011.10.20
C++시작하기  (0) 2011.10.18