win32/코드팁

windows 프로그램, 특히 Visual C++에 관련된 유용한 코드 팁을 담는 곳.

내용

  1. Link: Knowledge Base
  2. 다이알로그에 스킨 입히기
  3. 투명 윈도우 만들기
  4. 내 IP 얻는 방법
  5. 트레이 아이콘
  6. 패스 분리하는 방법
  7. FTP 관련
  8. Downloaded Program Files 폴더의 OCX 삭제방법
  9. 디버깅 용도의 실행시간 출력 코드
  10. Trace Tip
  11. 모니터 끄기
  12. 프로세스간 데이터 교환
  13. Log 함수
  14. Ctrl+Esc, Alt+Tab, and Alt+Esc를 막는 법
  15. About box에 URL 링크 걸기
  16. 특정 파일 오픈시 바로 프로그램 불러오기
  17. 드래그 앤 드롭으로 파일 오픈
  18. app가 트레이에만 띄우도록 하려면
  19. single thread 어플리케이션에 취소 버튼 구현
  20. PC시간 셋팅하기

1 Link: Knowledge Base

[WWW]Knowledge base : MFC 및 Visual C++ 프로그래밍에 대한 방대한 tip과 know-how를 담고 있다.

2 다이알로그에 스킨 입히기

void CDlgPictureDlg::OnPaint()  
{ 
    if (IsIconic()) 
    { 
        CPaintDC dc(this); // device context for painting 
 
        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 
 
        // Center icon in client rectangle 
        int cxIcon = GetSystemMetrics(SM_CXICON); 
        int cyIcon = GetSystemMetrics(SM_CYICON); 
        CRect rect; 
        GetClientRect(&rect); 
        int x = (rect.Width() - cxIcon + 1) / 2; 
        int y = (rect.Height() - cyIcon + 1) / 2; 
 
        // Draw the icon 
        dc.DrawIcon(x, y, m_hIcon); 
    } 
    else 
    {     
        CWindowDC dc(this); 
        CDC memDC; 
        memDC.CreateCompatibleDC(&dc); 
        CBitmap bitmap; 
        BITMAP bm; 
        bitmap.LoadBitmap(IDB_BITMAP1);      <<-- 비트맵 이미지를 만들어야한다. 
        bitmap.GetBitmap(&bm); 
        CBitmap* pOld = memDC.SelectObject(&bitmap); 
        dc.BitBlt(5, 30, bm.bmWidth, bm.bmHeight, &memDC, 0, 0, SRCCOPY); 
        dc.SelectObject(pOld); 
        memDC.DeleteDC(); 
        CDialog::OnPaint(); 
    } 
  
} 

3 투명 윈도우 만들기

BOOL CWin1Dlg::OnInitDialog() 
{ 
    CDialog::OnInitDialog(); 
  
    SLWA pSetLayeredWindowAttributes = NULL;     // 함수포인터 선언, 초기화. 
    HINSTANCE hmodUSER32 = LoadLibrary("USER32.DLL");  // 인스턴스 얻음. 
    pSetLayeredWindowAttributes=(SLWA)GetProcAddress(hmodUSER32,"SetLayeredWindowAttributes");   //함수포인터 얻음. 
    HWND hwnd = this->m_hWnd;                              //다이얼로그의 핸들 얻음. 
 
    SetWindowLong(hwnd, GWL_EXSTYLE,GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); 
    pSetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA); 
 
    return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
// 해당 다이알로그의 상단에 추가 
#define WS_EX_LAYERED           0x00080000 
#define LWA_COLORKEY            0x00000001 
#define LWA_ALPHA               0x00000002 
#define ULW_COLORKEY            0x00000001 
#define ULW_ALPHA               0x00000002 
#define ULW_OPAQUE              0x00000004 
  
typedef BOOL(WINAPI *SLWA)(HWND, COLORREF, BYTE, DWORD); 

4 내 IP 얻는 방법

CString GetMyIPAddress() 
{ 
    char        chName[255]; 
    CString        sAddress; 
    PHOSTENT    pHostEntry; 
    IN_ADDR        inAddr; 
 
    if( gethostname( chName, 255 ) != 0 ) return ""; 
    else 
    { 
        if( ( pHostEntry = gethostbyname( chName ) ) == NULL ) return ""; 
        else 
        { 
            memcpy( &inAddr, pHostEntry->h_addr, 4 ); 
            sAddress.Format( "%s", inet_ntoa( inAddr ) ); 
            return sAddress; 
        } 
    } 
} 

5 트레이 아이콘

void CWin1Dlg::OnButton1()  
{ 
            //일단 트레이아이콘 생성 
 
    NOTIFYICONDATA nid;     
                     
    nid.cbSize = sizeof(nid);  
    nid.hWnd = m_hWnd;         
    nid.uID = IDR_MAINFRAME;   
    nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; 
    nid.uCallbackMessage = WM_ICON_NOTIFY; 
    //이 부분이 중요 - 트레이 아이콘에서 이벤트 발생시 발생되는 메세지 정의하는 부분..  
    nid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
    strcpy(nid.szTip,"Test"); 
    Shell_NotifyIcon(NIM_ADD,&nid);  
    SendMessage(WM_SETICON,(WPARAM)TRUE,(LPARAM)nid.hIcon); 
 
    //일단 아이콘 생성하기 전에 다이얼로그를 숨겨야 겠죠..^^ 
    ShowWindow(SW_HIDE); 
} 
 
void CWin1Dlg::OnButton2()  
{ 
    //다음 트레이아이콘 삭제 
    NOTIFYICONDATA nid; 
 
    nid.cbSize = sizeof(nid); 
    nid.hWnd = m_hWnd; 
    nid.uID = IDR_MAINFRAME; 
    Shell_NotifyIcon(NIM_DELETE,&nid); 
 
    //글구 이젠 다이얼로그를 나타나게.. 
    ShowWindow(SW_SHOW); 
} 
 
LRESULT CWin1Dlg::OnTrayNotification(WPARAM wParam, LPARAM lParam) 
{ 
    // 왼쪽 마우스 버튼이 더블 클릭되었을 경우 
   if (LOWORD(lParam) == WM_LBUTTONDBLCLK)  
   { 
                // 프로그램 정보 다이얼로그 박스 출력 
                SendMessage(WM_COMMAND, IDC_BUTTON2); 
   } 
   return 1; 
} 

6 패스 분리하는 방법

void _splitpath( const char *path, char *drive, char *dir, char *fname, char *ext ); 

를 쓰면 됩니다. 다음은 MSDN에 나와있는 예제입니다

#include  
#include  
 
void main( void ) 
{ 
   char path_buffer[_MAX_PATH]; 
   char drive[_MAX_DRIVE]; 
   char dir[_MAX_DIR]; 
   char fname[_MAX_FNAME]; 
   char ext[_MAX_EXT]; 
 
   _makepath( path_buffer, "c", "\\sample\\crt\\", "makepath", "c" ); 
  
   printf( "Path created with _makepath: %s\n\n", path_buffer ); 
  
   _splitpath( path_buffer, drive, dir, fname, ext ); 
  
   printf( "Path extracted with _splitpath:\n" ); 
   printf( "  Drive: %s\n", drive ); 
   printf( "  Dir: %s\n", dir ); 
   printf( "  Filename: %s\n", fname ); 
   printf( "  Ext: %s\n", ext ); 
} 

7 FTP 관련

#include"CFTPTrans.h" 
 
CFTPTrans::CFTPTrans() 
{ 
} 
 
CFTPTrans::~CFTPTrans() 
{ 
    DisConnect(); 
} 
 
BOOL CFTPTrans::Connect(char *serverName, int port, char *username, char *password) 
{ 
    hInternet = InternetOpen("File Transfer for FTP", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); 
    if(hInternet == NULL) 
    { 
        errCode = GetLastError(); 
        return FALSE; 
    } 
  
    hFtpSession = InternetConnect(hInternet, serverName, port, username, password, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0); 
    if (NULL == hFtpSession) 
    { 
        InternetCloseHandle(hInternet); 
        errCode = GetLastError(); 
        return FALSE; 
    } 
    return TRUE; 
} 
 
CFTPTrans::DisConnect() 
{ 
    InternetCloseHandle(hFtpSession);  
    InternetCloseHandle(hInternet); 
} 
  
BOOL CFTPTrans::ChangeDirectroy(char *dirName) 
{ 
    if(!FtpSetCurrentDirectory(hFtpSession, dirName)) 
    { 
        errCode = GetLastError(); 
        return FALSE; 
    } 
    return TRUE; 
} 
  
BOOL CFTPTrans::PutFile(char *source, char *destination) 
{ 
    if(!FtpPutFile(hFtpSession, source, destination, FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD, 0)) 
    { 
        errCode = GetLastError(); 
        return FALSE; 
    } 
    return TRUE; 
} 

8 Downloaded Program Files 폴더의 OCX 삭제방법

typedef HRESULT (WINAPI *REMOVECONTROLBYNAME) 
( 
             LPCTSTR lpszFile, 
             LPCTSTR lpszCLSID, 
             LPCTSTR lpszTypeLibID, 
             BOOL bForceRemove, 
             DWORD dwIsDistUnit 
); 
 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    HMODULE                   hMod; 
    REMOVECONTROLBYNAME       pfn =  NULL; 
 
    hMod = LoadLibrary("OCCACHE.DLL"); 
    if (hMod == NULL) 
    {   // Error loading module -- fail as securely as possible 
        return 0; 
    } 
 
    HRESULT hr; 
    pfn = (REMOVECONTROLBYNAME)GetProcAddress(hMod, "RemoveControlByName"); 
    if (pfn)  
    { 
        hr = (*pfn)(_T("C:\\WINDOWS\\Downloaded Program Files\\teechart5.ocx"), 
            _T("{B6C10532-FB89-11D4-93C9-006008A7EED4}"), 0, TRUE, TRUE); 
    } 
    FreeLibrary(hMod); 
 
    return 0; 
} 

위에서 빨간 글자는 레지스트리에서 아래의 위치와 같습니다.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Code Store Database\Distribution Units 위 값의 하위키를 보면 숫자로된 키가 그것입니다.
파란색 글자는 빨간색 숫자로된 키 밑에 '\Contains\Files' 로 들어가서 오른쪽 값을 참고하면됩니다.

9 디버깅 용도의 실행시간 출력 코드

디버깅시 TRACE로 시간정보를 출력하고 싶을때 사용한다.

#include <sys/timeb.h> 
 
void printCurrentTime() 
{ 
    time_t ltime; 
    struct _timeb tstruct; 
    struct tm *gmt; 
 
    time(<ime); 
    gmt = localtime(<ime); 
    _ftime( &tstruct ); 
    TRACE2("called - %u(ms) %s", tstruct.millitm, asctime(gmt)); 
} 

예)

while(1) 
{ 
    Sleep(10); 
    printCurrentTime(); 
} 
 
<실행결과> 
... 
called - 92(ms) Tue Oct 01 17:44:28 2002 
called - 102(ms) Tue Oct 01 17:44:28 2002 
... 

10 Trace Tip

출처: http://www.codeproject.com/debug/tracetips.asp
디버그 창에서 trace 메시지를 더블클릭하면 에디터 커서를 해당 라인으로 위치시킨다.

TRACE(_T("%s(%i) : Please double click on me!\n"), __FILE__,__LINE__); 

11 모니터 끄기

PostMessage( GetDesktopWindow(),WM_SYSCOMMAND, SC_MONITORPOWER, 2 );  

12 프로세스간 데이터 교환

보통 서로 다른 프로세스끼리 데이터를 주고 받을 때는 shared memory나 clipboard를 이용하는데 간단한 데이터를 주고 받을 때는 사용하기에 부담스러운 면이 있다. 이때 간편하게 이용할 수 있는 프로세스간 데이터 교환 방법을 이용한다.

1. GlobalAddAtom()을 이용한 데이터 전송
예)

서버측: 
 
ATOM atom = GlobalAddAtom("This is test!");  
 
HWND hWnd = ::FindWindow(NULL, "AtomClinet");  
 
::PostMessage(hWnd, WM_MYMSG, 0, atom); // atom값을 전송  
 
클라언트측: 
void CATOMClientDlg::OnGetMsg(WPARAM wParam, LPARAM lParam)  
{  
    char vc_b[256];  
 
    ATOM atom = (ATOM)lParam;  
 
    GlobalGetAtomName(atom, vc_b, 256);  // vc_b를 사용  
}  

2. WM_COPYDATA를 이용한 데이터 교환

// source window에서..  
void CSourceWnd::Write(const void* lpBuf, UINT nCount)  
{  
       CWnd *pTraceWnd = CWnd::FindWindow(TRACEWND_CLASSNAME, NULL);  
 
       if (pTraceWnd) {  
              COPYDATASTRUCT cds;  
 
              cds.dwData = ID_COPYDATA_TRACEMSG /* Flag 용도 */;  
              cds.cbData = nCount;  
              cds.lpData = (void*)lpBuf;  
 
              pTraceWnd->SendMessage(WM_COPYDATA,  
                     (WPARAM)AfxGetApp()->m_pMainWnd->GetSafeHwnd(),  
                     (LPARAM)&cds);  
       } else {  
              AfxMessageBox("윈도우를 찾을 수 없습니다.");  
       }  
}  
 
//////////////////////////////////////////////////////  
// target windows에서..  
 
// 메세지 핸들링 설치  
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)  
       //{{AFX_MSG_MAP(CMainFrame)  
       ON_MESSAGE(WM_COPYDATA, OnTraceMsg)  
       .  
       .  
       .  
       //}}AFX_MSG_MAP  
 
END_MESSAGE_MAP()  
 
LRESULT CMainFrame::OnTraceMsg(WPARAM wParam, LPARAM lParam)  
{  
       COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;  
 
       // pcds 를 사용한다..  
 
       return 0;  
}  

3. Shared section을 이용한 global variable 공유

#pragma data_seg("Shared") 
volatile LONG g_lSharedData = 0;   // initialized data 
#pragma data_seg() 

또는,

__declspec(allocate("Shared")) int g_nSharedData1 = 0;  // initialized data 
__declspec(allocate("Shared")) int g_nSharedData2;      // uninitialized data 

이때 dll의 프로세스간 데이타 공유라면 dll의 def파일에 데이타 공유 섹션을 지정해 줘야 한다.

SECTIONS 
        .Shared Read Write Shared 

이렇게 하면 g_lSharedData은 이 dll을 로딩한 모든 프로세스에서 공유해서 사용할 수 있다

4. File Map을 이용한 메모리 공유

// 
// 파일을 매핑하는 함수 
 
LPVOID InitFileMapping( HANDLE *phFileMap, char *pszShareName ) 
{      
     LPVOID lpMapView; 
 
     // 파일맵 핸들을 생성한다 
     *phFileMap = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 
                              0, sizeof(DWORD), pszShareName ); 
     if( INVALID_HANDLE_VALUE == *phFileMap ) 
          return NULL; 
 
     // 파일을 매핑한다 
     lpMapView = MapViewOfFile( *phFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); 
     if( NULL == lpMapView ) 
          return NULL; 
 
     // 매핑한 데이터의 선두번지를 리턴 
     return lpMapView; 
} 
 
.... 
 
// 
// 파일맵 데이터를 쓰는 부분(1번 프로세스) 
pdwShare = (DWORD*)InitFileMapping( &hFileMap, dszFileMapName ); 
 
DWORD dwCount = 0; 
 
while( !( GetKeyState( VK_ESCAPE ) & 0x8000 ) ) 
{ 
     *pdwShare = ++dwCount; 
 
     printf( "Write - [%3d] %3d\n", dwCount, *pdwShare ); 
 
     Sleep( 500 ); 
} 
 
... 
 
// 
// 파일맵 데이터를 읽는 부분(2번 프로세스) 
DWORD dwCount = 0; 
 
while( !( GetKeyState( VK_ESCAPE ) & 0x8000 ) ) 
{ 
     printf( "Read - [%3d] %3d\n", ++dwCount, *pdwShare ); 
 
     Sleep( 500 ); 
} 
 
... 
 
// 파일매핑 해제 
UnmapViewOfFile( pdwShare ); 
CloseHandle( hFileMap ); 

13 Log 함수

윈도우 프로그래밍을 하다보면 가끔 dll 소스코드를 디버깅해야할 때가 있는데 이때 MSDEV의 디버거를 이용할수도 없기 때문에 디버깅하기가 까다롭다. 때론 printf대용인 MessageBox를 사용하기도 했는데 아무래도 썩 좋은 방법은 아니다. 이때 로그 함수를 만들어서 로그 파일을 생성하는 방법도 유용한 대안이다.
아래는 Nasser Remy Rowhani라는 외국 친구가 쓴 코드인데 써보니 쓸만한 코드라 생각되서 소개한다. 굳이 디버깅 용도뿐만 아니라 API를 후킹하는 응용에서도 유용하게 쓸 수 있다.

#define LogFile "d:\\Logs\\LOG.txt"                   // log파일이 생성되는 위치 
#define Append(text) AppendLog(text, strlen(text))    // log를 기록하는 함수 
 
HANDLE   hLogFile=0;                // log파일의 핸들 
BOOL     IsLogging=false;           // log파일이 제대로 open되었는지 체크하는 플래그 
 
HANDLE OpenLog(char *Filename);     
BOOL CloseLog(HANDLE h=hLogFile);    
DWORD AppendLog(char *str, DWORD uSize, HANDLE h=hLogFile); 
 
HANDLE OpenLog(char *Filename) 
{ 
        HANDLE hLogFile; 
 
        hLogFile = CreateFile( Filename, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS,0,0); 
        if(hLogFile!=INVALID_HANDLE_VALUE) 
                IsLogging = true;//SetFilePointer(hLogFile, 0,0, FILE_END);//*/ 
         
        return hLogFile; 
} 
 
BOOL CloseLog(HANDLE h) 
{ 
        IsLogging = false; 
        return CloseHandle(h); 
} 
 
DWORD AppendLog(char *str, DWORD uSize, HANDLE h) 
{ 
        DWORD written; 
        if(!IsLogging) return 0; 
 
        SetFilePointer( h, 0, 0, FILE_END ); 
        WriteFile(h, str, uSize, &written, 0); 
 
        return written; 
} 

용례:

hLogFile = OpenLog( LogFile );   // 처음엔 log파일을 open한다. 
   ... 
sprintf(buf, "Error Code: %d", dwErr); 
Append(buf); 
   ... 
CloseLog();                     // 프로그램에서 exit할 때 log를 close 

14 Ctrl+Esc, Alt+Tab, and Alt+Esc를 막는 법

출처: http://msdn.microsoft.com/msdnmag/issues/0700/win32

/************************************************************************ 
Module:  DisableLowLevelKeys.cpp 
Notices: Written 2000 Jeffrey Richter 
**************************************************************************/ 
 
#define _WIN32_WINNT 0x0400 
#include <Windows.h> 
 
LRESULT CALLBACK LowLevelKeyboardProc(int nCode,  
   WPARAM wParam, LPARAM lParam) { 
 
   BOOL fEatKeystroke = FALSE; 
 
   if (nCode == HC_ACTION) { 
      switch (wParam) { 
      case WM_KEYDOWN:  case WM_SYSKEYDOWN: 
      case WM_KEYUP:    case WM_SYSKEYUP:  
         PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam; 
         fEatKeystroke =  
            ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) || 
            ((p->vkCode == VK_ESCAPE) &&  
            ((p->flags & LLKHF_ALTDOWN) != 0)) || 
            ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) &  
             0x8000) != 0)); 
         break; 
      } 
   } 
   return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam,  
          lParam)); 
} 
 
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) { 
 
   // Install the low-level keyboard & mouse hooks 
   HHOOK hhkLowLevelKybd  = SetWindowsHookEx(WH_KEYBOARD_LL,  
      LowLevelKeyboardProc, hinstExe, 0); 
 
   // Keep this app running until we're told to stop 
   MessageBox(NULL,  
      TEXT("Alt+Esc, Ctrl+Esc, and Alt+Tab are now disabled.\n") 
      TEXT("Click \"Ok\" to terminate this application and re-enable 
            these keys."), 
      TEXT("Disable Low-Level Keys"), MB_OK); 
   UnhookWindowsHookEx(hhkLowLevelKybd); 
 
   return(0); 
} 

15 About box에 URL 링크 걸기

About 대화상자에 웹으로 가는 링크를 넣는 방법. 이것은 액티브X 컨트롤을 이용하는 것이 가장 손쉬운 방법이다. IE에서 제공하는 오브젝트중 '마이크로소프트 웹브라우저'라는 것이 있는데 다음과 같이 하면 프로젝트에 포함된다.

  1. Project 선택
  2. Add to Project 선택
  3. 컴포넌트와 컨트롤 선택
  4. Registered ActiveX Controls 폴더를 선택
  5. Microsoft Web 브라우저라는 오브젝트 선택
  6. 컴포넌트 클래스 대화 상자에서 확인
  7. 대화상자 편집 모드에서 컨트롤 툴바에 등록된 웹브라우저 컨트롤을 대화상자에 드래그해 화면 디자인을 한다.
  8. Class Wizard를 사용해서 Member Variable 탭에서 IDC_WEBxxx에 대한 데이터 멤버를 지정한다. 이때 Add Member Variable 대화상자의 category 콤보를 컨트롤로 지정
  9. 이제는 OnInitDialog등 원하는 지점에서 m_Webxxx로 지정된 멤버 객체 데이터를 사용해 다음과 같이 작성한다.
     m_WebBrowser.Navigate("http://dasomnetwork.com/~leedw", NULL, NULL, NULL, NULL); 
     

위와 같이 해주면 대화상자가 기동 시에 동우의 홈페이지가 대화 상자에 나타날 것이다. 참고로 원격 사이트가 아닌 로컬에 html 문서를 미리 작성해서 가지고 있다가 URL 부분에 "file:///c:/My Documents/DHTML/ftv20/ftexample.html"라고 해주면 html이 나타난다.

16 특정 파일 오픈시 바로 프로그램 불러오기

ACDSee라는 그래픽 뷰어 프로그램같이 해당 그림 파일을 더블클릭하면 프로그램이 실행되면서 그 데이타를 불러오는 것과 같은 기능을 볼 수 있다. 이런 임의 파일의 싨행은 WinExec, ShellExecute API를 사용하면 구현할 수 있다. 여기서 원하는 것은 실행 파일 및 문서 파일들이므로 ShellExecute를 사용해야 한다.

HINSTANCE ShellExecute( 
    HWND hwnd,  
    LPCTSTR lpOperation, 
    LPCTSTR lpFile,  
    LPCTSTR lpParameters,  
    LPCTSTR lpDirectory, 
    INT nShowCmd 
);       

자세한 것은 MSDN 참조

17 드래그 앤 드롭으로 파일 오픈

윈도우 탐색기나 바탕 화면에서 드래그 앤 드롭으로 파일을 불러서 처리하고자 할 경우. 응용 프로그램에서의 드래그 앤 드롭의 처리는 InitInstance() 처리 부분에서 DragAcceptFiles라는 멤버 함수 또는 API를 수행하면 된다. 그러면 윈도우는 드래그 앤 드롭되는 것이 존재할 때 WM_DROP_FILES라는 메시지를 받는다.(이 메시지는 OnDropFiles(..)라는 멤버 함수가 처리한다.) 이 메시지에서 적당히 처리해주면 된다. 이것은 OLE와는 다른 것이니 주의한다.

18 app가 트레이에만 띄우도록 하려면

winamp같은 어플리케이션이 실행될 때 윈도우가 뜨더라도 상태바에는 뜨지 않고 트레이에만 생기는 모습을 보았을 것이다. 이것을 구현하려면 다음의 코드를 사용한다

void HideApplication(HWND hwnd) 
{ 
   ShowWindow(hwnd, SW_HIDE); 
   ShowOwnedPopups(hwnd, FALSE); 
    
   SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, 
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 
} 

CApp 클래스에 위와 같은 이름을 가진 멤버 함수가 존재하는데 그 함수를 사용해도 된다. 실제 응용 프로그램을 태스크 바에서 사라지도록 하는 것은 SetWindowPos API에 있다. 또한 Shell_NotifyIcon이란 API가 있는데 이것을 이용해봐도 될 것이다.

WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( 
    DWORD dwMessage,  
    PNOTIFYICONDATA pnid 
);       

주의해야할 것은 응용 프로그램은 메인 프레임을 가져야 하나 메인 프레임을 활성화시키지는 않도록 한다. 활성화만 안시키면 <Alt-Tab>에서 나타나지 않을 것이다. 대신 별도의 윈도우를 WS_POS으로 만들어 이를 트레이에 등록해야 한다. 즉, 트레이에 등록된 팝업 스타일의 윈도우가 모든 메시지를 가로채도록 하기 위함이다.

19 single thread 어플리케이션에 취소 버튼 구현

출처: http://www.fhcf.net/misc/id_ws/database/essays/fboyjoe/cancel/cancel.html

어플리케이션을 개발하다가 간혹 processor-intensive한 루틴을 작성해야할 때가 있다. 단일 쓰레드로 이를 구현했을 때는 하나의 루틴이 프로세서 자원을 다 잡아 먹기 때문에 윈도우즈 메시지를 처리할 수 없는 문제에 부딪힌다. 그래서 이때는 processor 자원을 많이 요구하는 연산 부분은 thread로 구현해서 돌려 놓고 원래의 thread는 윈도우 메시지를 처리하는 방법으로 구현을 한다. 그런데 별도의 쓰레드를 만들지 않고 단일 쓰레드에서 processor 자원 요구량이 많은 모듈과 윈도우즈 메시지를 동시에 처리할 수 있는 기법이 있어 소개한다.

결론을 미리 말하자면, processor-intensive한 연산 안에 message pump를 두어 메시지를 처리하도록 하며 유저가 언제든 취소를 원할 때 연산을 취소할 수 있도록 플래그를 검사하도록 하는 것이다. 플래그는 "취소"버튼을 눌렀을 경우에 셋팅되도록 한다. 핵심 부분을 코드로 살펴보면 다음과 같다.

void StartProcessing() 
{ 
   hCancelDialog = CreateDialog (inst, MAKEINTRESOURCE(IDD_DIALOG2),    
                               hwnd, CancelDialog); 
   ShowWindow (hCancelDialog, TRUE);          // 취소 버튼이 있는 대화 상자 출력 
   cancelled = 0;       // 취소 버튼이 눌렸는지에 대한 플래그 
    
   for ( ...) {       // 여기부터가 processor-intensive한 연산 부분이다. 
        .... 
    
        if(!MessagePump()) { // 연산 수행중에도 메시지를 처리할 수 있도록 한다. 
             return;       // WM_QUIT 메시지를 받으면 루틴을 빠져나간다. 
        }  
 
        if(cancelled) { 
            // 취소 플래그가 셋팅되면 연산을 중지한다. 
    
         .... 
    
   } 
   DestroyWindow(hCancelDialog); 
   EnableWindow(hwnd, TRUE); 
    
   .... 
 
BOOL MessagePump()        // 메시지 펌프 
{ 
   MSG msg; 
    
   while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {  // 메시지 큐에 메시지가 있는지 체크 
      if (!GetMessage(&msg, NULL, 0, 0)) {    // 메시지를 가져온다. 
         PostQuitMessage(0); 
         return FALSE; 
      } 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
   } 
   return TRUE; 
} 

예제 프로젝트 : CancelTestApp.zip

20 PC시간 셋팅하기

void CSetDateDlg::OnOK()  
{ 
        // TODO: Add extra validation here 
 
        CTime time( 2005, 1, 10, 22, 17, 43 );  
        SYSTEMTIME sysTime; 
 
        time.GetAsSystemTime(sysTime); 
 
        if (getSystemType() == VER_PLATFORM_WIN32_NT) 
        { // NT 계열이면 시간을 바꿀 수 있는 특권을 가져와야 한다. 
                HANDLE hToken; 
                TOKEN_PRIVILEGES tp; 
                LUID luid; 
 
                OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); 
                LookupPrivilegeValue(NULL, "SeSystemtimePrivilege", &luid); 
 
                tp.PrivilegeCount = 1; 
                tp.Privileges[0].Luid = luid; 
                tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
                AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); 
        } 
 
        SetLocalTime(&sysTime); 
         
        CDialog::OnOK(); 
} 
 
void CSetDateDlg::getSystemType() 
{ 
        OSVERSIONINFO osv; 
 
        osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 
        GetVersionEx(&osv); 
 
        return osv.dwPlatformId; 
} 



출처: http://www.dasomnetwork.com/~leedw/mywiki/moin.cgi/win32_2f_c4_da_b5_e5_c6_c1?action=highlight&value=VisualC%2B%2B%C6%C1%C1%F6%B5%B5

Posted by 나비 나비:D
태그 API

1. 버튼

 case WM_CREATE:

  CreateWindow(TEXT("button"), TEXT("click"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,20,20,100,25, hWnd

                        (HMENU)0, g_Inst, NULL);

  return 0;

 case WM_COMMAND:

  switch(LOWORD(wParam))

   case 0:

    MessageBox(hWnd, Text("clicked"), "TEXT(button)", MB_OK);

    break;

  return 0;

버튼 컨트롤 사용 방식이다.. 윈도우 생성시 버튼을 만든 것이고, 버튼이 클릭되었을때 메시지박스를 띄우는 것이다.

CreateWindow(만들윈도우클래스, 윈도우제목, 스타일, 좌표,좌표,좌표,좌표, 부모윈도우, 아이디값, 윈도우인스턴스핸들, MDI사용될 구조체);

 스타일을 살펴보면 차일드라는 속성이 사용되었다. 이것은 메인 윈도우가 만들어지면 그안에 포함되는 컨트롤인 된다는 것이다.

 비지블은 보여준다, 푸쉬버튼 누른다. 라는 의미이다.

 자식윈도우로 지정을 했으면 부모의 핸들을 부모윈도우 자리에 넣어주면 되고 아이디 값을 그 버튼을 눌렀을때 wParam으로 넘어가는 값을 말한다.. 커맨드에선 하이워드의 wParam을 조사하여 그에 해당하는 코드를 넣어주면 된다.



2. 체크 박스

 생성방식은  위와 동일 하다..

static HWND c1;    // 체크박스 핸들저장,,, (체크 확인여부위해서)

static bool draw = false;  // 그림을 그릴것인가에 대한 변수

RECT rt;

GetClientRect(hWnd, &rt);   //현제 윈도우 클라이언트 영역을 얻어온다


case WM_CRATE:

 c1 = CreateWindow("button", "checkbox", WS_CHILD | WS_VISIBLE | BS_CHECKBOX, 20, 20, 160, 25, hWnd, (HMENU)1, g_hInst, NULL) ;   //수동체크박스 생성, 자동으로 하려면    BS_AUTOCHECKBOX로 변경한면 된다

break;


case WM_COMMAND:

 switch(LOWORD(wParam))

  case 1 :

   if(SendMessage(c1, BM_GETCHECK, 0, 0) == BST_UNCHECKED)  //센드메시지는 전에 보았다.. 찾아봐라
   {                          //체크 확인 메시지            // 체크 되있지 않다면
    draw = TRUE;
    SendMessage(c1, BM_SETCHECK, BST_CHECKED, 0); // 체크박스로 다시 보내 체크 하도록 요구한다
   }                          // 변경               // 체크상태
   else
   {
    draw = false;
    SendMessage(c1, BM_SETCHECK, BST_UNCHECKED, 0);
   }                                                   //비체크상태
   InvalidateRect(hWnd, &rt, true);   //이것도 전에 보았다.
   break;

인자는 동일하다,,,, 굳이 설명할 필요가 없다 체크 메시지와 체크 상수만 알아보겠다.

 BM_GETCHECK  체크상태를 조사.. 리턴값으로 돌려진다
 BM_SETCHECK  체크상태 변경... wParam에 변경할 상태를 지정
 BST_UNCHECKED  체크안됨
 BST_CHECKED  체크됨
 BST_INDETERMINATE  아무것도 아닌상태


3. 라디오 버튼

체크박스 생성방법과 동일하다 다만, 생성할 때 3번째 인자..

즉, 속성을 BS_RADIOBUTTON 이나 BS_AUTORADIOBUTTON으로 변경해봐라...

일반과 오토의 차이점은 체크상태를 스스로 변경하는가, 그렇제 않는가의 차이이다..


4. 에디트

 문자열을 입력받을때 사용하는 컨트롤이다...

#define ID_EDIT 100


 CHAR str[128];

 HWND hEdit;     //에디트 컨트롤을 담을 핸들


case WM_CREATE:

 hEdit = CreateWindow("edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 10, 10, 200, 25, hWnd, (HMENU)ID_EDIT, g_hInst, NULL);

 return 0;


case WM_COMMAND:

 switch(LOWORD(wParam))

  case ID_EDIT:

   switch(HIWORD(wParam))   //하이워드에서 문자열 변경상태를 파악한다

    case EN_CHANGE    // 변경되었다면

     GetWindowText(hEdit, str, 128);  // 에디트 핸들에 써진것을 가져와서

     SetWindowText(hWnd,str);    // 윈도우 캡션바 이름을 바꾼다

별로 특별한 것은 없다.  스타일과 메시지에 대해서만 간단히 알아보겠다

 ES_AUTO(H),(V)SCROLL  H는 수평, V는 수직 스크롤바가 생긴다
 ES_MULTILINE  여러 줄을 편집
 ES_READONLY  읽기전용으로 만든다


 EN_CHANGE  문자열이 변경되었을때
 EN_(H), (V)SCROLL  H는 수평바 클릭시, V는 수직바 클릭시
 EN_(KILL), (SET)FOCUS  KILL은 포커스를 잃었을때, SET은 포커스를 얻었을때
 EN_UPDATE  문자열이 변경되기 직전....


5. 리스트 박스

 #define ID_LISTBOX 100

 CHAR str[128];

 HWND hListbox;     //에디트 컨트롤을 담을 핸들

 int i;


case WM_CREATE:

 hListbox = CreateWindow("listbox", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY, 10, 10, 200, 250, hWnd, (HMENU)ID_LISTBOX, GetModuleHandle(0), NULL);
   SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)"aaa");   //문자열 추가, 엘파람 으로 문자가 넘어간다.
   SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)"BBB");  //문자열 추가

 return 0;

case WM_COMMAND:

 switch(LOWORD(wParam))

  case ID_LISTBOX:

   switch(HIWORD(wParam))   //하이워드에서 리스트 선택  상태를 파악한다

    case LBN_SELCHANGE    // 변경되었다면

     i = SendMessage(hListbox, LB_GETCURSEL, 0, 0);   //현제 몇번째 셀인지 조사한다      

    //구현하고 싶은 내용

사용 방식이 거의 동일하다... 역시 속성과 메시지만 알아보겠다..

 LBS_MULTIPLESEL  여러개의 항목을 선택할 수 있다
 LBS_NOTIFY  목록중 하나를 선택했을때 부모 윈도우로 메시지를 날린다
 LBS_SORT  항목을 정렬한다
 LB_(ADD), (DELETE) STRING  add는 문자열 추가, delete는 문자열 삭제
 LB_GETCURSEL  현재 선택된 항목의 번호를 얻어온다
   



6. 콤보박스

 리스트박스와 거의 동일하다... 바뀌는 부분말 말하겠다..

 listbox 부분을 combobox로 바꾸어준다... 속성을 CBS_DROPDOWN 으로 바꾸어 준다. 센드 메시지 안을 LB(리스트박스)에서 CB(콤보박스)로 바꾸어 준다.. 이러면 생성이 된다..

 

 case WM_COMMAND:

 switch(LOWORD(wParam))

  case ID_LISTBOX:

   switch(HIWORD(wParam))   //하이워드에서 리스트 선택  상태를 파악한다

    case CBN_SELCHANGE:    // 변경되었다면

     i = SendMessage(hListbox, CB_GETCURSEL, 0, 0);   //현제 몇번째 셀인지 조사한다      

    //구현하고 싶은 내용

    case CBN_EDITCHANGE:

     //구현하고 싶은 내용


난 간단히 하기 위해서 메시지 박스로 확인을 해봤다..


7. 스크롤 바

지금까지 컨트롤과는 조금 다르다..일단 생성은 동일하다

listbox 부분을 scrollbar로 바꾸어준다... 속성을 SBS_HORZ 으로 바꾸어 준다.  ID값 변경은 센스다.

생성한 후 다음 코드를 입력 한다.

 case WM_CREATE:

  //생성코드


  SetScrollRange(hScroll, SB_CTL, 0, 255, TRUE);  // 스크롤바 범위 셋팅

                                                                     //첫번째 스크롤바핸들, 두번째 별도의 컨트롤 지정하겠다는 의미

                                                                  //세번째 최소값,  네번째 최대값, 다섯번째 화면 재 출력여부

  SetScrollPos(hScroll, SB_CTL, 0, TRUE);   //스크롤바 스크롤의 초기 위치 지정

                                                              //나머진 동일하도 3번째가 초기 위치가 된다.

  return 0;

case WM_HSCROLL:
 if ((HWND)lParam == hRed) TempPos = Red;
  switch (LOWORD(wParam)) {
   case SB_LINELEFT:
    TempPos=max(0,TempPos-1);
    break;
   case SB_LINERIGHT:
    TempPos=min(255,TempPos+1);
    break;
   case SB_PAGELEFT:
    TempPos=max(0,TempPos-10);
    break;
   case SB_PAGERIGHT:
    TempPos=min(255,TempPos+10);
     break;
   case SB_THUMBTRACK:
    TempPos=HIWORD(wParam);
     break;
}
if ((HWND)lParam == hRed) Red=TempPos;

SetScrollPos((HWND)lParam,SB_CTL,TempPos,TRUE);
InvalidateRect(hWnd,NULL,FALSE);
return 0;


8. 스태틱

 간단한 컨트롤이다.... 에디트랑 비슷하며.... 글을 쓰는것이 아니라 저장된 글을 그냥 출력만 시키는 컨트롤이다..

CteateWindow("static", "넣고싶은텍스트", WS_CHILD | WS_VISIBLE, 20, 20, 120, 25, hWnd, (HMENU)-1, g_hInst, NULL);


Posted by 나비 나비:D

자 ! 이렇게 외우자 !! 아니, 외우지 말고 이렇게 이해하자!!!

  • 연산자 우선순위는 일단 15층짜리 건물로 생각을 하자. 보통 예전에는 아파트 15층 건물이 많지 않았는가? 쉽게 연상이 될 것이다.
  • 연산 순위가 낮은 연산자가 높은 층을 차지한다. 아무래도 1층과 가까운 층이 출구로 나오기 편하지 않겠는가? 그러므로 순위가 가장 낮은 컴마 연산자는 15층, 가장 높은 괄호 연산 등은 1층이다.
  • 각 층에 각각 연산자가 산다고 생각하자. 당연히 우선 순위가 중요한 것이 낮은 층에 위치시키고, 조금 낮은 순위를 높은 층에 위치시키자.
  • 연산자를 ‘외운다’ 고 생각하지 말고, 이제 한 ‘아파트’에 있는 ‘이웃’이라고 생각하자. 연산자의 특성을 생각하면서 ‘이웃’의 순서를 상기하자.
  • 연산자들은 각 역할 별로 고유한 특징이 있다. 그 특징을 바탕으로 연산자에게 좀더 ‘이웃’다운 성격을 부여하고 그 특징을 상기해 보자. 훨씬 이해하기 쉬울 것이다.

 

C 연산자 도시에는 많은 연산자들이 살고 있었다. C 연산자는 각각 그 나름대로의 개성과 고유한 역할, 성품이 있었고 연산자 도시에서 가지고 있는 사회적 지위, 재산과 평판을 가지고 있었다. 각각 연산자들은 자신의 역할을 담당하고 있었고, 그 역할에 따라 숫자 문자 논리값들은 각각 적절히 계산이 되어 결과가 나왔다. 연산자는 ‘연산’이라는 직업을 가지고 있었고, 그렇게 연산을 통해 생계를 꾸려갈 수 있었다.

 

어느 날 모든 연산자들은 연산자 타워라는 한 건물에서 살도록 프로그래머에게서 명령을 받았다. 제아무리 뛰어난 연산자라도 프로그래머의 명령은 절대적이었기 때문에 복종할 수밖에 없었다. 제각각 살던 그들은 이제 한 건물에서 살아야만 했다.

 

연산자 타워는 15층짜리 건물이었는데, 높은 층일수록 넓고 살기 좋았지만 한 층 한 층 올라갈수록 호되게 가격이 올라갔고, 1층 입구를 통해 바깥으로 나가 자신의 직장으로 출근하기도 어려웠다 게다가 높은 층에 걸맞은 사회적 지위가 없다면 눈치가 보여서 입주하기도 어려운 ‘불문율’이란 것이 있었다. 결국 누가 어느 층에서 살지를 의논하기 시작하였다.

 

15층은 너무나 좋아서 모든 연산자들이 탐을 낼만한 층이었다. 하지만 가격이 너무 비싸 선뜻 구입할 연산자가 없었다. 문득 컴마(,) 씨가 일어나 자신이 15층에 살겠다고 말하였다. 모든 연산자는 찬성하였다. 이미 컴마 씨는 다양한 분야에서 경험을 수많은 경험을 쌓은 베테랑이었고, 넉넉한 성품으로 유명하여 사회적으로도 명망이 높은 연산자였다.

컴마 씨의 재산 또한 어마어마하고, 최근 일선 업무에서 물러나 후진 양성에 힘쓰기로 하여 잦은 출퇴근을 할 이유가 없었으므로 결국 15층은 컴마 씨의 소유가 되었다.

 

14층은 연산 도시의 대부인 ‘할당 연산자’ 이퀄(=) 씨가 소유하기로 했다. 다른 연산자들도 동의하였다. 이퀄 씨 또한 이미 오래전부터 다양한 분야에서 활약을 펼친 존재였기 때문에 컴마 씨에 버금가는 사회적 지위와 재산을 누리고 있었다. 게다가 이퀄 씨의 할당 연산이 없이는 제아무리 복잡한 연산도 무용지물에 불과했다. 이퀄 씨 또한 후학 양성에 매진하였는데 그들의 직계 제자들은 다름아닌 += -= *= /= %= <<= >>= &= |= ^= 들이다. 이들은 종래 볼 수 없던 참신한 연산으로 연산업계의 새로운 화두로 떠오르고 있다.

 

13층은 의외로 삼항 연산자 씨가 소유하겠다고 말해 이목을 집중시켰다. 독특한 개성의 소유자인 삼항 연산자 씨는 젊을 때부터 C 연산업에서 주목받는 존재였다. 지금은 프리랜서 선언을 하고 조용히 자신의 창작 활동에 전념하고 싶은 터였다. 그에게 있어 13층은 자신의 거처로 더할 나위 없이 적당한 장소였다.

 

12층과 11층은 각각 논리 연산 오어(||) 씨 부부, 논리 연산 앤드(&&) 씨 부부가 맡기로 하였다. 각각 10층과 8층 비트 연산 오어(|) 씨, 비트 연산 앤드(&)씨의 형이기도 한 논리 오어 씨, 논리 앤드 씨는 맞벌이 부부였다. 두 부부 다 논리 연산에서 중요한 업무를 관장하고 있어 사회적 지위도 높았고 재산도 상당하였다.

원래 오어 씨가 11층을 먼저 선택하였다. 하지만 앤드 씨가 조금이라도 출근의 편의를 위해 11층에서 살기를 간곡히 원했고, 평소 앤드 씨와 친분이 깊은 데다 앤드 씨 부부의 바쁘디 바쁜 스케줄을 이미 잘 알고 있는 오어 씨는 ‘허허’하고 웃으며 선선히 11층을 양보해 주었다.

 

이미 언급하였듯 10층과 8층에는 논리 연산 오어 씨와 앤드 씨의 동생인 비트 연산 오어 군(|)과 앤드(&) 군이 살기로 하였다. 둘 다 각자의 형 못지않은 실력과 재능을 갖고 있어 비트 연산계의 젊은 인재로 촉망받는 두 연산자였다. 다소 파격적인 일이었지만 그들의 촉망받는 장래성과 논리 연산 오어 씨와 앤드 씨의 얼굴을 보아 다들 그 두 동생의 소유를 인정하는 분위기였다.

 

하지만 논리 연산 오어(||)씨와 앤드(&&)씨 부부는 내심 탐탁지 않다. 이제는 그 두 동생들도 알맞은 짝을 찾아 결혼하여 자신들처럼 아이도 낳고, 좀 더 행복하게 살기를 원했지만 아직 두 동생은 아직 결혼할 마음이 없는데다, 두 사람 다 9층에 있는 비트 연산 배타적 오어(^) 양에게 마음을 빼앗겨 있는 상황이기 때문이다.

 

논리 연산 오어 씨와 논리 연산 앤드 씨는 배타적 오어 양을 볼 때마다 속이 부글부글 끓어 올랐다. 자신들이 끔찍이 아끼는 동생들이 결혼할 생각도 하지 않고 오어 양에게만 매달려 있는 꼴이 맘에 들지 않아 사실 오어 양이 9층은 물론 연산자 타워에 입주하는 것조차도 반대하고 싶었기 때문이다. 게다가 자신들의 동생 사이 층에서 살겠다고 한 것은 대체 무슨 속내인지 알 수가 없었다.

하지만 그런 배타적 오어 양에게 무조건 몰아붙일 수만은 없었다. 배타적 오어 양은 깐깐하고 도도하기는 했지만 독특한 개성과 장기를 살려 이미 수많은 비트 연산 업무를 수월하게 진행한 그녀의 능력은 사실 그들 동생들을 능가할 정도이기 때문이었다.

 

그렇게 10층에는 비트 연산 오어 (|)군, 9층에는 비트 연산 배타적 오어(^)양, 8층에는 비트 연산 앤드 군(&)이 살기로 결정되었다.

 

7층에는 이퀄 씨의 아들이자 쌍둥이 같다(==) 씨와 다르다(!=) 씨가 같이 살기로 하였다. 생김새는 엇비슷하지만 (살펴보면 제법 다른 구석이 있다) 성격은 전혀 다른 두 연산자는 이퀄씨의 성격을 닮아 정직하고 우직한 성격이다. 아버지의 예전 업무(수학에서 =, ≠)를 물려 받아 C 연산 업무를 성실하게 또 하루하루 바쁘게 살고 있다.

 

6층에는 같다 씨와 다르다 씨보다 더욱 분주한 스케쥴을 보내는 관계 연산의 사총사가 입주하기로했다. 지방에서 지내다가 일약 C 연산자 업계의 다크호스로 떠오른 네 연산자 크거나 같다(>=), 작거나 같다(<=), 크다(>), 작다(<) 네 연산자는 의리로 똘똘 뭉친 친구들이었다. 같다 씨와 다르다 씨와 하는 일은 같지만, 수많은 연산 업무에서 더욱 많은 호출을 받는 탓에 항상 시간이 모자란 그들은 좀 더 출근에 유리한 6층에서 살기로 하였다.

 

5층에서 살기로 한 연산자는 말썽꾸러기 비트 이동 연산자(<<, >>) 두 남매였다. 두 남매는 매우 비사교적이었다. 솔직히 바쁘기로 따지만 관계 연산자나 논리 연산자들이 더욱 바쁘고 비트 이동 연산자는 매일 집에 틀어박혀 얼굴도 비추지 않고 무엇을 하는지 도통 알 수가 없었다.

그리고 비트 이동 연산자는 곱하기(*) 씨와 나누기(/) 씨에게 걸핏하면 트집을 잡았다. 지위가 좀 더 높은 까닭에 관계 연산자나 논리 연산자가 높은 층수에서 살았기에 망정이지.... 아무튼 비트 이동 연산자는 말썽꾸러기였다. 더 낮은 층도, 더 높은 층도 그들에게는 어울리지 않았다.

 

4층에는 너무나 유명한 더하기 씨(+), 빼기 씨(-) 부부, 3층에는 곱하기 씨(*), 나누기 씨(/) 부부, 그리고 그들의 자식인 몫 구하기(%)가 살기로 하였다. 이들 부부는 14층의 이퀄(=)씨 만큼이나 유명한 삶을 살았지만, 재물에는 초연하였다. 그들은 좋은 집을 원하지 않았다. 그리고 여전히 연산업에서 핵심적인 업무를 수행하기 때문에 이동이 편한 3층과 4층을 각각 원했고, 전통적으로 곱하기 씨와 나누기 씨 가족이 좀 더 우선순위가 주어졌기 때문에 곱하기 나누기 부부가 3층을 맡고 더하기 빼기 부부가 4층을 맡기로 했다.

 

2층에는 혼자만의 삶을 살기로 결정한 각 연산 분야의 많은 단항 연산자들이 모여 살기로 결정했다. 그들은 따로 또 같이 자신들이 원하는 삶을 살기로 결정하고 서로 간섭하지 않는다는 조건 하에 2층에서 뭉치기로 결정하였다. 그들은 반전(!), 비트 보수(~), 전치 증가(++) 전치 감소(--), 플러스 기호(+), 마이너스 기호(-), 주소 연산(&), 역참조 연산(*), 캐스팅 연산, sizeof 연산이었다.

 

1층에는 프로그래머의 잦은 호출로 24시간 항시 대기하는 연산자와 여러 도구들을 놓아두기로 하고 연산자들의 층 배분 토론은 끝이 났다. 이들은 [ ], 포인터 참조(->), 점 연산자(.) ... 프로그램 언어만 찾을 수 있는 연산들이었다.

그리고 괄호 연산자가 특이하게 그 도구들과 같이 살아가기로 했다. 다른 연산자는 그러려니 하고 생각하였다. 대관절 괄호 연산자는 괴짜인지, 도인인지 그 정체를 알 수 없었다. 그의 말 한 마디에 연산 전체가 좌지우지됨에도 불구하고, 재물도 지위도 그 어떤 것도 원하지 않았기 때문이다. 한편 괄호 연산의 강한 카리스마에 홀려 2층에서 1층으로 살기로 결심한 두 연산자가 있었으니 바로 전치 증가, 전치 감소 연산의 쌍둥이 형제 후치 증가(++), 후치 감소(--)이다. 이들은 항상 알 수 없는 행동을 하며 가끔씩 프로그래머조차 혼란에 빠뜨리는 기행을 저지르곤 한다.

Posted by 나비 나비:D

C++/C :: 강좌

2008.05.14 10:05

출처 : 네이버 :: 지식iN




C++을 배우신다면 C는 배우셨는지 모르겠네요.


일정이 바쁘신게 아니라면 씨부터 배우는 것을 추천합니다.


물론 C++부터 배운다고 나쁜거는 아니지만 C부터 배우면


정말 기본 부터 배울수가 있습니다.


일단 C 강좌는


http://www.chanywa.com/pl/ 자료 만땅!

http://goldkorea.x-y.net/frame.htm 강좌.있는곳.

http://cprogramming.ce.ro/ 강좌있는곳..가끔 18x같은배너떠서 짜증남.

http://ns2.dongju-c.ac.kr/~syhong/teaching/c/c13.htm# 책처럼 자세한 강좌

http://loveisstar.hihome.com/홈페이지/공부방/c.htm 포인터 강좌, 캠퍼스 C강좌, 정복 터버C강좌 있음.. 여기가 강좌로만 치면 제일많음..

http://romeo.hufs.ac.kr/~dondek/ 상돈형님의 사이트 포인터 부분..

http://www.terms.co.kr/ 용어사전 텀즈..강추

http://www.winapi.co.kr/ pdf자료 만땅. 강좌도 쓸만함.

http://spnode10.knou.ac.kr/computer/html/08.htm 걍 함번 가보면 좋음.
음성이 나옴-_______-;


이렇게 있습니다.


완전 초보시라면 크레듀(http://www.credu.com) 와 같은 교육 싸이트의 동영상 강의도


좋습니다. 초보에 맞게 진행되고 씨와 씨뿔뿔 어려 과목이 있습니다.


C++ 싸이트로는 아래의 링크를 이용해 주세요


윈도우즈 API(Win32 API) 전문 사이트 : http://winapi.co.kr/


프로그래머를 위한 C++ : http://higasijoe.nasse.net/Main/index2.htm


C언어 길라잡이 : http://www.c-language.wo.to/


ProGramma : http://www.hanpoi.wo.to/


C++언어 강좌(기초) : http://cplus.ubedu.com/


C++ 온라인 동영상 강좌(무료) : http://cla.ib96.com/study/index.php


C 구조대 : http://www.sosc.nuri.cc/


지키미 : http://www.zikimi.co.kr/


워킹 C : http://workingc.com/


골드코리아 : http://goldkorea.x-y.net/html/frame.htm


민호의 프로그램 공부방 : http://oa.colorn.com/


지니야닷넷 : http://www.jiniya.net/bbs/portal.php


Standard C++ Library : http://oopsla.snu.ac.kr/~sjjung/stl/


생각하는 C++ : http://tc.pukyung.co.kr/index.htm


김중태의 C언어 이야기 : http://www.dal.co.kr/chair/c/c.html


데브피아 : http://www.devpia.com/


C 언어 길라잡이 : http://www.web-reader.co.kr/c-vb/c-edu.htm


C : http://hanuri.jnu.ac.kr/lecture/language/clang/


C 강좌 : http://www.mydosu.com/LEC/cpp/main_cpp.asp


http://fhl.com.ne.kr/school/C/cm.html

1주차 강의 C 의 기초지식,소개
2주차 강의 C 의 기본 문법
3주차 강의 기본적인 입출력 함수
4주차 강의 제어구조
5주차 강의 배열
6주차 강의 포인트
7주차 강의 포인트 배열
18주차 강의 8주는 시험
9주차 강의 함수의 이해
10주차 강의 데이터형과 기억 클레스
11주차 강의 구조체와 공용체
12주차 강의 프리프로세서
13주차 강의 표준 라이브러리 함수
14주차 강의 파일처리


동주대학 전산과 C : http://www.dongju-c.ac.kr/~syhong/teaching/c/


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

C C++ 무료 개발툴 다운로드

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


MS Visual C++ Toolkit 2003 : http://msdn.microsoft.com/visualc/vctoolkit2003/


볼랜드 BC++ 컴파일러 : http://www.borland.com/products/downloads/download_cbuilder.html


아래의 Compiler 라고 써있는 링크를 클릭하면 다운로드 받을 수 있음.

Compiler Windows 5.5 08/24/2000 8.7 Mb

 







Posted by 나비 나비:D

▩ 포인터(Pointer)


   - Pointer는 지시자의 뜻

   - 기억장치의 주소를 변수의 값으로 사용 하는것이 목적

   - 포인터 변수의 선언: 데이터 타입 *포인터변수명
     . int* pk; int * pk; int *pk;

   - & 연산자: 변수의 메모리상에 데이터가있는 주소를 알려줌
     . int k=10; 이라고 선언했다면 &k라고하는 것은 k라는 변수의 값 10이 있는 메모리의 주소를 가

       져옵니다.
     . k변수의 주소입니다.

   - 출력은 주소는 양수만 있음으로 %u로 출력함

   - * 표시는 포인터 변수 선언문이 아닌 곳 즉 수식문에서는 그 포인터 변수가 가지고 있는 주소의

       값을 가지고 옴

   - 포인터 변수는 Borland C에서는 2바이트, Visual C++에서는 4바이트임

   - 포인터를 사용하면 함수로 인자의 주소를 전달할 수 있어 매우 편리하다.
     scanf("%d", &kuk);의 경우를 이해할 것. 


#include <stdio.h>

void main( void )
{
   int   i, result;
   float fp;
   char  c, s[81], d;


   //printf("%d", d);
   //exit(0);
  
   printf( "\n\n정수, 실수, 문자, 문자열을 입력하세요.\n");

   result = scanf( "%d %f %c %s %d", &i, &fp, &c, s, d);
   printf( "\n입력받은 데이터의 수 %d\n", result );
   printf( "The contents are: %d %f %c %s %c\n", i, fp, c, s, d);

}


   - 포인터 변수는 더하거나 빼는 연산을 할 수 있다.
    . 포인터 변수 + 1: 포인터 변수가 가리키는 곳의 주소가 포인터 변수의 데이터형 만큼 증가한다.
    . *포인터 변수 + 1: 포인터 변수가 값으로 가지고있는 주소가 가르키는 값을 1 증가 시킨다.
    . *(포인터 변수 + 1): 포인터 변수가 가리키는 곳의 주소를 포인터 변수의 데이터형 만큼 증가시

      킨 후 그 값을 1 증가시킨다.



1. 포인터 변수의 선언
     int k=10;
     int *kp = &k;
     printf("%d\n", *kp);  라고 선언하면
     . int *kp는 포인터 변수를 의미한다.
     . &k는 k변수의 주소를 의미한다.
     . 포인터 변수 kp는 k의 주소를 저장한다.
     . kp는 int형 포인터 변수임으로 int형 변수의 주소만 저장할 수 있다.
     . 수식문에서 *kp라고하면 kp가 값으로 가지고있는 주소의 값을 가져온다.



>>>>> 포인터 변수의 선언


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int i;

   printf("i의 값은 %d입니다.\n", i);
   printf("i의 주소는 %X입니다.\n", &i);

   printf("\ni의 값을 입력하세요 : ");
   scanf("%d",&i);
  
   printf("i의 값은 %d입니다.\n", i);
   printf("i의 주소는 %X입니다.\n", &i);
   getch();
 }




>>>>> 정수형 변수의 주소 출력, 주소 할당의 진행 방향의 이해


 #include <conio.h>
 #include <stdio.h>

 void main() {
   int i = 10;
   int j = 20;
   int k = 30;
 
   printf("정수형 변수 i의 값은 %d입니다.\n", i);
   printf("정수형 변수 i의 주소는 %u입니다.\n", &i);

   printf("정수형 변수 j의 값은 %d입니다.\n", j);
   printf("정수형 변수 j의 주소는 %u입니다.\n", &j);

   printf("정수형 변수 k의 값은 %d입니다.\n", k);
   printf("정수형 변수 k의 주소는 %u입니다.\n", &k);
   getch();
 }




>>>>> 다양한 데이터형의 주소 출력


   char c = 'A';
   int i = 10;

 변수의 선언 형태가 위와 같을 경우 Borland C는 int변수는 2바이트를 사용하고 1바이트는 버린다.
   VisualC++은 char는 무조건 4바이트를 사용합니다.


 #include <stdio.h>
 #include <conio.h>

 void main() {
   char c = 'A';
   int i = 10;
   float f = 2.1;
   char c1 = 'A';
   char c2 = 'B';
 
   printf("문자형 변수 c의 값은 %c입니다.\n", c);
   printf("문자형 변수 c의 주소는 %u입니다.\n", &c);

   printf("정수형 변수 i의 값은 %d입니다.\n", i);
   printf("정수형 변수 i의 주소는 %u입니다.\n", &i);

   printf("실수형 변수 f의 값은 %f입니다.\n", f);
   printf("실수형 변수 f의 주소는 %u입니다.\n", &f);

   printf("문자형 변수 c1의 값은 %c입니다.\n", c1);
   printf("문자형 변수 c1의 주소는 %u입니다.\n", &c1);

   printf("문자형 변수 c2의 값은 %c입니다.\n", c2);
   printf("문자형 변수 c2의 주소는 %u입니다.\n", &c2);

   getch();
 }




2. 포인터 변수의 작동

   메모리 할당 모델                               대응하는 소스코드
   =========================================================
       Mapping 변수명    주소    값
   ----------------------------------
              int k             1000    10                int k = 10;      
   ----------------------------------
              int m             996     20                int m = 20;
   ----------------------------------
              int* pk          992     1000              int* pk = &k;
   ----------------------------------
              int* pm          988     996               int* pm = &m;
   ----------------------------------



>>>>> 다양한 데이터형의 포인터 변수의 출력


  #include <stdio.h>
 #include <conio.h>

 void main() {
   char c='A';
   int i=10;
   float f=2.1f;

   char *cp;  //char형 변수의 주소를 저장합니다.
   int *ip;   //int형 변수의 주소를 저장합니다.
   float *fp; //float형 변수의 주소를 저장합니다.

   //각종 타입의 변수의 주소를 포인터 변수에 저장
   cp=&c;
   ip=&i;
   fp=&f;

   printf("문자형 포인터 cp의 값은 %c입니다.\n", *cp);
   printf("정수형 포인터 ip의 값은 %d입니다.\n", *ip);
   printf("실수형 포인터 fp의 값은 %f입니다.\n", *fp);

   printf("char형 변수 c의 주소:%d \n", &c);
  
   getch();
 }



변수   주소   값
-----------------
c      5052   A     <--- c='A'
i      5048   10
f      5044   2.1f
cp     5040   5052  <--- cp = &c;
ip     5036   5048  <--- ip = &i;
fp     5032   5044  <--- fp = &f;

- c: 'A'
- &c: 5052

- cp: 5052
- &cp: 5040
- *cp: 'A'




>>>>> 포인터 변수의 초기화


   char *cp=&c;
   은 char *cp;    cp=&c;로 분리 실행된다.


 #include <stdio.h>
 #include <conio.h>

 void main() {
   char c='A';
   int i=10;
   float f=2.1;

   char *cp=&c;
   int *ip=&i;
   float *fp=&f;

   printf("문자형 포인터 cp의 값은 %c입니다.\n", *cp);
   printf("정수형 포인터 ip의 값은 %d입니다.\n", *ip);
   printf("실수형 포인터 fp의 값은 %f입니다.\n", *fp);
   getch();
 }




UP!!!▷ 'k'라는 변수를 선언해 100을 대입하고, 'kp'라는 포인터 변수를 선언하고,
        'kp'란 포인터 변수를 이용해 'k'의 값을 출력하는 프로그램을 작성하세요.




>>>>> 포인터 변수 자신의 주소 출력하기 1


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int i=10;
   int *ip=&i;  //i 변수의 주소를 ip포인터 변수에 할당합니다.

   printf("==================================================\n");

   printf("i의 값은 %d입니다.\n\n", i);

   printf("i의 자신의 주소는 %u입니다.\n", &i);
   printf("ip의 값은 %u입니다.\n\n", ip);

   printf("ip가 가지고 있는 주소의 값은 %d입니다.\n", *ip);
   printf("ip의 자신의 주소는 %u입니다.\n", &ip);

   printf("==================================================\n");
   getch();
}





3. 아래와 같이 선언된 경우 c 변수는 1바이트를 버린다., Visual C는 무조건 4바이트씩 사용


>>>>> 포인터 변수 자체의 주소 출력


 #include <stdio.h>
 #include <conio.h>

 void main() {
   char c='A';
   int i=10;
   float f=2.1;

   char *cp=&c;
   int *ip=&i;
   float *fp=&f;

   printf("==================================================\n");
   printf("①문자형 변수 c의 값은 %c입니다.\n", c);
   printf("②문자형 변수 c의 주소는 %u입니다.\n", &c);
   printf("③문자형 포인터 cp의 값은 %c입니다.\n", *cp);
   printf("④문자형 포인터 cp의 실제 주소는 %u입니다.\n", &cp);
   printf("⑤문자형 포인터 cp의 참조 주소는 %u입니다.\n", cp);
   printf("==================================================\n");
   printf("⑥정수형 변수 i의 값은 %d입니다.\n", i);
   printf("⑦정수형 변수 i의 주소는 %u입니다.\n", &i);
   printf("⑧정수형 포인터 ip의 값은 %d입니다.\n", *ip);
   printf("⑨정수형 포인터 ip의 실제 주소는 %u입니다.\n", &ip);
   printf("⑩정수형 포인터 ip의 참조 주소는 %u입니다.\n", ip);
   printf("==================================================\n");
   printf("⑪실수형 변수 f의 값은 %f입니다.\n", f);
   printf("⑫실수형 변수 f의 주소는 %u입니다.\n", &f);
   printf("⑬실수형 포인터 fp의 값은 %f입니다.\n", *fp);
   printf("⑭실수형 포인터 fp의 실제 주소는 %u입니다.\n", &fp);
   printf("⑮실수형 포인터 fp의 참조 주소는 %u입니다.\n", fp);
   printf("==================================================\n");
   getch();
}


--출력 결과
==================================================
①문자형 변수 c의 값은 A입니다.
②문자형 변수 c의 주소는 1245052입니다.
③문자형 포인터 cp의 값은 A입니다.
④문자형 포인터 cp의 실제 주소는 1245040입니다.
⑤문자형 포인터 cp의 참조 주소는 1245052입니다.
==================================================
⑥정수형 변수 i의 값은 10입니다.
⑦정수형 변수 i의 주소는 1245048입니다.
⑧정수형 포인터 ip의 값은 10입니다.
⑨정수형 포인터 ip의 실제 주소는 1245036입니다.
⑩정수형 포인터 ip의 참조 주소는 1245048입니다.
==================================================
⑪실수형 변수 f의 값은 2.100000입니다.
⑫실수형 변수 f의 주소는 1245044입니다.
⑬실수형 포인터 fp의 값은 2.100000입니다.
⑭실수형 포인터 fp의 실제 주소는 1245032입니다.
⑮실수형 포인터 fp의 참조 주소는 1245044입니다.
==================================================




4. 포인터 변수의 이용
 #include <stdio.h>
 #include <conio.h>

 void main() {
   int i=20;
   int *ip;
   int *ip2;

   ip = &i;

   printf("ip       : %u\n", ip);  //1245052
   printf("*ip      : %d\n", *ip); //20
   printf("i의 주소 : %u\n\n", &i); //5052


   *ip = 50;

   printf("*ip      : %d\n", *ip);  //50
   printf("i의 주소 : %u\n", &i);    //5052
   printf("ip 포인터 변수 자체의 주소 : %u\n\n", &ip); //5048

   ip2 = &i;  //
   *ip = 100;

   printf("i의 값 : %d\n", i);    //100
   printf("ip2    : %u\n", ip2);  //5052
   printf("*ip    : %d\n", *ip);  //100
   printf("*ip2   : %d\n", *ip2); //100
   printf("ip2 포인터 변수 자체의 주소 : %u\n\n", &ip2); //5044
   getch();

 }

Posted by 나비 나비:D
태그 C

▩ 다차원 배열


   - 1차원배열의 연속적인 형태
   - 논리적으로 테이블의 구조를 가지고 있으나 메모리상으로는 1차원배열의 연속임
   - 배열 처리시 일반적으로 for문이 2개이상 사용되는 경우가 많음
   - 배열명은 배열의 첫 요소의 주소를 가지고 있으나 상수형태임으로 포인터 변수처럼 배열의 주

     소를 증감할 수 없음


1. 2차원 배열
   - 자료형  배열 이름[첨자1, 행][첨자2, 열]
   - 2차원 배열의 선언
     . int arr[3][3];
     . char arr[3][3] =
       {
         {'A', 'B', 'C'},
         {'D', 'E', 'F'},
         {'G', 'H', 'I'},
       };


2. 3차원 배열
   - 자료형  배열 이름[첨자1, 면][첨자2, 행][첨자3, 열]
   - 3차원 배열의 선언
   int arr[2][3][4] =
   {
     {
       {1, 2, 3, 4},
       {5, 6, 7, 8},
       {9, 10, 11, 12}
     },
     {
       {51, 52, 53, 54},
       {55, 56, 57, 58},
       {59, 60, 61, 62}
     }
   };





▩ 다차원 배열 예제



>>>>> 2차원 배열의 사용


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int arr[3][4];
   int k, m;

   for(k=0; k<3; k++) {
      for(m=0; m<4; m++){
        arr[k][m]=k+m;
//        printf("arr[%d][%d]=%d  ", k, m, k+m);
        printf("k=%d m=%d  k+m=%d / ", k, m, k+m);
      }
      printf("\n");
   }

   printf("\n");

   for(k=0; k<3; k++) {
      for(m=0; m<4; m++){
        printf("arr[%d][%d] = %d  ", k, m, arr[k][m]);
      }
      printf("\n");
   }
   getch();
 }


UP!!!▷ 배열에 2의 배수로 입력되어 출력되도록 수정하세요.



>>>>> 2차원 배열에 값을 입력받아 역순으로 출력하는 프로그램


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int arr[2][3];
   int k, m;

   for(k=0; k<2; k++) {
      for(m=0; m<3; m++) {
        printf("arr[%d][%d]의 값을 입력하세요 : ", k, m);
        scanf("%d", &arr[k][m]);
      }
   }

   for(k=1; k>=0; k--) {
      for(m=2; m>=0; m--){
        printf("arr[%d][%d] = %d  ", k, m, arr[k][m]);
      }
      printf("\n");
   }
   printf("\n");
   printf("for문이 끝난 후의 k, m값:k=%d m=%d\n", k, m);
   getch();
 }



>>>>> 2차원 배열의 초기화 1


 #include <stdio.h>
 #include <conio.h>

 void main() {
   char arr[3][3] =
   {
     {'A', 'B', 'C'},
     {'D', 'E', 'F'},
     {'G', 'H', 'I'},
   };
   int k, m;

   for(k=0; k<3; k++) {
      for(m=0; m<3; m++){
         printf("arr[%d][%d] = %c  ", k, m, arr[k][m]);
      }
      printf("\n");
   }
   getch();
 }



>>>>> 2차원 배열의 초기화 2


 #include <stdio.h>
 #include <conio.h>

 void main() {
   char arr[3][3] =
   {
     {'A', 'B', 'C'},
     {'D', 'E', 'F'},
     {'G', 'H', 'I'},
   };
   int k, m;

   printf("* 원래의 값 * ===============================\n");
   for(k=0; k<3; k++) {
      for(m=0; m<3; m++){
         printf("arr[%d][%d] = %c  ", k, m, arr[k][m]);
      }
      printf("\n");
   }

   printf("* 변경된 값 * ===============================\n");
   for(k=0; k<3; k++) {
      for(m=2; m>=0; m--){
         printf("arr[%d][%d] = %c  ", k, m, arr[k][m]);
      }
      printf("\n");
   }
   getch();
 }



>>>>> 3차원 배열의 사용


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int arr[2][3][4] =
   {
     {
       {1, 2, 3, 4},
       {5, 6, 7, 8},
       {9, 10, 11, 12}
     },
     {
       {51, 52, 53, 54},
       {55, 56, 57, 58},
       {59, 60, 61, 62}
     }
   };
   int k, m, n;

   for(k=0; k<2; k++) {
      for(m=0; m<3; m++) {
  for(n=0; n<4; n++){
     printf("arr[%d][%d][%d] = %d  ", k, m, n, arr[k][m][n]);
  }
            printf("\n");
      }
   printf("\n");
   }
   getch();
 }

Posted by 나비 나비:D
태그 C

▩ 배열의 개념과 1차원 배열


   - 같은 데이터형을 가진 데이터들의 집합
   - 데이터의 형태가 집합적인 형태를 가지면서 같은 처리 방식을 가질 경우 사용
   - 배열은 인덱스를 이용하여 각 요소가 구분됨
   - 배열의 인덱스는 0부터 n-1까지 사용함
   - 배열 처리시 일반적으로 for문을 1개 정도 동반함
   - 배열의 선언:
     . int arr[5]; - 5개의 정수를 저장할 수 있는 배열을 선언합니다.
     . int arr[5] = {1,2,3,4,5};
       5개의 정수를 저장할 수 있는 배열을 선언하면서 5개의 정수를 배열에 저장합니다.

1. 배열에 값을 저장한 다음 출력하는 일반적인 프로그램

 #include <stdio.h>
 #include <conio.h>

 void main() {
   int i;
   int arr[10];

   for(i=0; i<10; i++)
      arr[i]=i;

   for(i=0; i<10; i++)
      printf("arr[%d] = %d\n", i, arr[i]);
   getch();
 } 




▩ 1차원 배열, 2차원 배열 예제



>>>>> 1차원 배열의 사용


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int k;
   int arr[10];

   for(k=0; k<10; k++)
      arr[k]=k;

   for(k=0; k<10; k++)
      printf("arr[%d] = %d\n", k, arr[k]);
   getch();
 }


UP!!!▷ 배열에 들어가는 값이 1부터 10이 되도록 수정하세요.


UP!!!▷ tot란 변수에 배열의 모든 값의 합을 구해서 출력해 보세요.


UP!!!▷ 배열에 들어가 있는 값중에 짝수인 수들의 합을 구해서 출력해 보세요.



>>>>> 영어 대문자를 배열에 저장하고, 역순으로 출력하는 프로그램


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int k;
   char alpha[26];

   for(k=65; k<=90; k++){
      alpha[k-65]=k;
   }

   for(k=90; k>=65; k--){
      printf("alpha[%d] = %c\n", k-65, alpha[k-65]);
   }
   getch();
 }


UP!!!▷ 알파벳이 Z부터 역으로 5개씩 출력되는 프로그램으로 수정하세요.


UP!!!▷ 알파벳이 A부터 5개씩 출력되는 프로그램으로 수정하세요.




▩ 최대/최소값 추출의 원리


   - MAX변수에는 최소값을 초기값으로 준다.
   - MIN변수에는 최대값을 초기값으로 준다.
     0 ~ 3000 사이의 데이터를 기준으로 한다면 max=0, min=3000으로 주어야 한다.

   - if문을 이용하여 최대값보다 큰 값이 나타나면 최대값에 새로운 값을 대입한다.
     if (max < readData) max = readData;

   - if문을 이용하여 최소값보다 작은 값이 나타나면 최소값에 새로운 값을 대입한다.
     if (min > readData) min = readData;



>>>>> 배열의 이용(입력 수의 범위:0~3000)


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int i, mx_cn=1, mn_cn=1;
   int max=0, min=3000;
   int jum[5];

   for(i=0; i<5; i++) {
      printf("%d번째 수를 입력하세요 : ", i+1);
      scanf("%d", &jum[i]);
   }

   for(i=0; i<5; i++) {
      if(jum[i]>max) {
  max=jum[i];
  mx_cn=i+1;
      }
      if(jum[i]<min) {
  min=jum[i];
  mn_cn=i+1;
      }
   }
   printf("\n");
   printf("최대값 : %d, 입력번호 : %d\n", max, mx_cn);
   printf("최소값 : %d, 입력번호 : %d\n", min, mn_cn);
   getch();
 }



>>>>> 배열의 크기


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int k;
   int num[] = {25, 36, 45, 45};
   char alpha[] = {'A', 'B', 'E'};

   for(k=0; k<4; k++)
      printf("배열 num[%d]의 크기 : %d\n", k, sizeof num[k]);
      printf("배열 num의 크기 : %d\n", sizeof(num));

   for(k=0;k<3;k++)
      printf("배열 alpha[%d]의 크기 : %d\n", k, sizeof alpha[k]);
      printf("배열 alpha의 크기 : %d\n", sizeof(alpha));
   getch();
 }




>>>>> 문자열의 초기화


 #include <stdio.h>
 #include <conio.h>

 void main() {
   char alpha1[] = {'A', 'B', 'C', 'D', 'E'};
   char alpha2[] = {'A', 'B', 'C', 'D', 'E', '\0'};
   char alpha3[] = "ABCDE";

   printf("배열 alpha1의 내용 : %s\n", alpha1);
   printf("배열 alpha1의 크기 : %d\n", sizeof(alpha1));
   printf("\n");
   printf("배열 alpha2의 내용 : %s\n", alpha2);
   printf("배열 alpha2의 크기 : %d\n", sizeof(alpha2));
   printf("\n");
   printf("배열 alpha3의 내용 : %s\n", alpha3);
   printf("배열 alpha4의 크기 : %d\n", sizeof(alpha3));
   getch();
 }




>>>>>  문자 배열의 이용


 #include <stdio.h>
 #include <conio.h>

 void main() {
   char fm[]= "File MENU";
   char em[]= "Edit MENU";
   char hm[]= "Help MENU";
   char wm[]= "Wrong Input";
   char c;

   printf("메뉴 코드를 입력하세요 : ");
   if((c=getch()) >= 97) c -= 32;

   while(c!='X') {
     switch(c) {
     case 'F' :
  printf("\n%s\n", fm);
  break;
     case 'E' :
  printf("\n%s\n", em);
  break;
     case 'H' :
  printf("\n%s\n", hm);
  break;
     default :
  printf("\n%s\n", wm);
     }
     printf("계속하려면 메뉴 코드를, 종료하려면 X를 누르세요.");
     if((c=getch()) >= 97) c -= 32;
   }
   printf("\n프로그램을 종료합니다.");
   getch();
 }





[참고] 데이터 정렬의 원리
   - swap 알고리즘
     a[0]=100, a[1]=200의 값을 바꾸는 경우, temp는 임시변수

     temp=a[0];
         ↙
     a[0]=a[1];
         ↙
     a[1]=temp;


           temp
       ①↗    ↘ ③
     a[0]   ←   a[1]  
            ② 

       기준수 a[0], 총 비교횟수 4회
       ↓
 비교1 500      400 300 100 200
 비교2 400      500 300 100 200 a[0], a[1] 비교후의 수
 비교3 300      500 400 100 200 a[0], a[2] 비교후의 수
 비교4 100      500 400 300 200 a[0], a[3] 비교후의 수
          100      500 400 300 200 a[0], a[4] 비교후의 수


            기준수 a[1], 총 비교횟수 3회
           ↓
 비교1 100 500      400 300 200
 비교2 100 400      500 300 200 a[1], a[2] 비교후의 수
 비교3 100 300      500 400 200 a[1], a[3] 비교후의 수
          100 200      500 400 300 a[1], a[4] 비교후의 수


                     기준수 a[2], 총 비교횟수 2회
                    ↓
 비교1 100 200      500 400 300
 비교2 100 200      400 500 300 a[2], a[3] 비교후의 수
          100 200      300 500 400 a[2], a[4] 비교후의 수


                        기준수 a[3], 총 비교횟수 1회
                       ↓
 비교1 100 200 300      500 400
          100 200 300      400 500 a[3], a[4] 비교후의 수


for (i=0; i<=3; i++)  <-- 기준수
   for(j=i+1; j<=4; j++)  <-- 대응수



>>>>> 5개의 정수를 입력받아 정렬하는 프로그램


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int i, j, t;
   int jum[5];

   for(i=0; i<5; i++) {
   printf("%d번째 수를 입력하세요 : ", i+1);
   scanf("%d", &jum[i]);
   }
   printf("\n");
   printf("입력된 자료\n");

   for(i=0; i<5; i++) {
   printf("%d ", jum[i]);
   }

   for(i=0; i<=3; i++) {
      for(j=i+1; j<=4; j++) {
         if(jum[i]>jum[j]) {
           t=jum[i];
           jum[i]=jum[i];
           jum[j]=t;
  }
      }
   }
   printf("\n정렬된 자료\n");

   for(i=0; i<5; i++) {
      printf("%d ", jum[i]);
   }
   getch();
 }

Posted by 나비 나비:D
태그 C

▩ Call By Value를 이용한 함수로의 데이터 전달 방법


   - Call By Value로 사용되는 데이터타입은 원시데이터 타입인 char, short int, int, float... 수

     치 형태의 데이터 전부 해당
     ※ 문자열이나 주소 형태의 데이터는 Call By Reference입니다.

1. EXE 프로그램의 Memory 사용영역(System Memory Model)
   - 기본적으로 64Kb의 조각 메모리를 5가지 단계의 방법으로 사용하는 모델을 가지고 있습

     니다.
┌────────────┐CS: Code Segment
│[코드 영역]                   │
│C의 Source가 등록되는  │
│영역, 각종 함수             │
├────────────┤DS: Data Segment
│[Data 영역]                   │
│static변수,                     │
│static 메소드 저장          │
│한번 초기화가 진행되면  │
│재 초기화가 발생안됨     │
├────────────┤SS: Stack Segment
│[Stack 영역]                  │
│함수가 사용하는 영역     │
│함수 안에서 선언되는     │
│지역변수가 선언,           │
│함수 처리가 끝나면        │
│메모리가 자동으로         │
│회수됨, 지역변수 삭제    │
├────────────┤
│[Heap 영역]                  │
│malloc() 함수를 이용해   │
│동적으로 메모리를 할당 │
│하는 영역                      │
│개발자 필이 메모리        │
│해야만 함                      │
└────────────┘

 

2. Call By Value 방식을 이용한 데이터의 전달, 메뉴 코드를 입력받아 메뉴 문자열을 출력하는 프로그램
 #include <stdio.h>
 #include <conio.h>

 void print_menu(char m) {
   switch(m) {
      case 'F' :
        printf("\nFile MENU\n");
        break;
      case 'E' :
        printf("\nEdit MENU\n");
        break;
      case 'H' :
        printf("\nHelp MENU\n");
        break;
      default :
        printf("\n잘못된 입력입니다.\n");
   }
 }

 main() {
   char c;
   printf("메뉴 코드를 입력하세요 : ");
   if((c=getch()) >= 97) c -= 32;

   while(c!='X') {
     print_menu(c);
     printf("메뉴코드를 입력하세요. 종료하려면 X를 누르세요.");
     if((c=getch()) >= 97) c -= 32;
   }
   printf("\n프로그램을 종료합니다.");
   getch();
 }


3. 입력된 값의 제곱값을 구하는 프로그램
 #include <stdio.h>
 #include <conio.h>

 long int sqr(int i) {
   long int res;

   if(i>0) {
     res=(long)i *(long)i;
     return res;
   }
   else if(i==0)
     return 0;
   else
     return -1;
 }

 main() {
   int a;
   char c;

   printf("시작하려면 ENTER를 누르세요.\n");
   c=getch();
   while(c!='X') {
     printf("\n계산하려는 숫자를 입력하세요 : ");
     scanf("%d", &a);
     printf("%d의 제곱은 %ld입니다.\n", a, sqr(a));
     printf("계속하려면 아무키나 누루세요, 종료하려면 X를 누르세요.");
     if((c=getch()) >= 97) c -= 32;
   }
   printf("\n프로그램을 종료합니다.");
   getch();
 }




4. 국어, 영어, 수학 점수를 (1~100점) main()함수에서 입력받아 총점은 tot(kor, eng, mat) 함수에

   서, 평균은 ave(kor, eng,mat) 함수에서 구한후 main()함수에서 출력하는 프로그램을 만들어 보

  시오.

 #include <stdio.h>
 #include <conio.h>

 int tot(int kor, int eng, int mat);
 float ave(int kor, int eng, int mat);

 void main() {
   int kor, eng, mat;
     
   printf("국어 점수를 입력하세요 : ");
   scanf("%d", &kor);
   printf("영어 점수를 입력하세요 : ");
   scanf("%d", &eng);
   printf("수학 점수를 입력하세요 : ");
   scanf("%d", &mat);

   printf("\n국어\t영어\t수학\t총점\t평균\n");
   printf("--------------------------------------\n");
   printf("%d\t%d\t%d\t%d\t%5.1f\n", kor, eng, mat, tot(kor,eng,mat), ave(kor,eng,mat));
   getch();
 }
 
 int tot(int kor, int eng, int mat){
    int tot;
    tot = kor+eng+mat;
    return tot;
 }

float ave(int kor, int eng, int mat){
    float ave;
    ave = (kor+eng+mat)/3.0;
    return ave;
}

/*
소스영역    Stack영역
--------    ---------
main()      int kor   90 -┐
               int eng   90 │
               int mat   90  │
---------   ---------  │
tot()         int kor ←-─┘90 복사    
               int eng
               int mat
               int tot
---------   ---------
ave()       int kor
              int eng
              int mat
              float ave
*/



▷ 아래처럼 학점이 출력되는 프로그램으로 수정하세요. (90~100: A, 80~89: B, 70~79:C, 60~69: D, 59이하:F)

국어 점수를 입력하세요 : 85
영어 점수를 입력하세요 : 90
수학 점수를 입력하세요 : 90

과목: 국어    영어    수학    총점    평균
-------------------------------------------
점수: 85      90      90      265      88.3
학점: B       A       A     



▩ 함수의 설계


1. 지하철 승차권 판매 함수 설계
#include <stdio.h>
#include <conio.h>

//처리 로직 시작 함수 void sale(점검중|판매중)
void sale(int k);

//목적지 입력 함수
int target(); 

//동전 금액 입력 void coin(목적지 금액)
void coin(int kum);

//승차권 인쇄
//void print_ticket(목적지 금액,입력 금액);
void print_ticket(int kum, int tot);

void main(){
    int k;  //1:판매중, 2:점검중 구분

    sale(1);  
    getch();
}

void sale(int k){
    int sw=1;
    if (k == 0){
        printf("판매기 점검중\n");   
        return;
    }

    if (k == 1){
        printf("판매기 작동중\n");
        while(sw){
            sw=target();
        }
    }

}

int target(){
    int kum;  //금액 입력
    int sw=1; //0: 정상 금액, 1: 비정상 금액
   
    printf("                  승차권                      \n");
    printf("----------------------------------------------\n");   
    printf("승차권: 700 750 800 850 900 950 1000 1050 1100\n\n");

    while(sw){
        printf("목적지에 해당하는 금액을 눌러 주세요. ");
        scanf("%d", &kum);

        if (kum==9999) {
            printf("\n점검중입니다.\n");
            return 0;
        }else if (kum < 700){
            printf("700원 이하 승차권은 없습니다.\n");
        }else if (kum > 1100) {
            printf("1100원을 초과하는 승차권은 없습니다.\n");
        }else if (kum % 50) {
            printf("승차권은 50원 단위입니다.\n");
        }else{
            sw=0;
        }
    }
    coin(kum);
    return 1;
}

void coin(int kum){
    int sw=1;  //0: 정상 금액, 1: 비정상 금액
    int tot=0; //입력한 금액의 합계
    int in;    //금액을 입력 받는 변수
   
    printf("\n\n");
    printf("입력 가능 화폐(동전/지폐 가능)\n");
    printf("------------------------------\n");   
    printf("종 류: 10 50 100 500 1000\n\n");

    while(sw){
        printf("금액 투입!!!. ");
        scanf("%d", &in);

        if (in < 10){
            printf("10원 이하 금액은 사용할 수 없습니다.\n");
        }else if (in > 1000) {
            printf("1000원을 초과하는 지폐는 사용할 수 없습니다.\n");
        }else if (in % 10) {
            printf("입력 금액은 10원 단위까지 가능합니다.\n");
        }else{
            tot = tot+in;
            if( tot >= kum) sw=0;
            printf("\n현재 입금한 금액:%5d\n", tot);
        }
    }
    print_ticket(kum, tot);
}

void print_ticket(int kum, int tot){
    printf("\n\n");
    printf("%5d원 금액의 승차권이 발매 되었습니다.\n", kum);
    printf("남은 잔액은 %5d원 입니다.\n", tot-kum);
    printf("지하철을 이용해 주셔서 감사합니다.!!!\n\n");
}

Posted by 나비 나비:D
태그 C

▩ 함수(function)


1. 일반적인 프로그램의 구성
   ┌----- 메인 루틴
   │
   ├----- 프로시저(Procedure) : Return 값이 없음
   │
   └----- 함수(Function) : Return 값이 있음
    


2. C언어의 함수 구성 : main() 함수와 일반 함수로 구성됨
   ┌----- 메인 함수 main()
   │
   │
   └----- 함수(Function) : Return 값이 있음, Return 값이 있음


3. 함수의 기본 구성
   return 형 함수명(인수형과 가인수의 나열...){
       함수내 변수 선언;
       실행문;
   }

☞ 함수의 작성 규칙
   1) main() 함수는 기능을 정의 하는 함수가 아니라 다른 함수를 이용하는 통제소의 역활을 한다.
      따라서 처리 로직을 main()안에 두면 안된다.
   2) 가인수와 실인수의 데이터 타입과 갯수는 반드시 일치 시킨다.
   3) 함수안에 선언되는 변수는 모두 지역변수이다. 따라서 메인에서는 사용할 수 없다.
   4) 함수를 처리한 후 함수의 리턴값의 데이터형은 함수의 원형에 선언된 타입과 일치해야한다.
   5) 변수명과 함수명이 같으면 함수의 인식이 안된다.


4. 프로토타입을 선언하는 이유
   - main() 함수로 하여금 어떤 함수가 이 프로그램에 선언되어 있는 지 알려주는 역활을 함
   - 사용자 정의 함수가 main()앞에 있으면 프로토타입이 필요 없고, main()뒤에 선언되면 반드시 프로토타입을 선언해야 한다.


5. 실인수와 가인수의 의미
   - 실인수 : 실제로 값을 가지고 있는 함수를 호출하는 측의 변수
   - 가인수 : 임시로 함수에서 지역 변수로 사용되는 변수


6. 값의 return 유형
   - 상황에 따라 1개이상의 return문이 올 수 있다.
   - return a;
   - return (a);
   - return 1;
   - return a+b;

☞ return을 사용하는 이유
   1) 함수에서 처리 값을 돌려줄 경우  
   2) 함수의 실행을 종료하는 역활을 한다.


7. void 형 함수 : 값을 return 하지 않는 함수, 주로 출력을 하는데 사용
   - void main(){}


8. void 형 인수 : 인수를 받지 않는 함수
   - void kkk(void){ } == void kkk(){ }




▩ 함수응용 예제


1. 함수 원형(Prototype) 정의의 이해
//함수는 한번 재작하면 반복해서 호출할 수 있습니다.
//따라서 소스를 매우 구조적으로 만들어 줍니다.

 #include <stdio.h>
 #include <conio.h>

//함수 선언, 함수 원형 선언, 함수 프로토 타입
 void print_line();

 void main() {
   int x, y;
   char c;

     //1회는 무조건 실행됨으로 do~while()사용
     do {
       print_line();
       printf("\n 첫번째 수를 입력하세요 : "); scanf("%d", &x);
       print_line();
       printf("\n 두번째 수를 입력하세요 : "); scanf("%d", &y);
       print_line();
       printf("\n %d 곱하기 %d는 %d입니다.\n", x, y, x*y);
       print_line();
       printf("\n 계속=>Enter, 종료=>Q");
       c=(getch());
     } while(c!='Q');
     getch();
 }

 //함수 정의
 void print_line() {
   int i;
   for(i=1; i<=30; i++){
      printf("-");
   }
 }




2. 기본적인 함수의 사용

▷ 국어, 영어, 수학 점수를 (1~100점) main()함수에서 입력받아
   총점은 tot(kor, eng, mat) 함수에서, 평균은 ave(kor, eng,mat) 함수에서 구한후 main()함수에서
   출력하는 프로그램을 만들어 보시오.



>>>>> 처리 형태 1


 #include <stdio.h>
 #include <conio.h>

 //              ┌---- 가인수
 //함수 선언  ↓
 int tot(int kor, int eng, int mat);
 float ave(int kor, int eng, int mat);
 //↑
 //└---- return 되는 데이터의 타입

 void main() {
   int kor, eng, mat;
     
   printf("국어 점수를 입력하세요 : ");
   scanf("%d", &kor);
   printf("영어 점수를 입력하세요 : ");
   scanf("%d", &eng);
   printf("수학 점수를 입력하세요 : ");
   scanf("%d", &mat);

   printf("\n국어\t영어\t수학\t총점\t평균\n");
   printf("--------------------------------------\n");
   printf("%d\t%d\t%d\t%d\t%5.1f\n", kor, eng, mat, tot(kor,eng,mat), ave(kor,eng,mat));
   getch(); //                                                                  │
 }//                                                                               │
 //                                                                                │
 //             ┌-------------------------------------------┘
 //함수정의  ↓실인수, 값 복사가 발생함, 실인수 <=== 가인수
 int tot(int kor, int eng, int mat){
    int tot;
    tot = kor+eng+mat;
    return tot; //정수형 합계 리턴
 }

float ave(int kor, int eng, int mat){
    float ave;
    ave = (kor+eng+mat)/3.0;
    return ave;
}



>>>> 출력결과:


국어 점수를 입력하세요 : 85
영어 점수를 입력하세요 : 90
수학 점수를 입력하세요 : 90

국어    영어    수학    총점    평균
--------------------------------------
85       90       90       265     88.3



>>>>> 처리 형태 2


 #include <stdio.h>
 #include <conio.h>

 int tot(int kor, int eng, int mat);
 float ave(int kor, int eng, int mat);

 void main() {
   int kor, eng, mat, total;
   float average;
     
   printf("국어 점수를 입력하세요 : ");
   scanf("%d", &kor);
   printf("영어 점수를 입력하세요 : ");
   scanf("%d", &eng);
   printf("수학 점수를 입력하세요 : ");
   scanf("%d", &mat);

   total = tot(kor, eng, mat);
   average = ave(kor, eng, mat);

   printf("\n국어\t영어\t수학\t총점\t평균\n");
   printf("--------------------------------------\n");
   printf("%d\t%d\t%d\t%d\t%5.1f\n", kor, eng, mat, total, average);
   getch();
 }
 
 int tot(int kor, int eng, int mat){
    int tot;
    tot = kor+eng+mat;
    return tot;
 }

float ave(int kor, int eng, int mat){
    float ave;
    ave = (kor+eng+mat)/3.0;
    return ave;
}



>>>>> 처리형태 3(권장 아님, 전역변수 사용은 최대한 피해야 합니다.)


 #include <stdio.h>
 #include <conio.h>

 void tot();
 void ave();

 int kor, eng, mat, total;
 float average;

 void main() {
   printf("국어 점수를 입력하세요 : ");
   scanf("%d", &kor);
   printf("영어 점수를 입력하세요 : ");
   scanf("%d", &eng);
   printf("수학 점수를 입력하세요 : ");
   scanf("%d", &mat);

   tot();
   ave();

   printf("\n국어\t영어\t수학\t총점\t평균\n");
   printf("--------------------------------------\n");
   printf("%d\t%d\t%d\t%d\t%5.1f\n", kor, eng, mat, total, average);
   getch();
 }
 
 void tot(){
    total = kor+eng+mat;
 }

 void ave(){
    average = (kor+eng+mat)/3.0;
}



▩ 함수의 반복 호출


#include <stdio.h>
 #include <conio.h>

 void print_long(void) {
   int i;
   for(i=0; i<=30; i++){
      printf("*");
   }
   printf("\n");
 }

 void print_short(void) {
   int i;

   printf("*");
   for(i=0; i<=28; i++){
      printf(" ");
   }
   printf("*");
   printf("\n");
 }

 void main() {
   int x;

   print_long();
   for(x=0; x<=5; x++)
      print_short();
   print_long();
   getch();
 }



▩ 함수의 중첩 예제 : main()함수안에서 호출한 함수안에 함수가 있는 경우


 #include <stdio.h>
 #include <conio.h>

 void print_long(void) {
   int i;
   for(i=0; i<=30; i++)
      printf("*");
 }

 void print_short(void) {
   int i;
   for(i=0; i<10; i++)
      printf(" ");

   for(i=0; i<10; i++)
      printf("*");
 }

 void print_one(void) {
   int j;
   for(j=0; j<=5; j++) {
      print_long();
      printf("\n");
   }
 }

 void print_two(void) {
   int k;
   for(k=0; k<=10; k++) {
      print_short();
      printf("\n");
   }
 }

 void main() {
   print_one();
   print_two();
   print_one();
   getch();
 }


☞ 함수원형을 추가한 후의 소스 (권장 유형)

 #include <stdio.h>
 #include <conio.h>

 void print_one(void);   //print_long() 호출
 void print_two(void);   //print_short() 호출
 void print_long(void);  //특수 문자를 30개 출력
 void print_short(void); //공백을 10개 출력, 특수문자 10개 출력
 

 void main() {
   print_one();
   print_two();
   print_one();
   getch();
 }


 void print_one(void) {
   int j;
   for(j=0; j<=5; j++) {
      print_long();
      printf("\n");
   }
 }

 void print_two(void) {
   int k;
   for(k=0; k<=10; k++) {
      print_short();
      printf("\n");
   }
 }

 void print_long(void) {
   int i;
   for(i=0; i<=30; i++)
      printf("*");
 }

 void print_short(void) {
   int i;
   for(i=0; i<10; i++)
      printf(" ");

   for(i=0; i<10; i++)
      printf("*");
 }

Posted by 나비 나비:D
태그 C

▩ C언어를 이용한 필수 기초 알고리즘 - 제어 반복문의 활용 1


1. 100~999 사이에 7의 배수의 갯수와 합을 구하는 프로그램을 작성하세요. 답 : 128, 70336
 
#include <stdio.h>
#include <conio.h>

void main(){
    long int i,cnt,sum,nmg;

    cnt=sum=0L;

    for(----- ? -----){
        nmg = ----- ? -----;
        if(nmg)
            continue;
  else {
         printf("현재 발견된 7의 배수: %d\n", i);
            sum += i;
            cnt++;
        }
    }
    printf("\n 7의 배수의 갯수: %5ld\n  합 : %5ld\n",cnt,sum);
    getch();


▷ 7의 배수를 한줄에 15개씩 출력하는 프로그램을 작성하세요.


2. 100~999 사이에 7의 배수가 아닌 수들의 갯수와 합을 구하는 프로그램을 작성하세요.

답 : 772, 424214


3. 최대값 , 최소값을 구하는 프로그램을 제작 하세요.

#include <stdio.h>
#include <conio.h>

void main(){
    int  no,data,max,min,cnt;

    printf("입력할 자료의 갯수는 ? ");
    scanf("%d",&no);
    cnt=1;
   
    printf("데이터를 입력해 주세요.\n------------------------\n");

    scanf("%d",&data);

    ----- ? -----

    do {
        cnt++;
        scanf("%d",&data);
        if( max < data ) max = data;
        if( min > data ) min = data ;
    } while( cnt < no );

    printf("\n   최대값 : %5d\n   최소값 : %5d\n", max, min);
    getch();
}


4. 5개의 정수를 입력 받아 수의 범위를 구하는 프로그램을 작성하시오.

#include <stdio.h>
#include <conio.h>

void main(){
    int  tbl[5], i, max, min, range;

    for(i=0;i<5;i++){
     scanf("%d", &tbl[i]);
    }

    printf("입력받은 데이터 : \n");

    for(i=0;i<5;i++){
        printf("%5d",tbl[i]);
    }

    ----- ? -----
 
    for(i=1;i<5;i++){
        if(max<tbl[i]) max=tbl[i];
        if(min>tbl[i]) min=tbl[i];
    }

    ----- ? -----
   
    printf("\n\n   입력받은 수의 범위 : %5d\n",range);
    getch();
}                                                   


5. 하나의 수를 입력받아 양수, 음수 인지 출력하는 프로그램 작성하세요.


6. 하나의 수를 입력받아 부호를 무조건 양수로 바꾸어 출력하는 프로그램을 작성하세요.


7. 세 과목의 점수(0~100)를 입력받아 평균을 구한 후 평균이 90점 이상이면 "A", 80이상이면 "B", 70 이상이면 "C", 60 이상이면 "D", 그렇지 않으면 "F"를 출력하는 프로그램을 작성하세요.

 #include <stdio.h>
 #include <conio.h>

 void main() {
   int kor, eng, mat, ave;
             
   printf("국어 점수를 입력하세요 : ");
   scanf("%d", &kor);
   printf("영어 점수를 입력하세요 : ");
   scanf("%d", &eng);
   printf("수학 점수를 입력하세요 : ");
   scanf("%d", &mat);
   --------?--------;
   printf("점수의 평균은 %d입니다.\n", ave);

   switch(--?--) {
     case 10 :
     case 9 :
 printf("당신의 평가는 A입니다.");
 break;
     case 8 :
 printf("당신의 평가는 B입니다.");
 break;
     case 7 :
 printf("당신의 평가는 C입니다.");
 break;
     case 6 :
 printf("당신의 평가는 D입니다.");
 break;
     default :
 printf("당신의 평가는 F입니다.");
   }
    getch();
 }



▩ 제어 반복문 활용 2


1. 아래 문제의 ---?--- 칸을 채우세요. 대문자로 변경하는 로직이 들어가야 합니다.

 #include <stdio.h>
 #include <conio.h>

 void main() {
   char c;

   do {
     printf("메뉴 코드를 입력하세요.(F, E, H, X, 기타) : ");
     c=getch();
     putchar(c);
     if(c>=97) c -= --?--;

     switch(c) {
       case 'F' :
           printf("\nFile MENU\n");
       break;
       case 'E' :
       printf("\nEdit MENU\n");
       break;
       case 'H' :
       printf("\nHelp MENU\n");
       break;
       case 'X' :
       printf("\n프로그램을 종료합니다.\n");
       break;

       default :
       printf("\n잘못된 입력입니다.\n");
     }
   } while(c!='X');
   getch();
 }


2. 1부터 3까지 a와 b의 값를 출력하는 데, a, b가 같은 경우는 출력되지 않도록 프로그램을 작성해 보세요.

출력 결과:

a=1 b=2
a=1 b=3
-------
a=2 b=1
a=2 b=3
-------
a=3 b=1
a=3 b=2


 #include <stdio.h>
 #include <conio.h>

 void main() {
   int a, b;

   printf("=========\n");
   for(a=1; a<=3; a++) {
      for(b=1; b<=3; b++) {
 if(a--?--b){
    --?--
           }

 printf("A=%d, B=%d\n", a ,b);
      }
   printf("=========\n");
   }
   getch();  
 }


3. 제어문을 이용하여 아래와 같이 출력되는 프로그램을 제작해 보세요.

 1
 2   3
 4   5   6
 7   8   9  10
11  12  13  14  15


4. 제어문을 이용하여 아래와 같이 출력되는 프로그램을 제작해 보세요.

 3
 6   9
12  15  18
21  24  27  30
33  36  39  42  45


5. 제어문을 이용하여 아래와 같이 출력되는 프로그램을 제작해 보세요.

                     1
                2   3
            4   5   6
       7   8   9  10
11  12  13  14  15


#include <stdio.h>
#include <conio.h>

main(){
 int i, j, cnt;
           cnt=0;
 for(----- ? -----){
  for(j=1; j<=5; j++){

   if(i>j){
    printf("     ");
   }else{
                                  cnt=cnt+1;
    printf("%5d", cnt);
                                }
  }
           printf("\n");
 }
    getch();
}


6. 제어문을 이용하여 아래와 같이 출력되는 프로그램을 제작해 보세요.

                 15
            14  13
       12  11  10
     9   8   7   6
5   4   3   2   1



▩ 제어 반복문의 활용 3


▶ 구구단 출력하기

1. 2단만 출력

#include <stdio.h>
#include <conio.h>

void main(){
 int i;

 for(i=1; i<=9; i++){
      printf("2*%d=%d\n", ----- ? -----);
    }
    getch();
}


2. 3단식 출력하기

#include <stdio.h>
#include <conio.h>

void main(){
 int k, i, p;

    for(----- ? -----){
  for(i=1; i<=9; i=i+1){
   printf("\t%d*%d=%d", k, i, k*i);
    printf("\t%d*%d=%d", k+1, i, (k+1)*i);
   printf("\t%d*%d=%d\n", k+2, i, ----- ? -----);
  }
  printf("\n---------------------------------------------------------\n");
                     p=getchar();

 }
    getch();
}


3. 배열을 이용하여 구구단 출력하기

#include <stdio.h>
#include <conio.h>

void main(){
 int k, i, ----- ? -----, p;


 for(k=0; k<=8; k=k+3){
  for(i=0; i<=8; i=i+1){
   a[k][i] = (k+1)*(i+1);
   a[k+1][i] = (k+2)*(i+1);
   a[k+2][i] = ----- ? -----;
  }
 }

    for(----- ? -----){
  for(i=0; i<=8; i=i+1){
   printf("\t%d*%d=%d", k+1, i+1, a[k][i]);
    printf("\t%d*%d=%d", k+2, i+1, a[k+1][i]);
   printf("\t%d*%d=%d\n", k+3, i+1, a[k+2][i]);
  }
  printf("\n---------------------------------------------------------\n");
        p=getchar();
 }
    getch();
}


▷ 1부터 100까지 짝수의 합 구하기 (답 : 2550)


▷ 1부터 100까지 홀수의 합 구하기 (답 : 2500)


4. 아래와 같이 출력되도록 프로그램을 작성하세요.

♡♡♡♡♡
♡♡♡♡
♡♡♡
♡♡


5. 아래와 같이 출력되도록 프로그램을 작성하세요.
   - ♡ 하나는 공백문자 2개에 해당합니다.

            ♡
         ♡♡
      ♡♡♡
   ♡♡♡♡
♡♡♡♡♡

Posted by 나비 나비:D

BLOG main image
by 나비:D

공지사항

카테고리

분류 전체보기 (278)
Programming? (0)
----------------------------- (0)
나비의삽질 (5)
Application (177)
SQL (51)
Web (27)
etc. (14)
Omnia (0)
---------------------------.. (0)

글 보관함

달력

«   2018/02   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28      
Total : 911,941
Today : 30 Yesterday : 99