[C++] 02. C언어 기반의 C++ (2)
강의 <윤성우의 열혈 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 = #
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++을 새롭게 공부하니까 시간이 걸린다.
예제를 많이 풀면서 감을 익혀야겠다.
Author And Source
이 문제에 관하여([C++] 02. C언어 기반의 C++ (2)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@serinyoon/C-02.-C언어-기반의-C-2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)