C++2012.01.01 20:53


이번 강좌에서는
  • new 와 delete 의 사용
  • Welcome to Object Oriented Programming World!


  안녕하세요~ 여러분. 오랜 공백기간을 뚫고 찾아온 Psi 입니다. 그동안 많이 기다리셨죠? 이제 부터 본격적으로 이전의 C 에서 탈피하여 C++ 의 세계로 인도해드릴 것입니다.

   메모리를 관리하는 문제는 언제나 중요한 문제였습니다. 프로그램이 정확하게 실행되기 위해서는 컴파일 시에 모든 변수의 주소값이 확정되어야만 했습니다. 하지만, 이렇게 위해서는 프로그램에 많은 제약이 따르기 때문에 이를 탈피하기 위해 메모리에 '힙(heap)' 이라는 공간이 따로 생겼습니다. '힙(heap)' 은 자유롭게 할당(allocate) 하고 해제(free) 할 수 있는 공간으로써 사용자가 원하는 만큼 사용할 수 있는 공간입니다. 하지만 이전에 컴파일러에 의해 완벽히 확정되어 안정성이 보장되는 스택(stack) 과는 다르게 힙은 사용자가 스스로 제어해야 하는 부분인 만큼 많은 책임이 따르지요. (위 문단을 이해하지 않는 분이라면 이 글을 읽어보도록 합시다)

  이를 위해서 C 언어에서는 malloc 과 free 함수를 지원하여 힙의 할당을 지원하였습니다. C++ 에서도 마찬가지로 malloc 과 free 함수를 사용할 수 있습니다. 하지만, 언어 차원에서 지원하는 것으로 바로 newdelete 라고 할 수 있습니다. new 는 말 그대로 malloc 과 대응되는 것으로 메모리를 할당하고 delete 는 free 에 대응되는 것으로 메모리를 해제합니다. 그럼 한 번 소스를 살펴볼까요.

/* new 와 delete 의 사용 */
 #include <iostream>
using namespace std;

int main()
{
int* p = new int ;
*p = 10;

cout << *p << endl;

delete p;
return 0;
}


성공적으로 컴파일 하였다면


위와 같이 int 영역이 잘 할당 되어서 10 이 출력이 되었음을 알 수 있습니다.

int* p = new int ;


먼저 위와 같이 int 크기의 공간을 할당하여 그 주소값을 p 에 집어 넣었음을 알 수 있습니다. new 를 사용하는 방법은

    T* pointer = new T;


와 같습니다. T 에는 임의의 타입이 들어가겠지요. 그리고 이제 p 위치에 할당된 공간에

*p = 10;


를 통해서 값을 집어넣었고 이를 출력하였습니다. 마지막으로 할당된 공간을 해제하기 위해서 delete 를 사용하였는데

delete p;


위와 같이 delete p 를 하게 되면 p 에 할당된 공간이 해제됩니다. 물론 delete 로 해제할 수 있는 메모리 공간은 사용자가 new 를 통해서 할당한 공간만 가능합니다.

/* 지역 변수 delete 하기 */
#include <iostream>
using namespace std;

int main()
{
    int a = 5;

    delete &a;

    return 0;
}


  만일 위 처럼 지역 변수를 무리하게 delete 로 해제해버리려 한다면


위와 같이 Heap 이 아닌 공간을 해제하려고 한다는 경고 메세지가 나타나게 됩니다.

   new 로 배열 할당하기 
 

/* new 로 배열 할당하기 */
#include <iostream>
using namespace std;

int main()
{
    int arr_size;

    cout << "array size : ";
    cin >> arr_size;

    int *list = new int [arr_size];

    for(int i = 0; i < arr_size; i ++)
    {
        cin >> list[i];
    }
    for(int i = 0; i < arr_size; i ++)
    {
        cout << i << "th element of list : " <<  list[i] << endl;
    }

    delete [] list;
    return 0;
}


  성공적으로 컴파일 하였다면


  위 소스에는 많은 새로운 내용이 담겨 있으니 차근 차근 살펴보도록 합시다.

    int arr_size;

    cout << "array size : ";
    cin >> arr_size;

    int *list = new int [arr_size];


  먼저 위와 같이 배열의 크기를 잡을 arr_size 라는 변수를 정의하였고 그 값을 입력 받았습니다. 그리고 list 에 new 를 이용하여 크기가 arr_size 인 int 배열을 생성하였습니다. 배열을 생성할 때 에는 [] 를 이용해 배열의 크기를 넣어주면 되는데,

    T* pointer = new T [size];


  T 를 임의의 타입이라 하면 위와 같이 하면 됩니다. 따라서 list 는 이제 크기가 arr_size 인 int 배열을 가지게 됩니다. 사실 여기서 한 가지 놀라운 점이 있는데 C 에선 변수의 선언을 모두 최상단에 몰아서 해야 했지만 C++ 은 그렇지 않다는 점입니다. C++ 에서는 편리하게도 소스의 아무대서나 변수를 선언할 수 있으며, 그 변수는 그 변수를 포함하고 있는 중괄호를 빠져 나갈 때 소멸됩니다. 예를 들어서 아래와 같은 코드를 봅시다.

     // 생략
    {
        int a = 4;
        cout << "안에서 a : " << a;
    }

    cout << "밖에서 a : " << a ;


  만일 여러분이 위와 같이 중괄호 안에서 변수 a 를 선언하였다면 변수 a 의 사용 범위는 그 중괄호 안 뿐입니다. 즉 안에서 a 는 4 로 잘 출력이 되겠지만 "밖에서 a :" 문장은 오류가 나게 될 것입니다. 왜냐하면 변수 a 가 그 곳에서는 존재하지 않기 때문이죠. 따라서 여러분은 이 점을 항상 유의하셔야 겠습니다. 또한 한 가지 더 재미있는 점은, 어떤 변수를 사용할 때 컴파일러는 그 변수를 가장 가까운 범위(scope) 부터 찾게 됩니다. 예를 들어 아래의 코드를 보세요

    int a = 4;
    {
        cout << "외부의 변수 1" << a << endl;
        int a = 3;
        cout << "내부의 변수 " << a << endl;
    }

    cout << "외부의 변수 2" << a << endl;


  외부의 변수 1 의 출력 결과를 보면 자명하게 4 가 될 것입니다. 왜냐하면 그 때까지 정의된 변수 a 는 앞서 정의한 int a = 4 하나 거든요. 하지만 그 아래에서 새롭게 int a = 3; 으로 정의한 후 (분명히 이 변수는 위에서의 a = 4 와 다른 변수 입니다) 내부의 변수를 출력해보면 3 이 나옵니다.

  이는 앞서 말한 '가장 가까운 범위에서 찾는다' 라는 원칙 하에서 '내부의 변수 << a ' 에서 a 를 사용할 때 가장 가까운 범위 내에 있는 변수는 바로 같은 중괄호 내에 있는 int a= 3; 이므로 3 이 출력되는 것이지요. 바깥 범위에 있는 a = 4 의 a 는 내부에 있는 a =3 의 a 에 의해 '가려집니다'. 그리고 중괄호를 지나면서 이 내부 변수는 소멸됩니다.

이제 다시 외부의 변수 2 를 출력할 때에는 a = 4 에서의 a 가 출력되어 4 가 나오게 되는 것입니다. 하지만 아래와 같이 같은 범위 안에 동일한 변수를 선언하는 것은 허용되지 않습니다.

    int a;   
    a = 3;
    int a;


  왜냐하면 그 다음에 a 를 사용하였을 때 둘 다 같은 범위 안에 있기 때문에 컴파일러는 어떠한 a 를 사용할 지 모르기 때문이지요. 한 가지 당부하고 싶은 말은 결코 위와 같은 변수의 선언 범위를 고려할 만큼 쪼잔하게 변수 이름을 짓지 말자 입니다. 사람의 눈은 컴파일러가 아니기 때문에 위와 같이 변수 이름을 중복해서 사용한다면 큰 혼동이 있을 뿐더러 나중에 디버깅시 곤란해질 수 있으니 항상 변수 이름은 다르게 짓는 습관을 들이는 것이 좋습니다.

  이제 다시 본론으로 돌아와서 원래 코드를 살펴봅시다.

    for(int i = 0; i < arr_size; i ++)
    {
        cin >> list[i];
    }
    for(int i = 0; i < arr_size; i ++)
    {
        cout << i << "th element of list : " <<  list[i] << endl;
    }


그림과 같이 for 문 안에서 int i 를 선언하여 cin 을 이용하여 list 를 받았습니다. 이렇게 for 문 초기식에서 정의된 i 는 과연 for 문 안에서 정의된 것일까요. for 문 밖에서 정의된 것일까요. 즉 i 를 for 문 밖에서도 사용할 수 있을까요? 답은 안에서 정의된 것입니다. 즉 i 는 밖에서 사용할 수 없지요. 이렇게 for 문 초기식에 i 를 정의해버리면 좋은 점이 설사 밖에 i 를 다른 용도로 사용했더라도 for 문 안에서는 i 를 카운터(counter) 로 사용할 수 있기 때문에 오류가 발생할 가능성이 줄어듭니다.

아무튼 이렇게 해서 list 의 각 원소들을 입력받고 또 이를 출력할 수 있었습니다.

    delete [] list;


마지막으로 살펴볼 부분은 delete 하는 부분으로 앞서 new [] 를 이용해서 할당 하였으면 아래에서는 delete [] 를 통해서 해제하면 됩니다. 즉 new - delete 가 짝을 이루고 new [] - delete [] 가 짝을 이루는 것이지요.

   돌아온 마이펫


   아마도 예전에 저의 C 언어 강좌를 보신 분들이라면 switch 문을 배우면서 간단하게 만들어보았던 마이펫을 기억하실 것입니다. 이번에는 그 때 기억을 살려서 동물 관리 프로그램을 간단하게 만들어보았습니다. 소스를 보기 전에 여러분들도 간단히 만들어보시는 것도 좋을 것 같습니다. 일단 조건은 다음과 같습니다.

  • 동물(struct Animal) 이라는 구조체를 정의해서 이름(char name[30]), 나이(int age), 체력(int health), 배부른 정도(int food), 깨끗한 정도의(int clean) 값을 가진다.
  • 처음에 동물 구조체의 포인터 배열(struct Animal* list[30])을 만들어서 사용자가 동물을 추가할 때 마다 하나씩 생성한다.
  • play 라는 함수를 만들어서 동물의 상태를 변경하고 show_stat 함수를 만들어서 지정하는 동물의 상태를 출력한다.
  • 1 턴이 지날 때 마다 동물의 상태를 변경한다.
  대략 이 정도로만 하고 저는 한번 아래와 같이 소스를 짜보았습니다.

#include <iostream>
using namespace std;

typedef struct Animal
{
    char name[30]; // 이름
    int age; // 나이

    int health; // 체력
    int food; // 배부른 정도
    int clean; // 깨끗한 정도
} Animal;

void create_animal(Animal *animal)
{
    cout << "동물의 이름? ";
    cin >> animal->name;

    cout << "동물의 나이? ";
    cin >> animal->age;

    animal->health = 100;
    animal->food = 100;
    animal->clean = 100;
}

void play(Animal *animal)
{
    animal->health += 10;
    animal->food -= 20;
    animal->clean -= 30;
}
void one_day_pass(Animal *animal)
{
    // 하루가 지나면
    animal->health -= 10;
    animal->food -= 30;
    animal->clean -= 20;
}
void show_stat(Animal *animal)
{
    cout << animal->name << "의 상태" << endl;
    cout << "체력    : " << animal->health << endl;
    cout << "배부름 : " << animal->food << endl;
    cout << "청결    : " << animal->clean << endl;
}
int main()
{
    Animal* list[10];
    int animal_num = 0;

    for(;;)
    {
        cout << "1. 동물 추가하기" << endl;
        cout << "2. 놀기 " << endl;
        cout << "3. 상태 보기 " << endl;

        int input;
        cin >> input;

        switch(input)
        {
            int play_with;
        case 1:
            list[animal_num] = new Animal;
            create_animal(list[animal_num]);

            animal_num ++;
            break;
        case 2:
            cout << "누구랑 놀게? : ";
            cin >> play_with;

            if(play_with < animal_num)
                play(list[play_with]);

            break;

        case 3:
            cout << "누구껄 보게? : ";
            cin >> play_with;
            if(play_with < animal_num)
                show_stat(list[play_with]);
            break;
        }

        for(int i = 0; i != animal_num; i++)
        {
            one_day_pass(list[i]);
        }
    }
    for(int i = 0; i != animal_num; i++)
    {
        delete list[i];
    }
}


  성공적으로 컴파일 하였다면


  그림과 같이 잘 작동됨을 알 수 있습니다. 사실 위 코드에는 그다지 특별한 것이 없습니다. 일단 주요 부분을 살펴볼까요.

typedef struct Animal
{
    char name[30]; // 이름
    int age; // 나이

    int health; // 체력
    int food; // 배부른 정도
    int clean; // 깨끗한 정도
} Animal;


위와 같이 Animal 구조체를 만들어서 typedef 를 통해 struct Animal 을 Animal 로 간추렸습니다. 그리고,

            list[animal_num] = new Animal;
            create_animal(list[animal_num]);


위와 같이 Animal 을 new 로 생성하면 create_animal 함수를 통해서 Animal 의 각 값들을 초기화 해주었고요, 사용자가 놀기를 요청하면

            if(play_with < animal_num)
                play(list[play_with]);

위 처럼 play 함수를 호출해서 놀기를 수행하였습니다. 마지막으로 사용자가 각 동물의 상태를 보기 원한다면

            if(play_with < animal_num)
                show_stat(list[play_with]);


show_stat 함수를 호출해서 사용자가 지정한 동물의 상태를 출력하도록 하였습니다. 사실 매우 간단한 이야기 입니다. 그런데 무언가 상당히 낭비 같지 않으세요? 사용자가 play 를 호출하면 list[play_with] 를 전달해야만 했습니다. 하지만 이러면 어떨까요? Animal 구조체 자체에 함수를 만들어서, 각 구조체 변수가 각각 자신의 함수를 가지게 되는 것입니다. 그러면 list[play_with]->play() 와 같이 "각 변수 자신의 함수" 를 호출하여 자신의 데이터를 이용해서 처리하게 되는 것이지요.

  이렇게 할 수 만 있다면 play 함수에 귀찮게 인자를 전달할 필요도 없고 또 함수 내부에서도

void play(Animal *animal)
{
    animal->health += 10;
    animal->food -= 20;
    animal->clean -= 30;
}


  위와 같이 귀찮게 animal-> 을 앞에 붙여가면서 작업할 필요도 없습니다. 왜냐하면 list[play_with]->play() 라고 했을 때 play 는 '자기 자신의 함수' 이기 때문에

    health += 10;
    food -= 20;
    clean -= 30;


  이렇게 해도 된다는 것입니다. 왜냐하면 list[play_with]->play() 이라 했을 때 health, food, clean 이 의미하는 것이 list[play_with] 의 것이기 때문입니다. 상당히 괜찮은 생각 아닌가요? 위 소스에서 불편한 점은 이것만이 아닙니다. new 를 통해 새로운 동물을 할당하는 부분을 살펴봅시다.

            list[animal_num] = new Animal;
            create_animal(list[animal_num]);


  new Animal 을 통해 동물을 생성한 다음에 반드시 create_animal 함수를 호출해야만 했습니다. 왜냐하면 new Animal 을 통해 새로운 Animal 을 할당한 상태라면 health, food 등 변수에 아무런 값이 들어가 있지 않기 때문이죠. 다시 말해서 만일 프로그래머가 실수로 Animal 을 생성한 후 create_animal 을 호출하지 않는다면 나중에 play 함수 등을 호출 할 때 끔찍한 오류가 발생하게 됩니다. 초기화 되지 않는 값에 연산을 수행하는 오류이지요.

  그렇다면 만일 new 로 새로운 Animal 을 생성할 때 자동으로 호출되는 함수가 있으면 어떨까요. 즉 new 가 알아서 호출해주는 그런 함수. 그렇게 된다면 사용자는 귀찮게 create_animal 을 호출할 필요도 없고, 자동으로 호출되는 함수에서 멤버 변수들 (health, food, ...) 들을 초기화 해준다면 나중에 초기화 되지 않아서 생기는 오류도 막을 수 있을 것입니다.

  자 이제. 여러분은 위 동물 프로그램이 크나큰 인기를 얻어서 확장팩을 제작하게 되었습니다. Animal 이라 단순하게 분류하였던 것을 조금 더 세분화 해서 Bird, Fish 등으로 나누어서 처리하려고 합니다. Bird 와 Fish 는 기본적으로 Animal 과 유사하지만 Bird 에는 현재 날고 있는 고도를 나타내는 변수인 int height; 가 새로 추가되고, Fish 에는 현재 잠수하고 있는 수심을 나타내고 있는 변수인 int deep; 이 추가되었습니다.

  그러면 여러분은 아래와 같이 소스를 짤 것입니다.

typedef struct Bird
{
    char name[30]; // 이름
    int age; // 나이

    int health; // 체력
    int food; // 배부른 정도
    int clean; // 깨끗한 정도

    // 여기까지는 Animal 과 동일하다.
    int height; // 나는 고도

} Bird;

typedef struct Fish
{
    char name[30]; // 이름
    int age; // 나이

    int health; // 체력
    int food; // 배부른 정도
    int clean; // 깨끗한 정도

    // 여기까지는 Animal 과 동일하다.
    int deep; // 나는 고도

} Fish;


  와 정말로 시간 낭비가 아닐 수 없었습니다. Animal 과 거의 똑같지만 조금조금씩 달라진 것 때문에 구조체를 새로 두 개나 만들어야 한다는 말입니다. 그냥 Animal 과 동일한 부분은 가져다 쓰고 새로 추가된 부분만 살포시 추가해 주면 안될까요? 그런데 문제는 이 뿐만이 아닙니다. 여러분은 더이상 Animal* 배열 하나로 살 수 없게 됩니다. 이제 Animal* 따로, Fish* 따로, Bird* 따로 만들어서 관리해야 될 뿐더러 play 함수, show_stat 함수도 모두 Animal, Fish, Bird 에 맞게 각각 새로 작성해야 합니다. 다시 말해서 고작 int height 나 int deep 변수 하나 추가한 덕분에 여태까지 짠 코드 양의 2 배를 써야 하는 위기 상황에 처했습니다.

  정말 말이 안되지요. 하지만 C 언어의 세계에 살고 있던 여러분은 이 모든 것을 꿋꿋히 해내고 있었을 것입니다.

그리고 이제. 이곳을 탈출할 때가 온 것 같습니다.

여러분,

객체지향프로그래밍의 세계로 오신것을 환영합니다.


강좌를 보다가 조금이라도 궁금한 것이나 이상한 점이 있다면 꼭 댓글을 남겨주시기 바랍니다. 그 외에도 강좌에 관련된 것이라면 어떠한 것도 질문해 주셔도 상관 없습니다. 생각해 볼 문제도 정 모르겠다면 댓글을 달아주세요.

현재 여러분이 보신 강좌는<<씹어먹는 C++ - <3. C++ 의 세계로 오신 것을 환영합니다. (new, delete)>>> 입니다. 이번 강좌의 모든 예제들의 코드를 보지 않고 짤 수준까지 강좌를 읽어 보시기 전까지 다음 강좌로 넘어가지 말아주세요




Posted by Psi

댓글을 달아 주세요

  1. 이전 댓글 더보기
  2. 진짜 c언어 처음배울때 psi님 강좌본게 2년전인데..
    지금은 자바,c,c++은 문법적으로 다 뗐네요.
    여기서 배운것을 행운으로 생각하고있어요 정말


    여기서 닉네임 스프라고 썼었는데 지금은 저도 너구리란 닉네임으로 티스토리를를 하고있네요. ㅋㅋ
    잘보고갑니다 ㅋ

    2012.01.28 12:38 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 기억이 납니다 :)

      저도 님과 같은 사람과 함께한 것을 행운으로 생각합니다^^

      2012.02.28 19:50 신고 [ ADDR : EDIT/ DEL ]
  3. 람포

    안녕하세요~^^ 학교에서 C언어를 배우고 여기서 다시 공부하며 새롭게 알아가고 이제 C++언어를 배우기 시작한 학생입니다~ ㅎㅎ 다음 강의는 먼가 새로워질 것 같네요 ㅎ
    질문이 있습니다.
    new로 배열 할당하기 예제에서
    delate []list; 이렇게 하셨는데
    밑에 동물 예제에서는 for문으로 일일이 다 제거 해줬는데 차이점이 뭔가요?
    그리고 동물 예제에서 동물 추가할때 new animal로 공간을 할당해주었습니다.
    그 할당하는 이유가 먼가요? 할당안해도 될거같은데 포인터라서 그런가요?
    그리고 list를 포인터로 한 이유를 모르겠네요 지금 1차원 배열만 쓰니깐 그냥 포인터만 쓰거나
    1차원 배열만 쓰면 되는 것 같은데 궁금합니다~

    2012.02.15 21:24 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • pointer 로 해서 배열과 다르게 동적으로 크기를 할당할 수 있게 됩니다. 그리고 delete[] list 는 그냥 배열을 해제한다고 생각하시면 되요

      2012.02.28 19:51 신고 [ ADDR : EDIT/ DEL ]
  4. 아소유

    지금 마지막에 구조체 쓰신것도 마지막에 클래스로 다시 만들어서 강의 하실껀가요?

    2012.03.16 11:10 신고 [ ADDR : EDIT/ DEL : REPLY ]
  5. inflawless

    글이 정말 멋있어요ㅠ ㅋ

    2012.08.03 12:07 신고 [ ADDR : EDIT/ DEL : REPLY ]
  6. 포도알맹이

    포인터를 사용해서 new 로 배열을 지정하셨는데 혹시 이중배열 고차원 배열을 지정하고 싶을땐 어떻게 해야되죠? 저 부분에서 int **ptr = new int [array_size][array_size]; 이렇게 되는건가요?

    2014.01.15 21:09 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 안됩니다. new 로는 한 번에 1 차원 배열만 만들 수 있습니다. 따라서 2 차원 배열을 만들려면 두 번에 걸쳐서 할당해줘야 합니다. (C 언어 강좌에서 malloc 을 이용해 어떻게 했었는기 기억을 해보세요!)

      2015.01.07 16:50 신고 [ ADDR : EDIT/ DEL ]
  7. C++?

    c언어 강의에서도 한두번 있었던것 같은데 위에 지역변수 delete로 해제하는 예시는 code::block에서는 에러가 안뜨네요.
    혹시나해서 변수랑 주소를 출력해보니 둘다 전과 같음... 뭘 지운걸까요?

    2014.04.21 19:49 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 그 지역 변수 안에 들어있는 값에 해당하는 주소(예를 들어서 a = 3 후에 delete a 하면, 주소값 '3' 에 해당하는 위치)에 있는 데이터를 지운 것입니다.

      2015.01.07 16:51 신고 [ ADDR : EDIT/ DEL ]
  8. 비밀댓글입니다

    2014.12.02 07:32 [ ADDR : EDIT/ DEL : REPLY ]
    • 컴퓨터에서 배열에 해당하는 메모리를 할당해 줄 때, 바로 그 다음에 다른 데이터가 온다고 보장되지 않습니다. 예를 들어

      int a[10];

      한다고 해서, a[9] 뒤에 바로 다른 변수들의 데이터가 반드시 온다는 보장이 없습니다. 그렇기 때문에 a[11] 의 값을 덮어 씌우더라도 문제가 생기지 않을 수 있지만, 만일 거기에 중요한 데이터가 있엇다면 문제가 생기겠지요.

      메모리 상에 변수들이 어떠한 형태로 배열되는지는 운영체제 마음이기 때문에 실행할 때 마다 결과가 달라지게 됩니다.

      2015.01.07 16:53 신고 [ ADDR : EDIT/ DEL ]
  9. 마지막 부분에서 말못할 떨림이..

    2015.02.22 11:36 신고 [ ADDR : EDIT/ DEL : REPLY ]
  10. 비밀댓글입니다

    2015.03.29 14:28 [ ADDR : EDIT/ DEL : REPLY ]
  11. 토끼

    강의 감사합니다^.^! C++은 정말 좋네요. C 공부할 때 답답했던 점들을 하나하나 개선해 나가는 게 정말 재미있습니다.
    다음 강의가 기대되네요~

    2015.12.28 16:56 신고 [ ADDR : EDIT/ DEL : REPLY ]
  12. 비밀댓글입니다

    2016.01.30 18:07 [ ADDR : EDIT/ DEL : REPLY ]
  13. 정말

    감사합니다~

    2016.10.20 22:16 신고 [ ADDR : EDIT/ DEL : REPLY ]
  14. 수강자

    마이펫에서 list[10] 에서 10의 의미는 무엇일까요? 단순이 배열의 크기를 정의해 준걸까요?
    10을 1로 바꿔도 펫은 계속 생성이 가능 한데, 도대체 이 숫자의 의미를 모르겠습니다.
    그렇다고 안을 비우면 크기를 알 수 없는 배열이라면서 컴파일 에러가 났습니다.
    그리고 [10]을 지워 보았더니 나중에 함수에서 배열이 아니라며 컴파일 에러가 났습니다.
    C때는 *list를 malloc함수로 주소를 배정하면 list[]의 형태로 사용이 가능했는데,
    new는 조금 다른 모양이군요...

    2018.03.08 17:44 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 배열의 크기를 나타납니다. Animal* 타입 변수 10개를 저장하는 배열을 의미합니다.

      자세한 내용은

      http://itguru.tistory.com/18?category=194983

      강좌를 참조하세요

      2018.03.08 18:09 신고 [ ADDR : EDIT/ DEL ]
  15. 수강자

    일반적인 경우 배열의 크기를 나타낸 다는건 아는데,
    제 말은 []안에 1이던 10이던 어떤 숫자를 넣던 그걸 초과하는 펫이 만들어 진다는 겁니다.
    궁금해서 계속 해봤더니, list[10]인 상태에서 펫이 20마리도 만들어집니다.
    왜 이런 걸까요?

    2018.03.11 23:02 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 아마 오버플로우가 났는데에도 넘어 간것 같네요.

      실제로는 배열의 크기를 넘어선 구간에 접근할 시에 어떠한 일이 벌어질지 아무도 알 수 없습니다. (다른 변수의 값 위에 덮어쓸 수도 있고, 함수 리턴 주소를 바꿀수도 있고 ..)

      자세한 내용은 버퍼 오버플로우에 대해 찾아보세요.

      2018.03.12 03:21 신고 [ ADDR : EDIT/ DEL ]
  16. 수강자

    정상적인 상태는 아니라는 거네요!
    고맙습니다!

    2018.03.13 12:23 신고 [ ADDR : EDIT/ DEL : REPLY ]
  17. 수강자

    암만 생각해도 답이 안나와서 질문드립니다.,,.,
    char *str = new char[10];을 했을 때,
    str 자체의 주소가 아닌 str이 가리키고 있는 주소를 cout으로 출력할 수 있나요??
    이걸 못해서 지금 printf("%p\n", str); 을 쓰고 있네요...

    2018.03.22 13:24 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • str 에는 str 가리키는 곳의 주소가 들어가 있습니다.

      즉 cout << str; 을 하면 str 이 가리키는 곳의 주소가 나오게 됩니다.

      만약에 str 자체의 주소를 보고 싶다면

      cout << &str; 을 하면 됩니다.

      2018.03.22 17:43 신고 [ ADDR : EDIT/ DEL ]
  18. 수강자

    char *str = new char[10];
    cout < str;
    하면 str이 가리키고있는 문자열이 나옵니다...
    검색해봐도 안나오네요 cout으로 문자열포인터의 문자열주소를 출력하는게...

    2018.03.23 08:50 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 아 무슨말인지 이해 했네요

      cout << (int) str;

      으로 해보세요.

      str 값 자체를 int 로 캐스팅 해서 보여줍니다.

      2018.03.23 11:16 신고 [ ADDR : EDIT/ DEL ]
  19. 수강자

    오 해결했습니다!
    cout << (int)str; 은 str을 int로 캐스팅한 값이고,
    cout << (int*)str; 을 하니까 str이 가리키고 있는 주소가 나오네요!
    printf("%p", str); 이랑 값이 같아졌습니다! 고맙습니다!

    2018.03.23 18:33 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 네 정확히 말하면 (int *) 로 캐스팅 하는게 맞겠네요 :)

      해결되었으니 다행입니다

      2018.03.23 18:46 신고 [ ADDR : EDIT/ DEL ]
  20. 앜ㅋㅋㅋㅋ 중간까지 읽다가 너무 객체프가 간절해지는 순간에 "여러분, 객체지향프로그래밍 세계에 오신 것을 환영합니다."
    라는 문구를 보고 너무 폭소해버렸어요 ㅋㅋㅋㅋㅋ C++ 강좌 하나하나 너무 주옥같은 글 감사합니다.

    2018.06.28 18:07 신고 [ ADDR : EDIT/ DEL : REPLY ]
  21. misoj

    마지막 멘트에서 소름이 끼쳤습니다.. C의 예제를 들면서 객체지향프로그래밍이란 무엇인지 확 와닫는 설명이었습니다.
    정말 좋은 글 같습니다.. 좋은 정보 감사히 배우겠습니다!

    2018.07.13 05:43 신고 [ ADDR : EDIT/ DEL : REPLY ]