iterator

iterator는 C++만의 개념이 아니다. python도 있고 java에도 있다.

C++에서 iterator의 개념만 확실히 잡으면 다른 언어에서 iterator는 공짜다.

 

iterator는 한마디로 그냥 포인터다. 어떤 포인터? 배열의 요소를 가르키는 포인터

C++ 표준 라이브러리 Vector에서 begin 함수는 배열의 처음 주소를 반환하는 함수다.

 

그러니깐 scores.begin()이라고 하면 scores Vector 배열의 첫번째 주소를 반환해준다 

iter = scores.begin()에서 iter는 첫번째 주소를 가지고 있는 포인터니깐 *iter라고 하면 그 값을 참조해서 가져온다.

 

참고로 주의해야 할 점은 end함수는 vector의 마지막 요소 바로 뒤 그러니깐 쓸모없는 값을 가르키는 주소를 반환해준다! 그래야 for loop 돌릴때 편하기 때문!(조건 iter != socres.end())

#include <stdio.h>
#include <iostream>
#include <vector>

int main()
{
	std::vector<int> scores;
	scores.reserve(3);

	scores.push_back(10);
	scores.push_back(20);
	scores.push_back(30);


	for (std::vector<int>::iterator iter = scores.begin(); iter != scores.end(); ++iter)
	{
		std::cout << *iter << std::endl;
	}

}

 

iterator 그림

포큐아카데미 C++

 

 

iterator insert, delete
	std::vector<int>::iterator it = scores.begin();
	scores.insert(it, 90);

위의 코드에서 it는 socres의 첫번째 배열 주소를 가리키는 포인터다.

그 상태에서 insert를 하게되면 첫번째 주소에 90을 넣으라는 코드다.

 

그 다음 index에 insert 하고 싶으면 it++ 연산자를 이용해서 주소를 (+) 하면된다

 

삭제도 간단하다 insert 대신 erase를 사용하면 된다

 

insert, delete를 하면 연속된 배열이기 때문에 어쩔수없이 메모리 복사가 및 재할당이 일어난다.

위의 코드처럼 첫번째 요소에 90을 넣을때 모든 배열 요소를 한칸씩 뒤로 미루는 우로밀착을 한뒤에 90을 넣어야 한다(복사)

 

재할당은 현재 사용중인 배열의 capacity를 초과했을때 메모리를 다시 할당하는(malloc)을 해줘야한다. 세상에 공짜는 없는듯하다

 

'C++' 카테고리의 다른 글

C++ 템플릿  (0) 2020.04.21
C++ 객체 백터 Vector  (0) 2020.04.17
C++ 정적 바인딩, 동적 바인딩  (1) 2020.04.09
C++ 멤버함수의 메모리 위치  (0) 2020.04.09
C++ 객체 생성  (0) 2020.04.02
C++의 기본 바인딩은 정적 바인딩이다.

C++ 포큐아카데미

Animal을 상속받아 만든 Cat 클래스가 있다. Cat 클래스에 Speak 메소드를 오버라이딩 했다.

두개의 오브젝트를 만드는데 타입을 하나는 Cat으로 하나는 부모클래스인 Animal로 했다. 그때 speak()메소드를 호출하면 누가 나올까?

 

JAVA는 무조건 오버라이딩된 자식 메소드가 나오고 C++는 무늬 즉 타입(포인터)따라 간다.

JAVA의 기본 바인딩은 동적 바인딩이고 C++의 기본 바인딩은 정적 바인딩이다.

 

정적 바인딩

C++ 포큐아카데미

위의 그림에서 Cat 오브젝트를 만들고 타입도 Cat*다. 그래서 힙에 할당한 모든 메모리를 그냥 쓰면된다. 전혀 문제가 안됨

 

C++ 포큐아카데미

하지만 위의 그림은 Cat 오브젝트를 만들었지만 타입은 부모 클래스 즉 Animal이다. 이럴때 Animal의 것만 포인팅한다.

Cat의 메모리 영역에 접근하고 싶으면 Type, 포인터를 Cat*으로 변경해야 한다.

 

C++ 포큐아카데미

정적 바인딩을 그림으로 잘 표현한 예다. C++는 기본적으로 타입 따라간다. 왜냐? 정적바인딩이니깐

 

 

가상함수(동적 바인딩)

C++ 포큐아카데미

그렇다면 C++에서 자바처럼 무조건 만들어진 오브젝트 즉 자식 클래스의 메소드가 호출되려면 어떻게 해야 할까?

virtual 키워드를 붙이면 된다. virtual을 붙이면 자바처럼 동적 바인딩을 하겠다는말이다.

참고로 자바는 기본적으로 모든 것이 다 virtual이고 final을 붙이면 정적 바인딩이 된다.

 

동적 바인딩은 실행 중에 어떤 함수를 호출할지 결정되고 정적 바인딩 보다 느리다. 실행 중에 어떤 함수를 결정하기 위해 가상 테이블이 생성된다.

 

가상테이블

C++ 포큐아카데미

컴파일시에 virtual을 정의한 메소드에 한해서 가상 테이블이 생성되는데 오브젝트를 생성할 때 해당 클래스의 가상 테이블 주소가 함께 저장된다. (EX __vfptr, 0x00459bd8)

 

위의 가상테이블을 활용하면 오브젝트가 메소드를 호출할때 가상테이블로 가서 "야! Move 메소드 호출할건데 부모거말고 내걸로 호출해라! 니가 주소 알고 있지? 그 주소로 Jump해서 호출하고와라" 이런식으로 가상 테이블에 접근해서 메소드를 호출한다. 그렇기 때문에 느리다.

 

'C++' 카테고리의 다른 글

C++ 객체 백터 Vector  (0) 2020.04.17
C++ iterator 개념  (0) 2020.04.17
C++ 멤버함수의 메모리 위치  (0) 2020.04.09
C++ 객체 생성  (0) 2020.04.02
C++ 임시객체(이동 생성자) 중요!  (0) 2020.02.07
멤버함수

C++ 포큐아카데미

Cat 클래스는 Animal 클래스를 상속해서 만들었다.

myCat과 yourCat 오브젝트는 각각의 메모리 영역을 가진다(그림 참조)

그러면 과연 멤버함수 GetName은 어디에 존재할까?

myCat과 yourCat의 멤버변수처럼 각각 존재하는건지, 아니면 하나만 존재하는건지 헷갈린다.

 

정답은 각각 존재하지 않고 하나만 존재한다. 위치는 메모리의 코드섹션에 존재하며, 각 멤버 함수는 컴파일 시 딱 한번만 메모리에 할당된다. 그리고 저수준에서는 클래스의 멤버함수는 사실 전역함수와 같다.

C언어에서 전역함수인데 매개변수로 구조체를 받는 함수가 있다고 가정하면 C++에서 멤버함수는 전역함수에 속하고 매개변수는 구조체 대신 오브젝트의 포인터(주소)가 된다.

 

 

C++ 포큐아카데미

myCat, yourCat 오브젝트가 GetName 메소드를 실행하면 코드섹션에 0x0A16C7주소에 있는 함수를 실행하는 것을 확인할 수 있다.

그리고 GetName 메소드는 매개변수로 Cat*를 받는다. 그 포인터로 멤버변수에 접근한다는 말.. 멤버변수는 각각의 메모리공간을 가지니깐!

 

'C++' 카테고리의 다른 글

C++ iterator 개념  (0) 2020.04.17
C++ 정적 바인딩, 동적 바인딩  (1) 2020.04.09
C++ 객체 생성  (0) 2020.04.02
C++ 임시객체(이동 생성자) 중요!  (0) 2020.02.07
C++ 대입 연산자  (0) 2020.02.02
객체 생성
class Vector 
{
	int x;
	int y;
}

C++ 포큐아카데미

python이나 java 등 보편적인 언어는 클래스 객체 생성을 Heap 영역에 하는 반면 C++는 자유도가 높아 객체를 스택에도 생성할 수 있다. 물론 스택에 너무 큰 용량의 객체를 만들면 스택 오버플로우가 나니 조심해야 한다.

 

class Vector 
{
	int x;
	int y;
}

Vector v;

위의 예제처럼 객체를 만들면 8바이트(int 4 바이트라고 가정) 만큼 스택에 할당한다.

 

public class Vector 
{
	int x;
	int y;
}

Vector* v = new Vector();

C++ 포큐아카데미

위의 예제처럼 객체를 생성하면 스택영역의 변수 b에 Vector를 할당한 Heap영역의 메모리 첫번째 주소를 담는다.

 

 

객체 배열 생성

C++ 포큐아카데미

우측의 C++부터 보면 Heap영역에 Vector 객체 10개를 만들고(8바이트 * 10 = 80바이트) 그 첫번째 주소를 스택의 list 변수에 담는다. 그래서 list 변수의 타입은 Vector *이다.

 

반면에 Java의 경우 new Vector[10]을 해도 객체를 10개 만들지 않고 Vector 객체를 담을 수 있는 레퍼런스(주소)를 반환한다. (포인터가 4바이트라고 가정하면 4바이트 * 10 = 40바이트) 실제로 값을 담으려면 for문을 10번 돌면서 값을 생성해주면 된다.

 

 

C++ 포큐아카데미

정리하면, 힙에 Vector 10개를 바로 만드려면 Vector* list = new Vector[10]을 하면 되고, JAVA에서는 불가능하다. 왜냐하면 모든게 다 레퍼런스 즉 포인터라서.

 

C++에서 Java의 Vector 객체를 담을 수 있는 레퍼런스(주소) 10개를 반환하는 코드를 만드려면

Vector** list = new Vector*[10] 이렇게 하면된다.

 

list 타입을 설명하자면 처음의 * 포인터는 배열 그 자체 그러니깐 전체를 나타내는 것이고 두번쨰 * Vector는 각각의 배열은 Vector 객체를 가르키는 포인터를 담는다는 뜻이다. 

 

C++ 포큐아카데미

마지막으로 객체를 삭제할때다. C++에서 delete를 안해주면 큰일난다. Java처럼 자동으로 가비지컬렉터가 지워주지 않기때문이다. 반드시 삭제하도록 하자

'C++' 카테고리의 다른 글

C++ 정적 바인딩, 동적 바인딩  (1) 2020.04.09
C++ 멤버함수의 메모리 위치  (0) 2020.04.09
C++ 임시객체(이동 생성자) 중요!  (0) 2020.02.07
C++ 대입 연산자  (0) 2020.02.02
C++ 깊은복사 얕은복사  (0) 2020.02.02
#include <iostream>
using namespace std;

int main()
{
    char a[] = "leeseungwoo";
    char* first = (char*)a;
    char* last = (char *)a + strlen(a) -1;

    while (first < last)
    {
        char temp = *first;
        *first = *last;
        *last = temp;
        
        first++;
        last--;
    }

    cout << a << endl;

}

 

'C' 카테고리의 다른 글

해쉬테이블 기초(간단)  (0) 2020.02.28
C언어 스택, 큐 자료구조 소스 코드  (0) 2020.02.26
C언어 빌드과정(컴파일)  (0) 2020.02.25
C언어 배열 삽입, 삭제  (2) 2020.01.03
C언어 void*  (0) 2019.12.20
해쉬 테이블

검색, 삽입, 삭제 모두가 다 O(1)인 엄청난 녀석이다.

삽입, 삭제가 O(1)이면 검색이라도 O(N)이 되어야 되는데 어떻게 모두가 다 O(1)일까?

검색이 O(1)이란 말은 인덱싱을 사용할 수 있다는 말이다.

 

C언어 포큐아카데미

가장 작은값 0부터 가장 큰 값 793까지의 배열을 만들고(총 794개) 값을 입력하면 1로 비어있으면 0으로 세팅한다.

이렇게 되면 입력할때 O(1)이 되고 검색할때도 인덱스를 사용할 수 있으니 O(1)이 된다. 이렇게 사용하지도 않은 메모리를 너무 많이 사용한다는 단점이 있다. 말그대로 무식 그자체다.

 

 

덜 무식하게

C언어 포큐아카데미

무식하게 모든 범위의 메모리를 잡아 두지말고 임의의 숫자에 메모리 인덱스를 매핑 시키면 좀 더 아름다워진다.

배열의 크기가 10이라고 가정하고 숫자에 메모리 인덱스를 매핑 시키는 방법은 간단하게 10으로 나눈후 나머지를 인덱스값으로 세팅하면 된다.

 

여기서 중요한 점은 중복이 발생한다는 점이다. 703이나 793이나 나머지는 3으로 똑같다. 이미 3번 인덱스에는 703이 들어가있는데 793의 값이 들어오면 덮어 쓸수도 없고 난감해진다. 중복을 제거해보자.(물론 불가능)

 

배열의 크기도 충분히 늘리고(2배) 나누는 값을 소수로 두면 중복을 최소화 할 수 있다. 하지만 중복을 막을 순 없다 중복이 하나라도 발생한다면 데이터의 신뢰성이 보장 될 수 없다. 어떻게 하면 좋을까?

 

 

중복 제거(불가능)

원칙은 나머지값의 인덱스에 값을 넣으면 되지만, 이미 그 인덱스에 값이 존재한다면(충돌) 가장 인접해 있는 빈 공간에 값을 넣으면 된다. 즉 색인을 1씩 증가 시키면서 빈 공간을 찾다가 비어 있으면 넣는다는 말이다. 물론 이때는 자신의 나머지 값을 인덱스로 같지 않는다.

 

일단 배열을 만들면 절대 사용하지 않을 값 INT_MIN으로 초기화 한 뒤 자신의 인덱스에 해당하는 배열에 값을 넣는다.

 

1. 793을 11인덱스에 넣는다

2. 724를 11인덱스에 넣으려고 한다. 하지만 793이 이미 있다

3. 인덱스를 1증가 시키면서 빈공간을 찾은뒤 가장 가까운 빈공간에 넣는다.(12 인덱스에 넣음)

4. 계속 반복

 

 

코드
#include <limits.h>

#define	BUCKET_SIZE (23)
int s_numbers[BUCKET_SIZE];

void init_hashtable(void)
{
	size_t i;

	for (i = 0; i < BUCKET_SIZE; i++)
	{
		s_numbers[i] = INT_MIN;
	}
}

int has_value(int value)
{
	int i;
	int start_index;

	start_index = value % BUCKET_SIZE;
	i = start_index;

	do
	{
		if (s_numbers[i] == value) {
			return true;
		}
		else if (s_numbers[i] == INT_MIN) {
			return false;
		}

		i = (i + 1) % BUCKET_SIZE;

	} while (i != start_index);

	return false;
}

int add(int value)
{
	int i;
	int start_index;

	start_index = value % BUCKET_SIZE;
	i = start_index;
	do
	{
		if (s_numbers[i] == value || s_numbers[i] == INT_MIN)
		{
			s_numbers[i] = value;
			return true;
		}
		i = (i + 1) % BUCKET_SIZE;
	} while (i != start_index);
	
	return false;
}

int main()
{
	init_hashtable();

	add(703);
	add(793);
	add(724);
	add(441);
	add(219);
	add(1);
	add(81);
	add(546);
	add(777);
	add(747);

	return 0;
}

'C' 카테고리의 다른 글

문자열 뒤집기(포인터 사용)  (0) 2020.03.12
C언어 스택, 큐 자료구조 소스 코드  (0) 2020.02.26
C언어 빌드과정(컴파일)  (0) 2020.02.25
C언어 배열 삽입, 삭제  (2) 2020.01.03
C언어 void*  (0) 2019.12.20
스택
#include <stdio.h>
#include <cassert>

enum { MAX_NUMS = 8};
int s_nums[MAX_NUMS];
size_t s_num_count = 0;

void push(int arr[], int n)
{
	//시간 복잡도 O(1)
	assert(s_num_count < MAX_NUMS);
	arr[s_num_count++] = n;
}

int is_empty(void)
{
	return s_num_count == 0;
}

int pop(void)
{
	//시간 복잡도 O(1)
	assert(is_empty() == false);
	return s_nums[--s_num_count];
}

int search(int n)
{
	//시간 복잡도 O(N)
	//제일 위부터 찾을 때까지 검색
	int result = -1;
	size_t temp_count = s_num_count;
	while (s_num_count > 0)
	{
		int value = pop();
		if (value == n) 
		{
			result = s_num_count;
		}
	}
	
	s_num_count = temp_count;
	return result;
}

int main()
{
	push(s_nums, 88);
	push(s_nums, 44);
	push(s_nums, 22);
	printf("%d\n", search(22));
	push(s_nums, 11);
	push(s_nums, 5);
	for (size_t i = 0; i < s_num_count; i++)
	{
		printf("%d\n", s_nums[i]);
	}
	printf("%d\n", search(5));

	return 0;
}

push와 pop으로 이루어진 스택 자료구조. 간단하다 

주의할점은 search할때 pop으로 망가진 배열을 다시 원상 복구 해줘야한다는점..

 

 

#include <stdio.h>
#include <cassert>

enum { MAX_NUMS = 8};
int s_nums[MAX_NUMS];
size_t s_front = 0;
size_t s_back = 0;
size_t s_num_count = 0;


int is_empty(void)
{
	return s_num_count == 0;
}

void enqueue(int n)
{
	assert(s_num_count < MAX_NUMS);

	s_nums[s_back] = n;

	s_back = (s_back + 1) % MAX_NUMS;

	++s_num_count;
}

int dequeue(void)
{
	int ret;

	assert(is_empty() == false);

	ret = s_nums[s_front];

	--s_num_count;
	s_front = (s_front + 1) % MAX_NUMS;

	return ret;
}


int search(int n)
{
	//시간 복잡도 O(N)
	int result = -1;
	for (size_t temp = s_front; temp < s_back; temp++)
	{
		if (s_nums[temp] == n)
		{
			result = temp - s_front;
		}
	}
	return result;
}

int main()
{
	enqueue(10);
	enqueue(20);
	enqueue(30);
	enqueue(40);
	enqueue(50);

	dequeue();
	dequeue();
	printf("%d\n", search(30));
	return 0;
}

'C' 카테고리의 다른 글

문자열 뒤집기(포인터 사용)  (0) 2020.03.12
해쉬테이블 기초(간단)  (0) 2020.02.28
C언어 빌드과정(컴파일)  (0) 2020.02.25
C언어 배열 삽입, 삭제  (2) 2020.01.03
C언어 void*  (0) 2019.12.20
기본사항

포큐아카데미 C언어

 

포큐아카데미 C언어

 

전처리기

입력값: 내가 작성한 소스코드

출력값: 트랜스레이션 유닛

설명: 전처리기는 주석을 제거하고,  include header 파일을 복붙한다.

예를들면 #include "adder.h" 라는 코드가 있으면 adder.h로 가서  int add(int a, intb);와 같은 선언을 복사 붙이기 해준다.  include <stdio.h> 하면 약 2천5백줄의 선언들을 복붙해줌.

 

 

 

컴파일러

입력값: 트랜스레이션 유닛

출력값: 어셈블리 코드

설명: 트랜스레이션 유닛 소스코드를 어셈블리어로 바꿔준다.(아직은 기계어가 아님) 여기서 핵심은 구멍이다. 똥구멍....

포큐아카데미 C언어

핵심은 일단 헤더(선언)만 보고 컴파일한다. 원형(내용)은 신경쓰지 않는다.

임의의 함수를 CALL하면(main에서 add 함수 호출) 링커가 그 구멍을 메워줄테니 일단은 컴파일하자!

 

 

어셈블러

입력값: 어셈블리 코드

출력값: 오브젝트 코드 : 기계어, 바이너리코드, 이진코드

설명: 어셈블러와 마찬가지로 구멍이 있음

 

포큐아카데미 C언어

 

 

링크

입력값: 모든 오브젝트 코드

출력값: 실행파일(.exe 파일)

설명: 모든 오브젝트 코드를 모아다 구멍을 메꾼 뒤 실행파일로 저장

좀 더 자세히(서술): 링커가 오브젝트 파일을 다 모아서 하나의 이진(binary)파일로 만들고 있었다. 그러다가 main 함수에서 add를 호출하는 것을 보았다. 현재 main함수에 add call은 선언만 있지 정의(내용)은 없다 즉 구멍이 뚫려있다. 이것을 본 링커는 똥구멍을 긁으며 "내가 오브젝트 파일을 다 검토하고 있는데 add 함수의 정의(내용)는 XX주소에 있는걸 확인했어 그러니 그 구멍에 XX주소로 점프하는 코드를 넣어줄게!

 

왜 링킹하냐?

 

'C' 카테고리의 다른 글

해쉬테이블 기초(간단)  (0) 2020.02.28
C언어 스택, 큐 자료구조 소스 코드  (0) 2020.02.26
C언어 배열 삽입, 삭제  (2) 2020.01.03
C언어 void*  (0) 2019.12.20
C 언어 변수에 함수 할당  (0) 2019.12.20

+ Recent posts