midas+son의 크리에이티브(creative) 이야기

#include <iostream>

using namespace std;
/*
Fibonacci(피보나치 수열) 만들기
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ....

처음에 0, 1 로 시작 할 수도 있고 1, 1 로 시작 할 수도 있다.
문제에 따라서 첫 수가 다를 수도 있다.
처음 수와 두번째 수를 더한 것이 그 다음수이고
두번째 수과 그 다음수를 더한것이 그 다다음수,
이처럼 처음과 두번째를 제외하고 
이전 수와 그 이전 수를 더한 값이 본인 값인 수열이 피보나치 수열이라고 한다.
*/
int Fibonacci(int n)
{
if (n == 1) return 0;
else if (n == 2) return 1;
else if (n > 0)
{
int first = 0;
int second = 1;
int temp = 0;
int count = n - 2;
for (int i = 0; i < count; i++)
{
temp = first;
first = second;
second += temp;
}
return second;
}
else
{
return -1;
}
}

void main()
{
cout << Fibonacci(10) << endl;
getchar();
}


출처 : 내 머리, 내 손

'공부 > c++(c, STL)' 카테고리의 다른 글

Swap (베타적 OR - XOR 사용)  (0) 2016.06.24
[코딩문제]계단 오르기 - 3 계단  (0) 2016.06.23
[코딩문제]셀프 넘버(self-number) 풀이  (0) 2016.06.18
[코딩문제]문자열 거꾸로 출력  (0) 2016.06.16
C++11 람다 식  (0) 2016.06.10

#pragma once
#include <iostream>

using namespace std;
/*
****문제****
어떤 자연수 n이 있을 때, d(n)을 n의 각 자릿수 숫자들과 n 자신을 더한 숫자라고 정의하자.

예를 들어

d(91) = 9 + 1 + 91 = 101

이 때, n을 d(n)의 제네레이터(generator)라고 한다. 
위의 예에서 91은 101의 제네레이터이다.

어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 
101의 제네레이터는 91 뿐 아니라 100도 있다. 
그런데 반대로, 제네레이터가 없는 숫자들도 있으며, 
이런 숫자를 인도의 수학자 카프이카가 셀프 넘버(self-number)라 이름 붙였다. 
예를 들어 1,3,5,7,9,20,31 은 셀프 넘버 들이다.  

1 이상이고 5000 보다 작은 모든 셀프 넘버들의 합을 구하라.

*/
//제네레이터 구하는 함수
int GeneratorCheck(int n)
{
int num = n; //첫 수
int generator = 0; //결과 제네레이터

int temp = num;    //나누고 나머지 계산할 임시변수
while (true)
{
generator += temp % 10;    //나머지는 더해주자. (1의 자리)

if (temp / 10 == 0)    //몫이 0이면 더이상 계산 할게 없는 것
{
break;
}
else
{
temp = temp / 10;    //몫이 남아 있다면 다시 나머지를 구하기 위해 몫부분만 넣어준다.
}
}
generator += num;    //마지막으로 처음 들어온 수도 더해준다.
return generator;    //제네레이터 값 리턴
}

//메인함수
void main()
{
const int maxNum = 5000 - 1; //5000미만이니 1 ~ 4999 만 체크 해도 되겠지?
//체크할 숫자 배열 변수
int* numArr = new int[maxNum];

//체크할 숫자 배열 초기화
for (int i = 0; i < maxNum; ++i)
{
numArr[i] = i + 1; //모든int배열에 값 추가
}

//제네레이터 체크
for (int i = 0; i < maxNum; ++i)
{
int g = GeneratorCheck(i + 1);
if (g < maxNum)
{
numArr[g - 1] = 0; //제네레이터 값은 0으로 값 변환
}
}

//합계산
int sum = 0;
//셀프 넘버(제네레이터가 아닌 값) 체크
for (int i = 0; i < maxNum; ++i)
{
//셀프 넘버 표시용 - 셀프넘버가 뭔지 알고 싶으면 주석 풀어요
//if (numArr[i] != 0)
//{
// cout << numArr[i] << ", ";
// sum += numArr[i]; //셀프 넘버 합
//}
//단순 합 - 0은 더해봤자 0
sum += numArr[i]; //셀프 넘버 합
}
cout << endl << "결과 합 : " << sum << endl; //결과 출력

getchar();
}

//합만 구하는게 목적일 경우 int배열이 아니라 bool배열로 false, true체크해서 for문의 int i값만 더하는게 더 가볍다.


코딩 출처 : 내 머리, 내 손

#include <iostream>


using namespace std;


void CopyStr(char* dst, int descSize, const char* src)

{

const char* tempSrc = src; //주소 복사

while (*tempSrc != '\0')         //널문자가 나올 때까지 루프

{

tempSrc++;     //주소 위치 증가

}

int size = tempSrc - src;   //루프된 주소와 원본 주소 위치를 빼주면 사이즈가 나옴


//dst 메모리 초기화

char* tempDst = dst;   //주소 복사

for (int i = 0; i < descSize; i++)        //배열 사이즈 만큼 루프

{

*tempDst++ = '\0';              //널문자로 초기화하며서 주소 증가

}


for (int i = 0; i < size; i++, dst++)   //위에서 구한 원본 사이즈 만큼 루프, 복사할 주소인 dst도 증가

{

*dst = *(--tempSrc);             //tempSrc는 처음에 '\0'이 들어 있으므로 먼저 빼주면서 진행. 내부 값을 복사

}

}


int main()

{

char src[] = "hello world";      //원본문자

char dst[512];                     //복사할 공간

CopyStr(dst, sizeof(dst), src);  // 복사 함수

        //출력

cout << dst << endl;    

getchar();

}


입력 : hello world

출력 : dlrow olleh



출처 : 내 머리, 내 손

https://msdn.microsoft.com/ko-kr/library/dd293608.aspx

//c++11에서 추가된 람다 식 MSDN 참조


C#에서도 썼던 기법인데....

뭔가 설명이 더 엄청 어렵다.


C++11 전에는 없었다.


C++11 부터 생겼는데

C++14 에서 뭔가 더 추가 되었다.


아직 c++ 에서 정식으로 사용하기엔 

사용법에 대한 설명이 난해한것 같다.


//TODO - 더 알아보고 내용을 추가하자

지난번 UI를 만들 때

벡터에 있는 객체들을

순차적으로 그려줄때

맨 마지막 벡터 객체가 맨 위로 올라오게 됩니다.


업데이트 순서는 그러면 역순으로 처리해야 

창이 겹칠때의 처리 영역이 올바르게 동작하는데

일반 iterator로는 역순으로 검색도 못하고 

erase 할 때에도 문제가 있더라고요.


그래서 구글링으로 찾아본 결과

reverse_iterator 라는 존재를 알게 되었습니다.


오늘은 이 reverse_iterator 에 대한 정리입니다.


헤더에 아래외 같이 벡터와 이터레이터 

역순 검색을 위한 reverse_iterator 를 설정했습니다.

비교를 위해 일반 iterator 도 주석으로 보여놨습니다.


vector<userInterface*> _vUI;

//vector<userInterface*>::iterator _viUI;

vector<userInterface*>::reverse_iterator _vriUI;



실제 cpp코드에서 사용할 때에는 아래와 같았습니다.


//역순 검색 -> reverse_iterator 사용

if (!_vUI.empty()) //비어있지 않다면

{

for (_vriUI = _vUI.rbegin(); _vriUI != _vUI.rend();) //반복문 에 rbegin(), rend()은 reverse용 begin(), end()라고 생각하심 됩니다.

{

//보여지는 상태이냐?

if ((*_vriUI)->isShow())

{

//그러면 업데이트

(*_vriUI)->update();

++_vriUI;

}

else

{

//삭제

(*_vriUI)->release();

_vriUI = vector<userInterface*>::reverse_iterator(_vUI.erase(_vriUI.base() - 1)); 

//reverse_iterator 형으로 바꾸어 주어야 합니다. 지우는 위치는 _vriUI.base() - 1

}

}

}


erase부분이 남달랐습니다만 

잘 동작하고 있습니다.


벡터를 역순으로 탐색 하고자 하는 분들은 참고하시면 되시겠습니다.

그럼 오늘은 구정 전날이므로

새해복 많이 받으십시오.

콘솔로 프로그래밍 건드리는 중에

데코(?)라고해서 글자들 쓰기 위한 커서의 위치를 조정하는 함수나

색상을 주는 함수를 자주 사용하는데 

매번 새로운 프로젝트 생성 시 마다

계속 복사 붙여넣기를 하다보니

좀 번거로운 감이 없지 않아 있었다.


그래서 공통 해더로 만들어서 

#include하여 쓰자!! 라고 생각했는데

애매한 에러 때문에 1시간 30분 넘게 시간을 잡아 먹어 버렸다.


그 유의사항을 공유하도록 하겠다.


class가 하니라 header에 함수를 넣어 놓고 사용을 할 것이므로

아래와 같이 지정을 했었다.


다른 헤더에서 참조하여 써도 

그 당시에는 에러가 발생 하지 않는다.

잘 참조 한다는 것이다.


하지만 빌드를 하면 아래와 같은 에러를 보게 될 것이다.


LNK2005 에러...

구글링 해보니까 별에별 설명이 다 되어있는데

납득이 안되는 얘기들이 좀 많았다.

Visual Studio 어디 가서 설정해라... MFC어쩌구 CRT어쩌구... 


그래서 더 찾아 보았다.

msdn 정식 사이트에서 원하는 답을 찾을 수 있었다.

https://msdn.microsoft.com/ko-kr/library/72zdcz6f(v=vs.80).aspx 

(위에 주소 링크)


뭐 다 떠나서 해결은 "static 변수를 선언합니다." 만 봤다.

void 앞에 static만 추가 시켰다.


잘된다 (눈물의 1시간 반)

그냥 메모리에 공간좀 차지 한다고 해도 쓰자.

시간은 오래 걸렸지만 쉽게 해결 됐다.


만든 header파일은 아래 처럼 include해야지 header안에 만들어놓은 함수 사용에 지장이 없다.

참고로 #include 다음에 <>로 되어있는 것은 

시스템에 이미 만들어져 있는(내장되어 있는) 헤더이고 

""로 되어있는 것은 내가 만들어서 추가한 헤더이다.

그러므로 common.h라는 이름의 헤더를 내가 만들어 썼다는 얘기이다.


//=======================================================================================

추가 2015. 10.12

위의 방법보다 더 효율적인 방법을 알게 되어 추가 한다.

위와 같이 inline을 사용하는 것이다.


inline으로 만든 함수는 호출하게 되면

실행시 호출하는 그 자리에 

함수가 통째로 복사가 되어 돌아가게 된다고 한다.


복잡하고 무거운 함수로 하면

자원 소모가 크겠지만

간단한 함수를 자주 사용하게 된다고 하면

inline이 효율이 좋은 것 같다.


당연한 얘기지만 

다른 class에서 사용하려고 하면

저 함수를 제작한 헤더를 

#include해주어야 한다.

C++의 class에서 다른 class를 사용하는 변수를 지정할 때

보통 포인터 변수로 지정하는데 

포인터 변수로 선언했을 떄와 그냥 class 명으로만 선언했을 때 차이가 있다.


class명 만으로 변수를 만들게 되면 

해당 변수에 그 객체의 전체

모든게 들어 있다고 생각하면 된다.

그래서 만들자마자 생성자가 실행이 되어버린다.


class명 뒤에 *을 붙여서 변수를 만들면

해당 class에 대한 주소만을 변수에 담을 수 있다고 생각하자.

일단 더미 값이 들어가 있을 텐데

이 변수에 'new class명' 하게 되면

이것이 바로 동적 할당이다.

damagochi라는 class가 있고

헤더에 damagochi.h를 include하여

'damagochi* dam;' 라고 변수 선언 해주고

생성자에서 'dam = new damagochi;' 라 해주면

이때 damagochi 클래스의 생성자가 실행이 된다.

포인터 변수로의 접근은 'dam->함수나 변수'로 가능해진다.

(일반 변수라면 'dam.함수나 변수')


생성자, 소멸자 실행 차이를 확인해보자.

main이 되는 class에서 참조할 class의 이름 헤더와

이름의 변수를 그냥 참조 했을 시 어떻게 되는지 같이 확인하겠다.


mainGame이라는 class에서 damagochi라는 class를 가져다 쓰고자 한다.


차이를 파악하기 위해

mainGame과 damagochi의 생성자, 소멸자에 cout으로 표시를 해두었다.


포인터 변수 없이 class 사용법은 아래와 같다.



damagochi 클래스를 받아오는데 포인터 없이 선언하였다.

위와 같이 선언된 것들은 보통 사용할 때에는 dam. 처럼 

변수명 뒤에 점을 붙이면 damagochi class에 public 으로 

선언해둔 함수 리스트 들이 보인다.


하지만 실행했을 때 차이를 확인해볼 수 있다.



main이 되는 class는 mainGame인데

damagochi class가 먼저 생성되고 소멸자도 mainGame보다 늦게 된다.

이는 나중에 문제가 될 여지가 있을 수 있다고 생각되어진다.

(가능성의 얘기지 실제 문제가 된 것을 본것은 아니다. 

공부 중이므로 잘못된것은 알려주길 바란다.)


그럼 포인터로 하면 어떻게 될까?

아래처럼 class명 뒤에 *를 붙여 보았다.



결과는 

damagochi class에 대한 생성자와 소멸자가 나타나지 않는다.


new 로 동적 할당 하지 않는 이상 damagochi의 생성자가 나오지 않고

delete dam;을 하지 않으면 소멸자가 나타나지 않는다.


동적할당 하지 않아도

dam 변수명에 -> 로 접근하면 

damagochi class의 함수들이 나타나기는하지만

보통 초기화가 되지 않은 변수를 참조하게 되므로

안전하게 동적할당을 해주고 

생성자에서 변수들을 초기화 하거나

별도의 init()함수를 만들어서 init()을 먼저 호출한 뒤

사용해주기로 하자.


-------------------------------------

이 글은 정리 겸 차이를 적어 기억하고자 하는 글입니다.

틀린부분이 있으면 알려주시기 바랍니다. 

근거와 출처가 존재하는 가르침은 환영합니다. 감사합니다.