두번째 열혈강의
이전까지 C++에서 namespace를 알아보았다. 사실 여기서는 C를 다 안다고 하고 가기 때문에, 기본서를 한번도 보지 않은 사람은 아예 이해가 되기 힘들수도 있다고 생각한다. 심지어 이 책은 벌써 설계에 대한 얘기가 나온다. 그럼 진행해 보도록 하자.
OOP
먼저, OOP 단계별 프로젝트 1단계라 하는 소제목이 나온다. 그리고 아직 익숙치 않다면 책을 한번 다 보고 진행하라고 한다.
난 내가 설계를 가장 좋아하고 잘 하고 싶어하는 사람으로써 이 챕터가 벌써 나온다는 것에 너무 만족한다.
그럼 제대로 내용을 알아 보도록 하자.
C++을 공부하면서 가장 어려움을 겪는 부분이 문법의 이해가 아닌 구현
이라고 한다. C언어와 다르기에 활용함에 있어 많은 시간과 노력을 요구하는데, 무엇보다도 경험이 없으면 시작이 막막하다. 그러므로 프로젝트
를 하나 진행하려고 한다고 한다.
앞으로 총 7단계에 걸쳐 진행해 나가도록 한다.
프로젝트 설명
먼저 우리가 하려고 하는 것은 은행 계좌 관리 프로그램
이다. 처음은 C스타일의 진행을 해보도록 하자.
구현 기능은 다음과 같다.
그리고 몇가지 가정이 필요하다.
그럼 시작해 보도록 하자.
실행의 예
사실 책의 내용을 그대로 가져와서 적어 넣는 듯한 느낌이 들어, 실행의 예는 단순히 말로만 적어 보면, 메뉴를 먼저 보여주고, 거기에서 선택을 입력 받으면 상황에 따라 처리하는 형식이다. 여기서는 먼저 자신의 코드를 만들어보고 저자의 코드를 보라고 되어있다. 뭐 내 블로그다 보니 다 적어놓을 수는 없지만 궁금하다면 책을 보길 바란다. 사실 나도 C스타일이 기억이 안나서… 참 부끄럽지만 (역시 나 스스로 개발자라고 하기엔 아직 부끄러운게 너무 많다.) 조금 찾아보면서 만들게 되었다.(특히, 최근 1년간 javascript만 했다보니 객체밖에 떠오르지 않아서.. 하…) 못난 나를 꾸짖는 좋은 시간이였다.
내가 만든 코드를 올리려다 일단 무료공개해둔 코드를 적었다. 출처는 이곳을 참조하면 된다.
이 코드를 작성하는 것이 1단계의 시작이다. 차차 C++ 코드로 변환시켜 나갈 것으로 예상된다.
CHAPTER 2
CHAPTER 2에 들어왔다.
CHAPTER 2를 진행하기에 앞서, 이 책에서는 C를 굉장히 중요시 여긴다. 당연한 것이다. C++이라는 것이 C + class
라고 하기도 하므로 중요할 수 밖에 없다. 여기서도 이 부분에서 C 복습을 시킨다.
문제가 3개 주어진다.
어찌보면 기본적이고, 가장 중요한 것들이다. 하나하나 알아보자.
const
“1. 키워드 const의 의미”에 있어서 예시들이 있는데, 다음과 같다.
C를 공부 제대로 안했으면 뭐가 뭔지, 아마 const가 뭔지부터 헤깔릴 수도 있으니 잘 알아두도록 하자.
먼저 const
의 의미는 상수화 이다. 내가 느끼고 이해하기 쉬운 말로는 고정
이라고 본다.
일단 책에서의 설명을 적어보자면
1번은 변수 num을 상수화
2번은 포인트 ptr1을 이용해서 val1의 값을 변경할 수 없음
3번은 포인터 ptr2가 상수화 됨
4번은 포인터 ptr3가 상수화 되었으며, ptr3를 이용하여 val3의 값을 변경할 수 없음
이라고 한다.
내가 만약에 설명을 한다면, 상수의 반댓말을 "변수"정도라고 생각하고 "고정"이라는 단어를 이용하려고 한다.
1번은 int형 변수 num의 값을 상수 10으로 고정
2번은 int형 포인터 ptr1이 가르치는 값을 고정, ptr1은 val1의 주소
3번은 int형 ptr2 포인터가 가리키는 값의 주소를 고정, ptr2는 val2의 주소
4번은 int형 ptr3가 가리키는 값과 주소를 둘다 고정, ptr3는 val3의 주소
정도로 정리 될 것이다.
즉, 중요한 것은 포인터의 개념도 들어가는데, int* ptr
이라고 할 때 변수는 ptr이지 *ptr이 아니다. (*은 연산자이다.) 포인터를 생각할 때는, 그림을 그려도 좋고 자신이 이해하기 쉬운 쪽으로 생각하면 된다.
개인적으로는 정리를 해둔 PPT가 있어 헤깔릴 때마다 그 자료를 보다보니 자연스럽게 이해가 되었다.
간단히 설명하면, int* ptr
이라 할때, ptr도 자신의 저장공간을 가지고 선언이 되는 것이고, 그 저장공간에는 포인터가 가리키는 곳의 주소가 저장된다. (즉, 포인터도 자신의 주소는 따로 있다.) 좀더 자세하게 하면 포인터 변수
는 ptr, ptr이 가리키는 값
은 *ptr, ptr이 기리키는 값의 주소
는 ptr이라고 정리된다.
그럼 포인터 함수가 또 헤깔릴 수가 있는데, void swap(int* A, int* B)
라는 함수가 있다고 하자. 우리는 main에서 어떻게 입력하냐면 swap(&num1, &num2);
와 같은 식으로 함수를 호출한다. 이게 또 포인터에 대한 개념이 헤깔리면 어려워 보이는데, 포인터 변수는 A와 B
이다. 즉, 포인터 변수 A에 num1의 주소를 넣어준 것이고, A는 포인터로서 가르키는 값의 주소
가 num1의 주소
가 된 것이다. 그렇다면 *A는 num1의 값이 되는게 당연하다.
이것도 이해가 힘들다면 쉽게 생각하자. int* A = &num1;
이 되는 것이고, int* B = &num2;
가 되는 것이다. 이렇게 보고나면 포인터의 기본 선언문이 되므로 쉽게 접근이 된다.
배열
이 포인터라는 것도 다들 알지만 이해하기 힘들어 하는데, 배열을 한번 보도록 하자.
배열 int arr[10];
을 선언 했다고 하자. 그럼 arr[0]
은 *(arr)
과 같다.
이걸 외우는 사람이 많다. arr[2] == *(arr+2)
이런식으로 말이다. 이건 외우지 않아도 된다.
배열이 포인터라면 배열을 선언할 때, arr은 제일 첫번째 배열 값의 시작 주소를 가지고 있는 것이다. 이게 무슨 뜻이냐면 값들은 메모리 어딘가 나눠져 있겠지만, 배열은 포인터로써 자신의 자료형 크기만큼 하나씩 할당하여 일렬로 값이 있는 주소를 가지고 있는다는 뜻이다. 그렇다면 재밌는 코드를 하나 보도록 하자.
C로 짰으면 더 좋았겠지만 원하는 바는 표현이 된다.
중요한 것은 ptr
의 출력과 ptr + 1
의 출력이다.
ptr주소와 ptr주소에 1을 더한 값인데 놀랍게도 1만 더한게 아니라 8이나 더한 값이 나올 것이다.
그 이유는 ptr이 double형 포인터
라 단순히 1이 더해진 것이 아니고, double형의 자료 한개 크기인 8바이트가 커진 것
이다.
이제 이것을 배열에 적용 해보자.
배열arr은 방금 말했듯이 첫 배열 값의 주소다. 그렇다면 arr+1
은 어떻게 될까? 해당 배열의 자료형 한개 값을 더한 크기이므로 배열 두번째 값의 주소
가 되는 것이다. 따라서 *(arr+1)은 arr[1]의 값이 되는 것이다.
C에서 나오는 포인터 개념을 줄글로 간단히 정리해보았다.
Memory 와 Call-by-value, Call-by-referance
그럼 원래 하던 얘기로 돌아와서 2. 실행중인 프로그램의 메모리 공간
에 대해 알아보자.
프로그램은 OS한테 메모리를 할당받는데, 이 때 크게 데이터, HEAP, STACK 영역으로 나눠진다.(이 책에서는 이렇게 나오지만 text 영역도 있다.) 이 때 어떠한 변수가 어디에 할당 되는지 알아보는 게 중요하다.
이것은 각각의 역할만 잘 알면 쉽다.
text는 CPU가 실행하는 머신코드
, 데이터는 전역변수, static 변수, 외부변수
, 스택은 지역변수나 매개변수
, 힙은 동적할당 영역
정도로 구분될 것이다.
생각보다 간단히 정리가 되었다.
그럼 마지막 3. Call-by-value, Call-by-referance
를 알아보자.
이건 사실 위에 포인터를 설명하면서 어느정도 감각적으로 알 수 있을 텐데, (특히 함수) 가장 직접적으로 알 수 있는 swap을 제대로 만들어 보면,
이정도로 볼 수 있다.
이후에 이 부분은 책에서 좀더 세밀하게 설명을 할 예정이라고 한다. 어느정도 감각만 가지고 있도록 하자.
아무래도 글이 길어져 다음 포스팅에서 이어서 하도록 하겠다.