[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; } ```
댓글
댓글 쓰기