'Pointer'에 해당되는 글 4건

Programming/C C++
C와 C++의 차이중 가장 큰 것이 바로 Class개념입니다. 현재에도 Class는 java나 C#그리고 VB.NET에까지 다양한 언어에서 객체지향프로그래밍(OOP)으로 Class개념이 사용되고 있습니다.

C++에서 Class는 원래 C의 구조체를 좀더 효휼적으로 바꾸고자 해서 등장했다는 얘기가 있습니다. 실제로 정말 그런지는 확실하지 않지만 만일 C에서 구조체를 접해보신 경우라면 'C의 구조체에 변수 Member와 더불어 함수까지도 포함시킬 수 있게 한것이 Class다.' 라고 이해(꼭 그렇다는 것은 아니지만...)하시면 될듯 합니다.

다음은 C++에서 구조체를 활용한 예입니다.

#include <iostream.h>
#include <string.h>

main()
{
  struct exam{
    char name[15];
    int kuk;
    int mat;
    int eng;
  };
 
  exam student;
 
  strcpy(student.name, "kim young soo");
  student.kuk = 90;
  student.mat = 100;
  student.eng = 80;
 
  cout << "학생이름 : " << student.name << endl;
  cout << "국어점수 : " << student.kuk << endl;
  cout << "수학점수 : " << student.mat << endl;
  cout << "영어점수 : " << student.eng << endl;
 
  return 0;
}


exam구조체를 선언하고 각 변수 Member에 값을 설정한뒤 설정한 값을 확인하는 Program입니다.


Pogram에서 쓰인 구조체를 Class화 하려면 다음과 같이 바뀔 수 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

위 구조체를 class로 바꾼것으로서 exam을 Class로 정의하였습니다. 이 Class안에 name과 kuk, mat, eng라는 Member변수와 더불어 name_input, memberprint, kuk_input, mat_input, eng_input이라는 Member함수도 같이 존재하도록 하였습니다.

여기서 Member함수는 위 Member변수를 설정할 수 있도록 하기 위해 정의한 것입니다. (Memberprint()함수는 각 설정값을 확인하기 위한 용도로 사용하려고 합니다.)

위 Class에서 private와 public은 현재 Class에서 어떤 Member에 대해 접근 가능하게 할지 또 어떤 Member에 대해서 접근을 막을지에 대해 지정하는 것이라고 보시면 됩니다. 이때 private은 해당 Member에 대해 접근을 불가능하게 하는 Keyword이며 public는 접근을 허락하는 Keyword입니다.(protected 라는 Keyword가 있지만 이는 잠시 후 설명드리도록 하겠습니다.)

물론 Member변수에 public Keyword를 쓴다면 접근이 가능하게 할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);

    int eng;
};


eng Member변수를 public하위에 정의하였습니다.

student.eng = 90;

public으로 정의된 eng는 직접접근이 가능합니다.

private의 경우에는 생략할 수도 있습니다. 이는 처음 Member는 private로 처리하는 것이 기본으로 되어 있기 때문에 가능한 것입니다.

class exam{
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

이렇게 생략하면 다른 Keyword가 등장할때까지 모든 Member는 private로 처리됩니다.

이와 더불어 각 Keyword를 반복해서 쓸 수도 있습니다. 이는 해당 Member를 특성에 따라 Group으로 구분하고자 할때 유용하게 사용됩니다.

class exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
 
  public:
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
   
  private:
    int kuk;
    int mat;
    int eng;
};

private과 public Keyword는 여러번 쓸 수 있습니다.

Class안의 Member변수를 private에 둘것인가 public에 둘것인가 또는 Member함수를 private에 둘것인가 public에 둘것인가 하는 문제는 어디까지나 개발자의 자유이므로 어떤형태로든지 작성될 수 있습니다.

다음은 위 Class를 실제 Program적용시킨 예입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

main()
{
  exam student;
 
  int kukp;
  int matp;
  int engp;
 
  student.name_input("youngsoo");
 
  kukp = student.kuk_input(80);
  matp = student.mat_input(91);
  engp = student.eng_input(94);
 
  student.memberprint();

  cout << "국어점수(가산) : " << kukp << endl;
  cout << "수학점수(가산) : " << matp << endl;
  cout << "영어점수(가산) : " << engp << endl;
 
  return 0;
}


먼저 Program상단에 exam이라는 Class를 정의하였습니다. 이렇게 선언된 Class를 실제 사용하기 위해서는 Class의 Object를 생성해야 하며 생성 방법은 구조체를 사용할때와 비슷합니다.

exam student;

exam Class에서 student의 Object를 생성합니다.

보시는 바와 같이 Class는 Object생성해야 사용할 수 있습니다. Class에 바로 접근할 수 없다는 얘기인데 그 이유는 어느 한쪽에서 Class Member의 값을 수정하면 다른쪽에도 영향을 받을 수 있기 때문으로 Class를 사용할때는 Class자체를 특정이름으로 복사해서 사용해야할 필요성이 있는 것입니다. 이 Class의 복사본을 생성하는 과정을 흔히 Instance라고 하며 Instance에 의해 생성된 것(여기서는 student)을 Object(객체)라고 합니다.

위 Class는 Member변수와 Member함수를 가지도록 하였고 모든 Member변수는 private을 모든 Member함수는 public Keyword를 사용하였습니다. 따라서 Class의 Member변수에는 직접적으로 접근할 수 없지만 Member함수는 직접 접근이 가능합니다.

앞서 말씀드렸듯이 Class의 Member에는 접근이 불가능하므로 구조체를 사용할때 처럼 직접 값을 설정하는 것은 불가능합니다.

student.kuk = 90;

kuk Member변수는 private에 속하므로 위와 같이 값을 설정할 수 없습니다.

Class를 제대로 사용하기 위해서는 어떻게든 값을 설정해야할 필요가 있습니다. 그래서 public하위에 값을 설정할 수 있는 함수를 정의한 것입니다.

name_input, memberprint, kuk_input, mat_input, eng_input 함수는 public로 선언되었으므로 private로 선언된 Member변수와는 달리 직접 접근이 가능합니다. 이렇게 선언된 Member함수는 실제 이 함수가 어떤 기능을 수행할지 그 본체를 구현해야 하며 이때 구현은 Class밖에서 다음과 같은 방식으로 정의됩니다.

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}


Class안에 선언된 함수는 위와 같이 그 본체를 구현합니다.

위와 같은 방식은 Class의 특정 Member변수를 설정할때 꽤 유용하게 사용될 수 있는 부분입니다. 예를 들어 국어시험에서 모든 문제를 틀리면 0점이 됩니다. 시험을 아무리 못봐도 0이하(-값)은 될 수 없는데 만일 kuk이라는 Member변수에 -100을 설정하게 된다면 이것 자체가 오류가 됩니다.

이러한 상황이 생기는 것을 막으려면 kuk_input()함수를 다음과 같이 수정해야 합니다.

int exam::kuk_input(int pt)
{
  if (pt < 0){
    cout << "점수설정에 오류가 있습니다." << endl;
    return 0;
  }
 
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

pt값이 0이하이면 kuk member변수에 값을 설정할 수 없도록 합니다. 즉, 특정값에 따라 원하는 처리를 수행할 수 있도록 할 수 있는 것입니다.

또한 Class구현시 Class에서 선언된 각 Member함수와 실제 함수의 본체를 별도로 하는것이 불편하다면 다음과 같이 아예 Class안에서 모든것을 해결할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm){
      strcpy(name, nm);
    }
   
    void memberprint(){
      cout << "학생이름 : " << name << endl << endl;
      cout << "국어점수 : " << kuk << endl;
      cout << "수학점수 : " << mat << endl;
      cout << "영어점수 : " << eng << endl;
    }
   
    int kuk_input(int pt){
      int ptp = pt;
 
      if (pt >= 90)
        ptp = pt + 3;
 
      kuk = pt;
 
      return ptp;
    }
   
    int mat_input(int pt){
      int ptp = pt;
 
      if (pt >= 90)
        ptp = pt + 3;
 
      mat = pt;
 
      return ptp;
    }
   
    int eng_input(int pt){
      int ptp = pt;
 
      if (pt >= 90)
        ptp = pt + 3;
 
      eng = pt;
 
      return ptp;
    }
};

Class안에서 함수구현까지 모두 처리하고 있습니다.

위 함수에서 쓰인 exam:: 부분은 exam Class의 함수를 구현하겠다는 의미가 됩니다. 이렇게 함수를 구현한뒤 구조체처럼 함수를 호출하면 실제 위와 같이 구현된 동작을 수행하게 되는 것입니다.

참고 :
int exam::kuk_input(int pt)에서 ::문자를 Scope연산자라고 합니다. Scope연산자는 다양한 역활을 수행하는데 여기에서는 Class의 Member에 접근하도록 하는 역활을 수행하고 있습니다. 이때 Scope연산자는 exam의 kuk_input member 처럼 ~의 ~ 로 해석될 수 있습니다.

student.name_input("youngsoo");
 
  kukp = student.kuk_input(80);
  matp = student.mat_input(91);
  engp = student.eng_input(94);
 
student.memberprint();

Class의 함수를 호출합니다.

Class안의 각 함수는 Class안의 Member변수에 값을 설정할 수 있도록 구현되었습니다.(memberprint()함수는 값을 확인하도록 하였습니다.) 즉, Class안의 Member함수를 통해 Member변수에 접근하고 있는 것입니다.(이는 위에서 말씀드린 Scope연산자의 의해 가능해 집니다.)

이렇게 값을 설정하고 memberprint()함수를 호출하면 각 Member변수의 값을 확인할 수 있습니다.

위 Member함수에서 name이 아닌 kuk, mat, eng member변수를 설정하는 함수를 보면

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}


pt값이 90이상일때 3을 더하도록 구현되어 있음을 알 수 있습니다. 점수로 치면 90점 이상일때 가산점 3을 더하도록 하기 위한 의도입니다. 각 함수에서는 가산점이 붙은 값을 return하고 있으며 main()은 위 세개의 함수를 호출할때 계산된 가산점을 받도록 하고 있습니다.

kukp = student.kuk_input(80);
matp = student.mat_input(91);
engp = student.eng_input(94);

이처럼 Class의 Member함수도 일반 함수처럼 void로 할 수 있고 필요하다면 특정 값을 받도록 할 수도 있습니다. Class안의 함수라고 해서 일반함수와 특별히 다를 것은 없습니다.


만일 같은 Class에서 파생된 Object가 2개상이 있다면 상호간의 Object대입을 통해서 값을 초기화 할 수도 있습니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

main()
{
  exam student, student2;
 
  int kukp;
  int matp;
  int engp;
 
  student.name_input("youngsoo");
 
  kukp = student.kuk_input(80);
  matp = student.mat_input(91);
  engp = student.eng_input(94);
 
  student.memberprint();
  student2 = student;
  student2.memberprint();
 
  return 0;
}


exam Class로부터 student와 student2라는 Object를 생성하고 student object에서 값을 설정한 후 student2 Object에 student Object를 대입하였습니다.

student.memberprint();

이 후 student2 Object의 값을 확인해 보면 student Object와 값이 일치함을 알 수 있습니다.


위에서는 단일 Object를 설정하여 해당 Class에 값을 설정하였지만 Class를 통해 생성한 Object를 배열로 하면 해당 Class의 복사본을 배열길이만큼 확보할 수 있게 됩니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
    int mat;
    int eng;
 
  public:
    void name_input(char *nm);
    void memberprint();
   
    int kuk_input(int pt);
    int mat_input(int pt);
    int eng_input(int pt);
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

int exam::kuk_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  kuk = pt;
 
  return ptp;
}

int exam::mat_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  mat = pt;
 
  return ptp;
}

int exam::eng_input(int pt)
{
  int ptp = pt;
 
  if (pt >= 90)
    ptp = pt + 3;
 
  eng = pt;
 
  return ptp;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl << endl;
}

main()
{
  exam student[2];
 
  student[0].name_input("youngsoo");
  student[0].kuk_input(80);
  student[0].mat_input(91);
  student[0].eng_input(94);
 
  student[1].name_input("sooyoung");
  student[1].kuk_input(70);
  student[1].mat_input(81);
  student[1].eng_input(84);
 
  student[0].memberprint();
  student[1].memberprint();
 
  return 0;
}


exam student를 exam student[2]로 하여 2개의 배열길이만큼 Object를 생성합니다.

배열도 단일 Object와 똑같이 값을 설정하면 됩니다. [0]이나 [1]을 붙여 몇번째 배열에 Member를 호출하는지만 지정해 주면 되는 것입니다.


다만 일일이 첨자를 붙여 초기화 해주는 것이 불편하다면 문자배열을 초기화 하듯 {}를 써서 한꺼번에 초기화 할 수도 있습니다. 이는 생성자를 통해서 가능한데 자세한 내용은 생성자와 소멸자 부분을 참고해 주시기 바랍니다.

[Develop/C, C++] - [C, C++] Class구현시 생성자와 소멸자 활용

Class를 활용한 다음 Program을 봐주십시오.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
   student.memberprint();
 
  return 0;
}



위 Program에서 Class의 name과 kuk member에 접근하기 위해 Class내에서 memberprint()함수를 public으로 선언하였습니다.

따라서 이 함수외에 다른 외부함수에서는 name과 kuk member에 접근할 수 없게 되었습니다. 왜냐하면 name과 kuk member는 class안에서 private으로 선언되었기 때문입니다.

하지만 Program안에서 private Member에 접근할 수 있는 방법이 있는데 그것은 Class안에 friend함수를 선언하는 것입니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend void kukinout(exam ea);
};

위와 같이 Class안에서 friend함수를 선언하면 해당 함수는 private나 public의 적용을 받지 않습니다. 왜냐하면 friend함수는 Class의 Member가 아니기 때문입니다. 이것은 단지 Program내에서 kukinout함수가 있으면 이 함수안에서 만큼은 Class의 private Member에 접근을 허용한다라는 의미만 가지고 있을 뿐입니다. 즉, 외부함수와 Class간의 통로역활만 하고 있는 것입니다.

또한 friend함수에서 함수의 인수로 exam형의 인수(exam ea)를 지정하고 있습니다. 이는 Program안에서 kukinout함수를 작성할때 Class의 Member에 접근하기 위해 Class로 부터 파생된 Object를 전달해 줄 필요가 있기 때문입니다.

Class안에서 작성된 friend함수의 특성을 활용하기 위해서는 Program안에서 kukinout라는 똑같은 이름의 함수를 작성해야 합니다.

void kukinout(exam ea)
{
  ea.kuk = 20;
  cout << "국어점수 : " << ea.kuk << endl;
}

인수로 부터 전달받은 Object를 통해 Private Member인 kuk member의 값을 설정하고 그 값을 확인하고 있습니다.

kukinout함수는 Class가 아닌 Program안에서 쓰인 독자적 함수입니다. 따라서 함수의 원형도 선언할 수 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend void kukinout(exam ea);
};

void kukinout(exam ea);


함수의 원형을 Class밑에 선언하는 이유는 이 원형이 Class선언 이전에 위치하게 되면 exam이 정의되지 않았다는 오류를 일으키기 때문입니다.

이제 지금까지 말씀드린 모든 Code를 모두 조합하여 Program을 작성하면 다음과 같이 될 것입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend void kukinout(exam ea);
};

void kukinout(exam ea);
void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
  student.memberprint();
 
  kukinout(student);
 
  return 0;
}

void kukinout(exam ea)
{
  ea.kuk = 20;
  cout << "국어점수 : " << ea.kuk << endl;
}


kukinout(student); 로 kukinout함수를 호출합니다.


friend 함수는 Program안에서 쓰인 특정 함수에 대해서만 Class의 Member접근을 허용하는 것입니다. 하지만 Class자체를 friend화 하면 해당 Class전체에 대해서 Member접근을 허용할 수 있게 됩니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend class exam2;
};

class exam2 : public exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
};


위와 같이 Class자체를 friend로 선언하면 friend Class는 본래 Class의 모든 Member에 접근할 수 있게 됩니다. 단, Class exam2 : public exam 처럼 본래 Class로 부터 상속받는 Class인 경우에만 가능합니다.

Class의 상속에 대한 내용은 다음 글을 참고하여 주십시오.

[Develop/C, C++] - [C, C++] Class 상속

이렇게 되면 exam2 Class에서는 본래 Class Member를 원하는 대로 다룰 수 있게 됩니다.

void exam2::memberprint()
{
  kuk = 20;
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

exam2에서 exam Class의 kuk member에 접근하여 값을 설정하고 그 값을 확인하고 있습니다.(exam2 Class에서 Member변수는 name뿐입니다.)

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
   
    int kuk_input(int pt);
   
    friend class exam2;
};

class exam2 : public exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

void exam2::name_input(char *nm)
{
  strcpy(name, nm);
}

void exam2::memberprint()
{
  kuk = 20;
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
  exam2 student2;
 
  student.name_input("youngsoo", 90);
  student.memberprint();
 
  student2.name_input("sooyoung");
  student2.memberprint();
 
  return 0;
}



private는 Member로의 접근방지, public는 Member의 접근허용 용도로 사용됩니다. C++에서는 이와 더불어 protected라는 Keyword가 있습니다. 이것은 일반적으로는 private의 성격을 가지고 있으나 다른 Class가 해당 Class로터 상속될때에는 public성격을 가지는 특징이 있습니다.

Class의 Public는 다음과 같이 Program내에서 접근이 가능하지만

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
  student.memberprint();

  return 0;
}



이것을 protected로 고치면 상황은 달라집니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  protected:
    void name_input(char *nm, int i);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  exam student;
 
  student.name_input("youngsoo", 90);
  student.memberprint();

  return 0;
}



오류발생(접근할 수 없음) Error가 출력되는데 이는 protected Member로의 접근이 오로지 상속된 Class에서만 가능하기 때문입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  protected:
    void name_input(char *nm, int i);
    void memberprint();
};

class exam2 : public exam{
  public:
    void input();
    void print();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

void exam2::input()
{
  name_input("youngsoo", 90);
}

void exam2::print()
{
  memberprint();
}

main()
{
  exam2 student;
 
  student.input();
  student.print();
 
  return 0;
}


exam Class로 부터 상속하여 exam2 Class를 생성합니다.

상속된 Class는 기존 Class에서 protected된 Member에 다음의 형태처럼 접근하는 것이 가능해 집니다.

void exam2::input()
{
  name_input("youngsoo", 90);
}

void exam2::print()
{
  memberprint();
}


상속된 exam2 Class에서 exam Class의 protected Member인 name_input과 memprint Member에 접근하고 있습니다.


위의 friend설명부분에서 쓰인 memberprint()함수를 다시 한번 살펴보겠습니다.

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

이 함수에서는 exam Class의 name, kuk, mat, eng member변수의 값을 확인하도록 하고 있습니다. 그런데 만일 이 함수안에 어떠한 이유로 인하여 kuk이라는 변수가 새로 선언되었을때 결과는 어떻게 될까요?

void exam::memberprint()
{
  int kuk = 0;
 
  cout << "학생이름 : " << name << endl << endl;
  cout << "국어점수 : " << kuk << endl;
  cout << "수학점수 : " << mat << endl;
  cout << "영어점수 : " << eng << endl;
}

memberprint()함수안에 kuk이라는 변수를 선언하고 초기값을 0으로 합니다.


Program실행결과가 0으로 나왔습니다. 이는 Class의 kuk Member가 아니라 함수안에서 쓰인 kuk변수값을 가져오고 있기 때문입니다.

이렇게 혼동되는 문제를 해결하는 방법에는 두가지가 있는데 하나는 해당 Member에 Class를 지정해 주는 것이며

cout << "국어점수 : " << exam::kuk << endl;

다른 하나는 This Pointer를 지정하는 것입니다.

cout << "국어점수 : " << this->kuk << endl;

이 This Pointer는 이름에서도 알 수 있듯이 주소값을 갖는 Pointer로서 해당 주소는 다름아닌 Class에서 생성된 Object의 주소를 갖고 있는 것입니다.

결국

exam student;

student.memberprint();


이와같이 하였을때 This에는 student Object의 주소가 담겨져 전달되기 때문에 Class의 kuk Member값을 가져오게 됩니다.

방금전 This Pointer를 사용해 보았는데 이것으로 알 수 있는것은 Class의 Member에 접근하는데 Object를 통해서만 아니라 Pointer를 통해 접근할 수도 있다는 것입니다.

아래 예제는 위에서 다룬 Program에서 점수부분은 빼고 이름만 설정/확인할 수 있도록 간소화한 예제입니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
 
  public:
    void name_input(char *nm);
    void memberprint();
};

void exam::name_input(char *nm)
{
  strcpy(name, nm);
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
}

main()
{
  exam student;
 
  exam *p = &student;
 
  student.name_input("youngsoo");
  student.memberprint();
 
  p->memberprint();
 
  return 0;
}


student의 Object주소값을 exam형 Class의 Pointer에 전달하고 이 Pointer를 통하여 Class의 memberprint() Member함수에 접근하고 있습니다.

Object의 주소값을 Pointer에 넘기려면 해당 Pointer가 Object가 생성된 Class형으로 선언되어야 하며 이 Pointer에 & 연산자를 통하여 Object의 주소값만 넘겨주기만 하면 됩니다.

이 후 Object의 주소를 전달받은 Pointer는 -> 연산자를 통해 Class의 Member에 접근하도록 합니다.


Class로부터 생성된 Object를 Const로 선언하면 해당 Object에서는 각 Member에 접근할 수 없는 상황이 발생합니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    void name_input(char *nm, int i);
    void memberprint();
};

void exam::name_input(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint()
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  const exam student;

  student.name_input("youngsoo", 90);
  student.memberprint();
 
  return 0;
}


exam Class의 student Object를 const로 선언하였습니다.


잘 아시는 바와 같이 const는 상수입니다. 즉, 값을 바꿀 수 없는 것이기 때문에 Member접근 자체가 차단되는 것입니다.

값을 설정하는 name_input member함수는 그렇다 치고 단순히 값을 조회하는 memberprint()함수까지 차단되는 이유는 뭘까요? 이는 C++ Compiler가 어떤 함수에서 값을 변경하고 또 어떤 함수에서 값을 변경하지 않는지까지는 판단하지 않기 때문입니다.

즉, 값을 변경하는 부분과 값을 변경하지 않는 부분을 구분하지 않기 때문에 아예 모두 틀어막아 버릴 수 밖에 없게 되는 것이죠.

이렇게 되면 값을 확인할 수도 없어서 const로 설정하는 것 자체가 거의 무의하게 되지만 값을 바꾸지 않는 Class의 Member함수에 한하여 const로 선언하게 되면 해당 함수는 사용을 가능하게 할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    exam(char *nm, int i);
    void memberprint() const;
};

Class에서 memberprint() Member함수에 const선언하였습니다. memberprint()는 값을 설정하는 부분이 없고 오로지 값을 확인하는 부분만 존재합니다.

또한 해당 Class의 각 Member에 초기값을 설정하기 위해 exam생성자를 선언하였습니다. 만일 생성자가 아닌 기존에서 처럼

void name_input(char *nm, int i);

하여 Member함수로 값을 설정하려고 하면 해당 Object생성시 const로 했을때 값을 설정하는 Member로의 접근이 차단 되므로 초기값을 설정하는 것 자체가 불가능하게 됩니다.

생성자에 대해서는 다음글을 참고하여 주십시오.

[Develop/C, C++] - [C, C++] Class구현시 생성자와 소멸자 활용

Class에서 memberprint()함수에 const를 선언하고 나면 해당 함수의 정의부분에서도 const를 추가해야 합니다.
void exam::memberprint() const
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

함수 정의 마지막 부분에 const구문을 추가하였습니다.

만일 Class안에서 선언과 정의가 동시에 이루어 지는 경우라면 다음과 작성할 수도 있습니다.

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    exam(char *nm, int i);
    void memberprint() const {
      cout << "학생이름 : " << name << endl;
      cout << "국어점수 : " << kuk << endl;
    }
};

마지막으로 선언된 생성자에 대한 정의를 작성한 후

exam::exam(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

초기화를 수행하는 부분을 추가하면 다음과 같이 될것입니다.

main()
{
  const exam student("youngsoo", 90);
  student.memberprint();
 
  return 0;
}

student Object생성과 동시에 초기화 합니다. 이때 const선언도 같이 이루어 지도록 합니다.

위와 같은 내용으로 Program을 완성시켜 보겠습니다.

#include <iostream.h>
#include <string.h>

class exam{
  private:
    char name[15];
    int kuk;
 
  public:
    exam(char *nm, int i);
    void memberprint() const;
};

exam::exam(char *nm, int i)
{
  strcpy(name, nm);
  kuk = i;
}

void exam::memberprint() const
{
  cout << "학생이름 : " << name << endl;
  cout << "국어점수 : " << kuk << endl;
}

main()
{
  const exam student("youngsoo", 90);
  student.memberprint();
 
  return 0;
}


const에 대한 Member함수 접근


memberprint()는 const선언되었으므로 정상적인 처리 가능

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

표준 Library 함수 - Memory 관련 함수  (0) 2011.06.16
[C, C++] Class구현시 생성자와 소멸자 활용  (0) 2011.06.01
[C, C++] Class  (0) 2011.05.25
[C, C++] cout 서식지정  (0) 2011.04.14
[C, C++] 구조체  (1) 2011.04.13
[C, C++] 변수선언및 초기화  (0) 2011.04.07
0 0
Programming/C C++
구조체는 서로 연관된 변수(Data)를 한곳에 묶어놓은 형태를 말합니다. 예를 들어 어떤 학생의 국어, 영어, 수학 성적을 관리하기 위해 다음과 같이 변수를 선언하였을때

int kuk;
int eng;
int mat;

위 변수를 구조체로 묶으려면 다음과 같이 선언될 수 있습니다.

struct score {
 int kuk;
 int eng;
 int mat;
};

이때 구조체는 구조체 내부에서 또 다른 구조체를 포함할 수 있습니다.

struct score {
    int kuk;
    int eng;
    int mat;
};

struct total_score {
   int t_kuk;
   int t_eng;
   int t_mat;
   
   struct score sre;
 };
}


total_score구조체 안에 score구조체를 포함하고 있습니다. (이때 score구조체는 total_score안에서 sre라는 변수로 선언되었으며 이러한 형태의 구조체를 내부구조체라 합니다.)

구조체 이름과 변수명은 개발자 임의로 정할 수 있으며 또한 구조체 안에 변수는 그 Data형을 각각 다르게 지정할 수도 있습니다.

struct score {
 int kuk;
 char eng;
 float mat;
};

이때 구조체안에서 정의된 변수명과 외부에서 선언된 변수명이 같다하더라도 변수명은 충돌하지 않습니다.

struct score {
 int kuk;
 char eng;
 float mat;
};

int kuk;

이렇게 선언된 구조체는 이 구조체 하나만으로 새로운 Data형이 될 수 있습니다. 따라서 선언된 구조체를 실제 사용하려면 새로운 변수명으로 구조체를 선언해야 합니다.

struct score student_sre;

score구조체를 student_sre라는 이름으로 선언하였습니다. 하지만 정의와 선언을 구분하지 않고 정의와 동시에 선언할 수도 있습니다.

struct score {
 int kuk;
 int eng;
 int mat;
} student_sre;

score라는 구조체를 정의하고 student_sre라는 이름으로 선언합니다.

구조체의 정의와 선언을 별도로 처리하는 경우 구조체를 선언하려면

struct score student_sre;

라고 해야하지만 일일이 struct ... 를 사용하기 번거롭다면 typedef를 사용하여 구조체를 선언하는 것도 가능합니다.

typedef struct {
 int kuk;
 int eng;
 int mat;
} score;

또는

struct score {
 int kuk;
 int eng;
 int mat;
} typedef struct score student_sre;

이렇게 선언하면 정의는

score student_sre;

로 하여 struct를 생략할 수 있습니다. typedef는 구조체 선언시 해당 구조체의 이름을 score라고 할 수 있도록 해주고 있기 때문입니다.

구조체를 위와 같이 선언하고 해당 변수에 접근하려면 .(점)을 사용하여야 합니다. .(점)은 구조체 Member연산자로서 구조체의 각 Member에 접근할 수 있도록 해줍니다.

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
  };
 
  struct score student_sre;
 
  student_sre.kuk = 90;
  student_sre.eng = 100;
  student_sre.mat = 88;
 
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre.kuk, student_sre.eng, student_sre.mat);
}


구조체 선언변수명.member' 형식을 통해 각각 90, 100, 88이라는 값을 넣고 printf()를 통해 그 값을 확인하고 있습니다.


참고 :
구조체 안의 int kuk, int eng, int mat등.. 선언된 변수를 구조체 Member라고 합니다.

구조체안에 구조체를 포함한 경우에는 그 만큼 .을 연속해서 사용해 해당 구조체의 Member로 접근하면 됩니다.

#include <stdio.h>

main()
{
  struct tlt_score {
    char t_kuk[4];
    char t_eng[4];
    char t_mat[4];
  };
 
  struct score {
    int kuk;
    int eng;
    int mat;
   
    struct tlt_score sre;
  };
 
  struct score student_sre;
 
  student_sre.kuk = 90;
  student_sre.eng = 100;
  student_sre.mat = 88;
 
  strcpy(student_sre.sre.t_kuk, "kuk");
  strcpy(student_sre.sre.t_eng, "eng");
  strcpy(student_sre.sre.t_mat, "mat");
 
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre.kuk, student_sre.eng, student_sre.mat);
  printf("\n");
  printf("국어 : %s\n영어 : %s\n수학 %s\n", student_sre.sre.t_kuk, student_sre.sre.t_eng, student_sre.sre.t_mat);
}


store구조체 안에 tlt_score구조체를 sre라는 변수명으로 포함시키고 student_sre.sre.member형식으로 score안의 tlt_score구조체 Member에 접근하고 있습니다.

참고:
strcpy()는 문자배열에 문자열을 복사하는 표준 Library함수중 하나입니다.

이처럼 '구조체변수명.member명' 형식을 통해 구조체의 각 Member에 값을 초기화 하였는데 이렇게 Member를 일일이 호출하지 않고 구조체를 통틀어 값을 초기화 할 수도 있습니다.

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
  };
 
  struct score student_sre = {90, 100, 88};
 
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre.kuk, student_sre.eng, student_sre.mat);
}


{와 }를 통해 각각의 구조체 Member값을 초기화 하고 있습니다. {}를 쓴다는 점에서 배열을 초기화 하는것과 비슷하지만 구조체는 'struct 구조체명'이 선행되어야 한다는 점에서 일반배열초기화와는 틀리다고 볼 수 있습니다.

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
  }student_sre = {90, 100, 88};
 
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre.kuk, student_sre.eng, student_sre.mat);
}


구조체를 선언과 동시에 초기화 하고 있습니다.

만일 구조체를 배열로 활용한다면 다음과 같이 초기화 할 수 있습니다.

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
  };
 
  struct score student_sre[2] = {{90, 100, 88}, {80, 90, 70}};
...
}


구조체의 배열은 배열 수 만큼 {}를 사용해 초기화 하며 각 초기화 단위는 , 으로 구분합니다.


물론 구조체는 '구조체변수명.member' 또는 {}를 사용하거나 구조체 자체를 통해 값을 초기화 할 수 있으나 변수를 복사하듯 구조체 자체를 복사하여 다른 구조체의 변수에 값을 똑같이 초기화 하는 것도 가능합니다.

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
  };
 
  struct score student_sre_;
  struct score student_sre = {90, 100, 88};
 
  student_sre_ = student_sre;
 
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre.kuk, student_sre.eng, student_sre.mat);
  printf("\n");
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre_.kuk, student_sre_.eng, student_sre_.mat);
}


score구조체를 통해 student_sre_ 와 student_sre라는 이름으로 두개의 변수를 선언하였습니다. 이후 student_sre변수 값을 초기화 하고 해당 변수를 student_sre_변수에 대입함으로써 구조체의 복사를 시도하고 있습니다.


만일 선언된 구조체를 다른 함수간에 전달하려면 자연스럽게 구조체 자체를 넘기거나 주소를 통해서 전달하면 됩니다.

#include <stdio.h>

struct score {
    int kuk;
    int eng;
    int mat;
};
memberprnt(struct score v);

main()
{
  struct score student_sre = {90, 100, 88};
 
  memberprnt(student_sre);
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre.kuk, student_sre.eng, student_sre.mat);
}

memberprnt(struct score v)
{
  printf("memberprnt : \n");
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n\n", v.kuk, v.eng, v.mat);
 
  v.kuk = 10;
  v.eng = 20;
  v.mat = 30;
 
  printf("memberprnt : \n");
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n\n", v.kuk, v.eng, v.mat);
}


각 함수간 구조체를 값의 형태로 전달하고 있습니다.

함수간 구조체를 전달할때 문제가 되는 것은 함수원형부분입니다. 함수원형을 선언할때 인수 부분을 (struct score v)라고 하고 싶지만 그러기 이전에 구조체 score가 뭔지를 알려야 합니다. 때문에 구조체 선언부분을 함수원형을 정의하는 부분 위에다 작성하여 해당 구조체의 정의부터 먼저 이루어 지도록 해야 합니다.


다음은 주소를 통한 구조체 전달의 예입니다.

#include <stdio.h>

struct score {
    int kuk;
    int eng;
    int mat;
};
memberprnt(struct score *p);

main()
{
  struct score student_sre = {90, 100, 88};
 
  memberprnt(&student_sre);
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n", student_sre.kuk, student_sre.eng, student_sre.mat);
}

memberprnt(struct score *p)
{
  printf("memberprnt : \n");
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n\n", p->kuk, p->eng, p->mat);
 
  p->kuk = 10;
  p->eng = 20;
  p->mat = 30;
 
  printf("memberprnt : \n");
  printf("학생의 국어점수 %d\n학생의 영어점수 %d\n학생의 수학점수 %d\n\n", p->kuk, p->eng, p->mat);
}


각 함수간 구조체를 Pointer(주소)의 형태로 전달하고 있습니다.

함수간 구조체에 대한 Pointer를 전달하려면 &문자를 써서 주소값을 넘겨주어야 합니다. 또한 구조체를 전달받은 함수는 .대신 -> 를 써서 각 구조체의 Member에 접근해야 합니다.

위 Program은 주소를 통한 전달이므로 전달받은 함수측에서 구조체의 값을 바꾸면 본래의 구조체에도 영향을 미치게 됩니다.


구조체는 자신 스스로에 대한 값을 다시 참조하는 '자기참조 구조체'를 구현할 수도 있습니다. 즉, 구조체를 정의할때 자기자신을 Pointer로 하여 구조체를 정의하는 것입니다.

struct score {
    int kuk;
    int eng;
    int mat;
   
    struct score *n_score;
};

score 구조체 자신을 n_score라는 이름으로 Pointer(*사용에 주의)선언하여 자기참조구조체를 생성합니다.

실제 Program에서 score구조체를 통해 여러개의 변수가 선언되면

struct score stu_fir, stu_sec, stu_thi;

이들 변수들을 선언된 Pointer(*n_score)를 통해 서로 연결할 수 있게 되는 것입니다.

stu_fir.n_score = &stu_sec;

처음 변수(stu_fir)의 n_score pointer에 stu_sec변수의 주소를 대입합니다.

stu_sec.n_score = &stu_thi;

두번째 변수(stu_sec)의 n_score Pointer에 stu_thi변수의 주소(&사용에 주의)를 대입합니다.

이렇게 하면 각 변수의 n_score에 의해 다음과 같은 구조를 이루게 됩니다.


즉, stu_fir의 n_score는 stu_sec의 시작주소를 가지게 되고 다시 stu_sec의 n_score는 stu_thi의 시작주소를 가지게 되서 stu_fir과 stu_sec 그리고 stu_thi가 마치 기차처럼 서로 연결된 형태를 띄게 되는 것입니다.(이러한 형태를 '연결 List'라고 합니다.)

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
   
    struct score *n_score;
  };
 
  struct score stu_fir, stu_sec, stu_thi;
 
  stu_fir.kuk = 10;
  stu_fir.eng = 20;
  stu_fir.mat = 30;
 
  stu_sec.kuk = 40;
  stu_sec.eng = 50;
  stu_sec.mat = 60;
 
  stu_thi.kuk = 70;
  stu_thi.eng = 80;
  stu_thi.mat = 90;
 
  stu_fir.n_score = &stu_sec;
  stu_sec.n_score = &stu_thi;
 
  printf("stu_fir의 kuk값 : %d\n", stu_fir.kuk);
  printf("stu_sec의 kuk값(stu_fir.n_score pointer를 통해 확인) : %d\n", *stu_fir.n_score);
  printf("stu_thi의 kuk값(stu_sec.n_score pointer를 통해 확인) : %d\n", *stu_sec.n_score);
}


stu_fir.n_score = &stu_sec; 에 의해서 stu_sec의 시작주소가 stu_fir.n_score에 들어가게 됩니다. str_sec의 시작주소라 함은 str_sec구조체 처음 변수인 kuk주소를 의미하며 이후에 stu_sec.n_score = &stu_thi; 도 같은 맥락에서 동작하게 됩니다.


결국 printf()함수에서 *stu_fir.n_score와 *stu_sec.n_score를 통해 해당 주소가 가리키는 값을 가져오게 되면 stu_fir.n_score는 stu_sec.kuk주소를 가지고 있으므로 40을 그리고 stu_sec.n_score는 stu_thi.kuk주소를 가지고 있으므로 70을 표시하게 되는 것입니다.

또한

stu_fir.n_score = &stu_sec;
stu_sec.n_score = &stu_thi;

위와같이 하게 되면 각 변수의 첫 주소값(kuk)만 들어가게 되므로 결과에서 보듯 kuk에 해당하는 값만을 표시하게 됩니다. 이때 만일 eng나 mat의 값을 가져오고 싶다면 다음과 같이 처리합니다.

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
   
    struct score *n_score;
  };
 
  struct score stu_fir, stu_sec, stu_thi;
 
  stu_fir.kuk = 10;
  stu_fir.eng = 20;
  stu_fir.mat = 30;
 
  stu_sec.kuk = 40;
  stu_sec.eng = 50;
  stu_sec.mat = 60;
 
  stu_thi.kuk = 70;
  stu_thi.eng = 80;
  stu_thi.mat = 90;
 
  stu_fir.n_score = &stu_sec;
  stu_sec.n_score = &stu_thi;
 
  printf("stu_fir의 kuk값 : %d\n", stu_fir.kuk);
  printf("stu_sec의 kuk값(stu_fir.n_score pointer를 통해 확인) : %d\n", stu_fir.n_score->eng);
  printf("stu_thi의 kuk값(stu_sec.n_score pointer를 통해 확인) : %d\n", stu_sec.n_score->mat);
}


printf()에서 *대신 -> 연산자를 통해 해당 eng값과 mat값을 가져오도록 합니다. 여기서 -> 표시는 Member참조연산자로서 구조체나 공용체에서 해당 Pointer를 참조하는 전용 연산자 입니다. 이때 Pointer를 통해서도 . 연산자 사용이 가능합니다. 다만 Pointer를 괄호로 묶어 주어야 합니다.


이전의 구조체는 Pointer를 하나만 갖는 자기참조 구조체였습니다. 이 구조체의 단점은 해당 구조체로부터 Pointer를 따라 앞으로만 진행할 수 있다는 것입니다.

다시 뒤로 돌아올 수 없다는 것인데 이 문제는 다음이 아닌 이전으로 되돌아 갈 수 있는 전용 Pointer를 추가함으로서 간단히 해결이 가능합니다.

#include <stdio.h>

main()
{
  struct score {
    int kuk;
    int eng;
    int mat;
   
    struct score *b_score;
    struct score *n_score;
  };
 
  struct score stu_fir, stu_sec, stu_thi;
 
  stu_fir.kuk = 10;
  stu_fir.eng = 20;
  stu_fir.mat = 30;
 
  stu_sec.kuk = 40;
  stu_sec.eng = 50;
  stu_sec.mat = 60;
 
  stu_thi.kuk = 70;
  stu_thi.eng = 80;
  stu_thi.mat = 90;
 
  stu_fir.n_score = &stu_sec;
  stu_sec.b_score = &stu_fir;
  stu_sec.n_score = &stu_thi;
 
  printf("stu_fir의 kuk값 : %d\n", stu_fir.kuk);
  printf("stu_sec의 kuk값(stu_fir.n_score pointer를 통해 확인) : %d\n", stu_fir.n_score->eng);
  printf("stu_thi의 kuk값(stu_sec.n_score pointer를 통해 확인) : %d\n", stu_sec.n_score->mat);
  printf("stu_thi의 kuk값(stu_sec.n_score pointer를 통해 확인) : %d\n", stu_sec.n_score->mat);
 
  printf("다시 stu_fir의 mat값(stu_sec.b_score pointer를 통해 확인) : %d\n", stu_sec.b_score->mat);
}


구조체 생성시 현재 구조체의 이전과 다음구조체를 기억할 수 있도록 *b_score pointer와 *n_score pointer를 두었습니다.

Program에서는 stu_sec구조체의 b_score에 stu_fir을 n_score에는 stu_thi를 참조하도록 하고(stu_sec.b_score = &stu_fir, stu_sec.n_score = &stu_thi) 해당 구조체의 값을 stu_sec pointer를 통해 확인하고 있습니다.

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

[C, C++] Class  (0) 2011.05.25
[C, C++] cout 서식지정  (0) 2011.04.14
[C, C++] 구조체  (1) 2011.04.13
[C, C++] 변수선언및 초기화  (0) 2011.04.07
[C, C++] C에서 C++로의 변화  (1) 2011.04.06
[C, C++] 표준 Library 함수 - 각종 변환 함수  (0) 2011.04.05
1 0
Programming/C C++
 1. malloc

C언어에서 동적으로 Memory를 할당하려면 malloc함수를 이용합니다. 이 함수는 인수로 전달된 정수만큼의 byte크기를 Memory에서 할당하고(만일 할당에 실패하면 NULL을 반환합니다.) 할당된 Memory주소를 Pointer로 반환합니다.

#include <stdio.h>
#include <stdlib.h>

main()
{
  char *p;
 
  p = (char *)malloc(10);
}


10 byte의 Memory확보 후 해당 Memory위치를 Pointer p에 되돌립니다.

참고 :
malloc()함수사용시 반환부분에 (char *)형으로 변환시켜 주는 이유는 malloc()함수가 Memory를 확보한 후 해당 Pointer를 반환할때 형이 없는 void(*)를 반환하기 때문입니다. 이는 반환되는 Memory영역을 범용적으로 활용하기 위해서 입니다.

malloc()함수를 이용하면 구조체와 결합하여 해당 구조체를 동적으로 할당하고 할당된 구조체를 연결시킴으로서 연결 List를 생성할 수 있습니다.(연결 list라는 것은 같은 데이터형이 기차처럼 연결된 형태를 지닌다고 하여 붙여진 이름입니다.)

다음 Program은 구조체와 malloc()함수를 사용해 동적으로 구조체에 대한 Memory를 할당하고 연결 List를 생성한 예제입니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main()
{
  struct student{
    char name[5];
    int kuk;
    int eng;
   
    struct student *np;
  };
  struct student *p;
 
  p = (struct student *)malloc(sizeof(struct student));
 
  strcpy(p->name, "kim");
  p->kuk = 80;
  p->eng = 90;
 
  p->np = (struct student *)malloc(sizeof(struct student));
 
  strcpy(p->np->name, "choi");
  p->np->kuk = 90;
  p->np->eng = 100;
 
  printf("%s : kuk - %d, eng - %d\n", p->name, p->kuk, p->eng);
  printf("%s : kuk - %d, eng - %d\n", p->np->name, p->np->kuk, p->np->eng);
  free(p);
  free(p->np);
}


일단 Header File에서 stdlib.h는 malloc()함수 사용을 위해 선언되었으며 string.h는 strcpy()함수 사용을 위해 선언되었습니다.

다음은 구조체 선언부분입니다.

struct student{
    char name[5];
    int kuk;
    int eng;
   
    struct student *np;
};

struct로 구조체가 student라는 이름으로 선언되었습니다. 이 구조체는 학생의 점수관리를 위한 구조체로 학생의 이름과 국어점수 그리고 영어점수를 저장할 수 있도록 name과 kuk, eng Member로 구성되어 있습니다.

그리고 마지막 member에는 struct student *np;가 있는데 이는 자기 자신을 가리키는 Pointer를 Memeber(자기참조 구조체)로 가지기 위해서 존재합니다.

이 자기참조 구조체는 동적으로 같은 구조체가 Memory에서 생성될때 그 구조체의 시작주소를 갖게 됨으로서 자연스럽게 구조체간 연결 List를 이루도록 하는 것입니다.

구조체 선언 다음에는 구조체에 접근하기 위해 해당 구조체 Data형의 Pointer변수를 선언하였습니다.

struct student *p;

구조체와 Pointer를 선언하고 malloc()함수를 호출하여 구조체크기 만큼의 Memory를 동적으로 생성하도록 합니다.

p = (struct student *)malloc(sizeof(struct student));

보시는 바와 같이 malloc함수안에 sizeof함수가 사용되었습니다. 이 sizeof함수는 인수로 student구조체를 전달하고 그 크기만큼의 Byte값을 정수형태로 반환합니다. 그러면 malloc함수는 반환되는 값 만큼 Memory를 확보하고 그 수행 결과로 Memory의 시작주소를 Pointer p에 반환합니다.(이때 반환되는 Data형은 void형이므로 해당 Data형을 student 구조체로 변환해야 합니다.)

이렇게 Pointer p는 student구조체 형식으로 확보된 Memory시작 주소값을 가지게 됩니다.


이제 Pointer p를 이용해 학생의 이름과 점수를 Memory영역에 담아봅시다.

strcpy(p->name, "kim");
p->kuk = 80;
p->eng = 90;

Pointer에서 -> 를 사용하여 각 Member에 접근합니다. 그리고 kim이라는 이름과 국어점수 80점, 영어점수 90점을 저장합니다.

이때 학생은 단 한명이 아니라 2명 세명.. 그 이상도 될지 모르기 때문에 미리 일정한 구조체를 선언해 두는 것은 그리 좋은 선택이 아닐 것입니다. 따라서 이런경우 동적으로 할당한다는 개념이 필요하게 됩니다.

학생수가 늘어나면 그 만큼 더 많은 구조체가 할당되어야 하기 때문에 처음 구조체의 자기참조 구조체에 동적으로 할당한 다른 구조체의 Memory주소를 갖게 함으로서 연결 list형의 구조를 이루도록 하려 합니다.

p->np = (struct student *)malloc(sizeof(struct student));

p->np를 통해 구조체의 np Pointer에 student 구조체 만큼의 Memory영역을 할당하고 해당 Memory의 주소값을 전달하고 있습니다.

이렇게 되면 이전에 할당된 구조체의 np Pointer는 이후에 할당된 구조체의 시작주소를 가지게 됨으로서 연결 List를 이루게 됩니다.


이제 이전 구조체의 Pointer에서 다음 구조체의 Pointer를 통하여 해당 구조체의 Member에 접근해서 이름과 주소를 할당합니다.

strcpy(p->np->name, "choi");
p->np->kuk = 90;
p->np->eng = 100;

그리고 마지막으로 할당된 Memory영역이 더이상 필요가 없어지면 그 Memory영역을 해제하여 그 만큼의 영역을 다시 회수해야 합니다.

free(p);
free(p->np);

free함수를 호출하여 해당 Pointer에 위치한 Memory영역을 해제합니다.

이 작업이 이루어 지지 않으면 쓸데없는 Memory공간을 낭비하게 됩니다.


2. calloc()

calloc() 함수를 이용하면 같은 Data형의 Memory공간을 여러개 배열 형태로 할당할 수 있습니다.

#include <stdio.h>
#include <stdlib.h>

main()
{
  char *p;
  int i;
 
  p = (char *)calloc(5, 1);
 
  for (i = 0; i < 5; i++)
    printf("%d\n", p[i]);
}


calloc(5, 1)을 통해 1Byte의 Memory를 5개(0~4)의 배열로 확보하고 해당 Memory시작 주소를 Pointer p에 반환하도록 합니다.

그리고 p[배열인자]형식을 통해 각 배열의 값을 for문으로 돌면서 확인하고 있는데 그 결과는 다음과 같습니다.


참고:
calloc()함수는 Memory를 배열로 확보한고 각 배열의 초기값으로 0을 부여합니다.

이제 확보된 배열의 초기값을 직접 부여하여 그 결과를 확인해 보도록 하겠습니다.

#include <stdio.h>
#include <stdlib.h>

main()
{
  char *p;
  int i;
  char cal;
 
  p = (char *)calloc(5, 1);
 
  cal = 'a';
 
  for (i = 0; i < 5; i++)
    p[i] = cal + i;
   
  for (i = 0; i < 5; i++)
    printf("%c\n", p[i]);
  free(p);
}


확보된 각 배열 cal변수에 문자 'a'를 설정하고 for문을 통해 0부터 4까지 문자 'a'에 값을 1씩 더하여(그럼 'b'.. 'c'형태로 변할 것입니다.) 저장한 후 다시 for문을 통해 값을 확인하고 있습니다.


3. free

calloc()함수사용시에도 예외없이 free()함수를 호출하여 사용된 Memory영역을 해제해야 합니다.

사실 malloc()함수나 calloc()함수 사용시에만 free()함수를 쓸 수 있는건 아니고 필요하다면 다른 상황에도 호출하여 사용할 수 있습니다.
0 0
Programming/C C++
다음 Program은 변수를 활용한 간단한 예제입니다.

#include <stdio.h>

main()
{
  int i;
 
  i = 100;
 
  printf("i값 : %d\n", i);
}


이 Program은 결과로 i값을 출력합니다.


이 Program은 변수 i에 3이라는 값을 넣고 다시 i변수를 통해 해당 값을 출력하도록 작성된 예제입니다.

그런데 Computer의 입장에서 보면 단순히 변수 i가 있다는 것에서 끝나지 않습니다. 변수 i가 선언되면 Memory에 integer형의 Data를 담을 수 있는 공간을 확보하고 그 안에 3이라는 정수값을 저장합니다. 이때 저장된 해당 위치를 Memory의 Address라는 주소형태로 구분해야 합니다.

만일 변수라는 개념이 없이 개발자가 직접 Memory주소를 가지고 Data를 다루게 되면 Program구현이 상당히 어려워지고 위험해지게 될 것입니다. 그래서 Memory주소를 직접 다루는 대신 변수라는 Data를 다루기 시작한 것입니다.

일반적으로 변수를 참조하면 해당 변수에 들어있는 값을 다루게 되는데 만일 변수의 값이아닌 변수가 가리키고 있는 Memory주소를 직접 다루고자 한다면 Pointer를 사용해야 합니다.

#include <stdio.h>

main()
{
  int i;
  int *p;
 
  i = 100;
  p = &i;
 
  printf("i값 : %d\n", i);
  printf("i의 memory 주소값 : %d\n", p);
  printf("해당 memory주소에 있는 실제 data : %d\n", *p);
}


Pointer를 쓰기위해 int *p; 로 Pointer를 선언합니다. 이 Pointer는 p = &i;를 통해 i변수의 주소값을 저장하고 마지막 printf()함수를 통해 pointer가 가리키고 있는 Memory주소에서 Data를 가져와 보여주고 있습니다.


이처럼 특정 변수에 값이 아닌 주소를 직접 불러오려고 하면 변수 앞에 & 문자를 붙여 주기만 하면 됩니다. 이때 이렇게 불러들인 주소값을 직접 다루기 위해 Pointer가 사용되는 것입니다.

Pointer는 특정 변수가 가리키고 있는 번지를 기억하는 역활을 하며 Pointer를 통해 해당 Memory번지에 있는 Data를 가져오려면 Pointer앞에 *문자를 추가해야 합니다. 그러면 Pointer는 Memory주소에 있는 값을 직접 나타내게 되는 것입니다.

1. 배열과 Pointer의 활용

배열을 활용하고 있는 다음 Program을 보십시오.

#include <stdio.h>

sprint(char ss[]);

main()
{
  char s[6] = "hello";
 
  sprint(s);
}

sprint(char ss[])
{
  int i;
 
  for (i=0;i<=4;i++){
    printf("%c\n", ss[i]);
  }
 
  return;
}


이 Program은 main함수에서 char형 배열변수에 hello라는 문자열을 대입하고 sprint함수의 for문으로 해당 배열값의 각요소를 출력합니다.


main함수에서 sprint함수를 호출할때 작성한

sprint(s);

이 부분을 주목해 주세요.

배열을 전달할때는 위와 같이 배열변수 이름만이 사용되고 있습니다. 이는 배열전체를 모두 전달하는 것이 아니라 배열이 시작되는 Memory의 첫 주소값을 전달하고 sprint함수에서는 전달받은 주소값을 통해 배열값을 활용하고 있습니다.

즉 배열의 경우 배열변수이름만 쓰게되면 해당 배열이 시작되는 주소값을 얻게 된다는 것이고(일반변수처럼 & 문자를 붙이지 않습니다.) 이 특징 통해 Pointer에서도 배열을 다룰 수 있다는 의미가 됩니다.

#include <stdio.h>

main()
{
  char s[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
  char *p;
 
  p = s;
 
  printf("%s\n", p);
}


char배열 s의 시작주소를 char주소를 기억하는 p Pointer에 대입합니다. 그러면 s와 Pointer p의 주소는 같아지고 Printf함수에서는 배열 s가 아닌 p형 Pointer로 문자열을 출력할 수 있는 것입니다.(s배열로 문자열을 출력할때도 printf("%s\n", s); 로 주소값을 통해 문자열을 출력하였으므로 Pointer로 출력할때도 p를 그대로 사용하여야 합니다. *p로 하면 주소에 있는 값을 받아오므로 제대로된 결과를 얻을 수 없습니다.)


Pointer로 문자열 표현시 위에서 처럼 배열을 사용하는 경우도 있지만 Pointer자체에 직접 문자열을 초기화 하는 것도 가능합니다.

#include <stdio.h>

main()
{
  char *p = "hello";
 
  printf("%s\n", p);
}


Pointer p에 "hello"라는 문자열을 초기화 합니다. 이때 Pointer p는 "hello"문자열을 저장하고 있는 Memory에서 h로 시작하는 주소를 갖게 됩니다.


위 Program에서 p는 "hello"문자열의 시작주소를 가지고 있으므로 첨자로 배열주소를 지정하면 문자배열처럼 다룰 수 있습니다.

#include <stdio.h>

main()
{
  char *p = "hello";
  int i;
 
  for (i = 0; i < 5; i++)
    printf("%c\n", p[i]);
}



참고:
예제에서는 for문을 통해 Pointer p의 첨자를 증가시키면서 주소에 있는 값을 가져오고 있습니다. 이는 언뜻 보면 p Pointer의 주소를 1씩 증가시키는 것처럼 보일 수도 있으나 실제로는 그렇지 않습니다.

현재 Pointer p는 char형이므로 Pointer p에 +1을 한다는 것은 1byte만큼의 주소를 건너뛴다는 의미가 됩니다. 잘 알고계시는 바와 같이 char형은 8bit(1byte)의 Memory공간을 갖고있기 때문입니다.

2. Ponter를 통한 값의 변경

Pointer는 주소값을 가진다고 하였습니다. 이 Pointer에서 직접 값을 조작하면 원래 변수에 있던 값도 같이 바뀌게 됩니다. 왜냐하면 Pointer와 변수는 같은 주소를 유지하고 있기 때문입니다.

#include <stdio.h>

main()
{
  int a = 100;
  int *p;
 
  p = &a;
 
  *p = 200;
 
  printf("a의 값 %d - p의 값 %d\n", a, *p);
}


처음 변수 a에 100의 값을 대입하고 Pointer p에 해당 변수의 주소값을 건네준뒤 *p = 200;에서 Pointer가 가리키는 주소(변수 a의 주소)에 있는 값을 200으로 변경합니다. 이때 변수 a도 Pointer p와 같은 주소값을 가지고 있으므로 200의 값을 갖게 됩니다.


#include <stdio.h>

main()
{
  char s[6] = "hello";
  char *p;
  int i;
 
  p = s;
 
  *(p + 3) = 'p';
  *(p + 4) = '!';
 
  printf("%s\n", s);
  printf("%s\n", p);
 
  for (i = 0; i <= 5; i++){
    printf("%c\n", *(p + i));
  }
}


char형 배열 s에 "hello"라는 문자열을 초기화 한 후 배열의 시작주소값을 Pointer p에 전달합니다. Pointer p는 s배열의 시작주소을 가지므로 Pointer값을 1증가면 Pointer p주소값이 1만큼 늘어나게 되므로 Pointer p는 문자 'e'가 위치한 주소로 바뀌게 됩니다.

주의:
void형의 Pointer는 특정 범위를 주소값을 가지고 있는 상태가 아니므로 +나 -연산이 불가능합니다.

이런 원리를 통해 *(p + 3) = 'p'; 라고 하면 Pointer p의 주소값 3늘어나게 되고 (이때 p는 "hello"에서 4번째 배열을 가리키는 'l'의 주소값을 의미합니다.) 동시에 값을 'p'로 바꾸고 있습니다. 이와 같은 방법으로 마지막 배열의 주소값 Data도 '!'로 바꾼 후 최종적으로 조회하게 되면 다음과 같은 결과를 얻게 되는 것입니다.


3. const와 Pointer

Pointer변수를 const로 하면 값을 변경할 수 없는 Pointer가 됩니다. 이때 const를 어떻게 선언하느냐에 따라 주소값을 const로 할것인가 또는 값을 const로 할것인가가 달라지게 됩니다.

(1) 주소 const

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  char *const p = s;
 
  printf("%s\n", p);
}


*const p 형태로 Pointer를 선언해서 이 Pointer에 지정된 주소값 자체는 바꿀 수 없도록 하고 있습니다.


여기서 주소값을 바꿀 수 없다는 점에 주목해 주십시오. char *const p = s;로 Pointer를 선언함과 동시에 배열 s의 주소값을 대입하고 있는데 이렇게 하는 이유는 *const p로 인해 주소값을 바꿀 수 없기 때문에 선언과 동시에 주소값을 전달해 줘야 하기 때문입니다.

결국 다음과 같이 *const 로 Pointer를 선언한 뒤 새로운 값을 대입하는 것은 불가능한 것입니다.

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  char *const p;
 
  p = s;
 
  p += 1;
 
  printf("%s\n", p);
}


*const p로 Pointer를 선언하고 p에 s의 주소값을 대입하고 있으며 이후 Pointer자신의 값을 다시 1만큼 증가하도록 하고 있습니다.


Compil시 값을 바꿀 수 없다는 Error를 표시하고 있습니다.

(2) 값 const

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  const char *p;
 
  p = s;
 
  printf("%s\n", p);
}


const char *p로 Pointer를 선언하여 Pointer의 주소는 바꿀 수 있으나 값을 바꿀 수는 없도록 하고 있습니다.


예제에서 p = s;를 통해 주소값을 대입하고 있지만 해당 Pointer는 값을 바꿀 수 없는 형태의 Pointer이므로 아무런 문제 없이 Compil되고 실행됩니다.

#include <stdio.h>

main()
{
  char s[7] = "hello!";
  const char *p;
 
  p = s;
 
  *p = 'x';
 
  printf("%s\n", p);
}


const로 선언된 Pointer에 *p = 'x';의 형태로 값을 바꾸도록 하고 있습니다.


p Pointer는 const로 선언되었으므로 값을 바꿀 수 없다는 Error를 내며 Compil에 실패합니다.

4. 범용 Pointer

Pointer의 선언은 원래

char *p;

처럼 해당 Pointer의 Data형을 지정됩니다. 하지만 어떤 Data형으로도 쓰일 수 있는 Pointer가 있는데 그것이 바로 범용 Pointer입니다. 이러한 범용 Pointer는 다음과 같이 선언됩니다.

void *p;

Pointer선언 부분에 Data형 대신 void라고 하면 해당 Pointer는 범용 Pointer가 됩니다. 이렇게 선언된 Pointer는 어떤 Pointer라도 포함할 수 있게 됩니다.

void *p;
char *cp;
int *ip;
 
p = cp;
p = ip;

하지만 범용 Pointer의 주소를 일반 변수에 대입할 때는 그Data형을 지정해 줘야 합니다. 왜냐하면 범용 Pointer는 주소값만 가질뿐이지 어떠한 Data형인지 지정되지 않았기 때문에 얼마만큼의 Memory를 확보해야 하는지에 대해서는 알 수 없기 때문입니다.

#include <stdio.h>

main()
{
  void *p;
  char c;
  int i;
 
  c = 100;
  p = &c;
 
  i = *(int *)p;
     
  printf("%d\n", i);
}


int i에 대입시 범용 Pointer를 int형 Pointer로 cast하여 대입(*(int *)p)하고 있습니다.


만일 위와 같이 하지 않고 그냥 대입하려 한다면

#include <stdio.h>

main()
{
  void *p;
  char c;
  int i;
 
  c = 100;
  p = &c;
 
  i = *p;
     
  printf("%d\n", i);
}


Compiler는 오류를 발생시키게 됩니다.


5. 함수와 Pointer와의 관계

변수를 선언하면 그 변수는 Computer의 Memory에서 해당 Data형에 맞는 크기 만큼의 영역을 확보하게 될 것입니다.

함수도 마찬가지 입니다. 함수자체도 Memory어딘가에 위치하고 있으며 결과적으로 함수가 위치한 이 주소값을 Pointer로 활용할 수 있습니다. 따라서 실제로 이런 동작을 구현하게 되면 직접 함수를 호출하지 않고도 Pointer만으로 함수를 호출한 것과 같은 결과를 얻을 수도 있습니다.

#include <stdio.h>

int plus(int i, int j);

main()
{
  int (*pls) (int i, int j);
  int ir;
  pls = plus;
 
  ir = pls(10, 20);
 
  printf("%d\n", ir);
}

int plus(int i, int j)
{
  return i + j;
}


int (*pls) (int i, int j);을 통해 함수형 Pointer인 pls를 선언합니다. 이때 Pointer를 함수처럼 호출할때의 인수도 int, int j같이 지정해 줘야 합니다.

이 Pointer를 pls = plus;와 같이 대입하면 plus() 함수의 주소값이 해당 pls Pointer에 대입되고 이후 pls(10, 20);를 통해 함수를 호출하듯이 사용할 수 있게 되는 것입니다.

이는 plus함수가 Memory의 1000번지에 있다고 가정한다면 plus(10, 20);라고 하였을 경우 1000번지에 10과 20을 넘겨 처리를 수행한다라는 의미가 되므로(주소값이 목적이 되므로) 주소값을 갖는 Pointer를 함수처럼 활용하는것 또한 가능해 지는 것입니다.


다음은 함수 Pointer를 조금 변형한 것으로 함수의 인수 자체를 함수 Pointer로 구현한 것이며 결과는 이전 예제와 같습니다.

#include <stdio.h>

int plus(int i, int j);

main()
{
  int ir;
 
  ir = callplus(plus, 10, 20);
 
  printf("%d\n", ir);
}

int callplus(int (*pls) (int i, int j), int x, int y)
{
  return pls(x, y);
}

int plus(int i, int j)
{
  return i + j;
}


callplus(plus, 10, 20)에 의해 함수자체를 함수 Pointer의 인수로 건네줍니다. 이때 callplus()함수는 그 내부에서 전달받은 함수 Pointer를 통하여 실질적인 함수호출을 실현합니다.

함수 Pointer에 대해 하나더 언급하자면 함수 Pointer도 배열로 처리하는 것이 가능하다는 것입니다. 이미 변수 Pointer를 언급할때 배열로서 처리할 수 있다라고 하였는데 이것은 함수 Pointer의 경우도 마찬가지 입니다.

#include <stdio.h>

int plus(int i, int j);
int mlus(int i, int j);

main()
{
  int (*pls[2]) (int i, int j);
  int ir;
  int ir2;
 
  pls[0] = plus;
  pls[1] = mlus;
 
  ir = pls[0](10, 20);
  ir2 = pls[1](30, 10);
 
  printf("%d\n", ir);
  printf("%d\n", ir2);
}

int plus(int i, int j)
{
  return i + j;
}

int mlus(int i, int j)
{
  return i - j;
}


int (*pls[2]) (int i, int j);을 통해 pls Pointer함수를 배열로 하여 2개(0~1)를 생성하도록 하였습니다.

이후 일반 배열처럼 pls[0], pls[1]... 과 같이 해당 함수 Pointer를 활용하기만 하면 됩니다.

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

[C, C++] Microsoft C, C++ Compiler  (0) 2010.01.22
[C, C++] Class 상속  (0) 2010.01.13
[C, C++] 함수작성및 Data전달  (0) 2010.01.07
C언어 함수사용 예제 Souce  (0) 2010.01.06
[C, C++] Pointer  (0) 2010.01.05
[C, C++] 변수통용범위(변수의 기억 Class)  (0) 2010.01.04
0 0
1
블로그 이미지

클리엘