티스토리 뷰
1. 구조체 정렬
struct Test { char a; // 1바이트 int b; // 4바이트 short c; // 2바이트 char d; // 1바이트 }
위와 같은 구조체가 있다고 가정합시다.
아래에서는 위의 코드를 기반으로 구조체가 메모리에서 어떻게 정렬되는 지에 대해서 그림으로 보여드리겠습니다.
데이터의 주소가 그 바이트의 배수에 해당하는 곳에 배치됩니다.
<1바이트 정렬>
<2바이트 정렬>
<4바이트 정렬>
<8바이트 정렬>
Visual Studio의 경우에는 8바이트 정렬을 기본으로 합니다.
위처럼 사용하게 되면 너무 낭비인 것이 아닌가? 그냥 1바이트를 사용하면 되는 것이 아닌가? 라고 생각할 수 있습니다. 그렇지만 라이브러리들은 8바이트 정렬을 사용하고 있습니다. 그렇기에 그냥 자연스럽게 8바이트 정렬을 사용한다고 생각하면 편합니다.
그렇기에 최선의 방법은 8바이트의 자료형을 사용하지 않는 것입니다. 만약 사용하게 된다면 같은 자료형끼리 묶으면서 작은 자료형부터 위에서 써주면 좋습니다.
자신이 구조체를 사용하게 된다면 sizeof를 사용해서 얼마나 데이터를 사용하는지 꼭 확인해야 합니다.
아니면 프로그램이 매우 비효율적으로 될 수 있습니다.
2. 링크드 리스트
자료 구조 중 하나인 링크드리스트는 연결 리스트라고 불리기도 합니다.
링크드 리스트는 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장하는 자료 구조입니다. 노드는 데이터를 포함하여 다른 노드와 연결될 수가 있습니다. 데이터를 담고 있는 노드들이 연결되어 있는데 노드의 포인터가 다음이나 이전의 노드와의 연결을 담당하게 됩니다.
단일 연결, 이중 연결, 원형 연결 리스트가 있습니다.
struct NODE { // 연결 리스트의 노드 구조체 struct NODE *next; // 다음 노드의 주소를 저장할 포인터 int data; // 데이터를 저장할 멤버 };
위의 코드는 노드 구조체를 적어본 것입니다.
링크드 리스트를 이해만 잘 한다면 차원 포인터를 이용할 필요가 없습니다.
왜 우리는 자료 구조를 공부해야 할까요? 대부분의 자료 구조는 라이브러리 안에 거의 제공되는데 말이죠?
그 이유는 라이브러리 안의 자료 구조들은 비효율적이기 때문입니다.
상황에 맞게 시간 복잡도까지 생각하여 가장 좋은 자료 구조를 써야하는데 그냥 라이브러리 안의 자료 구조들을 사용하게 되면 안 됩니다. 라이브러리에 있는 자료 구조들은 다양한 상황에 맞춰서 제작되었기 때문입니다.
3. 객체
객체란 일상적인 행위나 작업을 표준화시켜 하나의 완성품으로 만드는 것이라고 말할 수 있습니다. 이렇게 말하면 이해가 힘드실 수 있어서 예를 들어보겠습니다. 커피를 만들어 먹기 위해서는 여러 재료를 조합해서 만듭니다. 그 여러 재료들을 직접 조합해서 만들기는 귀찮겠죠. 그렇기 때문에 사람들은 이런 커피 만드는 작업을 커피 자판기라는 것으로 모두가 커피를 쉽게 마실 수 있도록 표준화 시켰습니다. 여기서 커피자판기는 C++가 됩니다. 왜냐하면 C++ 또한 객체를 만들기도 하고 사용하기도 하기 때문입니다.
4. class
C++에서는 객체를 만들어서 프로그래밍을 하기 때문에 객체를 정의하는 class 문법을 사용합니다. class 문법은 C언어에서 구조체에서의 struct 문법과 비슷한 구조를 가지고 있습니다. 그렇기 때문에 쉽게 생각하면 struct 구조체 대신 class가 선언됐다고 생각하면 됩니다. 그리고 구조체 안에 선언된 변수들은 C++에서는 멤버 변수라 부릅니다.
/* C */ struct People { char name[10]; // 이름 short age; // 나이 double height; // 키 }; /* C++ */ class People {
char name[10]; // 멤버 변수 short age; // 멤버 변수 double height; // 멤버 변수 };
C++에서 class 문법 사용 시 멤버 변수에 직접 값을 대입하게 되면 오류가 발생하게 됩니다. 왜냐하면 접근 제한자라는 개념이 C++에서 추가되기 때문입니다. 접근 제한자를 적지 않으면 private이라는 접근 제한자가 생략된 것이라고 생각합니다. 접근 제한자인 private를 적게 되면 객체 외부에서 직접 접근이 불가능합니다. 그렇기 때문에 객체 외부인 값을 객체 내부에 존재하는 멤버 변수에 대입하지 못하는 것입니다.
위의 코드는 원래 아래 코드가 되는 것인거죠.
class People { private: // 접근 제한자 char name[10]; // 멤버 변수 short age; // 멤버 변수 double height; // 멤버 변수 };
만약 객체 외부에 직접 값을 멤버 변수에 접근하고 싶다면 public를 적으면 됩니다.
class 문법은 변수뿐만 아니라 함수로도 나타낼 수 있습니다. 이것을 멤버 함수라 부르며, 멤버 함수 안에는 멤버 변수가 선언됩니다. 여기에 선언된 멤버 변수는 접근 제한자에 상관없이 사용이 가능합니다.
class People { private: // 접근 제한자 char name[10]; // 이름 short age; // 나이 double height; // 키 void Func() // 멤버 함수 Func를 선언 { age = 20; // 멤버 변수 age에 20을 대입 } };
멤버 함수도 함수이기 때문에 함수 안에 지역 변수를 선언할 수 있습니다. 그렇기 때문에 아래와 같이 지역변수를 선언하게 되면 멤버 변수와 이름이 중복되어 버그가 발생할 수 있습니다.
class People { private: // 접근 제한자 char name[10]; // 이름 short age; // 나이 double height; // 키 void Func() // 멤버 함수 Func를 선언 { int age; // 지역 변수 age를 int형으로 선언 age = 20; // 지역 변수 age에 20을 대입 } };
위와 같은 코드를 사용하면 버그가 발생할 수 있기 때문에 아래와 같이 멤버 변수 이름 앞에는 ' m_ '을 붙여서 많이 사용합니다.
class People { private: // 접근 제한자 char m_name[10]; // 이름 short m_age; // 나이 double m_height; // 키 void Func() // 멤버 함수 Func를 선언 { int age; // 지역 변수 age를 int형으로 선언 m_age = 20; // 지역 변수 age에 20을 대입 } };
5. 오버로딩
오버로딩에 대해 보우기 전에 Overload의 뜻을 알고 있나요?
Overload라는 단어의 뜻은 '너무 많이 주다, 과적하다' 입니다. 즉, 오버로딩은 한 개의 명령 문법이 둘 이상의 의미로 사용되는 것을 말합니다.
컴퓨터에서의 명령어 기호는 기본적으로 하나의 의미를 갖고 있습니다. 이 규칙은 C도 적용됩니다. 그러나 C++에서는 명령어가 두 개 이상의 의미를 갖는 것이 가능합니다. 이런 것을 오버로딩이라 부르며, 오버로딩에는 연산자 오버 로딩과 함수 오버 로딩이 있습니다.
<연산자 오버로딩>
char *p char str1[20]="abc";
char str2[20]="def"; p = str1 + str2; // 오류 발생
C에서는 수식에서 연산자를 발견하게 되면 연산자를 중심으로 피연산자를 보고 연산을 처리했습니다. 그 피연산자는 숫자가 아니라면 그냥 문법 오류로 처리해버렸었죠.
C에서 위와 같이 나타내게 되면 오류가 발생하게 됩니다. 왜냐하면 str1과 str2 둘 다 주소로 변하게 되는데 +연산자는 한쪽이 주소이면 다른 한쪽은 정수 값이어야 합니다. 그렇지만 위 소스 코드는 둘 다 주소를 더하기 때문에 오류가 발생하게 됩니다. 그래서 이런 오류를 피하기 위해서는 아래와 같이 작성해야 합니다.
c++에서는 이런 부분을 해결할 수 있습니다.#include <stdio.h> #include <string.h> // strcat 함수 사용하기 위해 선언 int main(void) { char *p; char str1[20]="abc", str2[20]="def"; // strcat 함수를 이용하여 "abcdef"로 만든다
// 그리고 "abcdef" 문자열을 저장한 str1의 주소를 반환 p = strcat(str1,str2); printf("%s\n",p); }
#include <stdio.h> #include <string.h> class MyString { private: char m_string[20];
public: void SetString(char *p) // 문자열 복사하는 멤버함수 { strcpy(m_string, p); }
// 기존 문자열에 새로운 문자열 추가 함수 char *ptr(char *p) { return strcat(m_string, p); } }; void main() { str1.SetString("abc"); // str1의 m_string에 "abc" 복사 char *p_string = str1.ptr("def");
// str1 객체의 m_string에 "def"를 추가
// 반환된 m_string 변수의 주소를 p_string 포인터에 저장 printf("%s\n",p_string); }
#include <stdio.h> #include <string.h> class MyString { private: char m_string[20]; public: void SetString(const char *p) // 문자열 복사하는 멤버함수 { strcpy(m_string, p); } // 기존 문자열에 새로운 문자열 추가 함수 char *operator+(const char *p) { return strcat(m_string, p); } }; void main() { MyString str1; str1.SetString("abc"); // str1의 m_string에 "abc" 복사 char *p_string = str1.operator+("def"); // str1 객체의 m_string에 "def"를 추가 // 반환된 m_string 변수의 주소를 p_string 포인터에 저장 printf("%s\n", p_string); }
int sum(int a, int b) { return a+b; } double sum(double a, double b, double c) { return a+b+c; } int main(void) { int data1 = sum(1, 2); // 매개변수가 2개 double data2 = sum(1.0, 2.0, 3.0); // 매개변수가 3개 printf("%d,%d\n",data1,data2); return 0; }
이러한 오버로딩 기능은 C에서는 지원이 안 됩니다! C++에서만 적용이 가능합니다.
'대외활동 > Tips 19기 강좌 정리' 카테고리의 다른 글
[19기 TIPS] 2018.07.30. 11차 (2) | 2018.08.02 |
---|---|
[19기 TIPS] 2018.07.26. 10차 (2) | 2018.07.30 |
[19기 TIPS] 2018.07.19. 8차 (0) | 2018.07.23 |
[19기 TIPS] 2018.07.16. 7차 (2) | 2018.07.19 |
[19기 TIPS] 2018.07.12. 6차 (2) | 2018.07.16 |