[C++] 02. C언어 기반의 C++ (2)

Serin Yoon·2021년 11월 8일
0

Graphics/C++

목록 보기
2/5
post-thumbnail

강의 <윤성우의 열혈 C++ 프로그래밍>을 참고하여 정리한 글입니다. 🙂
https://github.com/Serin-Yoon/cpp-study/blob/master/cpp%20study/chapter2.cpp

  • C 내용 복습
    • 데이터: 전역변수가 저장되는 영역
    • 스택: 지역변수 및 매개변수가 저장되는 영역
    • : malloc 함수호출에 의해 프로그램이 실행되는 과정에서 동적으로 할당이 이루어지는 영역
    • malloc & free: malloc 함수호출에 의해 할당된 메모리 공간은 free 함수호출을 통해 소멸되지 않으면 해제되지 않음

  • 함수 호출 형태 (Call-by-value & Call-by-reference)
void CallByValue(int num1, int num2) {
    int temp = num1;
    num1 = num2;
    num2 = temp;
}
void CallByReference(int* ptr1, int* ptr2) {
    int temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}

1. 상수화

const int num = 10; // 변수 num 상수화
const int* ptr1 = &val1; // 포인터 ptr1 이용하여 val1 값 변경 불가
int* const ptr2 = &val2; // 포인터 ptr2 상수화
const int* const ptr3 = &val3; // 포인터 ptr3 상수화 & ptr3 이용하여 val3 값 변경 불가


2. 자료형 bool

bool isBool; // true or false
cout << true << false << endl;
if (true) cout << "true!" << endl;
cout << sizeof(1) << endl; // 4byte
cout << sizeof(true) << endl; // 1byte

3. 참조자의 이해

int num1 = 10; // 변수 선언 → num1이라는 이름의 메모리 공간 할당됨
int &num2 = num1; // 참조자 선언 → num1의 메모리 공간에 num2라는 이름 추가로 붙음 (like 별칭)

int main(void) {
    int num1 = 10;
    int &num2 = num1;
    int &num3 = num2;
    num3 = 20;
    cout << num1 << endl; // 20
    cout << num2 << endl; // 20
    cout << num3 << endl; // 20
    return 0;
}

  • 참조자 선언 가능 범위
/* 참조자 선언 성립X 예시 */
int &ref = 20; // 상수를 대상으로 참조자 선언 불가능
int &ref; // 참조자 생성과 동시에 무언가를 참조해야 함
int &ref = NULL; // NULL로 초기화 불가능

/* 참조자 선언 성립 예시 */
int arr[3] = {1, 2, 3};
int &ref1 = arr[0];
int &ref2 = arr[1];
int &ref3 = arr[2];
cout << ref1 << ref2 << ref3 << endl; //123

배열의 요소는 변수의 성향을 지니기 때문에 참조자 선언이 가능


  • 포인터 변수 대상의 참조자 선언
int num = 10;

int* ptr = &num;
int** dptr = &ptr;

int &ref = num;
int* (&pref) = ptr; // ptr 역시 변수 (주소값을 저장하는 포인터 변수)
int** (&dpref) = dptr; // dptr 역시 변수 (주소값을 저장하는 포인터 변수)

cout << ref << pref << dpref << endl; // 101010

4. 참조자와 함수

  • Call-by-value & Call-by-reference
// Call-by-value: 값 전달 (함수 밖의 변수 접근 불가)
void SwapByValue(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    cout << a << b << temp << endl;
}

// Call-by-reference: 주소값 전달 (함수 밖의 메모리 공간 접근 가능)
void SwapByRef(int* ptr1, int* ptr2) {
    int temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
    cout << *ptr1 << *ptr2 << temp << endl;
}

  • Call-by-value? Call-by-reference?
int func(int* ptr) {
    return ptr + 1;
}

포인터 ptr에 전달된 주소값의 관점에서 보면 Call-by-value이고, 주소값을 전달받아 함수 밖의 메모리 공간에 접근했으므로 Call-by-reference이기도 함

C++ 2가지 형태의 Call-by-reference
1) 주소값을 이용
2) 참조자를 이용


  • 참조자를 이용한 Call-by-reference
void CallByReference(int &ref1, int &ref2) {
    int temp = ref1;
    ref1 = ref2;
    ref2 = temp;
}

int main(void) {
    int val1 = 10;
    int val2 = 20;
    CallByReference(val1, val2);
    cout << val1 << endl;
    cout << val2 << endl;
    return 0;
}

매개변수 = 함수 호출될 때 선언되는 변수
→ 함수 호출 과정에서 선언과 동시에 전달되는 대상으로 초기화 (int &ref1 = val1, int &ref2 = val2)


  • const 참조자

void func(int &ref) { ... }
함수의 정의 형태와 함수의 호출 형태를 보아도 값의 변경 유무를 알 수 없어 함수 몸체를 보아야 함 → 단점

void func(const int &ref) { ... }
함수 내에서 참조자 ref를 이용한 값의 변경을 허용하지 않을 것임을 명시

const 참조자 선언의 장점
1. 함수의 원형 선언만 봐도 값의 변경 유무 파악 가능
2. 실수로 인해 값 변경 일어나지 않음 (허용이 안 되므로)


  • 반환형 참조 vs 반환형 변수
int& refRetFuncOne(int& ref) {
    ref++;
    return ref;
}

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

int num2 = refRetFuncOne(num1); (O)
int& num2 = refRetFuncOne(num1); (O)
반환형이 참조인 경우 반환 대상을 참조자 또는 변수로 받을 수 있음

int num2 = refRetFuncTwo(num1); (O)
int& num2 = refRetFuncTwo(num1); (X)
반환형이 변수인 경우 반환 대상을 참조자로 받을 수 없음


  • 잘못된 참조 반환
int& retRefFunc(int n) {
    int num = 20;
    num += n;
    return num;
}

int main(void) {
    int& ref = retRefFunc(10);
}

지역변수를 참조 형태로 반환하는 경우, ref가 참조하는 대상이 소멸됨


  • const 참조자의 또다른 특징 (상수 참조)
/* 잘못된 코드 */
const int num = 20;
int& ref = num; // ref을 이용하여 값 변경 허용함을 의미 (const 무의미해짐)

/* 잘 작성된 코드 */
const int num = 20;
const int& ref = num;

const int& ref = 30;
const 참조자는 상수를 참조할 수 있음
(상수를 const 참조자로 참조할 경우, 메모리 공간에 상수를 임시적으로 저장하기 때문)


5. malloc & free를 대신하는 new & delete

malloc 대신 new, free 대신 delete 사용
(malloc = new, free = delete은 아님. 연산 특성의 차이 존재.)

int* ptr1 = new int; int형 변수의 할당
double* ptr2 = new double; double형 변수의 할당
int* arr1 = new int[10]; 길이가 10인 int형 배열의 할당
double* arr2 = new double[20]; 길이기 20인 double형 배열의 할당

delete ptr1; int형 변수의 소멸
delete ptr2; double형 변수의 소멸
delete []arr1; int형 배열의 소멸
delete []arr2; double형 배열의 소멸


  • 포인터 사용하지 않고 heap에 접근하기
int* ptr = new int;
int& ref = *ptr; // 힙 영역에 할당된 변수에 대한 참조자 선언
ref = 20;
cout << *ptr << endl; // 20

변수의 성향을 지니는 대상에 대해서는 참조자 선언 가능
(C의 경우 heap에 접근하기 위해 반드시 포인터를 사용해야 함)


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

c를 더하고 .h를 빼기
ex) #include <stdio.h>#include <cstdeio>

기본적으로 C의 함수는 C++에도 있음.
표준 C에 대응하는 표준 C++ 함수는 C++ 문법을 기반으로 확장됨.
C++는 함수 오버로딩 등을 지원하기 때문에 C++ 함수를 사용하는 것을 권장함.

/* C - 함수 오버로딩 지원 X */
int abs(int num);

/* C++ - 함수 오버로딩 지원하여 제약이 적음 */
long abs(long num);
float abs(float num);
double abs(double num);
long double abs(long double num);

C 문법을 많이 까먹은 상태에서 C++을 새롭게 공부하니까 시간이 걸린다.
예제를 많이 풀면서 감을 익혀야겠다.

profile
티스토리로 이사했습니다 🏠

0개의 댓글