숫자 3자리 단위로 컴마(',') 찍기

일반적인 숫자를 알아보기 쉽도록 3자리 단위로 컴마를 찍어주는 소스...
예전에 프로그램 짜다가 필요해서 직접 구현해보려다가 구찮아서 어디선가 퍼온 소스 ㅡㅡ
소스는 기본적으로 아래와 같다....매개변수, 리턴값 등 적절히 수정해서 사용하면 될듯....

CString CCommaDlg::Comma(double nData) 
{ 
	CString str, strReturn=_T(""); 
	str.Format("%.0f", nData); 
	
	for(int i=0; i<str.GetLength(); i++) 
	{
		strReturn += str.GetAt(i); 
		if( (str.GetLength() - i) != 1 && (str.GetLength() - i) % 3 == 1)
			strReturn += ','; 
	} 
	return strReturn; 
}


(사용언어 및 제작툴 : MFC / VC++ 6.0)
Posted by Gungume
,



예제 프로그램
실제 드라이브 목록

현재 시스템의 드라이브 정보를 얻기 위해서 GetLogicalDrives()라는 함수를 사용한다...
이 함수를 사용하면 DWORD형으로 값을 리턴해주는데 각각의 비트마다 해당 드라이브의 존재유무를 2진수로 알려준다.

기본적으로 아래와 같이 초기화를 해준다.
int m_nDrivePos = 0;
CString m_strDrive = "?:\\";
DWORD dwDriveList = ::GetLogicalDrives();

각각의 변수의 의미는 m_nDrivePos는 "a, c, d, e" 등 드라이브의 실제 이름을 정해줄때 아스키값 이용해서 사용할 변수이다...
m_strDrive는 "a:\", "c:\"와 같이 드라이브명을 지어주기 위해 사용한다...
위의 두 변수는 GetLogicalDrives() 함수는 현 시스템의 드라이브 정보를 2진수로만 알려주기 때문에 이것을 적절히 변경하여 알아보기 쉽게 바꾸기 위해서 사용한다.
마지막으로 dwDriveList는 GetLogicalDrives() 함수를 이용 실제로 드라이브 정보를 얻어오는 부분이다...2진수가 들어간다.

이렇게 얻어온 정보를 아래의 소스를 이용해서 실제적인 현 시스템의 드라이브명을 얻을수 있다
while(dwDriveList)
{
    // DWORD형으로 넘어온 값 하나씩 '&' 연산으로 드라이브 존재 유무 판단
    if(dwDriveList & 1)  
    {
         // "C:\"과 같이 드라이브를 표시하는 문자열로 만듦
         // ‘A' 값 기준으로 아스키코드 값 이용
         m_strDrive.SetAt(0,'A'+m_nDrivePos);
    }

    // 우로 1비트 이동(= 다음 드라이브 체크)
    dwDriveList >>= 1;
    m_nDrivePos++;
}

위의 소스를 설명하기 전에 dwDriveList의 값이 어떻게 설정되어 있는지 알아보면 다음과 같다.
예를 들어 현재 시스템에 드라이브가  "A, C, D, E" 가 존재한다고 하면 dwDriveList의 값은 11101이 된다.
이것을 좀더 분석해보면 저 수치를 오른쪽부터 읽어들이면 된다...
즉 오른쪽부터 "A, B, C, D, E" 드라이브의 존재 유무를 표시해준다...
값은 0이면 드라이브가 없음을...1이면 드라이브가 존재함을 의미한다...
즉 가장 오른쪽 값은 A드라이브의 존재유무를 알려주는데 값이 1로 설정되있으므로 현 시스템에는 A 드라이브가 있음을 알려준다.

이제 다시 소스 부분으로 돌아가서 분석하면...
일단 while 문에 dwDriveList를 넣었다....dwDriveList 를 계속 비트연산하다보면 결국에는 0이 된다...즉 루프탈출 조건은 모든 드라이브 목록을 구하면이다...

그 다음에 if 문을 보면 값 1을 가지고 "&연산"을 한다...
1로 "&연산"을 하면 피연산자가 1이면 1을 리턴하고 0이면 0을 리턴한다...
즉 if문의 조건이 참이라면 해당되는 곳은 드라이브가 존재한다는 뜻이다...
일단 1로 계산을 했으므로 앞에는 모두 0으로 계산하므로 가장 뒷자리만 계산을 한다...

위의 "11101"을 가지고 예를 들면....첫 반복문에서는 "11101 & 00001 = 1"이라는 결과가 나오므로 현 시스템에서 A드라이브가 존재함을 알수 있다.
그 다음에는 단순히 'A' 문자부터 시작하는 아스키 값을 이용해서 "A:\" -> 이런 형식으로 문자열을 바꿔준다...

이렇게하면 하나의 드라이브 목록을 구하는데 다음 드라이브 목록을 구하기 위해서 비트를 한단계 이동 시킨다...
그러면 11101 이라는 값이 1110으로 변경되므로 다음에는 1110이랑 1이랑 & 연산을 시켜서 드라이브 유무를 판단한다...

이런식으로 현 시스템의 모든 드라이브 목록을 얻고 원하는 형식으로 드라이브명을 변경시켜줘서 사용할 수 있다.

(사용언어 및 제작툴 : MFC / VS2003)

Posted by Gungume
,

기본적으로 많이 쓰이는 euckr의 문자셋을 UTF-8로 변경하는 방법...

요즘에 태터툴즈나 ZB5등이 유니코드 DB를 요구하고, 대세가 유니코드인것 같기에 아래의 방법을 이용해서 기본 문자셋을 변경...

vi 에디터 등을 이용해서 "/etc/my.cnf" 파일(MySQL 설정파일) 편집...

아래와 같이 각각의 항목을 찾아가서 임의위 위치에 "default-character-set=utf8" 를 입력...
[client]
default-character-set=utf8
[mysqld]
default-character-set=utf8
[mysqldump]
default-character-set=utf8

"/etc/my.cnf" 파일을 수정한 후 저장후에 mysql에 접속해서 "show variables like 'c%';"를 입력해서 아래와 같이 나온다면 변경 성공...
(이 작업은 기존에 생성된 euckr 기반의 DB가 유니코드 기반의 DB로 변경되는 작업은 아님...)

character_set_client : utf8
character_set_connection : utf8
character_set_database : utf8
character_set_results : utf8
character_set_server : utf8
character_set_system : utf8
character_sets_dir : /usr/share/mysql/charsets/
collation_connection : utf8_general_ci
collation_database : utf8_general_ci
collation_server : utf8_general_ci

Posted by Gungume
,




삭제할 번호 선택하는 로또 프로그램


친구들과 임의의 로또 번호를 먼저 뽑아서 그 번호는 제끼고 로또를 할때 편하게 하려고 만든 프로그램...

특별한 로직 없이 그냥 rand() 함수 이용함...

(사용언어 및 제작툴 : MFC / VC++ 6.0)

Posted by Gungume
,




다이얼로그 등에서 WM_KEYDOWN 처리

MFC 프로젝트 생성시 다이얼로그기반이나...기본 뷰클래스를 폼뷰로 설정하면 WM_KEYDOWN 메시지 핸들러를 오버라이딩해도 메시지 처리가 안된다...(나머지 경우는 모름;;;)

이유는....잘모름 ㅡㅡ;   처음 MFC 배울때 다이얼로그 기반에서 WM_KEYDOWN 메시지를 처리하려고 했는데 잘안되서 인터넷을 뒤져본 결과... PreTranslateMessage() 함수를 오버라이딩 해서 그곳에서 처리해야 한다는 것을 알게되었다....

다이얼로그나 폼뷰 기반에서 바로 KeyDown 메시지가 처리 안되는 이유는 정확하지는 않지만 컨트롤쪽으로 바로 메시지가 가서 그런것 같다...

어쨌든 위에서 말했듯이 위와 같은 상황에서는 PreTranslateMessage() 함수를 오버라이딩 한 후에 아래와 같은 식으로 처리하면 된다...

if(pMsg->wParam == VK_RETURN)
    AfxMessageBox("엔터키를 눌렀습니다.");

위와 같은 식으로 PreTranslateMessage() 함수의 매개변수를 이용해서 가상키코드를 직접 비교해서 사용하는 방법이 있고....

아래의 소스와 같이 WM_KEYDOWN 메시지를 일단 잡은 후에 사용자 정의 함수를 통해서 나머지 메시지를 처리하는 방법도 있다...

if(pMsg->message == WM_KEYDOWN)
{
    KeyDown(*pMsg);
}

// 가상키코드 처리할 사용자 정의 함수
void CPnameDlg::KeyDown(MSG pMsg)
{
    switch(pMsg.wParam)
  {
         case VK_LEFT :
                  AfxMessageBox("왼쪽 방향키를 눌렀습니다.");
                  break;
         case VK_RIGHT :
                  AfxMessageBox("오른쪽 방향키를 눌렀습니다.");
                  break;
    }
}

위에서 처리 내용을 보면 알겠지만 PreTranslateMessage() 함수는 함수명 그대로 어떤 메시지를 도중에 가로채서 처리하고자 할때 쓰일수 있는 함수이다...

데모프로그램을 보면 다이얼로그 기반에서는 ESC키나 Enter키를 누르면 다이얼로그가 닫혀버리는데(=프로그램 종료) 이런 경우에 위의 예제를 좀만 수정하면 ESC키나 Enter키에 대한 메시지를 중간에 처리함으로서 프로그램이 바로 종료되는 문제 등을 처리할 수 있다.

또한 PreTranslateMessage() 함수는 단순히 키보드 메시지외에도 다른 메시지도 오므로 매개변수를 잘 이용해서 다양한 메시지 처리를 할수 있다.

(사용언어 및 제작툴 : MFC / VC++ 6.0)

Posted by Gungume
,
LinM

도스시절에 많이 썼던 MDIR을 리눅스용으로 만든 프로그램...

KLDP에서 만든 프로그램인데 상당히 괜찮다...

거의 모든 기능이 도스시절의 MDIR과 같으며 다른 기능도 꽤 좋다...

앞으로 리눅스상에서 많이 이용하게 될것 같음...

출처 : http://kldp.net/projects/mls/
Posted by Gungume
,

MFC 폴더 다이얼로그

MFC/TIP 2006. 6. 30. 19:31


MFC 폴더 다이얼로그 프로그램
MFC 폴더 다이얼로그


데브피아에서 가져온 MFC 상에서 "SHBrowseForFolder" 클래스를 쉽게 사용하게 해주는 클래스...

실제 사용은 데모프로그램내의 "Shell.h" 파일 하나만을 사용함...

출처 : 데브피아 -> [Tip] SHBrowseForFolder 래퍼 클래스..
Posted by Gungume
,



키보드에는 방향키가 있습니다.(→←↑↓) 이것을 코드값을 이용해서 입력 받는 방법을 알아보겠습니다.

방향키의 코드값이 아스키코드에 있다면 getch()함수를 이용해서 쉽게 해결할 수 있겠지만, 아스키값에는 방향키가 없습니다. 그래서 다른 것을을 이용해서 방향키의 코드값을 입력 받아야합니다.

http://www.lookuptables.com/ ->"Scan Codes & EBCDIC" -> "IBM Scan Codes"를 이용합니다...

그곳에서 보면 10진수 값만을 따졌을 경우에 아래와 같이 각각의 코드값이 나옵니다.

UP = (00, 72), LEFT = (00, 75), RIGHT = (00, 77), DOWN = (00, 80)

즉, 방향키는 2개의 값을 가지고 있습니다. 예를 들어 다시 설명하면 "UP" 방향키를 눌렀을때 발생하는 코드값은 처음에 00을 리턴하고 그 다음에는 72를 리턴합니다.

리턴값이 2개이니까 간단히 설명하면 두번 입력을 받아주면 됩니다.

하나의 예를 들어보자면 char형으로 ch라는 변수를 선언한 후에 "ch=getch();"라는 명령어가 있다면 커서가 깜박일때 "A"를 눌렀다면 엔터를 칠 필요도 없이 "A"의 값이 ch변수에 들어갑니다.

그럼 원래의 목적인 방향키로 가봅니다. 위에서 말씀드렸듯이 방향키는 값을 2개 리턴하므로 getch()함수를 두번 쓰면 됩니다.

int형으로 cursor이라는 변수를 선언했다고 가정후에 아래와 같이 사용하면 cursor의 최종값은 방향키의 2번째 리턴값이 들어갑니다. 예를 들어 "UP" 방향키를 눌렀다면 cursor의 최종값은 72가 되겠죠...

int cursor=getch();
if (cursor==0 || cursor==0x00)
    cursor=getch();

프로그램이 실행되다가 소스의 첫번째 줄을 만나면 사용자에게 뭔가를 입력하라고 커서가 깜박이겠죠...

이때 방향키가 아닌 그냥 알파벳이나 숫자를 넣으면 해당되는 아스키값이 들어가겠죠...

그러나 방향키를 입력하면 리턴값이 2개니까 첫번째 줄을 실행하면서 첫번째 리턴값인 "00"을 cursor 변수에 넣습니다. 그리고 if문을 실행하면서 cursor값이 0인지를 검사합니다.

"00==0" 즉, 조건이 참이되므로 세번째 줄에 있는 getch()함수를 실행하겠죠...

세번째 줄에 있는 getch()문은 따로 입력 받는 것이 아니고 첫번째 줄에서 입력했던 방향키 값중에 두번째 리턴값을 자동으로 넘겨받게됩니다...

그래서 최종값이 "UP"키를 눌렀다는 가정하에 72가 되는것입니다....

이렇게 입력을 받았다면 이후에는 각각의 경우에 할일을 만들어 주면 되겠죠...

그리고 조건문중에 0x00부분도 있는데 이것은 0의 16진수입니다...저런식으로 같이 써주면 좋겠죠...

또한 저는 vc++7.0이라서 그냥 저렇게 했을때 작동을 했는데...어떤 사람은 vc++에서 "00"이 리턴이 안되고 "?"가 리턴이 된다는 사람도 있더군요....이 경우에는 조건문에 ?를 추가로 입력하면 됩니다.

첨부 파일은 위의 내용을 적용한 예제 프로그램입니다.

프로그램을 실행후에 방향키를 움직이면 방향키를 누른데로 *표가 움직입니다.

P.S *표의 위치를 표시하기 위해 터보C에서 쓰이는 gotoxy() 함수사용...vc++등의 개발툴에는 없는 함수이므로 www.winapi.co.kr에서 헤더파일 구해서 사용함...

Posted by Gungume
,

요일 구하기...

기타 TIP 2006. 5. 4. 18:04

일단 현재의 달력은 거의 모든 나라에서 사용하는 "그레고리력"입니다. 또한, 그레고리력에서 1년 1월 1일은 월요일이라고 하는 군요...

그리고 요일을 구하는 방법은 1년 1월 1일부터 원하는 날짜까지의 모든 일수를 더하고 나서 그 값을 7로 나눴을때의 나머지로 계산을 합니다.

7로 나눴을때 나머지가 0이면 일요일, 1이면 월요일, ...., 6이면 토요일입니다.

그럼 이제부터 모든 일수를 더하는 방법을 알려드리겠습니다...

2005년 5월 12일을 예로 들어서 알려드리겠습니다.

일단 주의할 점이 2005년 5월 12일은 2005년이 지나고 5개월이 지나고 12일이 지난것이라고 생각될 수도 있는데 이것은 잘못된 생각입니다....

2005년이 지나고 5개월이 지나고 12일이 지난 날짜는 2006년 6월 12일이겠죠...

다시 말하면 2004년이 지나고 4개월이 지나고 12일이 지난 날짜가 2005년 5월 12일이죠....

다음으로 넘어가서 일단 연도의 모든 일수를 구하는 방법을 알려드리겠습니다...

단순히 생각하면 위의 예를 기준으로 2004년이 지나간것이고 1년은 365일이니까 (2004년*365일)이 모든 일수겠죠....그러나 여기에서 윤년을 따져줘야 합니다....

(2004년*365일) 중에서 윤년인 경우는 2월이 하루가 더 많으니 윤년인 경우를 계산해서 그 일수를 더해주면 되겠죠...(윤년 계산방법은 아래 글에 있습니다...)

그럼 일단 1년 1월 1일부터 2004년 12월 31일까지의 모든 일수는 구해졌습니다....

이제 월을 구해보겠습니다....

위에서 말씀드렸듯이 5월달이라는 것은 4개월이 지났다는 뜻이니까 1~4월의 모든 일수를 더하면 되겠죠...(=31+28+31+30)

이 경우에도 역시 윤년이라면 +1을 해줘야겠죠....

월까지 구했다면 위에서 구한 연도의 모든 일수랑 월의 모든 일수를 더한후에 마지막으로 일수(12일)를 더합니다.(일수는 그냥 더하면 됩니다...)
그럼 원하는 날짜까지의 모든 일수가 구해집니다....

그 다음에는 7로 나누고 나머지를 구해서 요일을 따져주면 되겠죠....

아래에 수치적으로 계산을 한번 해보겠습니다.

예 : 2005년 5월 12일

연도 = (2004년*365일) + (2004/4) - (2004/100) + (2004/400)
       = 731460+ 501- 20.04 + 5.01
       = 731460+ 501- 20+5(소수부분 버림)
      = 731946일

월 = 1월~4월 = 31+28+31+30 = 120일
일 = 12일
총 일수 = 732078일
결과 : 732078 % 7 = 4 => 목요일

연도 구하는 부분에서 [+ (2004/4) - (2004/100) + (2004/400)] 이부분은 윤년을 계산후 처리하는 부분입니다.

아래 글 보시면 윤년에 대해서 아시겠지만 간략히 설명하면 (연도*365)일 해서 나온 총 일수에다가 일단 모든 윤년(=2004/4)을 더합니다.

그 다음에 (연도/100 = 2004/100)은 윤년이 아니기에 빼버려주고요....마지막으로 (연도/400 = 2004/400)는 또 다시 윤년이므로 더해줍니다...

이렇게 함으로써 특정날짜의 요일을 구할 수 있습니다....

Posted by Gungume
,

윤년 구하기...

기타 TIP 2006. 5. 4. 17:56
// 윤년 구하는 간단한 프로그램 소스   
#include<iostream>   
using namespace std;   
  
void main()   
{   
   int year;   
   cout << "년도를 입력하세요 : ";   
   cin >> year;   
  
   if((year%4==0 && year%100!=0) || year%400==0)   
          cout << "윤년\n";   
   else    
          cout << "평년\n";   
}  

- 윤년 구하는 방법 -
특정연도를 4로 나누었을때 나누어 떨어지면 그 해는 일단, 윤년.

그러나 100으로 나누었을때 나누어 떨어진다면 4로 나누어 떨어진다고 해도 그 해는 평년.

그리고 마지막으로 400으로 나누어 떨어진다면 100으로 나누어 떨어진다고 해도 윤년.
Posted by Gungume
,