[C++] 2. C언어 기반의 C++(2)
새로운 자료형 bool
C와 C++ 모두 정수 0은 ‘거짓’, 0이 아닌 정수는 ‘참’을 의미합니다~!
게다가 C++에서는 참과 거짓의 표현을 위한 키워드 true와 false를 정의하고 있는데,
true는 정수로 출력하면 1, false는 정수로 출력하면 0이지만,
둘 다 정수로 출력가능한 것이지 자료형이 정수는 아닙니다!
이 둘은 참과 거짓을 표현하기 위한 1바이트 크기의 데이터일 뿐입니다.
그래서 이들을 저장하기 위한 자료형이 별도로 정의되는 것은 당연한 일이지요~!
그 자료형이 바로 bool 입니다!
bool isTrue=true; //true 저장
bool isFalse=false; //false 저장
참조자의 이해
할당된 하나의 메모리 공간에 둘 이상의 이름을 붙이기 위해
C++에서는 참조자라는 변수를 제공합니다!
int num1=2010;
int &num2=num1; //참조자 선언
num2=100; //num1도 같이 바뀝니다!
위에서 보듯이 num2는 num1의 참조자가 되며,
num1이라 이름 붙어있는 메모리 공간에 num2라는 이름이 하나 더 붙습니다!
참조자는 자신이 참조하는 변수를 대신할 수 있는 또 하나의 이름입니다.
여기서 &는 주소 값을 반환하는 연산자가 아니라 참조자의 선언을 뜻하게 됩니다.
참조자의 수는 제한이 없으며, 참조자를 대상으로도 참조자를 선언할 수 있습니다.
따라서 다음과 같은 선언을 할 수 있습니다.
int num1=1;
int &num2=num1;
int &num3=num1;
//num1, num2, num3 모두 같은 메모리 공간을 가리킵니다.
int num1=1
int &num2=num1;
int &num3=num2;
그러나 참조자는 변수에 대해서만 선언이 가능하고, 선언됨과 동시에 누군가를 참조해야합니다~
따라서 다음과 같이 상수를 참조하거나 참조자 선언만 할 수 없습니다.
int &ref=30; (X)
int &ref; (X)
int &ref=NULL; (X) //NULL로 초기화도 안 됨
포인터 변수도 변수기에 참조자의 선언이 가능합니다.
int num=12;
int *ptr=#
int *(&pref)=ptr; //포인터변수 참조
//다음 선언은 같습니다
std::cout<<num<<std::endl;
std::cout<<*ptr<<std::endl;
std::cout<<*pref<<std::endl;
참조자는 변수이름에 별칭을 준다고 생각하면 편합니다!
참조자와 함수
C언어를 공부하면서 배운 함수의 두가지 호출 방식은
Call-by-value 그리고 Call-by-reference 입니다.
본래 C언어에서 말하는 Call-by-reference는 주소 값을 전달 받아서,
함수 외부에 선언된 변수에 접근하는 형태의 호출이였습니다.
하지만 C++에서는 함수 외부에 선언된 변수의 접근방법으로 두 가지가 존재합니다.
주소 값을 이용한 Call-by-reference,
참조자를 이용한 Call-by-reference 입니다.
이 둘을 구분하기 위하여 주소 값을 이용한 Call-by-reference는
Call-by-address라고도 합니다~!
어쨌든, 참조자를 이용해서도 함수 외부에 선언된 변수에 접근할 수 있습니다.
void Swap(int &ref1, int &ref2)
{
int temp=ref1;
ref1=ref2;
ref2=temp;
}
함수를 호출하는 방법은 다음과 같습니다
int num1=2;
int num2=3;
Swap(num1,num2);
//참조자는 상수를 참조할 수 없기에 다음과 같은 선언은 컴파일 에러를 발생시킵니다.
Swap(20,30); (X)
const 참조자
포인터는 잘못 사용할 확률이 높고, 참조자의 활용이 상대적으로 포인터의 활용보다 쉽기 때문에,
참조자 기반의 함수정의가 더 좋은 선택이라고 생각할 수 있지만,
참조자 기반의 함수도 단점이 존재한다.
예를들어 함수의 정의나 원형을 보고 함수의 특성을 파악할 수 없습니다.
int num=24;
function(num);
cout<<num<<endl; //과연 출력 값은??
void function(int prm){ ... } //Call-by-value이기에, num는 변경 안 되므로 24 출력
void function(int &ref){ ... } //이 함수에 의해 num가 바뀔 수도 있습니다
이러한 문제는 const 키워드를 이용하면 어느정도 해결할 수 있습니다.
함수 매개변수 참조자 부분에 const가 붙으면 참조자를 이용한 값의 변경은 불가합니다!
void function(const int &ref){ ... }
참조자에 의해 함수 외부의 변수에 접근할 수 있긴 하지만,
포인터를 사용하는 것이 코드를 더 명확히 작성하는 방법이 된다고 생각하기에,
많은 프로그래머들은 참조자를 잘 사용하지 않습니다.
반환형이 참조자인 경우도 있습니다~
int& Reffunction(int &ref)
{
return ref;
}
int main(void)
{
int num1=1;
int &num2=Reffunction(num1); //num2는 num1을 참조합니다.
int num3=Reffunction(num1); //num1의 값 1만 num3에 전달됩니다.
}
그리고 반환형이 참조자일 때는 지역변수를 반환하지 않게 조심해야 합니다.
int& Reffunction(int n)
{
int num=3;
num+=n;
return num;
}
위와 같이 선언하면 안 됩니다!!!
지역변수 num는 함수가 종료되면 소멸되기에 함수는 쓰레기 값을 반환하게 됩니다.
마지막으로 상수화된 변수에 대해 참조할 때에도 const를 이용합니다~
const int &ref=50; //상수화된 변수
여기서 50은 상수가 아니라 상수화된 변수입니다~
50을 임시변수에 저장하고 참조자는 그 임시변수를 참조합니다~
malloc & free를 대신하는 new & delete
C언어에서 힙의 메모리 할당 및 소멸에 필요한 함수는 malloc과 free 함수이였습니다!
C++에서는 이를 대체하는 new와 delete라는 키워드가 존재합니다~
int *ptr1=(int *)malloc(sizeof(int)); //malloc함수를 이용한 동적할당
int *ptr2=new int; //new를 이용한 동적 할당
double *arr1=(double *)malloc(sizeof(double)*7); //malloc함수를 이용한 동적할당
double *arr2=new double[7]; //new를 이용한 동적할당
free(prt1);
free(arr1); //free함수를 이용한 동적해제
delete ptr2;
delete []arr2; //delete를 이용한 동적해제
malloc과 free 보다 new와 delete가 훨씬 쉽죠오~~~
객체의 생성에는 반드시 new와 delete를 이용해야 합니다!
이차원 배열의 생성은 다음과 같습니다.
//3*3 이차원 배열의 생성
int **arr=new int[3];
for(int i=0;i<3;i++)
arr[i]=new int[3];
//delete를 이용한 소멸
for(int i=0;i<3;i++)
delete []arr[i];
delete arr;
그리고 힙에 할당된 변수는 포인터를 사용하지 않아도 접근할 수 있습니다!
int *ptr=new int;
int &ref=*ptr;
ref=20; //참조자를 이용한 힙에 할당된 변수에 접근
C++에서 C언어의 표준함수 호출하기
C++로 프로그래밍을 하다 보면, C언어의 표준함수를 사용하고 싶을 때가 있습니다.
그 때는 C언어의 헤더파일 선언 시 c를 더하고 .h를 빼면 됩니다.
#include <stdio.h> -> #include <cstdio>
#include <stdlib.h> -> #include <cstdlib>
#include <math.h> -> #include <cmath>
예를 들어 0이상 100미만의 난수를 5개 생성하는 예제를 만들어보면,
다음과 같습니다
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std
int main(void)
{
srand(time(NULL));
for(int i=0;i<5;i++)
{
printf("난수 %d: %d\n",i+1,rand%100);
}
}
//printf와 scanf와 같은 표준 함수들은 이미 이름공간 std 내에 선언되어있습니다.