4 분 소요

💎 새로운 자료형 bool

#include <iostream>

int main()
{
    int num = 10;
    int i = 0;

    std::cout << "true " << true << std::endl;
    std::cout << "false: " << false << std::endl;

    while (true)
    {
        std::cout << i++ << ' ';
        if (i > num)
        {
            break;
        }
        std::cout << std::endl;

        std::cout << "sizeof 1: " << sizeof(1) << std::endl;
        std::cout << "sizeof 0: " << sizeof(0) << std::endl;
        std::cout << "sizeof true: " << sizeof(true) << std::endl;
        std::cout << "sizeof false: " << sizeof(false) << std::endl;
        return 0;
    }
}

>>>
true 1
false: 0
0
sizeof 1: 4
sizeof 0: 4
sizeof true: 1
sizeof false: 1

true는 1, false는 0로 처리가 된다.
그래서 true + false는 1 + 0으로 처리될 수 있으나 일반적으로는 다른 데이터형처럼 사용된다.

#include <iostream>

bool IsPos(int num)
{
    if (num <= 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}

int main()
{
    bool isPos;
    int num;
    std::cout << "Input number: ";
    std::cin >> num;

    isPos = IsPos(num);
    if (isPos)
    {
        std::cout << "Positive number" << std::endl;
    }
    else
    {
        std::cout << "Negative number" << std::endl;
    }
    return 0;
}

>>>
Input number: 12
Positive number

💎 참조자의 이해

#include <iostream>

int main()
{
    int num1 = 2010;
    int &num2 = num1;

    num2 = 3047;
    std::cout << "VAL: " << num1 << std::endl;
    std::cout << "REF: " << num2 << std::endl;

    std::cout << "VAL: " << &num1 << std::endl;
    std::cout << "REF: " << &num2 << std::endl;

    return 0;

}

>>>
VAL: 3047
REF: 3047
VAL: 0x61ff08
REF: 0x61ff08

& 연산자는 변수의 주소 값을 반환하는 연산자이기도 하지만 새로 선언되는 변수의 이름 앞에 등장하면 이는 참조자의 선언 을 뜻하게 된다.



참조자는 변수를 대상으로만 선언이 가능하다. ‘/’

#include <iostream>
using namespace std;

int main()
{
    int arr[3] = {1, 2, 3};
    int &ref1 = arr[0];
    int &ref2 = arr[1];
    int &ref3 = arr[2];

    cout << ref1 << endl;
    cout << ref2 << endl;
    cout << ref3 << endl;

    return 0;
}

>>>
1
2
3

배열 하나의 요소만 참조하는 것도 가능하다.


🔆 포인터를 이용한 Call-by-reference

#include <iostream>

void SwapByRef(int *ptr1, int *ptr2)
{
    int temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}

int main()
{
    int val3 = 10;
    int val4 = 20;

    SwapByRef(&val3, &val4);
    std::cout << "val1: " << val3 << std::endl;
    std::cout << "val2: " << val4 << std::endl;

    return 0;
}
>>>
val1: 20
val2: 10

포인터를 이용한 함수를 보면은 인자값을 꼭 &를 붙혀서 사용해야됨을 알 수 있다. 당연한 사실이다. val3과 val4는 값이고, 매개변수로 전달되어야 하는 값은 포인터이기 때문이다.

🔆 참조자를 이용한 Call-by-reference

하지만 참조자를 이용한 함수의 경우는 다르다. 인자값을 잘 보면 알 수 있다.

#include <iostream>

void SwapByRef2(int &ref1, int &ref2)
{
    int temp = ref1;
    ref1 = ref2;
    ref2 = temp;
}

int main()
{
    int val1 = 10;
    int val2 = 20;

    SwapByRef2(val1, val2);
    std::cout << "val1: " << val1 << std::endl;
    std::cout << "val2: " << val2 << std::endl;

    return 0;
}

>>>
val1: 20
val2: 10

인자로 전달되는 값은 그냥 값을 전달하는 것과 동일하게 하면 된다. 이렇게만 된다면 포인터보다는 참조자를 사용하는 것이 훨씬 유리한 것 같다.
굳이 머리를 써서 포인터를 가리키는지 값을 가리키는지 보지 않아도 되기 때문이다. 하지만 이런 참조자를 이용한 방식에도 단점이 있다.



함수 내에서 값이 변경되는지 아닌지를 인자값만 보고는 알 수 없다. 따라서 int 앞에 const를 붙혀서 이를 명시하는 것이 좋다.

void HappyFunc(const int &ref)
{
    ...
}

🔆 반환형이 참조형인 경우

총 8가지 경우로 나뉠 수 있을 것 같다.. 근데 int 형은 ,,,,,아 ㅅ ㅈㄴ 헷갈려,,,,,,,,,,,,,,,,,,,,,,,,근데! int&형의 함수는 int, int&형으로 리턴값을 전달할 수 있지만 int형의 함수는 int형에게만 리턴할 수 있다.

int &RefRetFuncOne(int &ref)
{

}
int RefRetFuncTwo(int &ref)
{

}
int &RefRetFuncThree(int ref)
{

}
int RefRetFuncFour(int ref)
{

}

int num0 = 1;
int &num1 = RefRetFuncOne(num0);
// int &num2 = RefRetFuncTwo(num0);
int &num3 = RefRetFuncThree(num0);
// int &num4 = RefRetFuncFour(num0);
// int num5 = RefRetFuncOne(num0);
int num6 = RefRetFuncTwo(num0);
// int num7 = RefRetFuncThree(num0);
int num8 = RefRetFuncFour(num0);

num0는 위의 줄과 상관없이 모두 0이라고 가정한다.

앞에 참조값이 들어가 있지 않는다면 딱 함수에서 리턴한 값으로 초기화되는 형식이다. 그 이외의 값의 증감은 상관없다.
num1의 경우는 num0의 값의 참조값이 리턴되었으므로 num1이 증가하면 같이 num0도 증가하게 된다.

#include <iostream>

int &RefRetFuncOne(int &ref)
{
    ref++;
    return ref;
}

int main()
{
    int num1 = 1;
    int &num2 = RefRetFuncOne(num1);

    num1++;
    num2++;
    std::cout << "num1: " << num1 << std::endl;
    std::cout << "num2: " << num2 << std::endl;
}

>>>
num1: 4
num2: 4

💎 new & delete

malloc & free를 대신해서 C++에서는 new & delete를 사용한다.

c코드

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

char *MakeStrAdr(int len)
{
    char *str = (char *)malloc(sizeof(char) * len);
    return str;
}

int main()
{
    char *str = MakeStrAdr(20);
    strcpy(str, "I am so happy~");
    std::cout << str << std::endl;
    free(str);
    return 0;
}

이렇게 동적 할당을 하는 것은 2가지 문제가 있다.

  1. 할당된 대상의 정보를 무조건 바이트 크기로 전달해야 된다.
  2. 반환형이 void 형 포인터이기 때문에 적절한 형 변환을 거쳐야 한다.
    C++ 코드
#include <iostream>
#include <string.h>

char *MakeStrAdr(int len)
{
    // char * str = (char*)malloc(sizeof(char)*len);
    char *str = new char[len];
    return str;
}
int main()
{
    char *str = MakeStrAdr(20);
    strcpy(str, "I am so happy~");
    std::cout << str << std::endl;
    // free(str);
    delete[] str;
    return 0;
}

cpp에서는 더이상 malloc을 통해서 메모리 할당 받는 것이 아닌 new를 통해서 메모리를 할당받고, delete를 통해서 메모리를 해제한다.

💎 C++에서 C언어의 표준함수 호출하기

c를 더하고 h를 빼라

  • stdio.h -> cstdio
  • stdlib.h -> cstdlib
  • math.h -> cmath
  • string.h -> cstring


그래서 std라는 이름공간에 내용이 선언되어 있다는 사실만 제외하면 c++의 헤더는 C 언어의 헤더와 별 차이가 없다.

#include <cmath>
#include <cstdio>
#include <cstring>

int main()
{
    char str1[] = "Result";
    char str2[30];

    std::strcpy(str2, str1);
    std::printf("%s: %f\n", str1, std::sin(0.14));
    std::printf("%s: %f \n", str2, std::abs(-1.25));
    return 0;
}

>>>
Result: 0.139543
Result: 1.250000

댓글남기기