jam 블로그

[C++] 002. C기반의 C++ 2 본문

개발 및 관련 자료/C

[C++] 002. C기반의 C++ 2

kid1412 2013. 5. 12. 19:58
728x90

I. 들어가기에 앞서서

  • 강의에서 언급하는 내용이라 합니다. 혼자서 생각을 먼저 해보세요

    • const 키워드의 의미! 다음 문장은 어떤 의미를 지니는가?

      • const int n = 10;   //int n이 10으로 고정. 변수 상수화
      • const int *n;  //int *n을 고정 한다. (즉, 값은 고정 하나, 주소는 변경 가능하다.) 데이터 상수화
      • int* const n;   //*n을 고정합니다.(즉, 값은 변경 가능 하나, 주소가 고정이다.) 포인터 상수화
      • const int* const n;   //2번째, 3번째 줄 합친거와 같다.(즉, 값도 고정이고, 주소도 고정이다.)
    • 스택이라는 메모리 영역은 어떤 용도로 사용되는 메모리 공간이며, 그 특징은?

      •  지역변수, 매개변수 (컴파일 시 할당)
    • 힙이라는 메모리 영역은 어떤 용도로 사용되는 메모리 공간이며, 그 특징은?

      •  프로그래머 할당 (런타임 시 할당)
    • malloc과 free 함수를 사용해야만 하는 이유?(필요한 이유)

II. 새로운 형태의 자료형 bool

  • 전통적인 방법의 true와 false
  1. #include <stdio.h>
  2. const int TRUE = 1;
    const int FALSE = 0;
  3. int IsPositive(int i)
    {
     if(i<0)
      return FALSE;
     else
      return TRUE;
    }
  4. int main(void)
    {
     int num;
     int result;
  5.  printf("숫자 입력 : ");
     scanf("%d",&num);
  6.  result = IsPositive(num);
  7.  if(result == TRUE)
      printf("Positive numver \n");
     else
      printf("Negative number \n");
     return 0;
    }
  • bool형을 이용한 true와 false
  1. #include <iostream>
  2. using namespace std;
  3. bool IsPositive(int i)
    {
     if(i<0)
      return false;
     else
      return true;
    }
  4. int main(void)
    {
     int num;
     bool result;
  5.  cout <<"숫자 입력 : ";
     cin >> num;
  6.  result = IsPositive(num);
     if(result == true)
      cout <<"Positive number"<<endl;
     else
      cout <<"Negative number"<<endl;
    }
  • Bool형이 int 형으로 바뀌면 true 일때는 1 false 일때는 0가 나옵니다.

III. 레퍼런스의 이해

  • 레퍼런스 라는 것이 무엇 일까?

    • 이름을 지니고 있는 대상에게 지어주는 별명을 가리켜 레퍼런스라고 한다.
    • int &ref = val;

      • val이라는 int형 변수의 이름에 ref라는 별명을 붙인 것이다. C++에서 레퍼런스를 선언할 때에도 &를 쓰인다.
  • 레퍼런스의 특징
  1.  #include<iostream>
  2. using namespace std;
  3. int main(void)
    {
     int val = 10;
     int &ref = val;
     val++;
  4.  cout<<"ref : "<<ref<<endl;
     cout<<"val : "<<val<<endl;
     
     ref++;
  5.  cout<<"ref : "<<ref <<endl;
     cout <<"val : "<<val<<endl;
     return 0;
    }
  • ref는 val의 별명이기 때문에 둘다 같은 거라고 보면 된다. 따라서 ref가 증가하든 val가 증가하든 여튼 같은게 증가하는 것이다.

    • 레퍼런스를 가지고 있는 연산은 레퍼런스가 참조하는 변수의 이름을 가지고 하는 연산과 같은 효과
  • 레퍼런스의 제약

    • 초기화를 시켜주지 않는다던가
    • 상수가 오면 error

IV. 레퍼런스와 함수

  •  포인터를 이용한 Call-By-Reference
  1. #include <iostream>
  2. using namespace std;
  3. void swap(int *a,int *b)
    {
     int temp = *a;
     *a = *b;
     *b = temp;
    }
  4. int main()
    {
     int val1 = 10;
     int val2 = 20;
  5.  cout <<"val1 : "<<val1<<' ';
     cout<<"val2 : "<<val2 <<endl;
  6.  swap(&val1,&val2);
     cout <<"val1 : "<<val1<<' ';
     cout<<"val2 : "<<val2 <<endl;
    return 0;
    }
  •  레퍼런스를 이용한 Call-By-Reference
  1. #include <iostream>
  2. using namespace std;
  3. void swap(int &a,int &b)
    {
     int temp = a;
     a = b;
     b = temp;
    }
  4. int main(void)
    {
     int val1 = 10;
     int val2 = 20;
  5.  cout <<" val1 : "<<val1<<' ';
     cout<<"val2 : "<<val2 <<endl;
  6.  swap(val1,val2);
     cout <<" val1 : "<<val1<<' ';
     cout<<"val2 : "<<val2 <<endl;
    }
  •  레퍼런스를 이용한 성능의 향상

    • 개인정보를 입출력하는 예제이다.
  1. #include <iostream>
  2. using namespace std;
  3. struct _Person{
     int age;
     char name[20];
     char personalTD[20];
    };
    typedef struct _Person Person;
  4. void ShowData(Person p)
    {
     cout<<"******* 개인 정보 출력 ********"<<endl;
     cout<<"이    름 : "<<p.name<<endl;
     cout<<"주민번호 : "<<p.personalTD  <<endl;
     cout<<"나    이 : "<<p.age<<endl;
    }
  5. int main(void)
    {
     Person man;
  6.  cout<<"이    름 : ";
     cin>>man.name;
     cout<<"나    이 : ";
     cin>>man.age;
     cout<<"주민번호 : ";
     cin >> man.personalTD;
  7.  ShowData(man);
     return 0;
    }
  • 위의 소스는 Call-By-Value의 기본방식인 값의 복사를 이용해서 만든 것이다.

    • main 안에 ShowData에 man을 넘겨 주는데 man의 크기는 44바이트이다.(구조체 보면 int + 배열20+배열 20이다.)
    • 만약 인자로 전달하는 변수가 늘어나고 크기고 커지면 프로그램 자체가 부담스러워 진다.
  • 부담스러운 Call-By-Value를 대신하는 Call-By-Reference
  1. void ShowData(Person &p)
    {
     cout<<"******* 개인 정보 출력 ********"<<endl;
     cout<<"이    름 : "<<p.name<<endl;
     cout<<"주민번호 : "<<p.personalTD  <<endl;
     cout<<"나    이 : "<<p.age<<endl;
    }
  • 레퍼런스의 형태로 받게 되면, 이름만 하나 더 추가하는 것이므로 44바이트나 되는 크기의 복사는 발생하지 않는다.

    • 추가 설명 : Call-By-Value는 값을 복사 하는 거기 때문에 44바이트나 복사를 해야하지만 레퍼런스로 설정하면 복사가 아닌 가리키는 식으로 되어서 복사가 일어나지 않는다.
    • 그러나 ShowData는 그저 보여주는 함수이기 때문에 p값이 변경되면 안된다. 그것을 방지 하려면
  1.  void ShowData(const Person &p)
    {
     cout<<"******* 개인 정보 출력 ********"<<endl;
     cout<<"이    름 : "<<p.name<<endl;
     cout<<"주민번호 : "<<p.personalTD  <<endl;
     cout<<"나    이 : "<<p.age<<endl;
    }
  •  const를 붙여 주면 값을 변경 할수 없다.

    • 좀더 자세히 말하면 레퍼런스 p를 통한 데이터의 조작을 허용하지 않겠다는 것이다.

V. 레퍼런스를 리턴하는 함수의 정의

  • 레퍼런스를 리턴하는 적절한 형태의 함수와 그 의미

#include <iostream>

using namespace std;

int& increment(int &val)
{
 val++;
 return val;
}

int main(void)
{
 int n = 10;
 int &ref = increment(n);
 cout << "n : "<<n<<endl;
 cout<<"ref : "<<ref<<endl;
 return 0;
}

  • n이 넘어가 면서 reference로 val라는 이름이 추가 되고 리턴 되면서 val는 ref라는 이름이 생기고 호출이 완료되면 val는 사라진다.
  • 레퍼런스를 리턴하는 잘됫된 형태의 함수

    • 지역변수는 레퍼런스로 리턴할 수 없다.

#include <iostream>

using namespace std;

int& function(void)
{
 int val = 10;
 return val;
}

int main(void)
{
 int &ref = function();
 cout<<"ref : "<<ref<<endl;
 return 0;
}

  • 실행은 되지만(또는 값이 제대로 나오지만) 컴파일시 waring이 뜬다. 왜냐하면 지역변수는 함수 호출후 사라지기 때문이다.

    • waring을 뜨지 않게 하려면 static int val = 10; 를 치면 된다.

VI. new & delete

  • new와 delete는 C에서 malloc과 free랑 비슷하다.
  • 일단 malloc과 free에 대한 것이다.

#include <iostream>

using namespace std;

int main(void)
{
 int size;
 cout << "할당하고자 하는 배열의 크기 : ";
 cin >> size;

 int* arr = (int*)malloc(sizeof(int)*size);

 for(int i=0;i<size;i++)
  arr[i]  = i+10;
 for(int j=0;j<size;j++)
  cout<<"arr["<<j<<"] = "<<arr[j]<<endl;
 free(arr);
 return 0;
}

  • 위의 소스를 new와 delete로 바꾼다면 (별 다른 점은 없다. )

#include <iostream>

using namespace std;

int main(void)
{
 int size;
 cout << "할당하고자 하는 배열의 크기 : ";
 cin >> size;

 int *arr = new int[size];

 for(int i=0;i<size;i++)
  arr[i]  = i+10;
 for(int j=0;j<size;j++)
  cout<<"arr["<<j<<"] = "<<arr[j]<<endl;
 delete []arr;
 return 0;
}

  • 위에서 마지막에 delete []arr;이 있는데 delete[] arr; delete []arr; delete [] arr; 이런 식으로 쓰면 된다.

 

  •  NULL 포인터를 리턴하는 new 연산자

#include <iostream>

using namespace std;

int main(void)
{
 int size;
 cout << "할당하고자 하는 배열의 크기 : ";
 cin >> size;

 int *arr = new int[size];
 if (arr == NULL)
 {
  cout << "메모리 할당 실패"<<endl;
  return -1;
 }
 for(int i=0;i<size;i++)
  arr[i]  = i+10;
 for(int j=0;j<size;j++)
  cout<<"arr["<<j<<"] = "<<arr[j]<<endl;
 delete []arr;
 return 0;
}

  •  위 소스는 if문이 추가 되었는데 if문이 메모리가 제대로 할당이 되었는지 확인 하는 조건문이다.

    • 하지만 솔직히 if문 같은 비교문을 넣으면 성능만 저하 시킬수 있다고 판단을 한다.
    • 그래서 매크로를 사용하여 다르게 처리를 해보자

 #include <iostream>

using namespace std;
#define DEBUG 1 //테스트할 경우
//#define DEBUG 0 최종

int main(void)
{
 int size;
 cout << "할당하고자 하는 배열의 크기 : ";
 cin >> size;

 int *arr = new int[size];

 

#if DEBUG == 1
 if (arr == NULL)
 {
  cout << "메모리 할당 실패"<<endl;
  return -1;
 }
#endif

 

 for(int i=0;i<size;i++)
  arr[i]  = i+10;
 for(int j=0;j<size;j++)
  cout<<"arr["<<j<<"] = "<<arr[j]<<endl;
 delete []arr;
 return 0;
}

- 중간에 #if #endif 를 매크로와 함께 써서 테스트 일 경우에만  컴파일 되게 할 수도 있다.

'개발 및 관련 자료 > C' 카테고리의 다른 글

[C++] 004. 클래스의 완성  (0) 2013.05.12
[C++] 003. 클래스의 기본  (0) 2013.05.12
[C++] 001. C기반의 C++ 1  (0) 2013.05.12
[C] 26. 매크로와 전처리기  (0) 2013.05.12
[C] 25. 메모리 관리와 동적 할당  (0) 2013.05.12
Comments