Turbo-C
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
터보-C 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
Lua 게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C/C++ 강좌/문서
[34] (05) Pointer in C++
남병철.레조 [lezo] 12409 읽음    2009-06-21 12:04


[목차]

(1) 포인터의 개념
(2) 포인터의 이용
(3) new와 delete
(4) this와 const
(5) 예제 프로그램
    - String Class
    - Linklist Class
    - Binary Search Class (Auto Sorted)










(1) 포인터의 개념

    * 상위메모리 : 더 높은 주소나 상위메모리란 더 큰수를 의미한다.
                    ( 그림상의 위아래가 결정하는 문제가 아니다. )
    * 각 변수는 고유의 주소에서 시작한다.
    * 변수 이름앞에 적는 & 주소 연산자는 자료형 뒤에 적는 & 참조 연산자와
      엄연이 기능이 다른 종류의 연산자이다.
      ( 참조연산자와 주소연산자는 엄연히 기능이 다른 연산자이다. 사용될때의
        위치를 보면 분명 구별된다. )

    - 기본형 포인터
    int* ptr;은 변수 ptr을 int 포인터로 정의한다.
    이는 ptr이 int 변수의 주소를 보관할 수 있다는 것을 알려주는 방법이다.
    (포인터의 경우는 선언과 동시에 주소(설혹 쓰레기라도)를 갖게된다. 
     일반 변수의 경우는 선언후 초기화 하지 않고 사용하면 선언으로 할당된 주소의
     쓰레기 값이 사용될 것입니다. 이는 프로그램에 치명적일 수 있습니다.
     포인터 변수의 경우는 선언으로 할당된 주소에 위치해있는 쓰레기값(주소값)을
     사용하면 그 값(가리키는 주소값)은 시스템에 치명적 영향을 줄 수도 있는 주소일
     수 있습니다. 변수는 선언후 반드시 유효한 값으로 정의합시다.
     사용자가 원하는 주소값을 가리키기 위해서 새로이 주소를 초기화할 수 있다.
     일반 변수의 경우는 선언이후 값이 초기화 되는 시점에 고정된 주소값을 얻으므로 
     선언과 정의는 구별된다.)
    포인터 변수는 유효한 값(주소)을 주어야한다.

    char와 char*형은 기능이 전혀다른 형이다. 구별을 쉽게하려면 형의 이름이 완전히
    달라야 겠지만 C++은 *만 붙이면 새로운 형을 의미할 수 있는 방법을 사용했을 뿐이다.

    char* ptr1, * ptr2, * ptr3, * ptr4;  // char*형 변수 4개
    이렇게 표현하는 이유는 포이터(*)가 형(char)의 일부이지 변수 자체의 일부가 
    아니라는 것을 강조한 것이다.
    물론 사용은
    char *ptr1, *ptr2, *ptr3, *ptr4;
    이렇게도 가능하다.

    포인터를 사용할 때 주의해야할 사항으로..
    엉뚱한 포인터 값은 시스템을 정지시킬 수 있으며 컴파일러 경고 메시지가 발생하지
    않으므로 디버깅하기도 어렵다.
    즉, 포인터 변수를 사용하기 전에 반드시 유효한 주소를 주어야한다.

    * 객체의 크기를 포인터로 살펴보자.
//---------------------------------------------------------------------------
// 작성일 : 2001.09.05
// 제  목 : 객체 포인터
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

class employee
{
private:
    enum { LEN = 30 };      // 이름의 길이
    char name[ LEN ];       // 사원의 이름
    unsigned long number;   // 사번

public:
    employee( char* na, unsigned long nu ) : number( nu )
    { strcpy( name, na ); }
};

//---------------------------------------------------------------------------

void main()
{
    employee emp1( "Donlevy", 123123L );
    employee emp2( "LeBlanc", 234234L );

    cout << "Address values";
    cout << endl << &emp1       // 객체들의 주소를 출력
         << endl << &emp2;

    employee* ptr;

    cout << "\nPointer values";
    ptr = &emp1;
    cout << endl << ptr;

    ptr = &emp2;
    cout << endl << ptr;

    getch();
}

//---------------------------------------------------------------------------

(결과)
Address values
0012FF64
0012FF40
Pointer values
0012FF64
0012FF40

//---------------------------------------------------------------------------
* 간접연산자 : *ptr처럼 변수 이름의 왼쪽에 별포가 사용된 것이다. ( *(포인터) 오른쪽의 변수가 가리키는 주소의 값을 의미한다. ) - 직접 주소지정 VS 간접 주소지정
    int v;
    int* p;
    p = &v;
    v = 3;
    *p = 3;
위의 리스트중 v = 3;은 변수에 직접 값을 대입하는 직접 주소지정이고, *p = 3;은 p변수의 주소가 가리키는 곳에 값을 대입하는 간접 주소지정이다. - 범용 포인터 void* 일반적으로 int형에는 int*를 사용하고 float는 float*를 사용한다. 이렇듯 변수형과 포인터형이 일치해야하지만 모든 포인터형을 받을 수 있는 범용 포인터가 있다. 그것은 void*이다. 이것의 역은 성립하지 않는다. 즉, 범용포인터를 모든포인터로 바꿀수는 없다. 단지 void*는 void*로만 전달된다. 또는 타입 캐스팅을 통해서 바뀔수 있다. (2) 포인터의 이용 - 포인터로 배열에 접근하기
    int intarray[5] = { 31, 54, 77, 52, 39 };

    for( int j = 0; j < 5; j++ )
        cout << endl << intarray[j];

    for( int j = 0; j < 5; j++ )
        cout << endl << * ( intarray + j );
C++ 컴파일러는 데이터 주소에 대해 산술 연산을 수행할 때 데이터의 크기를 고려할 만큼 똑똑하다. 즉 위의 경우 j가 3일때 intarray + j 구문은 intarray배열 시작주소에서 3을 더하는 것이 아니라 4번재 주소(int형이 4byte이면 intarray + 12byte)를 의미한다. 즉 4번째 데이타의 주소를 가리키게 된다. 이러한 똑똑한 연산이 진행되려면, 컴파일러가 포인터형이 무엇인지 알아야한다. void*를 사용하면 컴파일러가 알리없다.
    for( int j = 0; j < 5; j++ )
        cout << endl << * ( intarray++ );
위의 코딩은 논리적으로 맞지않다. intarray는 주소값을 갖는 배열의 선두 주소이다. 즉 배열이 생성될때 갖는다. 바로 고정된 주소이다. 배열이란 연속 변수(?)에 값이 들어있는 샘이다. 즉, intarray는 주소값임에는 틀림없지만 그것은 곧 상수를 의미 한다. 그러므로 주소를 변경하기위해 변수를 사용해야하는데 이럴때 포인터 변수를 이용한다.(너무나 당연한 논리가 아닌가? 값은 값을 갖는 변수를, 포인터는 포인터를 갖는 변수를...)
    int* ptrint;
    ptrint = intarray;
    for( int j = 0; j < 5; j++ )
        cout << endl << * ( ptrint++ );
이렇게 하면 ptrint는 int형을 가만한 주소증가가 이루어진다. - 함수인수로 포인터 사용하기 참조는 원래 변수의 별명인 반면, 포인터는 원래 변수의 주소변수이다. 즉, 참조는 메모리 사용이 없지만 포인터 전달은 최소한 함수에서 포인터 변수의 생성이 있으므로 새로운 메모리를 사용하게 된다. < 함수 인수로 참조 사용 >
    void main()
    {
        void centimize( double& );
        double var = 10.0;

        cout << endl << "var = " << var << " inches";
        centimize( var );
        cout << endl << "var = " << var << " centimeters";
    }

    void centimize( double& v )
    {
        v *= 2.54;
    }
< 함수 인수로 포인터 사용 >
    void main()
    {
        void centimize( double* );
        double var = 10.0;

        cout << endl << "var = " << var << " inches";
        centimize( &var );
        cout << endl << "var = " << var << " centimeters";
    }

    void centimize( double* ptrd )
    {
        *ptrd *= 2.54;
    }
- 배열이 함수 인수로 사용될때 포인터 이용하기 배열이 함수 인수로 사용될때 아래의 예제는 포인터 전달의 묘미를 보여준다. 위에서 언급했듯이 함수에서 포인터 변수 인자는 메모리를 사용하지만 포인터 형이므로 그 사용은 최소화 된다. 게다가 새로인 생성된 포인터이므로 받아들이 배열을 탐색할 수 도있다. 바로 아래의 것이 그것이다. *ptr++의 의미? *(ptr++)인가? (*ptr)++인가? 일단 * 연산자와 ++ 연산자는 같은 우선순위를 갖는다. 이럴경우 컴파일러가 연산자 연관성이 어떻게되는지 분별하는게 중요하다. *, ++ 등의 1진 연산자는 오른쪽 연관성을 가진다. (연관성 : 컴파일러가 연산을 오른쪽의 연산자에서 시작하는지 왼쪽의 연산자에서 시작하는지에 관한 것이다.) 그러므로 *ptr++은 *(ptr++)로 해석되어 배열의 값이아닌 배열의 주소를 증가시키게 된다.
    const int MAX = 5;
    void main()
    {
        void centimize( double* );
        double varray[ MAX ] = { 10.0, 43.1, 95.9, 59.7, 87.3 };

        centimize( varray );
        for( int j = 0; j < MAX; j++ )
            cout << endl << "varray[" << j << "] = "
                 << varray[ j ] << " centimeters";    
    }

    void centimize( double* ptrd )
    {
        for( int j = 0; j < MAX; j++ )
            *ptrd++ *= 2.54;
    }
- 문자열 상수와 포인터 아래의 예제에서 str1은 주소(포인터 상수)인 반면, str2는 포인터 변수이다. 즉, str2는 주소를 바꿀수 있지만 str1은 그럴수 없다.
    char str1[] = "Defined as an array";
    char* str2 = "Defined as a pointer";
    cout << endl << str1;
    cout << endl << str2;
    // str1++;  // str1은 주소이므로 불가능
    // str2++;  // str2는 주소를 값으로 갖는 포인터 변수이므로 가능
    cout << endl << str2;  // str2 = efined..."으로 출력
- 함수 인수로서의 문자열 포인터로 정의된 문자열은 배열로 정의된 것보다 유용하다.
    void main()
    {
        void dispstr( char* );
        char str[] = "Idle people have the least leisure.";
        dispstr( str );
    }

    void dispstr( char* ps )
    {
        cout << endl;
        while( *ps )
            cout << *ps++;
    }
- 포인터를 이용한 문자열 복사 포인터의 쓰임을 익히기 위해 비슷한 예들을 들어본다.
    void main()
    {
        void copystr( char*, char* );

        char* str1 = "Self-conquest is the greatest victory.";
        char str2[80];

        copystr( str2, sr1 );
        cout << endl << str2;
    }

    void copystr( char* dest, char* src )
    {
        while( *src )
            *dest++ = *src++;
        *dest = '\0';
    }
- strcpy(); 라이브러리 함수와 비교. char* strcpy( char* dest, const char* src ); 여기서 const char* src가 어떤의미를 갖을까? strcpy();에서 src가 가리키는 문자를 변경할 수 없다는 의미이다. ( src 포인터 변수의 주소값을 변경할 수 없다는의미가 아니다. 그 주소의 값을 변경할 수 없다는 의미이다. 만약 주소를 상수로 만들려면, char* const src;라고 해야할 것이다. ) - 문자열 포인터 배열 포인터 배열이므로 각각의 배열 인자의 주소를 변경할 수 있다는 것을 이제 알것이다.
    char* arrptrs[ DAYS ] = { "Sunday", "Monday", "Tuesday",
                              "Wednesday", "Thursday",
                              "Friday", "Saturday" };
    for( int j = 0; j < DAYS; j++ )
        cout << arrptrs[j] << endl;
- 구성원 접근연산자 객체 포인터가 구성원에 접근하는 방법으로는... ptreng.getdist(); // 불가능하다. 하지만 포인터 참조 해제(포인터가 기리키는 객체를 가져옴)를 사용하면 가능하다. (*ptreng).getdist(); // 하지만 우아하지 못하다. ㅡ.ㅡ; 그래서 더 우아한 접근 방식은 -> 가 나오게 된것이다. ptreng->getdist(); '->' 연산자는 '.' 연산자가 객체에 적용되는 것처럼 객체 포인터에 적용된다.
//---------------------------------------------------------------------------
// 작성일 : 2001.09.06
// 제  목 : 구성원 관계 접근 연산자
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

class English
{
private:
    int feet;
    float inches;

public:
    void getdist() {
        cout << "\nEnter feet : ";  cin >> feet;
        cout << "Enter inches : ";  cin >> inches;
    }

    void showdist() {
        cout << feet << "\'-" << inches << '\"';
    }
};

//---------------------------------------------------------------------------

#pragma argsused
void main()
{

    English edist;
    English* ptreng = &edist;

    edist.getdist();
    edist.showdist();

    ptreng->getdist();
    ptreng->showdist();
    
    getch();

}

//---------------------------------------------------------------------------

(결과)
Enter feet : 5
Enter inches : 5.5
5'-5.5"
Enter feet : 55
Enter inches : 55.5
55'-55.5"

//---------------------------------------------------------------------------
(3) new와 delete - new 연산자와 delete연산자의 쓰임 객체에 new를 사용하면 객체의 메모리가 할당될 뿐만 아니라 객체의 생성자를 호출하는 식으로 객체를 만든다. 이것은 객체가 정확히 초기화되며 프로그래밍 오류를 막는데 아주 중요하다. 또한 new는 적절한 데이터형의 포인터를 리턴하는 반면, malloc()의 포인터는 해당 형으로 형 변환해야 한다. 특히, 객체에는 항상 new를 사용하고 절대로 malloc()을 사용하지 말아야한다. new 연산자마다 메모리를 다시 운영체제에 돌려 주는 delete 연산자를 넣어야 한다. 실제로는 프로그램이 종료할 때 메모리가 자동으로 해제되므로 delete가 필요없다. 그러나 프로그램 도중에 함수에 new를 사용한다고 가정해 보자. 함수가 새로 필요한 메모리 포인터로 지역변수를 사용하면, 함수가 종료할 때 그 포인터는 파괴되지만 메모리는 그 프로그램이 계속 차지하고 있다. 그 프로그램이 살아있는한 메모리는 고아가 되어버리는 것이다.
void main()
{
    char* str = "Idle hands are the devil's workshop.";
    int len = strlen( str );        // NULL은 포함하지 않고 크기리턴

    char* ptr;
    ptr = new char[ len + 1 ];      // 메모리를 할당 : size = str + '\0'

    strcpy( ptr, str );             // 스트링 및 NULL까지 복제된다.
    cout << "ptr = " << ptr;
    delete[] ptr;
}
ptr = new char[ len + 1 ]; new를 사용할 때에는 수치 크기를 대괄호'[]'로 묶는다는 것을 명심한다. 소괄호를 사용해도 컴파일러 오류는 없지만 결과는 메모리를 할당 받지않고 그냥 포인터 변수만 선언해서 비확정 영역에 적힌 스트링을 가리키게된다. 이경우 언제 그 스트링이 사라질지 알 수 없다.( -.- 불안한 영역이라... 쩝. 맞는지.. ) 일반적으로 소괄호 문법은 객체의 생성자를 이용하는 목적으로 사용된다. - 아래의 동적 xString클래스에 문제가 있다. ( 논리적으로 문제가 발생할 수 있음 )
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.08
// 제  목 : new를 사용한 xString객체
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

class xString
{
private:
    char* str;

public:
    xString( char* s ) {
        int length = strlen( s );        // 문자열 인수의 길이
        str = new char[ length + 1 ];    // 메모리를 확보
        strcpy( str, s );                // 인수를 그 메모리에 복사
    }

    ~xString() {
        delete[] str;
    }

    void display() {
        cout << str;
    }
};

//---------------------------------------------------------------------------

#pragma argsused
void main()
{

    xString s1( "Who knows nothing doubts nothing." );

    cout << endl << "s1 = ";
    s1.display();

    getch();

}

//---------------------------------------------------------------------------
- 문제점 해설 - 가령 s2 = s1과 같은 명령문을 통해 어떤 xString 객체를 또 다른 것에 복사하면, 포인터는 객체에 실제로 있는 데이터일 뿐이므로, 사실은 포인터만을 실제(char*) 문자열에 복사하는 셈이다. 이제 두 객체가 다 메모리 내의 같은 문자열이다. 그러나 한 xString을 삭제하면, 파괴자는 유효하지 않은 포인터를 가진 다른 객체는 남겨두고 char* 문자열을 삭제 한다. 이렇게 되면 지역 변수를 만든 함수가 리턴할 때와 같이 명확하지 않은 방법으로 객체가 삭제될 수 있다. < 앞으로 3가지 new를 사용한 예를 보게될 것이다. 그중 지금보다 더 똑똑한 xString 파괴자를 보게될 것이다. > * 프로그램이 종료되면 new로 할당된 메모리가 누수상태에 있더라도 모두 해제되지만 new로 할당한 것을 delete로 해제하는 것은 언제나 좋은 습관이다. - 객체 포인터 배열 배열 persPtr의 포인터가 가리키는 구성원 함수 setName()과 printName()에 접근해야 한다. 배열 persPtr의 각 원소는 배열 표기법으로 persPtr[j] 또는 포인터 표기법으로 *(persPtr+j)인 것으로 지정되어 있다. 원소는 person형 객체를 가리키는 포인터이다.(각 배열의 원소는 포인터 변수) 알다시피 포인터를 사용하여 객체의 구성원에 접근하려면 -> 연산자를 사용한다. 이것을 모두 합해놓으면 아래와 같은 문법이 이루어 진다. persPtr[j]->getName();
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.08
// 제  목 : 객체 포인터 배열
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

class person
{
protected:
    char name[ 40 ];

public:
    void setName( void ) {
        cout << "Enter name : ";
        cin >> name;
    }

    void printName( void ) {
        cout << "\n    Name is : "
             << name;
    }
};

//---------------------------------------------------------------------------

#pragma argsused
void main()
{

    person* persPtr[ 100 ];
    int n = 0;
    char choice;

    do {
        persPtr[n] = new person;
        persPtr[n]->setName();
        n++;
        cout << endl << "Enter another (y/n) ? ";
        cin >> choice;
    } while ( choice == 'y' );

    for( int j = 0; j < n; j++ ) {
        cout << "\nPerson number " << (j+1);
        persPtr[j]->printName();
    }
    while( n ) delete persPtr[--n];

    getch();

}

//---------------------------------------------------------------------------
(4) this와 const 정적 구성원 함수는 특정 객체가 아니라 클래스 전체와 관련되므로 this 포인터를 사용할 수 없다. 객체를 리턴할 때에는 언제나 참조로 리턴하는 것이 좋다. 구성원 함수와 겹지정 연산자에서 참조로 리턴하기는 불필요한 객체가 생기지게 하는 강력하고도 일반적인 접근 방식이다.
//---------------------------------------------------------------------------
// 작성일 : 2001.09.10
// 제  목 : this 포인터의 내용을 리턴
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

class alpha
{
private:
    int data;

public:
    alpha() {}

    alpha( int d ) { data = d; }

    void display() { cout << data; }

    alpha& operator = ( alpha& a ) {
        data = a.data;
        cout << "\nAssignment operator invoked";
        return *this;
    }
};

//---------------------------------------------------------------------------

#pragma argsused
void main()
{

    alpha a1( 37 );
    alpha a2, a3;

    a3 = a2 = a1;

    cout << "\na2 = ";
    a2.display();

    cout << "\na3 = ";
    a3.display();

    getch();

}

//---------------------------------------------------------------------------

(결과)
Assignment operator invoked
Assignment operator invoked
a2 = 37
a3 = 37

//---------------------------------------------------------------------------
- 포인터와 const 데이터형 앞에 const가 놓이면(p의 정의에서와 같이), 그 결과는 상수 변수에 대한 포인터이다. ( 포인터가 가리키는 변수의 값을 변경할 수 없다. ) 데이터형 뒤에 const가 놓이면(q의 정의에서와 같이), 그 결과는 변수에 대한 상수 포인터이다. ( 포인터의 주소를 변경할 수 없다. )
    int a;

    const int* p = &a;        // 상수 int 포인터
    ++p;                      // 좋음
    ++(*p);                   // 오류 :  const a는 변경 불가능

    int* const q = &a;        // int에 대한 상수 포인터
    ++q;                      // 오류 : const q는 변경 불가능
    ++(*q);                   // 좋음

    const int* const r = &a;  // 상수 int에 대한 상수 포인터
    ++r;                      // 오류 : const r는 변경 불가능
    ++(*r);                   // 오류 : const a는 변경 불가능
- const인 변수가 있는데 그 포인터를 정의하려 할 때
    const int b = 99;    // const 변수
    int* r = &b;         // 오류 : const를 const가 아닌 것으로 변환할 수 없음
    const int* s = &b;   // 좋음
    int* const t = &b;   // 오류 : const를 const가 아닌 것으로 변환할 수 없음
- const 리턴
    const int* func() {
        return &j;            // 좋음
    }

    const int* p = func();    // 좋음
(5) 예제 프로그램 - String Class strCount Class는 실제 문자열 포인터와 이 문자열을 가리키는 xString Class 객체 수를 포함하고 있다.
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.10
// 제  목 : xString 객체
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

class strCount
{
private:
    int count;
    char* str;

public:
    strCount( const char* const s ) {
        int length = strlen( s );
        str = new char[ length + 1 ];
        strcpy( str, s );
        count = 1;
    }

    ~strCount() {
        delete[] str;
    }

    char* getstr() {
        return str;
    }

    int getCount() {
        return count;
    }

    void incCount() {
        ++count;
    }

    void decCount() {
        --count;
    }
};

/////////////////////////////////////////////////////////////////////////////

class xString
{
private:
    strCount* psc;

public:
    xString() {
        psc = new strCount( "NULL" );
    }

    xString( const char* const s ) {
        psc = new strCount( s );
    }

    xString( const xString& S ) {
        cout << "\nCOPY CONSTRUCTOR";
        psc = S.psc;
        psc->incCount();
    }

    ~xString() {
        if( psc->getCount() == 1 )
            delete psc;
        else
            psc->decCount();
    }

    void display() {
        cout << psc->getstr();
        cout << " (addr = " << psc << ")";
    }

    xString& operator = ( const xString& S ) {
        cout << "\nASSIGNMENT";
        if( psc->getCount() == 1 )
            delete psc;
        else
            psc->decCount();
        psc = S.psc;
        psc->incCount();
        return *this;
    }
};

//---------------------------------------------------------------------------

#pragma argsused
void main()
{

    xString s1 = "When the fox preaches, look to your geese.";
    cout << "\ns1 = ";  s1.display();

    xString s2;
    s2 = s1;
    cout << "\ns2 = ";  s2.display();

    xString s3(s1);
    cout << "\ns3 = ";  s3.display();

    getch();

}

//---------------------------------------------------------------------------

(결과)
s1 = When the fox preaches, look to your geese. (addr = 008649FC)
ASSIGNMENT
s2 = When the fox preaches, look to your geese. (addr = 008649FC)
COPY CONSTRUCTOR
s3 = When the fox preaches, look to your geese. (addr = 008649FC)

//---------------------------------------------------------------------------
- Linklist Class Class나 Struct는 자체 형의 객체 포인터는 포함할 수 있지만 자체 형의 객체는 포함할 수 없다. class sampclass { sampleclass obj; // 포함 불가 samplecalss* ptr; // 포함 가능 };
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.11
// 제  목 : LinkList
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

struct link
{
    int data;
    link* next;
};

/////////////////////////////////////////////////////////////////////////////

class linklist
{
private:
    link* first;

public:
    linklist() {
        first = NULL;
    }

    void additem( int d );
    void display();
};

/////////////////////////////////////////////////////////////////////////////

void linklist::additem( int d )
{
    link* newlink = new link;
    newlink->data = d;
    newlink->next = first;
    first = newlink;
}

void linklist::display()
{
    link* current = first;
    while( current != NULL ) {
        cout << endl << current->data;
        current = current->next;
    }
}

//---------------------------------------------------------------------------

#pragma argsused
void main()
{

    linklist li;

    li.additem( 25 );
    li.additem( 36 );
    li.additem( 49 );
    li.additem( 64 );

    li.display();

    getch();

}

//---------------------------------------------------------------------------

(결과)
64
49
36
25

//---------------------------------------------------------------------------
- Binary Search Class (Auto Sorted) SortedArray의 insert() 구성원 함수에 2진 검색을 사용하여 새 구성원이 삽입될 자리를 알아내면 보다더 효율적인 프로그램이 될 것이다. Class 객체를 초기화할 때에는 반드시 그 생성자를 호출해야 한다.
    employee emparr[LIMIT] = 
        { employee("Webley", 468L),        // 생성자 호출
          employee("Suzuki", 672L),
          ...
          employee("O'Grady", 573L)
        };
하지만 객체의 배열을 구조체에서와 같이 초기화할 수 없다.
    employee emparr[LIMIT] = { {"Webley", 468L},   // 이런 방식은
                               {"Suzuki", 672L},   // 유효한
                               ...                 // 문법이
                               {"O'Grady", 573L},  // 아님
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.11
// 제  목 : 정렬된 사원 객체 배열을 2진 검색으로 사원을 찾는다.
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------

class employee
{
private:
    enum { LEN = 30 };
    char name[LEN];
    unsigned long number;

public:
    employee( char* na, unsigned long nu ) : number( nu ) {
        strcpy( name, na );
    }

    void putdata() const {
        cout << "\n    Name = " << name;
        cout << "\n    Number = " << number;
    }

    unsigned long get_number() const {
        return number;
    }
};

/////////////////////////////////////////////////////////////////////////////

class SortedArray
{
private:
    enum { SIZE = 100 };
    employee* arr[SIZE];
    int total;

public:
    SortedArray() : total(0) {}
    employee* operator[](int) const;
    void insert(employee*);
    employee* search( unsigned long );
};

employee* SortedArray::operator[](int n) const {
    return arr[n];
}

void SortedArray::insert( employee* data ) {
    int j = 0;
    while( j < total && data->get_number() > arr[j]->get_number() )
        j++;

    for( int k = total; k > j; k-- )
        arr[k] = arr[k-1];
    arr[j] = data;
    total++;
}

// 지정된 사번을 가진 사원을 찾는 2진 검색
employee* SortedArray::search( unsigned long num_to_find ) {
    int lower = 0;
    int upper = total;
    int index;

    while( upper > lower ) {
        if( upper - lower > 1 )
            index = lower + (upper - lower) / 2;
        else
            index = upper = lower;

        employee* ptr = arr[index];
        unsigned long num = ptr->get_number();
        if( num == num_to_find )
            return ptr;

        if( num < num_to_find )
            lower = index;
        else
            upper = index;
    }
    return NULL;
}

//---------------------------------------------------------------------------

#pragma argsused
void main()
{

    int j;
    SortedArray sa;
    unsigned long number;
    employee* pemp;
    const int LIMIT = 10;

    employee emparr[LIMIT] =
        { employee("Webley", 468L),
          employee("Suzuki", 672L),
          employee("Smith", 371L),
          employee("Gonzalez", 274L),
          employee("Wong", 431L),
          employee("LeMonde", 789L),
          employee("Weinstein", 147L),
          employee("DeCarlo", 223L),
          employee("Nguyen", 390L),
          employee("O'Grady", 573L)
        };
    for( j = 0; j < LIMIT; j++ )
        sa.insert( emparr + j );

    for( j = 0; j < LIMIT; j++ ) {
        cout << "\nEmployee " << (j+1);
        sa[j]->putdata();
    }

    cout << "\n\nEnter employee number to search for : ";
    cin >> number;
    pemp = sa.search( number );
    if( pemp != NULL ) {
        cout << "\nEmployee with that number is";
        pemp->putdata();
    }
    else
        cout << "\n such employee number in database.";

    getch();

}

//---------------------------------------------------------------------------

(결과)
Employee 1
    Name = Weinstein
    Number = 147
Employee 2
...
...
...
Employee 10
    Name = LeMonde
    Number = 789

Enter employee number to search for : 789

Employee with that number is
    Name = LeMonde
    Number = 789

//---------------------------------------------------------------------------
Lyn [tohnokanna]   2009-06-21 12:05 X
실시간 업데이트?~
남병철.레조 [lezo]   2009-06-23 01:04 X
포인터 예제 마지막 부분 작성한 날자가... 2001.9.11... ㄷㄷㄷ
그날 저녁 숙소로 돌아가서 씻고 나오니 헐리우드 영화의 한 장면 처럼 미국의 쌍둥이 빌딩을 향해 돌진하는 여객기의
모습을 볼 수 있었던 기억이 납니다. -_-;;



+ -

관련 글 리스트
34 (05) Pointer in C++ 남병철.레조 12409 2009/06/21
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.