{{ label!='' ? 'Label : ' : (q!='' ? '검색 : ' : '전체 게시글') }} {{ label }} {{ q }} {{ ('('+(pubs|date:'yyyy-MM')+')') }}

[C++] 스터디 CPPALOM 1주차: 열혈 C++ 프로그래밍 Part 1

(파워 포인트 파일(.pptx)을 Markdown으로 변환하여 업로드하였음)


# <br>1주차 - 열혈 C++ 프로그래밍 Part 1
# <br>cout, cin

* C언어의 printf와 scanf를 대체하는 입출력 함수
* 여러 개를 ‘>>’, ‘<<‘를 이용해 동시에 입력 혹은 출력할 수 있음
* std::endl의 경우, 개행(‘\n’)
* std::endl vs ‘\n’
  * std::endl의 경우 출력 버퍼를 비움!

```C++
#include <iostream>
int main() {
  std::cout << "Hi, your age?" << std::endl;
  int age;
  std::cin >> age;
  std::cout << "You were borned in " << 2023 - age << "!" << endl;
}
```

```C++
Hi, your age?
>25
You were borned in 1998!
```

# <br>문자열 입출력

* 배열 기반의 문자열 입출력
* char는 문자 하나를 받으며, 100 크기의 char 배열은 99자의 문자열을 받을 수 있음
  * 끝은 ‘\0’(NULL)으로 종결을 의미하는 문자가 필요함.

```C++
#include <iostream>
int main() {
  char name[100];
  std::cout << "이름은 무엇입니까? ";
  std::cin >> name;
  std::cout << "내 이름은 " << name << "입니다.\n";
  return 0;
}
```

```C++
이름은 무엇입니까? Subin
내 이름은 Subin입니다.
```

# <br>함수 오버로딩

* 함수의 Signature
  * 함수의 이름
  * 매개변수
* Signature가 다르면 다른 함수임!
* 특히, 이름이 같으나 매개변수가 다른 함수들을 정의 시 오버로딩한다고 함
* 주의:
  * _Signature_  _에 반환형은 포함되지 않음_

```C++
#include <iostream>
void MyFunc(void) {
  std::cout << "MyFunc(void) called" << std::endl;
}
void MyFunc(char c) {
  std::cout << "MyFunc(char c) called" << std::endl;
}
void MyFunc(int a, int b) {
  std::cout << "MyFunc(int a, int b) called" << std::endl;
}
int main(void) {
  MyFunc();
  MyFunc('A');
  MyFunc(12, 13);
  return 0;
}
```

```C++
MyFunc(void) called
MyFunc(char c) called
MyFunc(int a, int b) called
```

# <br>매개변수의 Default 값

* 매개변수에는 Default 값을 지정할 수 있음
  * Default 값을 지정하고 싶은 인자에는 다음과 같이  _선언 부분_ 에 값을 지정
  * 구현 부분에는 지정하지 않아도 됨 (header에만 지정)
  * Default 값을 지니는 인자들은  _뒤쪽에 위치_ 해야 함
    * 그래야 모호하지 않기 때문!

```C++
#include<iostream>
int BoxVolume(int length, int width = 1, int height = 1);
int main() {
  std::cout << "[3, 3, 3] : " << BoxVolume(3, 3, 3) << std::endl;
  std::cout << "[5, 5, D] : " << BoxVolume(5, 5) << std::endl;
  std::cout << "[7, D, D] : " << BoxVolume(7) << std::endl;
  std::cout << "[D, D, D] : " << BoxVolume(0) << std::endl; // compile error
  return 0;
}
int BoxVolume(int length, int width, int height) {
  return length * width * height;
}
```

```C++
[3, 3, 3] : 27
[5, 5, D] : 25
[7, D, D] : 7
```

# <br>인라인 함수

* 함수의 Signature 앞에 inline 키워드를 붙일 시, 인라인 함수가 됨.
  * 콜스택을 이용해 분리된 위치에서 해당 명령을 실행하는 것 대신, 즉시 실행되게 됨
  * 함수 호출 오버헤드가 없으므로 속도가 빠름

```C++
#include <iostream>
inline int SQUARE(int x) {
  return x * x;
}
int main(void) {
  std::cout << SQUARE(5) << std::endl;
  std::cout << SQUARE(12) << std::endl;
  return 0;
}
```

# <br>namespace

```C++
#include <iostream>
namespace BestComImpl {
  void SimpleFunc(void);
}
namespace BestComImpl {
  void PrettyFunc(void);
}
namespace ProgComImpl {
  void SimpleFunc(void);
}
int main(void) {
  BestComImpl::SimpleFunc();
  return 0;
}
void BestComImpl::SimpleFunc(void) {
  std::cout << "BestCom이 정의한 함수" << std::endl;
  PrettyFunc(); // 동일 이름공간
  ProgComImpl::SimpleFunc(); // 다른 이름공간
}
void BestComImpl::PrettyFunc(void) {
  std::cout << "So Pretty!!" << std::endl;
}
void ProgComImpl::SimpleFunc(void) {
  std::cout << "ProgCom이 정의한 함수" << std::endl;
}
```

* 서로 다른 모듈에서 우연히 같은 이름을 사용했을 때 충돌을 대비하기 위한 장치
* 해당 공간의 변수 및 함수를 참조하기 위해서는 이름공간의 이름을 붙여줘야 함
  * <이름공간>::<변수 및 함수 이름>

```C++
BestCom이 정의한 함수
So Pretty!!
ProgCom이 정의한 함수
```

# <br>using

* using 키워드를 이용해서 사용할 이름공간을 명시할 수 있음
* 주의:
  * header 파일에서 global하게 사용하지 말 것
    * 곧 모든 코드가 해당 이름공간을 사용하는 것과 동일해짐!
  * 함수 내부에서만 지역적으로 사용할 것

```C++
#include <iostream>
namespace Hybrid {
  void HybFunc(void) {
    std::cout << “So simple function!” << std::endl;
    std::cout << “In namespace Hybrid!” << std::endl;
  }
}
int main(void) {
  using Hybrid::HybFunc;
  HybFunc();
  return 0;
}
```

# <br>bool

* C, C++에서는 1은 참, 0은 거짓
  * 매크로에 의해 TRUE는 1, FALSE는 0으로 정의되어 있음
* 하지만 이러한 표현은 의미적으로 모호함
  * 따라서 C++는 true와 false 키워드를 이용해서 정수 0, 1과 논리 참, 거짓을 구분함!

```C++
#include <iostream>
using namespace std;
int main(void) {
  int num = 10;
  int i = 0;
  cout << "true: " << true << endl;
  cout << "false: " << false << endl;
  cout << "sizeof 1: " << sizeof(1) << endl;
  cout << "sizeof 0: " << sizeof(0) << endl;
  cout << "sizeof true: " << sizeof(true) << endl;
  cout << "sizeof false: " << sizeof(false) << endl;
  return 0;
}
```

```C++
true: 1
false: 0
sizeof 1: 4
sizeof 0: 4
sizeof true: 1
sizeof false: 1
```

# <br>자료형 bool

* bool은 int와 같은 기본 자료형
  * true 혹은 false를 담음
  * 이는 boolean expression을 담을 수 있음

```C++
#include <iostream>
using namespace std;
bool IsPositive(int num) {
  if (num < 0)
    return false;
  else
    return true;
}
int main(void) {
  bool isPos;
  int num;
  cout << "Input number: ";
  cin >> num;
  isPos = IsPositive(num);
  if (isPos)
    cout << "Positive number" << endl;
  else
    cout << "Negative number" << endl;
  return 0;
}
```

```C++
bool isAGreaterThanB = a > b;
bool isANotEqualsB = a != b;
```

```C++
Input number: 12
Positive number
```

# <br>참조자(Reference)

참조는 객체의 대체 이름

반드시 초기화를 수행해야 함!

```C++
void f() {
  int
  var = 1;
  int &r { var };   // r and var now refer to the same int
  int x = r;        // x becomes 1
  r = 2;        // var becomes 2
}
```

```C++
#include <iostream>
using namespace std;
int main(void) {
  int num = 12;
  int *ptr = #
  int **dptr = &ptr;
  int &ref = num;
  int *(&pref) = ptr;
  int **(&dpref) = dptr;
  cout << ref << endl;
  cout << *pref << endl;
  cout << **dpref << endl;
  return 0;
}
```

```C++
int var = 1;
int &r1 { var }; 	// OK: r1 initialized
int &r2; 		// error : initializer missing
extern int &r3; 	// OK: r3 initialized elsewhere
```

# <br>참조자의 시각화

```C++
void g()
{
    int var = 0;
    int& rr {var};
    ++rr; // var is incremented to 1
    int∗ pp = &rr; // pp points to var
}
```

* ++rr은 참조 rr을 증가시키는 것이 아닌, rr이 참조하는 var의 정수형 값을 증가시킴!
* 결론적으로, 참조의 값은 초기화 이후 변할 수 없음
* 만약 &rr을 사용할 경우, rr이 참조하는 객체의 주소를 얻게 됨
  * 즉, 참조의 포인터를 얻을 수도 없음

![](img%5Cweek1_subin0.png)

# <br>Call-by-value & Call-by-reference

* Call-by-value
  * 값을 인자로 전달하는 함수의 호출방식
* Call-by-reference
  * 주소 값을 인자로 전달하는 함수의 호출방식

```C++
int Adder(int num, int num2)
{
  return num1 + num2;
}
```

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

# <br>참조자를 이용한 Call-by-reference

매개변수로 선언된 참조자는 호출 시 해당 인자의 주소를 참조하게 됨

따라서 해당 참조자를 변경 시, 호출자의 인자가 변경되는 효과를 얻을 수 있음!

```C++
#include <iostream>
using namespace std;
void SwapByRef2(int & ref1, int & ref2) {
  int temp = ref1;
  ref1 = ref2;
  ref2 = temp;
}
int main(void) {
  int val1 = 10;
  int val2 = 20;
  SwapByRef2(val1, val2);
  cout << "val1: " << val1 << endl;
  cout << "val2: " << val2 << endl;
  return 0;
}
```

```C++
val1: 20
val2: 10
```

# <br>반환형이 참조형인 경우

* 해당 값을 받는 변수 역시 참조형인지 아닌지를 구별해야 함!
  * num2의 경우 참조형이 아니므로, 복사가 되어 값이 전달됨

```C++
#include <iostream>
using namespace std;
int & RefRetFuncOne(int &ref)
{
    ref++;
    return ref;
}
int main(void)
{
    int num1=1;
    int num2=RefRetFuncOne(num1);
    num1+=1;
    num2+=100;
    cout<<"num1: "<<num1<<endl;
    cout<<"num2: "<<num2<<endl;
    return 0;
}
```

```C++
int &RefRetFuncOne(int &ref)
{
    ref++;
    return ref;
}
int RefRetFuncTwo(int &ref)
{
    ref++;
    return ref;
}
```

```C++
int num2 = RefRetFuncOne(num1);	// ok, 복사가 되어 값을 받음
int &num2 = RefRetFuncOne(num1);	// ok, 참조로 값을 받음
int num2 = RefRetFuncTwo(num1);	// ok, 복사가 되어 값을 받음
int &num2 = RefRetFuncTwo(num1);	// error, 반환형이 참조형이 아님
```

```C++
num1: 3
num2: 102
```

# <br>잘못된 참조의 반환

* 위의 함수는 지역변수 num에 대한 참조를 반환하고 있다.
  * 따라서 다음 문장을 실행하면,
* ref는 num을 참조하나, num은 함수가 반환하면서 scope을 이탈해 소멸하게 된다.
  * ref는 쓰레기값을 참조하게 되며, segment fault 혹은 비정상적인 프로그램의 동작을 유발한다.
  * dangling reference(pointer)라고도 한다.

```C++
int& RetRefFunc(int n)
{
    int num = 20;
    num += n;
    return num;
}
```

```C++
int &ref = RetRefFunc(10);
```

# <br>const

* 다음의 코드를 보고 24가 출력될 것임을 확신할 수 있는가?
  * 그렇지 않다.
  * HappyFunc()에서 참조로 값을 받아 num을 변경할 수 있기 때문이다.
* 그러나 const 키워드를 이용하면, 이러한 불안을 해소할 수 있다.
  * 해당 참조자가 변하지 않을 것임을 컴파일 시기에 보장할 수 있기 때문이다.

```C++
int num = 24;
HappyFunc(num);
cout << num << endl;
```

```C++
void HappyFunc(int prm);	// Call-by-value
void HappyFunc(int &ref);	// Call-by-reference
```

```C++
void HappyFunc(const int &ref);
```

# <br>Const Correctness

* const를 올바르게 사용하는 것은 올바르게 동기화된 코드를 위해 필요하다.
* const는 그 자체로 self-document한 특성을 지닌다!
  * 값을 수정하지 않겠다는 의미를 지니기 때문이다.
* 따라서 해당 함수에서 인자를 수정하지 않는다면, const로 선언하는 것이 좋은 습관이다.

```C++
int MyFunction(const int& a, int& b); // a는 수정되지 않으며, b는 수정됨
```

# <br>new & delete

malloc -> new

free -> delete

```C++
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
char *MakeStrAdr(int len)
{
    char *str = (char *)malloc(sizeof(char) * len);
    return str;
}
int main(void)
{
    char *str = MakeStrAdr(20);
    strcpy(str, "I am so happy~");
    cout << str << endl;
    free(str);
    return 0;
}
```

```C++
#include <iostream>
#include <string.h>
using namespace std;
char *MakeStrAdr(int len)
{
    // char * str=(char*)malloc(sizeof(char)*len);
    char *str = new char[len];
    return str;
}
int main(void)
{
    char *str = MakeStrAdr(20);
    strcpy(str, "I am so happy~");
    cout << str << endl;
    // free(str);
    delete[] str;
    return 0;
}
```


댓글

이 블로그의 인기 게시물

[코딩의탑] 4층: 툰 쉐이딩

[코딩의탑] 3층: 바다 렌더링

[코딩의탑] 5층: 포탈(Portal), 더 나아가기