티스토리 툴바


타인이 자신의 쪽지, 대화 내용을 보지 않기를 원하신다면

chatdata, memodata 폴더를 삭제해 주시면 됩니다. 


요약하면 3가지 방법이 있습니다.

1. SQLite Database Browser 이용

2. Nateon Memo, DB(chat) Viewer 이용

3. 쪽지, 대화내용 폴더 직접 복사하여 확인하기


일단 아래의 3개의 프로그램을 다운받으세요.

1. SQLite Database Browser v1.3 

2. Nateon Memo, DB(chat) Viewer 


** 1) SQLite 를 이용하는 방법


네이트의 쪽지 및 대화내용은 오픈소스 데이터베이스 라이브러리인 SQLite(format 3)를 이용합니다.

(참고 : http://kldp.org/node/81635 ,  Google-O'Reilly 2005 OpenSource Award winner)

SQLite.org에서 제공하는 이 프로그램을 이용하면 SQLite를 이용한 DB를 탐색할 수 있습니다.

다운로드 링크에서도 보셨겠지만 실행 전 run.bat를 한 번 실행시켜 주세요. 다음부터는 다시 열지 않아도 됩니다.

이제 SQLite Database Browser를 실행시키고 File > Open Database를 누르면 열기 창이 뜹니다.


[C 드라이브에 설치, 윈도우용 네이트, 쪽지 및 대화내용이 존재할 경우] 찾아가야 할 주소는 다음과 같습니다.


C: \ Program files \ NATEON \ BIN \ 임의의난수 \ chatdata, memodata \ normal


임의의 난수는 예를 들면 이렇습니다. ex) 3519EC857F71E81D80A618AFF0B4C81F

이 임의의 난수 폴더에 들어가면 여러 폴더가 있는데 그 중 로그인한 사용자의 이메일 ID 주소가 있습니다.

사용자 동의 없이 로그인한 모든 사용자의 이메일 ID가 각각의 난수 폴더에 저장되어 있습니다.

자신이 원하는 사용자임을 ID로 확인했다면 chatdata, memodata \ normal \ 폴더로 가면 됩니다.

chatdata 폴더는 대화내용, memodata 폴더는 쪽지내용을 저장하고 있습니다.


아래는 어떤 파일을 열어야 하는지 폴더 내의 파일 구조를 보여주는 그림입니다.

미니바쩜넷
미니바쩜넷

주로 다루게 되는 파일은 CHATDATA 폴더의 경우 local_chat.db

                                  MEMODATA 폴더의 경우 local_inbox.db, local_outbox.db 가 되겠죠~


난수 폴더 내의 favoritedata, maildata 로 메일내용 등을 확인할 수도 있고

chatdata, memodata \ action, mobile 등을 통해 액션쪽지, 휴대폰 문자내용 등을 확인할 수도 있습니다.

야래는 이 파일들을 열어 DB를 확인하는 모습입니다.

[대화내용]

미니바쩜넷

BODYDATA 외에 NOREAD의 값을 통해 읽었는지의 여부(0이면 읽음, 1이면 읽지않음),

CONFIRM 을 통해 해당 쪽지에 대해 답장을 했는지의 여부 (0이면 답장함, n이면 답장안함) 등을 알 수 있습니다.


SK커뮤니케이션즈는 2006년 3월에 출시한 네이트 3.5 버전부터(현재 윈도우용 버전 3.7)

보안을 위해 대화내용을 암호화 처리하고 있다고 주장하나, 위에 소개해 드린 방법을

써보시면 알겠지만 사실이 아닙니다. 마음만 먹으면 누구나 쉽게 남의대화내용을

불순한 용도로도 확인할 수 있습니다. 또한, 그나마 대화내용은 사용자에게 저장 여부를 묻지만

쪽지내용은 사용자에게 저장 여부를 묻지 않고 자동 저장되므로 악용소지가 상당히 큽니다.


** 2) 직접 복사하여 확인하기


이 방법은 '통합 메세지함을 통하여' 자신 혹은 타인의 쪽지, 대화를 확인할 수 있습니다.

방법은 간단합니다. 위에서 해보신 분들은 난수폴더 내에 chatdata, memodata 폴더가 핵심 폴더임을

알고 계실 것입니다. 이 두 폴더를 백업해 두었다가 자신이 로그인 하는 이메일 ID가 있는 난수폴더 내에

붙여넣기 하시면 됩니다. 그리고 네이트을 들어가 통합메세지함을 확인하면 백업한 사용자의

쪽지 및 대화내용을 보실 수 있습니다.

다시 말하면, 원하는 사용자의 chatdata, memodata 폴더를 자신의 난수폴더에 복사하여 확인한다. 입니다~

** 3) Nateon Memo, DB Viewer 이용 - 가장 편리한 방법입니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 현수림

댓글을 달아 주세요

[VC++] Replace

Programming/VC++ 2007/08/01 16:42

특정문자를 다른 문자로 바꾸어 주는 함수


CString str;


str.Replace("\r\n", "\n");

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 현수림
TAG vc++

댓글을 달아 주세요

CPU 번호 체크

나도 평가하기 good10

seo01000

조회721 답변2

답변이 완료된 질문입니다. (2003-06-13 08:42 작성)

신고신고

프로그램을 외국에 있는 다른 업체에 보내야 하는대

절대로 프로그램이 유출되어서는 안된다고 하내요

그래서 보안기능이 있어야 하는대..

미리 설치할 피씨의 CPU 번호를 알아서 다른 CPU에서 실행할려고 하면

프로그램을 자동으로 삭제할려고 합니다.

CPU번호라고 해야하나 그런 것을 체크할려며 어떡해야하죠?

비쥬얼씨로 짠 프로그램이에요

MAC 주소로 하는 방법두 있는데...

log2189 (2003-06-13 09:28 작성)1대1 질문하기

신고신고|이의제기이의제기

Include nb30.h and link with netapi32.lib.
하시고요

typedef struct _ASTAT_
{
ADAPTER_STATUS adapt;
NAME_BUFFER NameBuff[30];
} ASTAT, * PASTAT;


CString GetMacAddress(CString sNetBiosName)
{
ASTAT Adapter;

NCB ncb;
UCHAR uRetCode;

memset(&ncb, 0, sizeof(ncb));
ncb.ncb_command = NCBRESET;
ncb.ncb_lana_num = 0;

uRetCode = Netbios(&ncb);

memset(&ncb, 0, sizeof(ncb));
ncb.ncb_command = NCBASTAT;
ncb.ncb_lana_num = 0;

sNetBiosName.MakeUpper();

FillMemory(ncb.ncb_callname, NCBNAMSZ - 1, 0x20);

strcpy((char *)ncb.ncb_callname, (LPCTSTR) sNetBiosName);

ncb.ncb_callname[sNetBiosName.GetLength()] = 0x20;
ncb.ncb_callname[NCBNAMSZ] = 0x0;

ncb.ncb_buffer = (unsigned char *) &Adapter;
ncb.ncb_length = sizeof(Adapter);

uRetCode = Netbios(&ncb);

CString sMacAddress;

if (uRetCode == 0)
{
sMacAddress.Format(_T("%02x%02x%02x%02x%02x%02x"),
Adapter.adapt.adapter_address[0],
Adapter.adapt.adapter_address[1],
Adapter.adapt.adapter_address[2],
Adapter.adapt.adapter_address[3],
Adapter.adapt.adapter_address[4],
Adapter.adapt.adapter_address[5]);
}
return sMacAddress;
}
이상은 맥주소를 얻어 내는 거구요..맥주소는 전세계에 1개 밖에 존재 하지 않으니까.. 이것두 될듯.


뭐 보안 이 필요한거라면.

이외에도 하드디스크 넘버나 windows 시리얼 넘버 부착된 장치 등을 검색해서.

동시에 검사 하는것도 한 방법이네요..

아니면 하드웨어를 한개 끼워줘서.

그거 없음 안되게 하는 방법도...

음... 최초 실행시 인터넷으로 인증 받는 것두 괘안을 듯...

도움이 되었길 바라네요..

참 위 소스코드는

http://www.devpia.com/forum/BoardView.aspx?no=265298&page=1&Tpage=2&forumname=vc2002_qa&iddlpage=30&stype=&answer=&KeyW=mac&KeyR=title&KeyC=

여기서 퍼온겁니다.

top

CPU 번호 체크

lynnweb (2003-06-13 09:44 작성)1대1 질문하기

신고신고|이의제기이의제기

말씀하신대로 CPU 번호등을 체크하여서 옳지않은 사용권한일 경우 삭제하는 것은
프로그램이 로딩중이면 삭제가 안되니깐 bat 파일 같은것으로 실행파일 띄우기전에
검사하는 실행파일을 별도로 동작시켜서 조건에 맞지 않으면 삭제하면 되겠죠.

그런데 말씀하신 방법이 보안성이 그렇게 있다라고 생각되지 않는군요.
실행코드가 그대로 드러나 있는 형태이고, 중간에서 누군가 가로채려고 맘먹고 유출된다면
해당 보안장치는 금방 간파될 수 있다고 생각됩니다.
그리고 Copy 작업등을 통해서 복제되어 테스트 된다면 설령 삭제된다 하더라도
님의 보안장치는 쉽게 와해될 수 있으며.. 실행코드 자체는 아무런 보호가 안되어 있기
때문에 그대로 유출되기 쉽죠.

차라리 암호화 하여서 압축한후 key를 별도의 경로로 클라이언트에 따로 전송하거나..
팩킹 하는 것이 현실적으로 더 보안성이 있다고 생각됩니다.
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 현수림
TAG C

댓글을 달아 주세요

중복, 오류를 체크해서 이상있는 리스트 행은 삭제하면서 계속 검색해 나가는 알고리즘 구현을 했는데,


이상하게 생각처럼 작동을 안하는 것이다.


또 다시 미궁속으로 빠져들어간 코딩...


결국 문제는 정말 간단하게 해결되었다.


루프 돌리는 순서를 i = 0에서 i = m_listCtrl.GetItemCount()로 바꿔줬다는거...


리스트 컨트롤의 아이템을 삭제 할 때는 뒤에서 부터 삭제해나가야 한다는 원칙을 무시한거지..


-_-;;

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 현수림
TAG vc++

댓글을 달아 주세요

CWordString


잘은 모르겠지만 Int형이나 CString 형의 값을 형 변환 없이 입출력 할 수 있게 하는 배열인 듯하다.


배열 크기는 65535(65536)으로 제한되어져 있다는 단점이 있다.


이것때문에 쌩 고생을 했다...

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 현수림
TAG C

댓글을 달아 주세요

error C2011: 'CFish' : 'class' type redefinition

나도 평가하기 good10

taijifan72

조회1,514 답변1

답변이 완료된 질문입니다. (2004-04-07 14:41 작성)

신고신고

c++을 하다가 오류가 생겼습니다.
어떤 오류인가요..

class CFish {
public:
int underwater ;
int fin ;

void eat();
};

여기에서 오류가 났어요
잘 됐었는데 파생클래스를 연결하고 부터는 잘 안돼네요.

re: error C2011: 'CFish' : 'class' type redefinition

ccode (2004-04-07 20:51 작성)1대1 질문하기

신고신고|이의제기이의제기

질문자 평

에러구문만 봐서는 헤더를 두번 인식시킨것 같은데...
#include 구문을 루프를 따라 두번 인식하는지 살펴보시는게...

그리고 헤더를 선언할때 tip이라 하면..
// 클래스가 선언된 지문이 cfish.h라고 가정하고
#ifndef CFISH_H
#define CFISH_H
//////////////////// 헤더 안 내용을 쓴다.

class CFish {
public:
int underwater ;
int fin ;

void eat();
};


//////////////////// 헤더 안 내용을 쓴다.
#endif

이런식으로 헤더를 만들면 redefine에러를 없애줍니다...
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 현수림
TAG vc++

댓글을 달아 주세요

 
2003-01-09 오후 8:18:50   /  번호: 270644  / 평점:  (-) category: VC++ 일반  /  조회: 167
 [급질문]_beginthreadex 에서 BOOL 함수 호출..그리고 파라메터 이종헌 / opt4life  
이종헌님께 메시지 보내기    이종헌님의 블로그가 없습니다  
리턴 값이 BOOL 인 함수를 쓰레드로 쓸려면 3번째 파라미터에 어떻게 선언해줘야되죠??
그리고 구조체를 파라미터로 넘길려고 그러는데..자꾸 이런에러가 뜨네요.
error C2664: '_beginthreadex' : cannot convert parameter 3 from 'unsigned int (struct st_ComPort *)' to 'unsigned int (__stdcall *)(void *)'
        None of the functions with this name in scope match the target type

어떻게 해야 되죠?? 파라미터를 넘겨야 되죠??
이 글에 평점 주기:  
  2004-10-15 오전 1:15:26   /  번호: 474101  / 평점:  (-)  
 Re: _beginthreadex 형변환문제 답변. 상도니 / moon1426  
상도니님께 메시지 보내기    상도니님의 블로그가 없습니다  

 c++ 은 자료형을 엄격히 구분해서 발생하는 문제입니다.


(HANDLE)_beginthreadex(NULL, 0, ClientConn, (void*)clntSock, 0, (unsigned *)&dwThreadID);


요렇게 사용하면 당근 님이 묻는 Error가 발생합니다.


이것땜시 저도 아주 두시간을 헤맸어용...ㅜㅜ;


문제는 세번째 인자에 있습니다. 요걸 이렇게 바꾸면 형변환 문제 해결... 아래 에러 왕짜증..

error C2664: '_beginthreadex' : cannot convert parameter 3 from 'unsigned long (void *)' to 'unsigned int (__stdcall *)(void *)'

        None of the functions with this name in scope match the target type


음 그니까 (HANDLE)_beginthreadex(NULL, 0, (unsigned int(__stdcall*)(void*))ClientConn, (void*)clntSock, 0, (unsigned *)&dwThreadID);


위에걸 이렇게 바꿔주시면 해결 될거에요....^^


즐공하세용!!


출처 : 데브피아(http://www.devpia.com)

크리에이티브 커먼즈 라이선스
Creative Commons License

'Programming > VC++' 카테고리의 다른 글

[C] CWordString  (0) 2007/08/01
[VC++] error C2011: 'CFish' : 'class' type redefinition  (0) 2007/08/01
[VC++] _beginthreadex...이거 찾느라 하루가 걸렸다.  (0) 2007/08/01
[VC++] C/C++/MFC FAQ 모음  (0) 2007/08/01
[C] const와 pointer의 조합  (0) 2007/08/01
[C] C언어 강좌  (0) 2007/08/01
Posted by 현수림
TAG vc++

댓글을 달아 주세요


원본 http://cafe.naver.com/cyberzone/583
트루 칼라를 사용하는 방법을 알고 싶거든요...???
pop3서버와 관련된 질문입니다.
컴터를 산지 5개월정도밖에 되지 않았는데....느려지고...
다이얼로그 박스기반의 윈도우에 메뉴를 띄우려면???
DAO에서 두개의 테이블 조인???
모달리스 다이얼로그와 작업표시줄...
뷰윈도우에서 차일드 윈도우 만들기..
OCX를 만드는데
현재 어플리케이션에 HWND얻어오는 방법
16bit 비트맵 파일의 헤더정보에 대해...
vb에서 만든 dll을 vc에서 쓰는법좀 가르쳐줘요...
메세지 훅킹에 의한 상하 좌우 키보드 조작법을 알고 싶습니다.
edit control에서 입력되는 FontSize를 줄이는 방법?
현재 프린트 스풀러에 대기중인 모든 작업에 대한 정보를 얻는 방법
비주얼씨에는 비주얼베이직의 DoEvents같은게 없나요??
ASX에 있는 ASF 파일을 다운로드 받을 수 있는 방법은?
Visual C++ 를 처음 시작하려 합니다. 도움이되는 사이트좀
실행프로그램을 항상 최상위 화면에 띄울려면..
숫자를 String으로 바꾸는 방법은?
DialogBar에 클래스를 만들었는데, 메인프레임에서도 핸들러 함수를
vfw 함수중 hwnd 의 핸들은 어떻게...
슬라이더 컨트롤 사용법 중에서... ( CSliderCtrl )
2개의 txt파일을 읽어 비교하고 새 txt파일에 다시 저장하기
[ActiveX]Visual C++가 설치 되지 않은PC에서 사용방법
mdi에서 활성화된 뷰 포인터 얻어오는게 잘 이해가..
화면출력할때 출력변수와 도큐먼트변수의 차이점이 뭔지요...
불안한데..
ACM을 이용한 음성 압축 방법에 대해
c파일을 c++로 전환하기..
waveform..
다이얼로그의 크기 조절은 어떻게..
avi 를 asf로 변환하는 방법?
여러종류의 MDI ChildFrame을 갖고싶은데....
다이얼 로그 화면에 있는 그림 제어하기
리스트 컨트롤에서....
VC에서의 에러 메시지
유니코드 정의는 어떻게...
분할윈도우에서 툴바의 활성화 상태를 체크 하는법
메일체커 프로그램을 만들고 싶습니다...
GetDescendantWindow()가 뭐하는 거죠?
activex에서 다른 프로젝트에 있는dialog form을 불러들이려면
컨트롤에 대한 질문
M/HTML 즉 HTML 기반 E-MAIL 프로그램을 만들고 싶습니다.
컨트롤을 제거하려면?
다이얼로그를 다른데서 붙여 넣기하니까 "빈문서 작성 실패" 메세지가 나와
압축된 *.bmp 을 풀어주세요
Dialog 스크롤
DAO로 작성한 프로그램 배포
CTreeControl의 특정아이템 폰트색바꾸기
VARIANT 사용법에 대하여...
[코덱]에 대해서...
컨트롤..
다이얼로그 박스에 선그리기
CFileDialog 에서...
디버그
static text 컨트롤에 그래프를 나타내려면..
CWinThread클래스를 얻으려고 합니다.
MDIGetActive()와 GetActiveFrame()의 차이는 뭐죠
다이얼로그 박스에 비디오로 찍은 화상을 원하는 위치에 디스플레이하려면??
mdi에서 활성회된 모든 뷰 없애기
홈페이지에서 링크를 눌러 pc의 프로그램을 실행시키는 방법
activex에서 버튼..을 만들려면
[질문]슈팅겜 유도탄 알고리즘은 어떻게 구현하나용 ^^;
이미지를 Formview 에 깔기..
컨트롤 리스트에 저장된 파일을 불러올수는....
비트맵을 이용한 하이퍼링크
DLL 함수에서 일반 application 내부 함수를 호출하려면?
변수들의 메모리해제 문제거든요?
조건문에서 like문 사용에 관해서...???
아주간단한 질문.진짜 쉬운거요...
다이얼로그 박스를 일정시간 지나면 사라지게 하려고요...??
시리얼 통신에서 0x13과 0x11이 안들어옵니다
여드름 없애려먼 어떻게 해야하나요?확실한 답변 부탁드려요..;
CArray 템플릿 사용에서 에러가 나는군요.
[급]ODBC 또는 ADO로 원격 Database접속 방법
영진출판사 bible 의 automation 예제 따라하다 가 이상한 메
E-Mail Client 를 짜려합니다. 로컬 vs 서버의 처리 부분이?
OpenGL에서 2D로 원을 그리는 함수가 뭐죠?
CreateSemaphore() 의 인자설명에 대해서
세마포어에서왜 for 문을 돌때마다 ReleaseSemaphore해주는지
html help workshop 는 어디에?
비쥬얼 C++ 에서비트맵 여는 소스
여러 함수에서 특정 클래스를 접근하려고 할때...
Formview 에서 글자 변경
[질문]소켓프로그래밍에서..서버쪽의 Accept에 대하여..
ListCtrl에서 몇번째item을 선택했는지 어떻게 알죠?
함수를 Parameter로 사용하고 싶은데요..
이 함수좀 알려 주세요....T.T
원자를 무한하게 쪼개면 어떻게 되나?
이미지의 윤곽만을 나타내고 싶습니다.
포인터 관련 질문
thread를 통한 다이얼로그 생성
RichEditView에서 이미지 추가시 추가 파일의 경로 아는법??
Printer 제어
버튼을 누르면 해당곳에 list가 나오도록
자신의 IP 주소를 아는 방법
파일에서 문자열 읽어오기
Win 32 Internet API (WinInet)에 대하여...
Makefile에 대한 궁금한점
OnInitialUpdate()호출하는 방법이 어떻게 되죠?
[질문] 다이얼로그에서 뷰로 SendMessage...
iehelper object에 대해서..
에러원인좀 ....
방화벽에 관해서
[질문] 이쁜 윈도우프레임과 버튼 만들어 붙이는 방법.....
파일 입출력에서 날짜가 있는 부분만 추출하고 싶습니다.
인스턴스를 종료시키는 방법
파일 삽입
자동으로 파일 카운트되어 파일 생성
프로그램 내에서 액셀 파일 생성 방법..
컴퓨터의 행동 기록하기-- 일종의 스크립트?
간단한 질문 하나 ~
용어 설명좀 부탁드립니다.
CStatic 클래스 다루기....
윈도우를 수동으로 만드는 예제
MFC 용 DLL 을 여러개 삽입해서 사용하는 방법이 궁금합니다.
capGetDriverDescription..
리스트 컨트롤 큰아이콘으로 보기에서 아이콘의 간격 조절하기..
리스트박스에서 멀티셀렉트 아이템 얻기
static에 그림 그릴때 이런경우는.....?
local function definitions are illegal?
PropertySheet에서의 창크기 조절...
텍스트 화일을 읽고 이진화일로 저장하기
c++관련한 oop?
파일 Size를 바꿀수 있나요...
VC++로 메일 보내기
CBitmap 형태의 비트맵을 DIB 로 변환하는 방법?
mdb파일에서 필드 속성을 날짜 시간으로 했는데, 그것을 ado를 써
에디트 박스에서....
변수선언에서 에라가 ..
폰트를 이용해서 글자의 색을 바꿀수가 있나요?
TV카드를 사용해서 VFW함수를 이용해 다이얼로그 박스에 화면 출력까진
빠르게 폴더 겟수 얻기
CFtpConnection::GetCurrentDirectory() 사용
아주 간단한 질문
http 를 사용해 post 방식으로 데이타나 파일을 보낼려고 하는데,
include
익스플로러의 경로알아내기
클래스와 클래스에서 데이터 교환
툴바의 위치 복원 문제
웹서버에 내용을 읽어 오는 mfc함수
CProperty sheet 의 생성은 어디에서 하나요?
[진짜진짜급한질문] 다이얼로그 박스를 SDI형식으로 만들기...
DLL작성시 LNK2005에러...
타이머를 2개 사용하여 각각 다른 행동을 하려 합니다
AfxMessageBox 를 자동으로 닫는다?
게임 프로그래머가 되기 위해서는?
포토샵의 layer처럼....
ie 의 인터넷 옵션값 읽어오기(레지스트리 뒤져서)
카운터 2개의 이용시 값이 같이 카운팅
MFC 오랜 경험자 우대 ~!
[질문] FTP에서 폴더 전체를 업다운로드시키는 방법...
파일 입출력???
클래스에 관한 질문입니다.
timer..
html preview는 어떻게...?
<질문>read only 컴파일에 대해서..
콤보박스의 사용법에 대한 질문
새로운 클래스에 이벤트를 넣고 싶어요..
RegQueryValueEx() 함수를 사용해 인터넷 옵션값을 읽어오는데
프로젝트 설계시 역할분담?
긴 문자열에서 원하는 문자열 짤라오기
다이얼로그 박스를 외부 프로그램에서 메세지 보내기.
한글에서와 같은 눈금 표시는 어떻게 하나요???
네트워크 프로그래밍에 대한 조언 부탁해요.
링크에라..?
capCreateCaptureWindow..?
[질문]메뉴와 툴바등을 DLL로 만들어서 프로그램에 적용시키기.
SendMessage에 대해서 해결 좀....
시계 사용법..
ListControl 에 검색에 관하여
MDI 에서 child frame을 화면중앙에 위치시키려면
초급이지만 급한 것!!! 다얄록 베이스에서 마우스 바꾸기~
turboC 에서 프로그램의 실행결과를 보려면
CLIstCtrl 에서 검색하기..
Dialog base에서 툴팁
프로그램실행에 대해??
쓰레드 종료시 생기는 메모리 릭에 대해서..
VC에서 .C 파일을 C++로 컴파일하도록 지시하는 법
질문]SendMessage에서...
CPropertySheet 폰트변경
H 로 시작하는 데이타 타입..
다이얼로그기반에서 (비)활성화는 어떻게...
[질문] MFC확장 DLL 실행.
LDAP로 oracle연동...
winsock2 programming?
C++에서..
c++의 새로운 형변환에 대해
MFC에서 캠자원 쓰는 프로그램을 하고싶은데.. 가이드할만한 자료좀 부탁
WM_ERASEBKGND
[질문] 익스플로러를 보면 앞으로 뒤로가 있고...
CFileDialog에서 선택한 파일을 열려면...
좌표계를 바꿀려면...?
여러개의 다이얼로그를 사용하는 프로그램
employee* employee::list = 0;의 의미는???
무슨 뜻의 에러인지 알려주세요
ocx등록?
하노이 타워 & 재귀함수...
윈플밍 초보자로서 질문 !
패기지,배포..
IE의 SaveAs ?
zip module
scanf함수에서..
32x32이상의 아이콘
DB를 리스트 컨트롤로 나타내려면...
냉장고 청소할때 에탄올을 어떻게 사용해야하나요???
곤충들은 왜 징그러울까요?
ODBC 나 DAO 화일처리시......
런타임오류에 대해
Media Player OCX Source를 구합니다
SendMessage, PostMessage, Message 핸들러..
콘돔을사용하면 정말 안심일까?
최대화 버튼을 내가 만든 비트맵으로 바꿔칠수 았나요?
double 형 변수를 출력하려고 하는데 문제가...
스트링 리소스..
PtInRect() 함수에서 마이너스 좌표 계산에서 뭔가 이상해요
DLL작성중 String Table의 ID로String처리를 하고자할경우
ftp에서 진짜 진짜 궁금하고 빠른답변을원하는질문....
[질문] 파일을 바이너리로 저장하는 방법
[질문] activeX 만들때 Size 조절을 못하게 하려고 합니다
텍스트 박스 동적으로 En/Disable 시키기
마우스 커서를 바꾸려고 하는데..
slider control를 비트멥(bitmap)이미지를 이용?
ftp에서 다운로드받을때 진행사항을나타내는 박스를 만드는법...
탐색기에서 오른쪽 마우스 눌렀을때
특정버퍼의 프린터 출력..
외부 html화일 실행시키기..
스플래쉬 윈도우 띄우는 방법
text_control 의 폰트크기변경
다른 윈도우의 컨트롤을 제어하는법...
프로그램 실행화일이 위치한 절대 경로 받기..
class들의 비교가 가능한가요??
마우스포인터가 위치한 곳의 문자열 가져오기(훅킹관련)
다이얼로그 base중에...
어들레스에 관한 질문
에러 해결
스태틱 콘트롤의 BN_CLICKED이벤트
키보드의 키를 동시에 2, 3, 4개를 눌렀을 경우 처리
다이얼로그를 항상 화면의 맨 위에 띄우게 하려면
모달리스 박스에서 저절로 닫힙니다.(에딧박스에서 엔터시)
로그온하는 dialog 이외의 부분을 누르면 띵 소리나며 반드시 로그온이
디이얼로그기반에 db연결할려면
WIN32 기반으로 EditBox를 구현하고 싶은데요.
5.0프로그램 열기?
에디트박스에 커서 위치시키기
스페이스 문자의 넓이조정...
일반뷰에서 데이터베이스 출력
변수 에라?
DC를 이용한 버튼만들기 질문입니다.
알고리즘영??
[급]다른 프로그램 실행...
함수를 알고 싶습니다.
[급..급..]og기반 Program에서
DC와 Bitmap의 관계?
전역 변수 사용법을 알려주세여...
splash는 꼭 SDI나 MDI에서만 되는지...
[질문] ActiveX에서 structure와 비슷한 형태로 사용하기..
내가 만든 클래스를 4대 클래스에 접근할 수 있는 방법
CEditView 클래스 의 클라이언트영역에 폰트를 바꿀려면.
조이스틱을 MFC에서 다루는 방법좀 알려주세요.
마스터 볼륨에서 마이크 옵션 컨트롤하기
타이틀바 속성 뺀 다이얼로그 에서 작업표시줄에 아이콘 표시하려면?
도형 이동하는 방법 알려주세요
고급기술 한가지 가르쳐 주세요
릴리즈모드에서 디버그모드로 바꾸는 법
다이얼로그에 jpg 올리려면 어떻게 하죠?
SendMessage로 데이타를 보내려는데......
시리얼화(serialization)에 대한 개념이 궁금해서요???
공부하는 방법이 영..; 감을 못잡겠네요
CEdit 개체에서 키보드 입력을 받지 않도록 하는 방법이요?
Bitblt()에 대하여
fgets()에 대하여
SDI에서 MoveWindow()를 통해 윈도우 전체 영역 이동하기...
IHTMLDocument3 Interface 를 사용하고 싶을경우는??
이런 오류를 경험 해보신분.........
바탕화면 위,아래에 도킹되는 윈도우
split window에서 보더 없애는 법.
메신져의 자리비움 기능
[질문]바꿀 수 있는 다이얼로그의 바탕색 수(종류)????
윈도우에서 실행중인 프로그램을 가져오는 방법
ShellExecute와 Win2000 ?
스트리밍기술을 배우고싶은데 어떻게 해야..
원하는 디렉토리 안의 디렉토리 리스트를 캐취해오고 싶습니다.
Tiff 그림 화일 포맷에 관한 c소스를 찾습니다.
[질]release 컴파일 후 OCX의 소켓이 다운되는 이유....
Window 좌표setting 함수에 대해
초기 화면view에 propersheet를 삽입하려고 합니다.
음성소켓의 전송 G723.1 코덱으로...
답변부탁드립니다꼭이요
장난치다가 제가 개 안경을 밟았다고 돈 반값만 달래요!!! 어떻게 해야돼
에러좀 잡아주세요!!
MFC SDI>> 이게 왜 지역 변수 선언이 안된다는 것인지?
크기가 차이가 있는이유는요?
sql server 7.0 연동..시작할때 로그인문제..
리스트컨트롤에 색깔 넣기..
Html help를 어떻게..
Internet Explorer 의 Temp Directory
Picture 콘트롤에 있는 비트맵 이미지 바꾸기
모드 변환하는거............(0점 좌표)
클라이언트 영역에 아이콘 그리는 방법????
현재 화면의 크기를 구할려면..??
저 좋아하는 사람이 있어요.
bitmap파일을 직접 로드하고 싶어요.
Out-of-band 라는 것이 머죠??
프로세스 동기화문제..
간단하지만 풀지 못하는 에러???;;
TWIP에 관하여
파일 입력..
메세지를박스 자동으로 없앨수 있나요?
트리의 TVN_ENDLABELEDIT에 관해서...
string형을 char배열에 치환하는 함수..?
하드웨어통신 프로그램에 대한 조언 부탁합니다.
C++프로그램을 웹에...???
데이타베이스에 관한 문제??
USB 포트를 이용하여 2대의 PC사이에서 통신을 할려고 합니다.
경로(폴더) 선택 대화상자
프로퍼티 시트의 위치 조정..
MFC 클라이언트 배경화면에 대하여 질문입니다.
오라클 db에 접속하는 방법좀...
Group Box에 색깔 입히기....
ActiveX Web에 올릴때..
포인터..?
odbc 데이터 원본이 없는경우는?
StretchDIBits함수의 인자를 어떻게 채우지요..
sizeof() 외 2개 더...
acmStream 계열 함수에 관한 질문
공용다이알로그에서 멀티Selectting하기
디버깅중 어셈블리 코드로 넘어갑니다.
부모 다이얼로그 포인터 얻어오는 방법
라디오 버튼에 관한 질문 입니다.
배열로 저장된 이미지 데이터를 화면에 뿌려주려면??
동적으로 생성한 리스트 컨트롤의 항목이 픽쳐 컨트롤 때문에 안보여요.
개인 방화벽과 같은 프로그램은 어떻게 만드나요?
OCX 웹브라우저와 연동하여 Debug하기
Window에도 fork라는 함수가 있나여..??
새로운 윈도우의 생성이 않됩니다.
DoDataExchange 같은 함수를 SDK 에서 쓰려면 ?
P/G 로딩될때 dialogBar에 그림을 넣고 싶은데요...
부탁드립니다. 오류검사
프로퍼티에서 질문 또다시..
급합니다. 적분하는 프로그램짜는 법좀 가르쳐주세요...
이런 함수 있나요?
int형과 float형에 관한 질문 ?
vc++6 에서..
Wav파일 재생시 이상한 소리가....
Detected Memory Leak?
스플리트윈도를 이용한 탐색기를 만들때....
콤보박스
이것이 도대체 무슨 에러인지??
디렉토리 만드는법
[질문]마우스를 클릭했을때 스크롤 되는 방법?
DrawText 에서 글자배경 투명하게 하려면 ??
라디오 버튼의 기본 설정 방법은 ......
"C"를 배워보고자 합니다.
CRect::PtInRect()에 대한 설명 좀 부탁합니다.
구조체에서 CString을 사용할수 있는지요...
형 변환시 에러가 뜹니다.
Install Shield로 인스톨 실행 화일을 만들고자 합니다.
임의의 값을 Edit해보려고 합니다.
구조체를 연결리스트로 구성할수 있는 방법....
스레드에 데이터 전송하기
소켓 프로그램에서....
CTreeCtrl에서 item 순서 바꾸는 방법 좀 ...
CString 값을 int 형(16진수)으로 변환하려면
왜 ON_COMMAND_RANGE가 지워지죠?
win2000에서...
그래픽 프로그램에서의 필터를 ....!
폴더 알아내기....
주어진데이타(x,y)로 그래프를 그리는 방법
TCP ->UDP
파일찾기
ComboBox 에 관하여
Application을 자동으로 저장하려면???
스트링다루는문젭니다.
게임을 만들고싶습니다.
[질문] MFC왕초보의 두가지 질문입니다.
View에서 DialogBar의 RadioButton의 control
CDROM에 CD가 들어있는 지 없는 확인하는 방법..
에디트창에서
리스트 컨트롤에 색깔 넣고 싶어요
그래프를 표현하기 위한 ActiveX Control소개 부탁...
원격강의 관련 질문
[급]avi플레이어에관한질문?
다른 언어로 작성된 소켓 프로그램
링크에러
nt 4.0 에서 directX8.0 과 direct8.0 SDK 가 설
다이얼로그바 여러개 바꿔가며 쓰는 법
strcpy와 lstrcpy의 차이점이 뭐죠?
CEditView..의 내용..
Active X 만들 때 프로퍼티 추가 방법요~~~
가상키보드를 이용하여 웹페이지의 에디터창에 글쓰는 방법
auto run 프로그램
raw파일이 어떻게 저장되는지?
프로그램 실행중에 콘트롤(edit, button) 옮기기..
ActiveX Server Component 에서...
Top,Left 구하기
초 단위를 시-분-초로 바꾸는 방법??
slider control 만들기
com 객체에 인터페이스를 추가하려면 어떻게 하죠?
dllimport, dllexport를 설명해주세요.. 자세히,,
[질문] 이미지데이터를 가장 빠르게 화면 출력하려면...
메모리 사용을 최소화 하는 방법...
프로그램 실행 도중 window에서 컨트롤 움직이기
현재 OS 알아내는 API
고수님들 제발~~~
DirectX에 관하여...
ERROR_SUCCESS ?
간단한 배열입니다.
dialog 에서
Access Violation...
installshield 프로그램 사용법 있으신분..
BMP 파일로 Wallpaper 셋팅하기
[질문union] 에러가 나네여
시리얼통신 프로그램 구합니다.
DIRECT X 공부를 시작하는데용... MFC 에서 구현할까.. 아님.
여러 cast 연산자의 구분?
동적메뉴
다이알로그박스나 폼뷰에서 탭 순서를 바꾸려면..
리스트컨트롤에서 컬럼단위로 정렬하기.
왜 미인은 잠꾸러기 라고 할까요??
[질문] MSND Development Platform ?
UI(user interface)Thread 에서 작업스레드 생성해서
sub classing된 에디트 박스에서의 copy&paste문제..
SendMessage에서...
하드웨어 정보를 알 수 있는 방법이 있을 까요?
애니메이션 컨트롤에 쓸수있는 AVI 만드는 법이나 구할수....
socket 프로그램에서 타이머 질문인데요.
레지스트리 값 읽어오기..
정수의 금액표시
c++과 msdn을 설치하려면 ...?
Remote Desktop Protocol에대해서..
회원인증에 관한 내용입니다.
시스템메뉴손대기
[질문] dialog based에서 redraw..
Tab Control에서 질문
후킹에 대한 질문.....
제발.....트리 컨트롤......
VC에서 자바 Function들을 사용할 수 있나요?
[급-질문]ReadEventLog 사용법
다이얼로그바에 배경색을 넣고 싶거든요.
두개의 MDB File 을 동시에 open할수있는지요.
VC++초보 핸들뜻이 무엇입니까?
프로젝트에서 파일을 삭제 할려면..
assert 관련 질문
이것좀 도와주세요!!!!
웹하드 구현하기?
CAsyncSocket에서 Create를 하려는데요..
Message Queue 사용법에 대해서 알고싶습니다.
GetWindowLong() 과 GetClassLong() 은 뭐하는 거
서비스로 등록시킨 프로그램에서...
작업표시줄에 아이콘 넣기
트리 컨트롤에서요.....
리스트 컨트롤에서 원하는 색으로 리스트 추가
ODBC(RECORDSET)으로 연결해서 INSERT처리는 어떻게...
제가...
[급질문!!] 소켓 프로그래밍 전문가님 꼭 좀 도와 주세영.
연결리스트 (Linked list)에 대해서....
다이얼로그???
Edit Box에서..
리스트 박스에서.....
DAO 배포문제.
fopen()에 대해서.....
스레드를 잠시 멈추게 하려면?
시작 > 실행과 같은걸 만들려고 합니다...
::MoveFile()에 대해서......
API 와 MFC 어느것을.....!
슬라이더 (slider) 컨트롤 사용
API함수중에.....
대화상자가 안떠요.....
CFile에 관한 질문다시 올립니다.
분할윈도우에 대한 질문입니다.
대화상자의 크기영역을 알아내는 함수
MDB 파일에서 Requery로 찾은 데이타
다이얼로그에서 현재 포커스가 있는 컨트롤 찾기.
메뉴에 대해서.....
클라이언트/서버에서 회원인증에 관한 것입니다.
윈도우 사이즈 조절
Excel 파일 저장시 다른 쉬트 사용하기??
익스플로어 형태의 툴바구성
구조를 모르는 DB 테이블의 레코드 삭제.
비주얼C++ 에서 OCX를 사용하고 싶은데...
Asp 에서 OCX 를 붙이는방법??
view클래스의 멤버를 쓸려면 어떻게......
윈도에서 네트웍상의 패킷을 잡는 방법.
CEdit 에서 글자수 제한과 마지막에 캐리지 리턴 넣는 방법
Unhandled exception 에러가 나는데 어디가 잘못된건지??
등록 정보랑 프로그램 연결 대화상자........
GetLastError에 대해서......
[질문]Windows CE를 PC에 포팅할려면..
우리 나라에 마법사들이 존재하고 있다면?
공용컨트롤 사용하는 방법........이....
MainFrame에서 ViewClass를 사용할때 에러가 나요..
DB를 오라클을 쓸려고 하는데??
App에서 View의 함수 호출
VC++내에서 직접 DAO를 써서 mdb를 만드는데 데이타 타입때문에..
프로그램 실행중 중단하는 방법?????
워드 가져다 쓰기..
메모리 관리에 대해
다른 클래스의 함수 호출 방법.
윈도우 만들기...
이거 뭐가 문제인지 좀 가르쳐주세요...
CFile에서 정해진 경로에서 파일 불르기에 관한 질문입니다.
볼이 뭐예요?
[질문] WIN32_LEAN_AND_MEAN ?
시간을 SETTING하는법 ( SetLocalTime을 이용하여...
가로방향 인쇄를 하고 싶습니다.
화일입출력에서...
서버로부터 클라이언트가 메세지 받을때
view 를 만들려고 합니다.
ODBC에서 DB table 연결...
NT에서 서비스 프로그램 등록
lan tcp/ip 통신중에
그래프와 도표..
버튼들이 사라집니다.....
eeswt.dll 요청 !!
ListView의 특정 라인에 바탕색을 넣는 방법?
자식윈도우에서 발생한 이벤트를 부모 윈도우 프로시저에서 처리하는 방법..
현재 위치한 폴더 알아내는 방법과 폴더생성하는 방법
다이얼 로그 클래스 포인터 얻기...................
포커스가 가 있는 버튼에 엔터키가 안먹습니다.
질문..
Edit 박스에 글을쓰면 그 글을..멤버변수로 저장할수있나여?..
CIPAddressCtrl 을 char배열로 변환하는 방법이 있나요?
다이얼로그에서 뷰 사용하기
고수님들의 조언부탁드립니다. (이것때문에 죽겠습니다. ㅜ.ㅡ)
SetTitle() 함수에 대한 설명좀 부탁^^..
레코드삭제시의 궁금한점.
[형변환]long->CSting 형으로
움직이는 메뉴나 프레임 만드는 법좀 가르켜주세용
정말 간단한거
버튼의 포인터???
시간형 레코드값에 NULL값을 넣을 수 있나요?
Random 함수에 관하여
(ODBC)sql data type (꼭 좀 부탁..)
다른 PC의 레지스트리값을 바꿔보고 싶습니다.
모달리스 에서...
특정 위치의 픽셀 정보(색상) 알아내기..
BIOS정보는 OS에 따라 어떻게 가져오는지요?
ActiveX에 Listcontrl
CRecordset에서 login dialog box 안뜨게???
switch()함수에 대해서???
파일이 잘 안 열어져요...
.tlb 파일에 관하여
제발 도와주세요...
키보드 반응에 관해...
[질문]이런 콘트롤은 있는지요...
record를 sort하고 싶은데요..
LineIn Assembly에서의 배열...
api socket server/client 자료 구함
스레드 중지..
WAB화일의 위치를 가져오고 싶습니다.
보고 싶은 영역만 보기...
API 에서 DB연결....
다른프로그램의 확인버튼누르기
WideCharToMultiByte 함수 설명 부탁드립니다.
제발 답변좀 해주세요~~~~~~~~~~
Visual c++을 설치하고 나서....
CTreeCtrl::GetNextSiblingItem 에 대해서.....
소켓으로 포인터 데이터를 전송하고 싶습니다.
Direct Sound로 Play할 때 문제점
다이얼로그박스에서 분할뷰의 포인터 얻기
[질문]다이얼로그바 에 프로퍼티 시트 삽입할려면?
알집의 ToolBar이미지를 어떻게 구현해야될지.. ㅜ.ㅡ
데이터 형 변환시에 데이터 손실이 어느 정도 인가요?
프로퍼티 페이지의 크기 변경...
일반적인 메신져 프로그램에서....
비주얼 C++ 6.0의 기능이라면... 어떤것들이 있을까요?
추가된 form view의 static control 변수 바꾸기
CComObject<> 포인터 선언하는 방식을 이렇게 하면 안되나요?
스토어드 프로시져 사용법을 알고싶습니다.
EDIT BOX에서 줄바꿈 할때 말인데요.
DLL 에서 소켓통신하기...
idl 로 생성되는 파일을 다른 프로젝트에서 공유하고 싶어요
MDI에서 새로운 ChildFrame생성
Win32 Api함수를 이용해서 문자열에서 문자 축출하기..
텍스트 파일의 내용을 받아서 그래프로 뿌리기
Outlook Express 핸들 하기
CRecordSet의 m_pSet의 초기화는 어디서..
아주 초보적인 오비리스트 질문..
프린터포트를 각각 제어하고 싶어요.
좀 봐주세여...
자신 IP알아내려는 함수가 있는지요...???
Active x 에서 html로 값을 넘기려고 하는데요...
파일 fragment하는 소스좀 가르쳐 주세요......
Value is not within allowable range....?
메모리 릭이 뭐죠..
[질문]Invalidate()를 하면 리소스를 계속 잡아먹던데...
Win32 Shell Programing. ㅡㅡa;
툴팁한 관한 짧은 질문..
dll을 만들었는데요.
delay 주는 방법.
CListCtrl 에서 글씨 색 변경
mfc에서 메뉴항목 추가를 공부하는중에...초보가..ㅜ.ㅜ
리스트 컨트롤에서.......
P2P 에 대해서 자세히 알고 싶습니다.
왜 메시지가.......
[급함]2차원 배열을 함수에서 인수로 받아야만 해요
다이얼로그를 플랫스타일로 만들려면...
다이얼로그바
CMonthCalCtrl 에서의 버그...?
Debug Assertion Failed Error
debug로 컴파일시에는 에러가 발생치 않는데.. release시 에러.
CEdiView에서 Edit창의 맨앞에 라인 번호를 추가하려면...
리스트 컨트롤을 리소스서 정렬기능을 활성화하여 사용하려는데요
리스트의 헤더를 왼쪽에 위치하는 방법
Burst모드 vs Handshake모드
띄어쓰기요~~~~~~이게 왜 않되죠~~?
남편을 이해할수 없네여..
Edit control 에서여
마우스 동작 영역 조정....?
쓰레드에서의 메모리 동적 할당/해제
EditBox에 임의의 코드넣기
뷰에서 함수를 추가하면
MDI에서 Child를 종료시키는 과정에 일어난 에러
MS사의 "Visual Studio 6.0 Service 이게...
초본데 주석 좀..
뷰 전환에 대해서 질문 드립니당..
소켓에 대한 질문입니다.
주석을 좀...
파일선택 다이얼로그에서 선택된 파일이름얻기..
스트링(CString)을 내 하드에 저장하는 방법을 가르쳐 주세여....
Edit박스에서 hexa로 출력
odl 파일
멤버함수창이 안뜹니다.
vcm 사용법에 대해서 도움을 요청드립니다....
Internet Explorer 새로고침...
뷰에서 라인 그리기 급합니다..제가 초보라서^^
16진수 관련 도와주세요.
이런 에러를 해결하려면
API 소스를 MFC로 불러와 ODBC 사용하기??
[초보질문] EditView에서
UDP통신을 하고 있는데요.
Cab 파일을 등록하고 설치하는 배포 프로그램 만들기
리소스 Load Failed..
LPCSTR을 BYTE로 형변환
ddk를 공부하려고 합니다. 도움을 부탁드립니다.
분할뷰(폼뷰와 뷰)에서..뷰 내용을 선택한후 폼뷰에서 삭제시...질문
VC에 있는 워크스페이스와 같은 기능을 하는 소스나 참고자료 부탁합니다.
ATL에서 여러개의 class를 만들어서 사용하는 방법
ListView의 일부 칼럼을 우측정렬하기
InitDialog에서 DTPICKER컨트롤에 특정날짜를 셋팅하는 방법
메인 프레임 클래스 이름 만들어 주기
ChartFX 어떻게 사용하나요?
Link 에러가 나서 그러는데요.
리소스를 열수 없습니다.
CDC 에 그려져 있는 일정 영역의 내용을 CBitmap으로 내릴려면.
이 화면에서도 보이는 툴바와 View 사이의 구분선 구현은...?
dll 분석방법좀 알려주세요
MDI에서
listview에서 한 item이 여러 라인을 가질수 있는지.
Api 에서 DLL 연결해서 사용하기
visual C++에서 모터제어 법
쓰레드 프로그램에 관련된 질문을 드립니다.
CreateThread 에서여
2개의 ASF 파일을 합치는 방법?
CString -> LPCOLESTR 형변환
특정 컨트롤이 위치해 있는 좌표값 얻기
new 로 컨트롤 동적생성시킨 다음 delete 시키기
listCtrl에서의 드래그를 할려구
Application간의 Message전달
중국어 NT에서...
DB Table list에서 primary key 얻어 오는 방법좀...
CAsyncSocket을 사용한 파일전송시 잘라보내는 방법 갈켜주세요.
레지스트리의 값을 읽어올때요.. 데이터가 자꾸 깨집니다.
include 문에 관해??
특정디렉토리의 파일 갯수를 알아내기
INVALIDARG 로 리턴하는 메소드 는 클라이언트에서 어떻게 에러 체
생성자 함수의 파라미터..
계산기 만들기
clrscr명령은 쓰면 안되나요?
메세지에서 int 형을 CString으로 바꾸어 출력하는법
ActiveX에서 ftpconnection 이럴때는...
바탕화면 영역 바꾸기
system idle process가 뭐하는건지 가르쳐 주세요
E메일 클라이언트..
oledb 에서 필터조건주기
다른 Dll을 로드해서 다른 Dll 만들기...
CRgn사용법에 대하여...
OPEN GL 관련 사이트 소개 부탁합니다...
이상하네요..초보임다..
랜상의 컴퓨터 리스트 알아내기
비주얼 씨에서 이진수에 관한 질문입니다.
NT4.0에서 작업관리자의 프로세서 마침을 구현하고 싶습니다.
하드웨어 장치에서 읽은 그림을 빨리 출력하기
메시지 박스를 자동으로 없애고 싶으면
settimer() 함수사용법
트리컨트롤에서 아이템 선택시 왜 이미지가 바뀔까요?
메소드의 인자가 올바르지 않으며 리턴시킬려고 하거든요
주석을 ...
out 파리미터를 2개 주면 스마트 포인터 쓸수 있나요?
CRichEditView에서 CStringArray의 값을 화면에
[질문] Edit box에서 영문만 입력받고 싶습니다.
소켓프로그램에서요...상대방의 IP를 얻어오는 방법의 정석은 과연?
[질문]MDI에서 활성화된 차일드윈도우얻기의 에러가...(Plz...)
ActiveX에서 웹브라우저를 종료시키려면
미리 알수 없는 컨트롤 삭제하기
FTP 에 관한 질문입니다...(MFC...혹은...API)
FormView에서 오픈한 Dialog의 Edit 값을 가져오고 싶어요~
windows98se인데 내 컴퓨터 들어갈때 문제가 있어요
아웃룩 익스프레스를 띄우고 자동으로 특정화일을 첨부 하도록 하고 싶슴다
VB의 Chr() 함수와 동일한 C++ 함수는?
제 프로그램에서 다른 프로그램을 호출....
연결자가 무엇인지...
리모콘 만드는법...
콘솔모드에서요...MFC클래스를 사용하는 방법은 무엇인가요?
화살표 키보드 메세지에 대해서...
ntdll 에서 error가 나거든요.
툴바(리바)에서 256컬러 비트맵 아이콘을 사용하는데 배경을 투명하게..
[질문]MDI에서 뷰클래스의 멤버함수 참조하는 방법좀 부탁합니다.
vb 에서 obuffer5 = Chr(2) 를 vc++ 로 바꾸려면 어떻
GDI 객체에 대해서 질문이 있습니다.
URL decoder
collection class 에 관한..(map/dictionary)
[질문] 자식윈도우의 위치를 얻는 방법
프로그램 패키지를 만들기(인스톨 쉴드 없이)
Url을 입력받아 html파일 가져오기..근데 아뒤와 패스워드 필요!!
인스톨쉴드에서 파일 존재체크 방법
다이알 로그 베이스에서 버튼 하나를 눌러서 다른 다이알 로그 박스 띄우는
Edit Box에 입력이 않됩니다.
리스트컨트롤(Report 스타일)안에다가 콤보박스를 넣는 방법
도스 명령어중 IP 주소 얻는 명령어..
시리얼 통신에서 버퍼에 있는 데이터를 editbox로 출력하는 방법..
oledb 에서 말하는 bookmark 가 뭐죠?
[급합니다]2차원동적배열할당을 삭제하는 방법
HBRUSH CTestView::OnCtlColor에서의 메모리 누수
윈도우 크기 조정
SDK 질문있습니다.........
[질문]레지스트리에 값 쓰기
Accept함수에 대해 좀 알려주세요..
sndPlaySound함수 실행시 에러...
프로그램 실행과 동시에 트레이 실행
내 컴의 도메인 이름을 알 수 있는 방법이 있을까요..???
VISUAL C++로 FTP프로그램을 짜보고 싶습니다.
멀티스레딩시 이렇게 하는것이 괜찮을까요?
초보자들이 알수 있는 OpenGL 소스 좀~~~
File의 내용을 읽어서 메모리에 저장할때...
주소록을 MFC로 짤려면 다이알로그기반으로 해야함니까
클래스는 어떻게 삭제하나요?
DB에 관련한 기본적인 질문입니다. 좀 봐주세요..
pDoc가 포인터 변수인데 왜 &pDoc라고 쓴 것인가요?
마우스가 다이알로그 밖에 나갔을 때 이벤트는?
다이얼로그 한번만 뛰우기
아주 초보적인 질문.. UNICode로 컴파일 할려면....
AFX_DATA
멀티 테스킹 기능 해제.
윈도우내에 놓여있는 DlgItem의 위치를 알아내는 방법은?
[질문] SDI에 도킹된 바.. 보였다 안보였다...
ISAM 화일에 관하여....
파일 생성 어떻게 하나요.
[질문]activex 관련 질문.( 웹페이지 새로고침에서..)
포인터에 관한 질문이에여..
버전체크 & 작업표시줄에 안나타나게 하려면?
sync, async 소켓 프로그래밍...
vc++ 왕초보질문
문자열 짜르기
소켓 프로그램 내에서 소켓 2개 생성...
CALLBACK로 TIMER 응용하기
클라이언트에서
edit box에 입력한 CString값을 배열에 입력하는 방법....
자동차 보험 가입 (본인차를 타인 명의로 가입?)
제 컴퓨터에 있는 어떤 프로그래을 찾아서 실행시키려고 합니다.
원소켓에서여
[왕초보] 2개이상 리턴값쓰기...
초보의 질문(웨이브파일은 어케 만들거나 얻을 수 있나여?)
이상한 AppWizard
간단한 부탁입니다...
이놈의 vc가 미쳤나.........
Static Control에서 AutoScroll은??
웹페이지에서 디버그창 뜨는문제.
vc++ 왕초보질문
DrawBitmap()의 사용법이 궁금합니다.
IErrorInfo는 어떻게 사용하는 것인지?
전문개발자님께 질문드립니다.
리소스 파일 추가할때 질문요...
MFC 로 생성한 뷰의 색깔 바꾸는 방법
와~! 이해 X MFC WIN32 로 넘아가야 겠는데 질문!!!
ODBC를 거치지 않고 원격지 db를 접속할 수 있나요?
sdk에서 파일 입출력문제입니다.
1:1 통신 가능한 프로그램 입니다..1:다 연결을 하고 싶은데요..
ShowWindow()함수에서요
UI Thread
MACRO 에서. 날짜 넣는 법이요..
서버와 클라이언트간의 통신.
분할뷰에서 포인터 얻기
콤보박스에서 프로그램 종료후에도 값받기..
에러 좀 해결해 주세요
첨 보는 문법입니다. 제발 도와주세여...^^;;
한문자 읽어오기
COM에서 QueryInterface와AddRef등이 안보여요
[질문]콤보박스에서여 디폴트로 어떤 값이 보여지게 할 수 있나요??
[급질문]파일오픈창 열때 원하는 경로를 디폴트디렉토리로 지정할수 없나요?
Editbox에서 Enter값의 들어왔는지 알고 싶은데요..
MySql안의 데이타를 검색, 수정, 삽입 하려면...
SetTimer 함수에 대해...
CFile 위치지정
listcontrol에 글자색을 변환시킬수 있나염???
리눅스의 C와 윈도우의 MFC간의 소켓통신 어떻게 하나요?
ordinal에 대해...
Win API프로그램에 OCX넣기
익스플로러에서 새창이 생성될때 그 창의 포인터를 얻는 방법
한번 실행된 프로그램이 또다시 실행되는걸 막으려면...
소캣통신에서 두개의 패킷이 가끔 붙어요..
gif animation Load & Save
에디트박스에서 엔터키 인식
다중 널문자가 포함된 BYTE 정보를 널 문자 포함, 다른 바이트 변수로
FarPoint사의 Spread사용중.....
이 알고리즘좀 알려 주세여..
모달리스와 모달 다이알로그..
View Class 중OnPaint
레지스트리에 저장..
툴바에 관해..
특정 폴더를 감시하여..
sql 구문에서...
문제좀 해결해 주셔요~~~~~~~~
이 어셈블리좀 번역 부탁드립니다.. (아주 급함,. 꼭 필요.. ㅠㅠ)
CStringList::GetTail함수,...
잘못 등록한 클래스 삭제..
CView_SDI 프로그램에서 메인창의 색깔 및 메뉴 색깔 바꾸기..?
MS FLEX GRID CONTROL 6.0(CMSFlexGrid)
VB dll 을 vc++에서 호출하려고 하는데......
ATL control에서 해당 컨트롤이 시작되고 종료될때 수행할 코드
(아주 급함) 다중접속 프로그램을 짜고 있습니다.. 연결리스트 노드 삭제
(아주 급함) 다중접속에서 연결리스트에서 자꾸 에러가 남니다...
리스트컨롤 파일저장에서 업로드
(꼭 필요함) X 버튼을 눌렀을때.. 종료하지말고 다른 함수 호출하기
리스트 컨트롤에 눌린 키 얻는 방법
리스트 컨트롤에서 선택모드(한개만, 멀티 선택) 변경방법
분할 윈도우안에 또 분할하기~~~
[질문] Win32API로 만든 클래스를 어떻게 DLL로 바꾸나요...?
variables 창은 프린트가 안 되나여?
툴바 높이 설정..
사운드음소거가삭제되서,,ㅠ,ㅠ소리가안나와염,,어떻하져,, ?
CListCtrl DrawItem에서 메모리 문제...
outlook 을 이용한 메일보내기
Menu의 font는 어떻게 변경하나요..?
API와 함수의 파라미터에 대한 자세한 설명 부탁드립니다.
에디트박스에서...
간단한 질문.. 프로그램 스타일문제인데.. #define문의 이용에 대해
다이알로그박스의 스크롤이 되지않아요...왜 그런가요?
html문서 다이얼 로그에서 보여주기
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 현수림

댓글을 달아 주세요

출처 블로그 > 게으른 엔지니어...
원본 http://blog.naver.com/asca99/80014320926

회사에서 시행되는 S/W 역량 강화 시험을 준비하다가 갑자기 생각나서 자료를 찾아 보았다.


cont keyword와 pointer를 같이 쓸때의 정확한 의미가 궁금해서 말이다.


기본적으로 const는 변수 정의시 같이 사용하면 변수의 값을 절대 바꿀수 없게 되어 있다.

때문에 const를 사용하여 변수 정의할 때는 초기화를 해 주지 않으면 그 변수는 다시는 값을 저장할 수 없는 경우가 발생한다.


포인터 변수에 const는 두 개까지 사용할 수 있다. 왜냐고?

포인터 변수를 생각해 보면 포인터 변수는 기본적으로 주소를 가지고 있고, 그 주소를 따라가면 뭔가 자료가 저장되어 있다. 그러므로 변경하지 못하게 하는게 두개가 생긴다. 바로 포인터 변수가 가지고 있는 주소값과 그 주소값에 저장되어 있는 값 말이다.

int a = 10;

int b = 5;

const int *p1 = &a;

int * const p2 = &a;


이렇게 변수를 const를 이용하여 정의 할 수 있다.

컴파일러가 이를 해석하는 입장으로 생각해 보자.


p1의 경우 const가 적용되는 부분이 int * 이다. 그러므로

*p1 = 20;

과 같이 사용하면 에러가 된다. 바꿀 수 없는 녀석을 바꿀려고 한다는 것이다. 대신 p1 = &b;는 가능하다.

두번째 경우인 p2의 경우

const p2 에만 적용이 된다. 즉 p2의 내용인 주소를 변경할 수 없다는 것이다.

그러므로

p2 = &b로 사용할 수 없다. 대신 *p2 = b; 는 가능하다.


그럼 이것들을 전부 적용해보면

const int * const p3 = &a;


는 p3가 가지는 주소값도 변경 못하면서, 그 주소값에 있는 값도 바꿀수 없게 된다.


요약하자면

"const는 그 다음에 오는 것을 상수화 시킨다"

크리에이티브 커먼즈 라이선스
Creative Commons License

'Programming > VC++' 카테고리의 다른 글

[VC++] _beginthreadex...이거 찾느라 하루가 걸렸다.  (0) 2007/08/01
[VC++] C/C++/MFC FAQ 모음  (0) 2007/08/01
[C] const와 pointer의 조합  (0) 2007/08/01
[C] C언어 강좌  (0) 2007/08/01
[C] 소켓 기본 함수  (0) 2007/08/01
[C] 고수준 파일 입출력 함수 정리  (0) 2007/08/01
Posted by 현수림
TAG C

댓글을 달아 주세요


원본 http://cafe.naver.com/csknouackr/6
 

C 언어 강좌


 총 3,500라인(약100여page)에 달하는 본 강좌는  C를 처음 시작하시려는 분과 포기하셨다가 다시 시작하시려는 새내기 여러분들을 위하여,    *** C에 대한 전반적인 사항을 단기간에 둘러볼 수 있도록 ***

  #개념과 예제 설명 위주로#  진행한 강좌입니다.  '언어 강좌'란의 다른 강좌들과 함께 본 강좌를 따라가시다 보면 어느새 C에 대해 자신감을 가지게 될 것입니다.


 특히, C에서 가장 난해하다고 인정되는 포인터에 관한 내용을 집중적으로 설명하였습니다. 필요하신 분은 그 부분만 참조하셔도 많은 도움이 될 것입니다.



강좌의 분량이 많으므로 캡춰를 해서 공부하시기를 바랍니다.

부디 본 강좌와 함께 C언어에 대한 자신감을 성취하시기를 바랍니다.


 #. 참고 서적 / 추천 서적

   **  박승제 저 'BASIC에서 C로' - 1989, 월간 마이크로소프트웨어(강의기본교재)

가. 황희융 편 'C언어 기초 + a' - 1986, 교학사 (입문서)

나. 임인건 저 '터보 C 정복' - 1990, 가남사 (입문/참고서)

다. '안녕하세요 Turbo C' - 1993, 정보문화사 (입문서)

라. 큰사람 저 '무서워요 C' - 1994, 도서출판 하늘소 (기술서)

(입문을 거친후, 실질적인 프로그램 작성의 요령과 여러가지 테크닉을 배우는데 아주 유용한 책이다)


  (참고로, C입문서는 1권쯤 가지고 있는 것이 좋습니다. 통신상의 강좌에서 보다 궁금한 것들은 더 자세히 살펴보는 것이 좋지요.

 또, 각 컴파일러의 레퍼런스 가이드란게 있는데, C 프로그래머에게는 필수입니다.  서점에 가면 아주 많으니, 자신의 구미에 맞는 것을 골라 보시기 바랍니다.)


제 1장 - C의 구조와 변수

  요즈음은 윈도우즈의 시대라고들 한다. Win95가 발표되고 아래 한글 3.0B가 대중화 되어가는 현 시점에서는 아마도 컴 사용환경의 80%이상이 Windows 기반일 것이다. 컴퓨터 언어를 이제 시작하고자 하는 사람들이나  기존의 프로그래머들도 이제는 Windows 프로그래밍으로 반드시 전환해야 하는 중요한 시기이다.

  하지만 그 Windows에서 돌아가는 프로그램을 작성하려고 해도 C언어가 기반이 되어야 한다. 그래야 훨씬 수월하다. Windows프로그래밍 공부의 시작요령은 마지막 회에서 언급하고자 한다.

  물론, 일반인들은 언어를 배울 필요가 없다. 하기야 이 글을 읽는 여러분들 중의 대부분은 컴퓨터에 대한 지적호기심을 가지고 있는 사람들과 전산관련분야로 진출하려는 사람들일 것이다. 모처럼 결심을 하고 컴퓨터 언어라는 전혀 새로운 언어 세계에 도전을 결심하고 남들이 모두들 배우라는 C언어라는 걸물을 만나게 되었을 것이다.

  그렇다! C언어는 분명 최고의 언어이다. 프로그램 개발에 최적을 효율성을 제공하고, C++, Assembly등 다른 언어로의 전환도 편리하며, 앞으로 표준이 될 윈도우즈 응용 프로그램도 C를 모르고서야 도무지 작성하기가  난감하다는 것이다.

  바로 여러분들은 최상의 선택을 하였으나, 앞을 가로막고 있는 난관이 보통이 아닐 것이다.

  C언어는 여타 언어에 비해 많은 장점과 다양한 기능을 가지고 있어 대부분의 프로그램들이 바로 이 C언어에 의해 코딩되고 있다.


  요즘의 주요 C 컴파일러들의 대표적인 특징으로는

가. 수행속도가 빠르며  사용이 편리한  통합환경에 의하여 최적 프로그램개발환경을 구축할 수가 있다.

나. 명령행 처리도 가능하여, 빠르고 간편한 개발이 가능하다.

다. ANSI 표준에 근거하고 있으며, 방대한 양의 자체 함수를 가지고 있다.

라. 6종류의 메모리 모델을 지원함으로서 큰 규모의 프로그램도 작성이 가능하다.

마. 어셈블리와 혼용하여 쓸 수 있으며, 다른 고급언어와의  연결(Link)도 가능하다.


  등등 다른 컴퓨터 언어에 비하여 많은 장점들을 가지고 있어 많은 사람들이 C언어로 프로그래밍을  하고 있고, 또 많이들 배우고 있다. 이러한  특성들이 전문 프로그래머에게는  다양한 표현방식을 제공하여 편리하겠지만 초보자의 경우에는 반대로 모든 특성을 이해하는데 많은 혼란을 가져올 수 있는 요소가 된다. 그렇기 때문에 C가 배우기 어려운 언어라는  말이 나오기 마련이다. 아울러 포기하는 사람도 많다.


  이 강좌의 목적은 이제 C를 배울려는 사람들과 과거에 C를 공부하다가 중도에 포기한 경험이 있는 이들로 하여금 자연스럽게 C의 세계로 입문할 수 있도록 하기 위한 것이다.  이 강좌를 읽다보면 모르는 사이에 저절로 C로의 입문이 가능해 지리라 믿는다.  이 글의 예제들은 모든 컴파일러가 지원을 하는 표준 C이므로 컴파일러가 무엇인지는  상관을 하지 않아도 된다.


1. C의 구조

  C에서는 프로그램의 형식이 있어 여기에 맞게 기술해야 한다. 형식이라고 해서 그리 대단한 것은 아니다. 여기 예제 프로그램이 있다.


/*  -- Sample --  */

 main()

 {

    printf("Hello, World!\n");

 } 

                     

  함수가 무엇인지는 여러분들 모두가 잘 알고 있을 것이다. 컴언어에서 함수란 어떠한 일을 처리하는 작은 프로그램이라고 보면 된다.

  C프로그램은 기본적으로 함수들의 집합으로 구성되어 있다.  그러므로 위의 프로그램은 main이라는 이름의 함수와  printf라는 이름의 함수로 구성되어 있음을 알 수가 있다. main()함수는 다른 자질구레한 기능을 하는 함수(여기서는 printf()함수)들을 모두 포함을 하는 가장 기본적인 함수이므로 프로그램에 반드시 포함이 되어야 하며, 프로그램의 내용은 { } 기호로 묶어서 시작과 끝을 나타낸다.

  C에서는 영어의 대문자와 소문자를 구별하므로 위의 예제를 반드시 소문자로 입력하여야 한다(abc와 ABC가 서로 다르게 인식된다).  C에서는 변수명을 제외한 프로그램의 대부분의 명령어를 소문자로 기술한다.

  C에서는 주석문을 /*과 */로 묶어서 표현한다. 주석문은 프로그램의 실행과는 무관하며, 적절히 붙여두면  후에  그 프로그램을 이해하는데 도움이 될 것이다.

  보통 프로그램의 본체는 관례적으로 { 다음에 서너칸 쯤 우측으로 물러나서 기술한다. 이러한 것을 indent(단짓기)라고 한다.

  베이직의 PRINT문과 유사한 기능을 하는 것이 출력의 기능을 담당하는 printf()함수이다. 화면에 출력하고 싶은 문자는 printf()함수의 괄호안에 "로 묶어서 나타낸다. C에서는 문장의  맨끝에 반드시  ; 을 붙여야 한다는 점을 명심해야 한다. 또한 main() 다음에는 ; 를 붙이지 않는다는 것도 명심하기 바란다. \n(개행문자라고 한다)은 행을 바꾸라는 의미이다.

printf("Hello, World! \n");

        --------------## -> 출력후 줄을 바꿈(개행문자)

    화면에 그대로 출력.


우선 예제를 통해 알 수 있는 C 프로그램의 기초적인 사항은,

1) C에는 행번호가 없다.

2) 대문자와 소문자가 구별되며, 주로 소문자에 기초하여 작성된다.

3) C는 main()으로 시작한다.

4) 프로그램(함수)의 본체는 { 와 }로 묶는다.

5) 한 문장은 반드시 ; 로 끝난다.(초보자가 실수를 잘한다)

6) 주석문은 /*  */로 묶어 표시한다.


2. C의 변수

 일반적으로 상수란 어떠한 정해진 값을 말하고, 변수란 어떠한 값을 보존하는 상자에 비유할 수가 있는데, 그 상자를 구분하기 위해서 붙이는 이름이 변수명이다.


 C에서 변수명이 갖추어야 할 요건은 다음과 같다.

1) 변수명은 보통 8문자까지 인식한다.

2) 변수명의 첫문자는 영문자(A-Z,a-z:대소문자가 엄격히 구분된다)나  _ 로 시작하며, 그 이후의 문자는 영문자나 숫자, 밑줄 어느 것이라도 상관없다(밑줄로 시작하는 변수는 주로 시스템 프로그램에서  사용하므로 실제의 경우에는 피하는 것이 관례이다).  

3ds : X ,  Son <> son

3) 명령어나 기존의 함수명은 변수명으로 사용할 수는 없으나 포함할 수는 있다.

for : X        fortune : O

4) 프로그램에서 사용할 변수는 반드시 프로그램의 첫머리에서 그 형:Type을 정의해야 한다.

int a, float b, char c ...


  위의 사항 중 초보자들이 가장 번거롭게 생각하는 것이 바로 4번이다.


  습관이 되면 불편하지 않게 되며, 오히려  프로그램의 분석에 커다란 도움을 주는 요소이며 구조적 사고를 하는데 도움을 주는 요소임을 깨달아야 한다.

 그러면 다음의 예제를 통해 변수의 형을 정의하는 방법을 익혀 보자.

<예제1> 밑변이 21, 높이가 4인 삼각형의 넓이를 구하는 프로그램 작성.

1:   main()

2:   {

3:      int a,b;

4:      float c;

5:      a = 21;

6:      b = 4;

7:      c = a*b/2.0;

8:      printf("넓이 = %f\n", c);

9:   }


  3행과 4행에서 변수 a와 b를 정수형으로, c는 실수형으로 선언한 것을 볼 수 있다. int는 그 다음의 변수를 정수형으로, float는 실수형으로 선언해 주는 예약어이다.여기서 변수 c를 실수형으로 선언한 이유는 다음과 같다. 위 프로그램의 결과는 나눗셈(/)이 있으므로 소수부분이 발생하는데, 정수형의 변수에 소숫점을 포함하는 실수형의 자료를 기억시키면  소수 부분이 절삭된다. 그러므로 계산의 결과를 고려하여  적절한 형(Type)을 선언하여야 한다.

  C에서는 변수의 선언과 동시에 초기값을 부여할 수가 있다. 3 - 7행을 좀 더 간단히 하면 다음과 같다.

int a=21, b=4;

float c;

c=a*b/2.0;

  C에서는 연산결과가 변수나 상수의 형에 의해 달라지게 된다.

정수 (연산) 정수 = 정수   

정수 (연산) 실수 = 실수

실수 (연산) 실수 = 실수


  그렇다면 3/4*4의 연산 결과는 얼마겠는가?

  3이라고 생각하겠지만 정답은 0이다. 3/4가  정수와  정수의  연산이므로 소수점 이하가 절삭되어 0이 된다. 이 0에다 4를 곱했으니 결과가  0이 되는 것이다.

  그러면 3/4.0*4의 결과는 얼마이겠는가? 대다수는 3이라고  생각하겠지만 여기서는 3이 아니라 3.0이 된다. 3/4.0이 정수와 실수의 연산이므로 연산 결과는 실수로 보존되어 0.75가 된다. 다음의 0.75 * 4 역시  실수와 정수의 연산이므로 결과는 실수가 되어 3.0이 된다.  3은 정수이고 3.0은 실수이므로 3은 올바른 답이 아니다. C에서는 3과 3.0을 엄격하게 구분하고 있으므로 혼돈하는 실수를 범하지 말기를 바란다. 이러한 실수는 프로그램의 실행결과에 심각한 영향을 미칠수 있기 때문에 항상 주의해야 한다.

  8행에서 " 안의 문자열을 제어 문자열이라고 하며, 제어 문자열은 인쇄가능 문자열과 기능 문자열고 구분된다.  인쇄가능 문자열은 화면에  그대로 출력되며, 기능 문자는 화면에 출력되는 대신에 특수한 처리를 한다. 이를테면 printf()함수 안의 \n 따위가 기능문자에 속한다.

|------| <-- 서로 짝이 된다

printf("넓이 = %f \n",c);

=======++=**  #

== : 화면에 그대로 출력된다(인쇄가능 문자)

++ : 인수(변수)를 10진 실수로 출력한다(형변환기호:기능문자)

** : 출력후에 줄을 바꾼다(기능문자)

 , : 제어문자열과 인수(변수)와의 구분

 # : 변수

  위의 도해에서 보듯이 %f는  제어문자열 다음의 인수와  한 쌍을 이룬다.

그러므로 인수가 3개이면 변환 기호도 3개가 기술되어야 한다.  정수형 인수를 출력할 경우에는 %f대신 %d를 기술한다.  printf()는 인수를 제어 문자열의 형식(format)대로 변환하여  출력해 주는 함수이다. 그러면 다른 예제를 통해 형변환 기호의 기능을 좀더 살펴보자.

 <예제2> 10 *  50 =  500

         100 / 3.0 = 33.3 을 출력하는 프로그램 작성.

 1:   main()

 2:   {

 3:      int a=10,b=50,c=100;

 4:      float d=3.0;

 5:      int sum1; float sum2; <- 두 문장이 한줄에 들어가도 된다

 6:      sum1 = a * b;              (;로 구분되어 있음에 유의)

 7:      sum2 = c / d;

 8:      printf("%3d * %3d = %4d\n",a,b,sum1);

 9:      printf("%3d / %3.1f = %4.1f\n",c,d,sum2);

10:   }


 9행의 의미를 분석하면,

*       #     @     * #  @   -->기능문자와 인수의 순서가  일치한다.

printf("%3d / %3.1f = %4.1f\n",c,d,sum2);

###===@@@@@===$$$$$--------

### : 정수를 세자리 넓이로 출력

@@@: 실수를 총 세자리 넓이로, 소수점이하 한 자리로 출력

 $$$ : 실수를 네자리 넓이로, 소수이하를 한자리로 출력

=== : 화면에 그대로 출력(공백포함)

--- : 인수( , 로 분리)


  위의 예에서 인수 a에 대한 %3d는 3자리를 확보한 후에 우측을  기준으로 출력하라는  의미로서 좌측의 남는 한칸은 공백으로 채워진다. ( ' 10'  )  좌측을 기준으로 출력할 경우는 %-3d와 같이 수치앞에  -기호를 붙인다. 자리수를 실수로 지정해서 출력할 경우에는 %7.3f처럼 기술한다. 7은 전체 자리수이며, 3은 소수 이하 자리수이다. 만약 소수 이하가 3자리를 초과할 경우에는 반올림이 되어 출력된다. 이 경우에도 우측을 기준으로 출력되며 좌측을 기준으로 출력할 경우에는  %-7.3f처럼 기술하면 된다.  만약 인수(변수)의 값이 변환기호의 자리수를 초과할 경우에는  변환 기호는 무시되어 인수의 자리수 길이만큼 출력된다. %7.3f로 3.14159를 출력하면 다음과 같다.

'^^3.142' (^은 공백을 나타냄) -->소수 네째자리에서 반올림된다

  printf()함수의 인수란에서 수식을 쓸 수도 있다. 즉, 8행을 printf("%3d * %3d = %4d\n",a,b,a*b);와 같이 기술해도 된다. 이 때는 sum1을 선언하지 않아도 된다(당연한 얘기!)

  이번장에서는 형변환 기호중 %d와 %f에 대해 알아 보았다.  하지만  다른 것도 있는데 변수의 형에 대해 좀더 깊이 공부하는 2장에서 언급하겠다.  수학에서는 소숫점을 포함하지 않는 모든 수가 정수이지만,  컴퓨터에서는 정수의 범위가 정해져 있다. 16비트(1워드)를 기본 단위로 하는 컴퓨터(일반PC)에서  -32,768 -- 32,767사이중 소수점을 포함하지 않는 수치만을 정수로 취급한다.  32비트를 1워드로 하는 중형급 이상의 컴에서는 정수의 범위가 -2,147,483,648 -- 2,147,483,647사이의 수치로 확장된다.

  컴퓨터에서 변수형에 따라 범위가 제한되어 있는 이유와 원리는  다음 장에서  알아보기로 하자.


3. 문자형 변수

  C에서는 프로그램의 선두에서 변수의 형을 정의하는데에 따라 ab가  수치변수가 되기도 하고 문자변수가 되기도 한다.  문자변수 중에서도 단일 문자를 기억하는 변수와 문자열을 기억하는 변수의 선언방식이 조금 다르다.

<예제3> '우리는 지금 C를 배우고 있어요.'을 출력하는 프로그램을 문자변수를 이용하여 작성하라. 변수 s에 '우리는 지금'을, 변수 c에 'C'를  기억시키고, '를 배우고 있어요.'는 문자열 상수로서 출력하라.

1:    main()

2:    {

3:       char c, *s;

4:       s = "우리는 지금";      /*  문자열은 "로 둘러싸고, */

5:       c = 'C';                /* 단일문자는 '로 둘러싼다 */

6:       printf("%s %c %s\n",s,c,"를 배우고 있어요.");

7:    }


  위에서 편의상 한글을 사용하였는데 한글의 한 문자는  영문의 두 문자에 해당한다. 그러므로 5행을 c = '씨'라고 표현해서는 안된다.

  3행의 char은 다음의 변수가 문자형 변수임을 선언하는 예약어이다. 문자형변수는 단 1개의 문자만을 기억하는 것을 의미한다. 만약 문자열을 기억/시키고 싶으면 변수명 앞에 *를 붙여서 *s처럼 선언하면 된다. *는 포인터를  의미하는데, 우선은 문자열 변수는  변수명 앞에 *를 붙여서 선언한다라고 알고 있자.  * 는 선언할 때에만 쓰이고, 값을 대입하거나 출력하는 경우에는 쓰지 않는다(쓰면 안된다는 것은 아니고,  우선은 쓰지 않는  것으로 하자:6장에서 배울 것이다).

  4행은 문자열을 대입하는 보기이며, 5행은 문자를 대입하는 예이다. 그리고 6행에서 문자열 자체나 수식자체도 인수가 될 수 있다.  C에서는 변수의 형 선언과 함께  초기값을 부여할 수도  있다고 하였으므로, 3 -- 5행을 한 문장으로 표현하면 다음과 같다.

char c = 'C', *s= "우리는 지금";

  물론 위의 프로그램을 printf("우리는 지금 C를 배우고 있어요.\n");처럼 1행으로도 처리가 가능하다.


4. 포맷 코드(형변환 기호)

  포맷 코드, 즉 출력 양식을 의미한다. C에서는 다양한 출력 양식을  제공한다. 밑의 표에서 code앞에 printf를 붙여 반드시 실행해 보기를 바란다.

<표1> 포맷 코드        a=1234, b=3.14159, c='A', s="ABCD" (=:공백)

code

출력형태

설                 명

("%d",a)

1234

정수의 출력

("%8d",a)

====1234

수치를 우측을 기준으로 8자리 출력

("%-8d",a)

1234====

좌측을 기준으로 8자리 출력

("%+8d",a)

===+1234

수치앞에 부호

("%08d",a)

00001234

수치앞의 공백을 0으로 채움

("%+08d",a)

+0001234

부호붙이고 공백을 0으로 채움

("%f",b)

3.14159

실수의 출력

("%8.3f",b)

===3.142

전체 8자리, 소수 3자리 출력

("%-8.3f",b)

3.142===

좌측기준 (소수이하 반올림)

("%+8.3f",b)

==+3.142

부호를 붙여서 출력

("%08.3f",b)

0003.142

앞의 공백을 0으로 채움

("%+08.3f",b)

+003.142

부호를 붙이고 공백을 0으로 채움

("%c",c)

A

문자 출력

("%8c",c)

=======A

우측을 기준으로

("%-8c",c)

A=======

좌측을 기준으로

("%s",s)

ABCD

문자열의 출력

("%8s",s)

====ABCD

우측을 기준으로

("%-8s",s)

ABCD====

좌측을 기준으로

# 출력하려는 수치, 문자의 길이가 포맷코드보다 크면  포맷코드는 무시됨

5.Escape Sequence(Esc문자열)

  이 문장은 어째 이상하지 않은가?

printf("멀티미디어 - 덩달이 왈 "아니 얘가 뭘 디빈디어?"\n");

  그러면 "는 어떻게 표현을 할까? 문장내의 "를 표현할때는 "앞에 \을  삽입하면 된다. printf("He said, \"I love you.\"\n");와 같이.

  위에서 보는 것과 같이 \로 시작하는 문자의 나열을 ESC 문자열이라고 한다. 이 것은 \"처럼 \다음 문자가 화면에 그대로 출력되는 경우가 있고, \n 처럼 화면에 출력되는 대신에 줄을 바꾸는 역할도 있다.


<표2> 이스케이프 시퀀스

e.s

명    칭

기             능

ASC코드

\a

Beep

'삑'소리를 낸다

0x07

\n

Line feed

줄을 바꾼다

0x0a

\t

TAB

다음 TAB위치로 이동

0x09

\b

Back Space

인쇄반대방향으로 1칸 후진

0x08

\r

Carrige Return

Return(Enter) 역할

0x0d

\f

Form feed

출력용지를 1페이지 전진

0x0c

\\

Backslash

\ 출력

 

\'

Apostrophe

' 출력

 

\"

Quote

" 출력

 

\0

Null

아무런 동작도 하지않음

0x00

%%

Percent

% 출력

 

# 0x는 8진수를 기술할 때 앞에 붙여주는 기호이다.

# 또한 \뒤에 직접 8진수인 3자리 수치를 입력함으로써 아스키문자를 출력할 수 있다. (\x00a는 \n과 같다)

<예제4> 다음 프로그램의 실행결과를 적어보시오.

 1:    main()

 2:    {

 3:       int a = 66;

 4:       float b = 3.14159;

 5:       char c = 65, *s = "알파벳의 첫문자는 ";

 6:       printf("%6d\t%-6d\n",a,a);

 7:       printf("%6c\t%-6c\n",a,a);

 8:       printf("%8.5f\t%-8.5f\n",b,b);

 9:       printf("%4c\t%-4c\n",c,c);

10:       printf("%4d\t%-4d\n",c,c);

11:       printf("\n%s%2c",s,c);

12:       printf(". %s\n","끝이라우.");

13:    }


  위의 프로그램에 이상한 부분을 발견하였는가?

  char c = 65가 바로 그것인데, 문자 변수에 단일 문자를 기억시킬 때는 '로 묶는다고 하였는데 이 문장에서는 문자 변수에 수치상수를 대입하였으니  오타가 아니냐는 오인도 했을 것이다.

  c를 정수형으로 선언하였다면 65가 대입이 된다. 하지만 지금은 문자형으로 선언하였으므로 아스키 코드의 65번 문자 A를 대입하라는 의미가 된다.

  문자 변수에 수치상수를 대입하면 C에서는 그 수치에 해당하는 아스키 값을 문자변수에 대입하게 된다( 물론, 이때 수치의 범위는 0 -- 255 사이의 정수값이라야 한다).

  컴퓨터는 문자를 아스키 코드로 기억하고 저장하므로  이 코드를  수치로 보느냐, 문자로 보느냐는 출력하기에 달려있다. 다시 말하면, 자료의 변환이 자유롭다는 것이다. 그러므로 정수를 %c로 출력하면 그 값을 아스키 코드로 하는 문자가 출력되며, 문자를 %d로 출력하면 그 문자의 아스키 코드가 출력되게 된다.

  예제의 실행결과는 직접 실행시켜 보기 바란다(백견이 불여일Run이라).

  이번 장에서는 C의 구조와 변수, printf() 함수에 대하여 알아보았다. 혹시 이해가 잘안가는 부분이 있을지 모르겠다.  '언어 강좌'란의 다른 강좌를 참조하거나 소동회의 실력자들이 모여 있는  C & C++ 질문과 답란을 이용해 주기를 바란다.

  하지만 언어를 배우는 데에는 이해가 될 때까지 고민해보고, 간단한 개념이라도 직접 컴파일 시켜 가면서 공부하는 것이 가장 좋은  방법이라는 것이 진리이다. 그리고  이 강좌를  충실히 따라가다 보면 절로 모르는 부분이 이해가 될 날이 닥칠 것이다.  시작이 반이다.  이제 여러분들은 1회를 무사히 마쳤으니  이 패기로 C의 초보딱지를 떼게 되는 8장까지 힘차게 따라와 주길 바란다.


제 2장 - C의 입출력 함수 및 수의 표현

  제 1장에서 우리는 C의 기본 문법과 print함수에 대해서  공부하였다. 이번장에서는 기본적인 입출력 함수들 각각의 기능과 차이점을  알아보고 상황에 따라 알맞은 입출력 함수를 선택할 수 있도록 할 것이다. 그리고 C언어에서 여러가지 수치의 표현방법과  수치의 형을 지정하는 이유를 알아보자.


1. 라이브러리(Library)에 관하여

      - C의 배움의 과정은 문법과 라이브러리 함수 마스터 이다.

  프로그램을 작성할 때 모든 루틴을 프로그래머가 일일이 작성해야 한다고 생각해 보자. 얼마나 비효율적인 일인가? 프로그래머가 입,출력 등의 프로그램의 사소한 부분까지 코딩해야 한다면 시간낭비요, 인력낭비일 것이다. 그래서 C와 같은 고급언어에서는 프로그램에서 주로 사용되는 기본적인 기능들을(함수들을) 미리 작성하여 라이브러리로 구축하여 놓고 프로그래머들이 하나씩 호출하여 쓸 수 있도록 해 놓았다.(이것을 표준 라이브러리라고 한다) printf()의 경우에도 라이브러리에 미리 작성되어 있는 함수이다.

  전장에서 C프로그램은 함수들의 집합으로 이루어져 있다고 배웠다. 화면에 문자를 원하는 형식대로 출력해 주는 기능의  printf()함수를 비롯하여 C에서는 수백가지의 함수들을 지원한다.  프로그래머는 이러한 다양한  함수들 중에서 자기가 필요로 하는 함수들을 호출하여 사용하는 것이다. printf()함수뿐만 아니라 오늘 우리가 배우려 하는 입출력 함수들도  일반적으로 많이 쓰는 함수이다.

  요즘에는 이러한 C표준 라이브러리 뿐만 아니라, C프로그래머들의 편의를 위하여 각종 상용 라이브러리들이 나와 있다. 우리가 지금 자체 한글을 지원하는 회원관리 프로그램을 작성한다고 치자. 그러면, 정작 중요한  자료 관리 부분보다는 먼저 한글과 프로그램 인터페이스를 작성하여야 할  것이다. 프로그램의 가장 중요한 부분인  자료관리 부분에 많은 노력이 들어가야 하는데, 그 이전에 덜 중요한(?) 부분에 매달려야 한다면 이것은 시간, 노력낭비가 아닐 수 없다. 하지만 시중에 나와있는 한글 라이브러리를  사용하여 원하는 기능을 가진 함수들을 호출하기만 하면 시간과 노력을 훨씬 줄이면서 프로그램을 작성할 수가 있는 것이다. 참고로 필자는 한라프로라는 자신의 프로그램에서 한글과 GUI를 마음대로 구현할 수 있는 공개 라이브러리를 쓰고 있다. 이 라이브러리는 동호회 자료실에 등록되어 있으니 필요하다면 다운받기 바란다.

  우리는 초보이므로 일단은  C에서 제공하는 기본 라이브러리 함수를 이용하는 방법부터 배워야 한다. 그러면 오늘은 먼저 입출력 함수에 대하여 알아보기로 하자.


2. 출력 함수

  C에는 printf()함수 이외에도 단일문자를 출력하는 putchar()함수와 문자열을 출력하는 puts()함수가 있다.

putchar('C')  ;         --> 단일문자 출력(줄을 바꾸지 않는다)

puts("I Love You!") ;  --> 문자열 출력(출력한 후 자동으로 줄을 바꾼다)

  위의 두 함수로 전장에서 배웠던 Esc문자열을 그대로 쓸 수가 있다. 즉 putchar('\n')은 줄을 바꾸며, puts("\a Error!")는 삑 소리를 내며 에러메시지를 출력한다.


<예제1> 변수를 이용하여 'I' 'like' 'C' 'Programming'을 기억시키고 다음과 같이 출력되도록 하는 프로그램 작성.

              I like C Programming!

이 프로그램은 두 가지 관점에서 작성될 수가 있다.

<리스트1>

#include <stdio.h>

main()

{

char c1='I', c2='C';

char *s1="like",*s2="Program";

printf("%c %s\n%c %s\n",c1,s1,c2,s2);

}

 

<리스트2>

#include <stdio.h>

main()

{

char c1='I', c2='C';

char *s1="like",*s2="Program";

putchar(c1);

putchar(' ');

puts(s1);       putchar(c2);

putchar(' ');   puts(s2);

}


  먼저 각 프로그램 첫머리의 #include <stdio.h>라는 문장을 주시하라.

  stdio.h는 standard input/output의 준말로서  표준입출력 함수에 관한 선언을 모아둔 Header화일이다.

 위에서 우리는 라이브러리에 대하여 알아보았다. 고급언어로 작성된 프로그램은 <컴파일>이라는 과정을 거쳐 컴퓨터가 이해할 수 있는 기계어로 번역이 되고,  프로그램에서 사용된 표준 함수들을  라이브러리(미리 기계어로 변환 되어 있다)에서 추출해 와서 프로그램에 결합하는  <링크>라는 과정을 거쳐야 비로소 하나의 실행화일이 만들어 지는 것이다.

  변수와 마찬가지로 프로그램에서 사용되어질 함수들은 모두 프로그램  첫머리에서 선언이 되어야 한다. C에서는 방대한 라이브러리 함수들을 그 기능별로 세분화하여 선언을 해 둔 헤더화일을 가지고 있다.  위 프로그램에서 사용되는 printf(), putchar(), puts()등과 잠시후 배울 입력 함수들에 관한 선언들은 모두 <stdio.h>화일에 들어있으므로  #include 명령을 써서 <stdio.h> 화일을 포함시켜 준 것이다.  #include <화일명>은  파일명으로 지정하는 프로그램 모듈을 그 위치에 삽입하여 컴파일 하라'는 의미로 C컴파일러에 주는 의사명령의 하나이다. 의사명령이란 예약어가 아니고  컴파일러에게 지시하는 명령어를 말한다(이러한 것을 전처리기라고 한다).

  그러면, 지난 장에서는 예제에서 printf()함수를 사용하였는데 왜 #include문장이 없었지? 라고 생각하는 분도 계실텐데, 'stdio.h'는 기본 입출력 처리루틴을 위해 준비된 것으로 #include문으로  지시하지 않더라도  자동적으로 삽입이 된다. 하지만 기술하여 주는 것이 바람직한 습관이라  하겠다.

 위의 두 프로그램을 비교해 보면 <리스트1>이 훨씬 간단하고 편리함을 알 수가 있다. 하지만, printf() 함수는 수치, 수식 등의 계산 결과와 문자, 문자열 등을 처리해야 하므로 당연히 수학적인 라이브러리가 일부  <링크>시에 포함이 된다. 그러나, putchar()함수나 puts()함수는 문자와  문자열만 처리하면 되므로 수학적인 라이브러리가 필요없다. 그러므로 <리스트1>이 소스코드는 간단하지만 실행화일의 크기는 <리스트2>가 작다.


3. 입력 함수

  다음은 C의 표준 입력 함수들에 관하여 알아보자.

# getch()

단일문자를 입력받으며, 입력하는 문자는 화면에 표시되지 않는다(No Echo)

# getchar()

단일문자를 입력받으며, 입력하는 문자는 화면에 표시된다(Echo Back)

<Enter>를 누르면 입력이 종료되며 여러문자를 입력해도 처음의 한 문자만을 유효하게 받아들인다.

# gets()

<Enter>를 누를 때까지 공백을 포함한 모든 문자열을 입력받는다.

# scanf()

여러개의 변수값을 입력받는다. 자료와 자료사이는 공백, 탭, \n 등으로 구분한다. 서식 제어 문자열(%d,%f,%c,%s 등)을 사용하여 지정된 형식으로 입력받기도 한다. 또한 수치변수에 값을 읽어 들일 때에는 인수명 앞에 &를 붙여야 한다. (printf()함수는 변수명칭, 상수, 수식 등을 인수로 사용하나 scanf()함수는 변수의 포인터를 인수로 사용한다. - 일단은 수치형을 입력 받을 땐 &를 붙이고, 문자열을 입력받을 땐 &를 사용하지 않는다고 알고 있자.)

<예제2> "당신의 이름은?"이라는 질문에 자신의 이름을 성과 이름을 구분하여 입력하여 "내 이름은 # ##입니다."를 출력하는 프로그램 작성.

<리스트3>

1:    #include <stdio.h>

2:    main()

3:    {

4:       char *s = "          ";

5:       printf("당신의 이름은? ");

6:       scanf("%s",s);

7:       printf("내 이름은 %s입니다.\n");

8:    }


  지난 장에서 문자열을 기억하는 변수는 변수명 앞에 *를 붙인다고 했다.

  변수명 앞에 * 를 붙인 것은 포인터를 의미하는데,  일단은 포인터 변수란 "어떤 자료가 메모리에 저장될 때 그 메모리의 번지를 기억하는 변수"  정도로 알고 있자. 문자열을 입력받기  위해서는 4행과 같이 먼저  문자열을 기억시킬 영역을 확보해 두어야 한다. 4행에서 공백은  입력받을 문자열의 길이와 같거나 길어야 한다. 이 문장의 s 변수는 공백 10칸이 저장된 메모리의 번지를 가지는 변수라고 해석할 수 있다. <리스트3>의 실행 결과는,

            당신의 이름은? 홍 길동

            내 이름은 홍입니다.

  6행에서 scanf()함수는 공백이 자료를 구분하는 역할을 한다고  했으므로 변수 s에는 '홍'만 기억되는 것이다.  그럼, <리스트3>을 어떻게 바꾸면 좋을까?

            4행을  char *s1 = "   ", *s2 = "       ";

            6행을  scanf("%s %s",s1,s2);          

  로 바꾸어 성과 이름을 넣는 변수를 각각 선언하고 값을 할당하면 된다.

  하지만 이것은 별로 바람직 하지가 못하다. 그러면 <리스트3>에서,

            6행을 gets(s);로 바꾼다.

  공백을 포함한 문자열을 입력받을 경우에는 gets()함수를 쓰면 된다.

  그리고 <리스트3>을 <리스트4>로도 기술할 수가 있다.

<리스트4>

1:  #include <stdio.h>

2:  main()

3:  {

4:     char *s, arr[20];

5:     s = arr;

6:     printf("당신의 이름은? ");

7:     gets(s);

8:     printf("내 이름은 %s입니다.\n",s);

9:  }


 위에서 'arr[20]'은 배열을 의미한다(배열은 후에 자세히 배울 것이다).

 char arr[20];의 뜻은 문자가 20개 저장될 만큼의 arr라는 이름의 빈 공간을 확보하라는 것이다.( int number[10];은 정수가 10개 저장될  number라는 방을 확보하라는 뜻이다)

 그러므로 5행은 20칸의 공백(을 가진 배열 arr)을 s에 대입한다는 의미이다.

 문자열을 입력받기 위해서는 먼저 문자열을 기억시킬 영역을 확보해 주어야 하는데, 그 방법은 다음의 2가지가 있다.

1) char *s = "          ";

2) char *s, arr[n];   ( arr: 임의의 배열명,

s = arr;              n: 임의의 수치     )


 <예제3>  사다리꼴의 3변(윗변,밑변,높이)를 입력하여 그 넓이를 구하는 프로그램 작성.

[입력]

DATA? 345 678 123 

[결과]

AREA =   62914.50

<리스트5>

 1:     #include <stdio.h>

 2:    

 3:     main()

 4:     {

 5:        int a, b, c;

 6:        float s;

 7:        printf("DATA ? ");

 8:        scanf("%3d %3d %3d", &a,&b,&c);

 9:        s = (a+b)*c/2.0;

10:        printf("AREA = %10.2f\n",s);

11:     }


 위에서 8행의 의미는

          @   #   $     @  #  $   <= 차례로 대응한다

          scanf("%3d %3d %3d", &a,&b,&c);   "   "안의 공백은 있어도 없어도 된다.

 %3d는 3자리의 정수를 입력 받는다는 의미이다.  scanf()함수의 제어코드는 지난 장에서 배운 printf()함수의 제어코드와 대부분 일치한다.

  그럼,  <리스트5>를 실행한 후, 345 678 123입력해 보라. 답이 제대로 나왔는가? 아마 -2621.50이라는 엉뚱한 수치가 출력될 것이다.

  그러면,34 56 78을 입력해 보자. 3510.00이라는 정확한 수치가 출력된다.

  얘가 왜 이럴까?

  전자의 경우는 답이 음수로 출력이 된다. 이것은 (a+b)*c 즉, (345+678)*123의 계산 결과가 int형 정수의 범위(-32,768 -- 32,767)을 넘어섰기  때문이다. 자료형의 범위를 넘어섰을 경우를 overflow가 발생했다고 한다. C에서는 이러한 프로그래머의 조그마한 실수의 책임을 전적으로 프로그래머 자신에게  떠맡긴다.  그래서 우리는 자료형의 범위를 알아놓을 필요가 있다.

  여기서 overflow가 발생하지 않도록 하려면,

    (1) 변수 c를 실수형으로 선언하고(c를 곱하는 과정에서 발생했으므로),

        8행을 scanf("%3d %3d %3f",&a,&b,&c);로 바꾼다.

 

c가 실수형이면,

(a + b)  *   c   /  2.0

(a + b)  *   c   /   2.0

정  수

정  수

실  수

정  수

실  수

실  수

 

 

 

 

 

 

 

 

 

 

 

 

 

정수(Overflow)

 

 

 

 

실수(Overflow발생안함)

 

 

 

 

 

 

 

 

 

 

 

 

 

실    수

 

 

 

실   수

 

 이 이유는 지난 장에서 자세히 설명하였다.

                                                             

   (2) 9행을 다음과 같이 기술한다.

       s = (float)(a+b)*c/2.0; 또는 s = (a+b)*(float)c/2.0;

       (float)의 의미는 뒤의 식의 결과나 변수값을 강제로 실수로 보존하라는 의미이다. 이렇게 자료형을 강제로 바꾸는 예약어를  cast 연산자라고 한다.

       물론 실수변수 float c;를 정수로 강제로 지정하려면 (int)c로 하면 된다.

   (3) 변수 a, b, c를 배정도 정수로 선언한다.(설명은 밑에 계속된다)

4. 수치자료의 표현

 컴퓨터에서의 수치자료의 형은 여러가지로 나누어 진다. 다음 표를 보자.


<표1> 기본 데이터형의 크기와 범위

구  분

종     류

선       언

크 기

범        위

문  자

부호있는 문자형

char

1

-128 -- 127

자  료

부호없는 문자형

unsigned char

1

0 -- 255

표  준

부호있는 정수

int

2

-37,768--32,767

정  수

부호없는 정수

unsigned int

2

0 -- 65,535

배정도

배정도정수(부호O)

long=long int

4

-21억4천만 -- 21억4천만

정  수

배정도정수(부호X)

unsigned long

4

0 -- 4,294,967,295

실  수

단일 실수

float

4

1.7*10^-308~ 1.7*10^308

배정도 실수

double

8

3.4*10^-308~ 3.4*10^308

# ^ 은 거듭제곱을 나타낸다.   # 위에서 크기의 단위는 Byte이다.

# 문자자료의 경우 C에서는 1 Byte정수형 자료로 처리한다.


  (수치의 형을 지정해야 하는 이유)

  위의 표에서 보듯이 수치의 범위에 따라 자유롭게  변수형을 선언할 수가 있다. 수치의 형을 왜 이리 복잡하게 나누어 놓았나 반문하는 사람도 있겠지만 표에서 위에 있는 형일수록 크기(Byte)가 작아 메모리 사용량도 줄어 들고 연산속도도 빨라진다. 작고 단순한 연산을 할 때에는 char형,  int형으로도 충분하겠지만, 심지어 우리가 가계부같은 프로그램을 작성하려  해도 최소한 배정도 정수형은 필요할 것이다. 그러므로, C에서는 사용자의 필요에 따라, 프로그램의 목적에 따라  속도와 메보리를 고려해 가면서 자유롭게 수치의 형을  선택할 수가 있는 것이다.


  (1) 정수 표현 방법

     정수형의 자료를 나타내는 int형은 2Byte(즉 1Word,16Bit)이므로  나타낼 수 있는 수치의 종류는 65,536가지이다.(2의 16승 - 수학시간에 졸지 않은 사람은 다 안다)

     부호를 사용할 필요가 없는 정수형 변수(Unsigned int)는 0에서 65,536까지 범위를 나타낼 수가 있으나, 일반 int형 변수는 양수, 0 ,음수를  모두 사용해야 하므로 반으로 나누어 -32,768 ~ 32,767 ( 0은 편의상 양수에 속한다 )사이의 범위를 가지게 되는 것이다.

     그러면, int a = 32767, b = 1, sum;

         sum = a + b ;           에서 sum의 값은 얼마일까?

     바로, 오버플로우가 발생한다. 실제는 32768이 되지만 범위를 넘어서므로 sum의 값은 -1이라는 어처구니 없는 값이 발생한다. 그러므로 우리는 연산을 할 때, 수치형의 범위를 고려하여야 괴짜 프로그램을 생산하지 않게 된다.

     이젠, <예제3>의 해결책 3가지 중 3번이 이해가 되리라고 본다.

      5행을 long a,b,c;

      8행을 scanf("%3ld %3ld %3ld",&a,&b,&c); 로 바꾸면 된다.

      (%ld는 배정도형 정수를 출력하거나 입력받을 때 쓰는 변환기호이다)

     컴퓨터에서는 모든 자료를 2진수로 취급한다.

     int a=15라고 했을 때, 컴퓨터 내부에서는 a를 000000000001111(int형은 2바이트 = 16비트이므로)로 기억한다.

    그러면, int b=-15라고 했을 때 어떻게 기억을 할까?

    컴퓨터는 2진수로 음수를 표현할 때 2의 보수를 취하는 방법을 이용하는데, 그 방법은 다음과 같다.

 (1) 양수값에다가 1의 보수를 취한다(비트반전).

 (2) (1)의 결과에 1을 더한다.

            15 => (1) 1111111111110000 (1의 보수를 취함)

                   (2) 1111111111110001 => -15 (1을 더함)

  부호를 고려하는 정수형(int)의 경우에는 맨좌측 최상위 비트가 0이면 양수로, 1이면 음수로 본다.

  하지만 unsigned int(부호없는 정수)형의 경우에는 양수만을  취급하므로 최상위 비트를 고려하지 않는다.

  예를 들어보자.    1111111111110001가 int형이라면, 최상위비트가 1이므로 이 값은 음수이므로 2의 보수를 취하여 0000000000001111(15)의 음수값인 -15가 된다. 반면에  1111111111110001이 unsigned int형이라면, 최상위비트와는 관계없이 10진수로 65521이 된다.

  장황하게 설명을 하였는데, 기본적으로 알아두어야 할 내용이므로 언급하였다.(전산학에서는 기본적으로 알아야 할 내용이다)

  일반적인  프로그램에서는  정수형이나 배정도 정수형 변수로도 프로그램작성이 가능하나, 수학적인 계산이  조금이라도  들어가는 프로그램에서는 실수형이 필요하게 된다. 그럼, 실수 표현 방식에 대하여 알아보자.

  (2) 실수 표현 방법 

  컴퓨터에서 실수(float형)를 표시하는 경우에는 부동소숫점 형식을  이용한다. 부동소수점 형식에서는 하나의 수치를 표시하는데에 4Byte를 할당한다.

첫 byte는 그 수치의 부호와 지수를 표시하며 남은 3 byte로는 1 byte 당 10진수 2자리를 BCD형식으로 표시한다.  BCD(Binary Coded Digit)는  우리말로 2진화 10진수라고 부르며, 4비트로 10진수 1자리를 표시하는  형식을 말한다.

  4비트로 표시할 수 있는 수의 종류는  2의 4승(0 ~ 15까지)가지가 있지만 BCD에서는 0에서 9까지만 표시한다.  1994를 BCD로 표시하면,

0001

1001

1001

0100

(4비트로 10진수 1자리를 표시)

1

9

9

4

 

     예를 들어 float a=1994; 일때 컴퓨터에서는,

 

 

(이 영역은 BCD형식으로)

xyyy

yyyy

0001

1001

1001

0100

0000

0000

(총 4 byte)

 

 

 

 

1.

9

9

4

0

0

 

 

 

 

 

 

 

 

 

     *소수점은 항상 이 위치에 있는 걸로 간주

 

 

지수(10의 멱승을 나타냄)    .여기선 0000011

부호(양수이면 0, 음수이면 1) .여기선 0

 

        ==> 1.99400 * 10의 3승 (1994.00) : 실수 표현 방식이다.


  위에서 보면 지수의 표현을 7bit로 하고 있다. 7비트로 할 수 있는  자료의 종류는 128가지인데, 음수, 양수를 구분해야 하므로 지수의 범위는  -64에서 63까지가 된다.

  위에서 보듯이 실수형(float) 자료의 유효 수치는 6자리이다. 그러므로 7자리 이상의 수치를 기억시키는 경우에는 7번째 자리에서 반올림이 행하여진다.

  C에서는 수치의 유효 자리수를 2배로 늘리기 위해  배정도 실수형(double)을 지원한다. 배정도 실수는 8byte로 표시하게 되며, 유효자리수는 14자리로 늘어난다.

( 총 8 byte )

xyyy

yyyy

0000

0000

0000

0000

0000

0000

....

0000

0000

0000

0000

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

지수비트

7 byte (유효자리수는 14자리로 늘어난다)

부호비트


5. 형 변환 기호(format code)

 지난 장에서 printf()함수를 배울 때 형변환 기호에 대해 언급하였다.

이번 장에서는 좀 더 자세히 알아보자.

<표2> 형 변환 기호

기  호

인수의 수형

변환의 내용

%d

정 수 형

인수를 부호있는 10진수로 출력한다

%u

정 수 형

인수를 부호없는 10진수로 출력한다

%ld

배정도 정수형

인수를 부호있는 배정도 정수로 출력한다

%lu

배정도 정수형

인수를 부호없는 배정도 정수로 출력한다

%o

정 수 형

인수를 부호없는 8진수로 출력한다

%x

정 수 형

인수를 부호없는 16진수로 출력한다(소문자로)

%X

정 수 형

인수를 부호없는 16진수로 출력한다(대문자로)

%c

문자(or정수형)

인수를 단일문자로 출력

%s

문자열 포인터

\0앞까지의 문자열이던가 지정된 길이만큼 출력

%f

부동소수점 실수

고정 소숫점 형식으로 출력 ex: 35.45600

%e

부동소수점 실수

부동 소숫점 형식으로 출력 ex: 3.54560e+01

%E

 

3.54560E+01

%g

부동소수점 실수

고정,부동 중 간단한 형식으로 출력(e)

%G

 

(E)

        # 제1장의 <표1>과 조합하여 출력이 가능하다.


scanf()함수는 printf()함수와 거의 같은 변환 기호를 사용한다. 가장 큰 차이점은 다음과 같다.

  1) %g, %G 옵션이 없다.(생각해 보면 당연한 것이다)

  2) %f와 %e는 같다.(둘 다 부호,소수점,지수부의 유무에 관계없이  받아들인다.

<예제4> 다음 프로그램의 실행결과를 적어 보아라.

/* 출력 형태 실습 - 여러가지 수를 입력해 보고 출력형  */

/*                   태를 예상하는 연습을 한다        */

#include <stdio.h>

  main()

  {

    float a;

    int b;

    printf("\n임의의 숫자(실수) 입력:");

    scanf("%f",&a);               /* 874563을 입력해보고, */

                                   /* 0.04568을 입력해보고,*/

                                   /* 756.355를 입력해보라 */

    puts("당신이 입력한 수치를");

    printf("고정소수점형식으로 출력하면 :%f\n",a);

    printf("부동소수점형식으로 출력하면 :%E\n",a);

    printf("\n임의의 양수를 입력하라 :");

    scanf("%d",&b);                 /* 3654를 입력해 본다 */

    printf("10진수==>8진수==>16진수\n");

    printf("%d ==> %o ==> %X\n",b,b,b);

    printf("\n 끝낼려면 아무키나 누르시오.");

    getch();

   }


  제 2장에서는 기본적인 C의 입출력 함수와 수치형의 종류에 대하여  알아 보았다. 여러분들께 자세히 전달하려고 노력하였으나, 혹시 애매한 부분이 있을지도 모르겠다. 하지만 10번 읽으면 이해되지 않는 것이 없다고 했다.

  C언어는 기본 개념을 확실히 잡지 않으면 후에 가서 고생을  하게 되므로 꼭  이번장의 내용을 이해하기를 바란다.

  다음 장에서는 제어 구조에 대하여 공부하겠다. 반복되는 이야기지만  예제들은 직접 입력하여 실행시켜 보고, 왜 그렇게 되었는지를 완전히  이해하는 것이 프로그램 언어를 공부하는 가장 좋은 방법이라고 했다. 이제 여러분들은 2장을 마쳤으니 1/4을 끝낸 셈이다. 부디 본 강좌와 함께 자연스러운 C언어 입문이 되기를 바라겠다.


제 3장 - 제어 구조

  제 2장에서 우리는 C의 기본 입출력 함수들과 수치형의 종류와 그 원리에 관하여 공부하였다. 우리가 단순한 입출력이나 계산을 할 때에도 프로그램에 융통성을 주어 작성할 수가 있다. 이번 장에서는 프로그램의 흐름을 다양하게 해주는 순환과 제어에 관한 방법에 대하여 배우겠다.


1. 제어문

  제어문이란 프로그램의 실행을 강제로 바꾸는 명령어이다.

  goto 문 ( goto label; ) - ## 있다는 것만 알고, 쓰지 말기를 바란다 ##

  goto문은 프로그램의 실행을 지정된 레이블이 있는 위치로 강제로 옮기는 명령어이다.  레이블명 뒤에는 반드시 :를 붙이며,goto명령과 결합된 레이블 뒤에는 :를 붙이지 않는다.


<예제/리스트1> 짝수가 계속 출력되는 프로그램



 한편 위의 프로그램은 멈추지 않는 무한루프에 빠지게 된다.  프로그램의 실행을 강제로 멈추게 하려면 <Ctrl> + <Break>키를 누르면 된다.  일반적인 경우에는 goto문을 쓰지 않는다. goto문은 프로그램의 논리적 측면에도 역행하고, 프로그램의 분석을 어렵게 하므로 우리는 이러한 게 있다는  것만 알아두자.


 if ... then ... else 문 (조건 제어문)

  조건 제어문이란 어떤 조건이 참, 거짓 여부를 판단하여 실행을 제어하는 구조를 말하며, 중첩사용도 허용이 된다.


 if(     )안의 조건식이 참이면 실행부1을 실행하고 거짓이면  실행부2를 실행하라는 뜻이다.


<예제2> 하나의 정수를 입력받아 짝수인지 홀수인지 판별하는 프로그램

         (리스트들의 단짓기 요령을 유심히 보아주기 바란다)


<리스트2>


  베이직에서는 = 가 대입할 때도 쓰이고 같다는 등호로도 쓰이지만, C에서는 = 과 == 을 엄격히 구별한다. 즉 = 는 대입 연산자로 쓰이고, == 는 같음을 나타내는 관계 연산자로 쓰인다.


          sum = a + b  => (대입연산자) a+b의 값을 sum에다 대입시켜라

          if ( a == b ) => (관계연산자)  만약, a와 b가 같다면,,


  첫번째 실행문은 복문이므로 { }로 묶었으나, 두번째 실행문은  단문이므로 { } 로 묶지 않아도 된다. 그리고 if나 else뒤에는 ; 가 붙지 않는다는 것도 주시하여야 한다.


 <예제3> 입력받는 정수가 양수면 '양수', 음수면 '음수', 0이면 '제로'라고 출력하는 프로그램 작성


<리스트3>


  위와 같이 else 다음에 다시 if..else문을 포함시킬 수가 있다. 그리고 C에는 elseif가 없으므로 else와 if를 반드시 띄어야 한다.

 <예제4> 1+(1+2)+(1+2+3)+...+(1+2+3+...+200)의 합을 구하는 프로그램

<리스트4>

  6행의 k = n = 0;은 n에 0을 대입하고, n값을 다시 k에 대입하라는  의미이다. 이와 같이 식을 우변부터 평가하는 성질을 '우결합성'이라고 하는데 연산자에 따라 우결합성, 좌결합성이 다르다. 일단은 대입연산자 =는 우결 합성을 가진다고 알고 있자. 몇가지 예를 더 들어보자.

 a = b = c = d = e = 1   ; (이 때 1이 기억되는 순서는 e,d,c,b,a순이다)

     a = 2*b = 3*c = 4*d = 5 ; (d에 5를 기억시키고, d에 기억된 값에 4를 곱해서 c에 기억시키고, c에 기억된 값에 3을 곱하여 b에 기억시키고, b에 기억된 값에 2를 곱하여 a에 기억시키라는 의미이다)


   하지만, int k=n=0;의 경우에는 에러이므로 쓰지 말기를 바란다.

   8 ~ 10행에서 +=란 걸 썼는데, 이것은 각각  k=k+1, n=n+k, sum=sum+n 과 같다. +=를 쓰는게 컴파일 후 실행속도가 더 빠르다고 한다. -=, *=,/= 도 마찬가지이다.


switch .. case문 (선택제어문)


  여기서 식1~식n은 반드시 상수 또는 상수식이어야 한다. 실행시 switch다음의 식(또는 변수)의 값가 case다음의 식(혹은 상수)을 비교하여 값이 같은 곳으로 제어를 옮긴다. 만약 값이 일치하는 곳이 없으면 default다음의 문장을 수행한다. case 다음의 문장들은 여러 개의 문장을 나열할 수 있지만 블럭이 아니므로 { }로 둘러싸선 안된다. case 다음의 명령문을 수행한 후에도 switch 블럭 ({ }안의 부분)을 빠져나가지 않고 그 밑의 case문 부터 최종 deault문까지 실행을 하므로 필요한 경우 case 명령문 끝에 break를 붙인다. break를 만나면, switch블럭{ }밖으로 빠져 나가게 된다.


<예제5> 점수를 입력받아 90점 이상이면 A, 80-89점이면 B, 70-79점은 C, 그 이하는 F를 출력하는 프로그램 (만일 점수로 -999를 입력하면 처리를 끝내게 한다)

<리스트5>

  9행의 !=는 관계연산자이다. ==가 등호를 나타낸다고 하였는데,  BASIC에서는 <>가 같지 않음을 나타내나 C에서는 !=가 부등호이다. 그러므로 score가 -999가 아니면 { }안의 문장을 수행하라는 의미이다.

  10행에서 score/10에 대하여 이상하게 생각하는 사람이 있을 것이다.  만약 95를 입력하면 9.5가 나오는데 case에서는 9.5가 없으니  default 값인 F가 출력되는게 아니냐하고 말이다. 하지만 지난장에서  배웠듯이  정수와 정수의 연산은 정수의 결과를 낳으므로 95/10은 9.5가 아니라 소수점 이하가 절삭되어 9가 된다는 것을 명심하기 바란다.


2. 순환문

 순환문이란 특정한 부분을 반복수행하도록 하는 명령들을 일컫는 말이다.

for문

[형식]  for(초기식;조건식;반복식)

           {반복할 부분;}   <= 반복할 부분이 단문이라면 { } 생략한다

 초기식은 for문이 처음 실행될 때 단 한번 실행이 되며 여러개의 식을 ,로 구분하여 기술할 수가 있다.

 조건식은 루프의 실행 중 매회 조사를 하며, 단 한 개의 문장만을 기술할 수 있으며, 조건식이 참(1)이면 루프를 반복하며 거짓(0)이면 루프를 빠져 나간다.

 반복식은 루프의 다음 실행을 준비하는 단계로서, 여러개의 식을 ,로  구분하여 나열할 수가 있다. 위에서 공부한 제어문들과 마찬가지로 for(...) 다음에는 ; 를 붙이지 않는다.

 for문의 블럭에서 강제로 빠져나갈 때는 switch문에서와 같이 break 명령어로 빠져나간다.(goto는 되도록 쓰지 말자)

<예제6> 1부터 100까지의 합을 구하여 1+2+3+....+100 = 5050를 출력하는 프로그램 작성

<리스트6>


 for 다음의 루프가 단문일 때는 { }를 쓰지 않고 일반적으로 5행과  같이 표현한다. 그럼, 5행을 분석해 보자.



while

 [형식1]    while (조건식) {      [형식2]    do {

                  .                              .

             반복할 부분;                      반복할 부분;

                  .                              .

            }                                } while (조건식)

 [형식1]은 조건식의 결과가 참(1)이면 반복할 부분을 수행하고, 거짓이면 블럭을 빠져 나간다. 그러므로 루프안에 조건식의 결과를 변화시키는 문장이 있어야 하며, 조건식의 변수를 변화시켜 주지 않은 경우엔 무한 루프를 돌게된다.  while문의 블럭에서 빠져나갈 경우에도 break문을 사용한다.

 [형식2]의 경우에는 루프를 먼저 실행한 다음에 while다음의 조건식을 검사하는 차이가 있다. [형식1]의 경우에 조건식이 바로 거짓이 되어 루프를 실행하지 않을 경우가 있으나 [형식2]에서는 루프를 반드시 한 번은  실행한다.( 이러한 것을  '판단후 처리형의 구조'와 '처리후 판단형의 구조'로 나누어 부르기도 한다 )


<예제7> <예제6>의 프로그램을 while문을 이용하여 구하라.

<리스트7>

 <리스트6>의 for안에는 i<=100 이지만 여기서는 i<100이다. 왜  그런지는 곰곰히 생각해 보면 알게 될 것이다.  그리고, <리스트4>와 <리스트5>에서 goto문을 남발하였는데 이제  순환문을 배울만큼 배웠으니, goto을 쓰지말고 for나 while문을 사용하여 반드시 작성해 보길 바란다. 자신이 직접 프로그램을 짜 보고 오류를 찾아보는 것이 가장 좋은 방법이다.


3. 중첩된 루프(nested loop)와 루프 예제들

 중첩된 루프란 다른 루프 내에 포함된 루프를 말한다. 그럼, 예제를 통해 루프를 중첩시키는데 대하여 알아보자.

<예제8> 구구단을 출력시키는 프로그램을 작성하라

<예제9> 입력된 어떤 수까지 그 이내에 들어 있는 모든 소수를 찾는 프로그램을 작성하라.

 위 프로그램은 프로그램 다운 골격을 어느정도 갖추었다.

 6,7행에서 보듯이 변수명에 의미를 부여하면, 프로그램의 판독도 쉽고 보기도 좋아진다. 또한, 12 - 15행에서 처럼 입력오류를 검사하는 루틴도 가지고 있다. 프로그램 중간중간에 주석문을 넣어줌으로서 판독이 쉽게 하였다. 이렇한 주석문들은 프로그램의 오류(버그)를 수정하기 쉽게 한다(이러한 것을 디버깅이라고 한다).  18행에서 27행까지의 루프는 2에서부터 limit까지의 숫자를 차례로  검사하는 루프이다.

 소수란 1과 자신으로만 나누어지는 수를 말한다.

 19,20행은 number와 중간에 나누어 떨어지는 수가 하나라도 있으면  21행으로 가라는 의미이다. 중간에 나누어 떨어지는 수가 없으면 결국  number는 자신으로 나누어 떨어져(number와 divisor이 같아져-결국은 소수이다), 21행의 조건을 만족시키므로 화면에 출력되는 것이다. count는 한 줄에 소수를 10개씩 찍기 위하여 만들어 놓은 변수이다.

 20행의 ;는 반드시 있어야 한다. 만일 없으면 if블럭이 for루프안에 속하게 되어 예기치 않은 결과가 발생하게 된다. 조건식(number%divisor!=0)이 참이면 계속 19,20행을 돌게 된다.

 앞에서 break는 switch, for, while문에서 루프를 강제로 빠져 나올때 쓰이는 명령어라고 배웠다. goto나 break같은 것은 프로그램의 구조적인  면을 반감시키므로 되도록이면 쓰지 않도록 하자.

 이번 장에서는 C언어의 제어문과 순환문에 대하여 알아보았다. 이 순환문과 제어문은 C뿐만 아니라 모든 언어에서 가장 많이 쓰이는 것이므로 여러분들은 각 명령어의 구조와 기능을 확실히 이해해 두어야 한다.

제 4장 - 연 산 자

 이번 장에서는 프로그램에서 연산을 가능하게 만들어 주는 연산자들에 관하여 알아 보겠다.

 연산자란 대상 자료에 대해 어떤 조작을 하는 부호를 말하며, 이 때 대상이 되는 자료들을 오퍼랜드(Operand)라고 부른다.  이러한  연산의 대상이 되는 오퍼랜드의 갯수에 따라 C의 연산자는 1항 연산자, 2항 연산자,  3항 연산자 등으로 구분할 수 있다.

 또한 각 연산자들은 우선 순위라는 게 있어 한 문장에서 여럿의 연산자들이 쓰였을 때 그 우선순위에 의거하여 연산을 수행하게 된다. 그리고 동일한 우선순위의 연산자들이 한 수식에 동시에 쓰였을 경우에는, 이 식을 좌측부터 평가하느냐 우측부터 평가하느냐에 따라 좌결합성과  우결합성으로 나누어 지는 성질을 가지는 것도 있다.

 위에서 언급한 연산자의 특징들이 초보자들에게는 혼란스럽겠지만,  일단 익혀두면 복잡한 알고리즘도 쉽고 함축성 있게 표현할 수 있어 유용하다.


<표1> 각 연산자들의 종류와 우선 순위

대 분 류

소분류

연      산      자

결합규칙

 

일 차 식

primery

( ) [ ] -> .

->

높다

단항 연산자

단 항

! ~ ++ -- - cast연산자 * & sizeof

<-

 

이항 연산자

승 제

* / %

->

가 감

+ -

->

쉬프트

<< >>

->

비 교

< <= > >=

->

등 가

== !=

->

비트AND

&

->

비트XOR

^

->

비트 OR

 

 

논리AND

&&

->

논리 OR

||

->

삼항 연산자

조 건

? :

<-

치환연산자

치 환

= += -= *= /= %=

<-

>>= <<= &= ^= !=

순차 연산자

순 차

,

->

낮다


1. 산술 연산자

 + : 오른쪽에 있는 값을 왼쪽에 있는 값에 더한다.

 - : 왼쪽에 있는 값에서 오른쪽의 값을 뺀다.

 * : 오른쪽의 수를 왼쪽의 수로 곱한다.

 / : 왼쪽의 수를 오른쪽의 수로 나눈다. 정수와 정수의 연산일 땐,소수점 이하는 버린다.

 % : 왼쪽의 수를 오른쪽의 수로 나눌때 나머지를 결과로 취한다. (정수에서만 사용)

 ++ : 오른쪽이나 왼쪽에 있는 변수의 값을 하나 증가시킨다.

 -- : 오른쪽이나 왼쪽에 있는 변수의 값을 하나 감소시킨다.


 그러면, ++와 --연산자의 사용에 대한 예를 들어보자.


 <예제1> ++,-- 연산자의 사용

<리스트1>


 프로그램의 실행결과는  a가 2, aplus가 1, b가 2, plusb가 2가 된다.

 애매하지만 아래를 보자.

 aplus = a++;  후위형 : a가 사용된 후, a의 값이 하나 증가한다.

 plusb = ++b;  전위형 : b의 값이 하나 증가한 후, b가 사용된다.


 그러면,  while (num<21) {     /* num이 5일때, 어떤 값이 나올까? */

             printf(%d  %d\n", num, num*num++);

             }

 이 식을 보면, 5  25를 찍고, num을 6으로 증가시키는 자연스러운 식처럼 보이나, 실제로 실행결과는 6  25가 찍힌다. 왜냐하면 printf()함수는  마지막 인자부터 먼저 넘긴다는 오묘한 진리가 있다.

          ans = num/2 + 5*(1 + num++);

 보통, num/2가 먼저 계산이 된다고 믿고 싶으나, 실제로는 먼저 num이 증가하고 나서 num/2에 사용된다. () 때문이다. 위의 여러가지 예에서 보듯이 ++/--연산자의 전위와 후위의 차이점을  명확히 이해하고 이 연산자를 너무  남용하거나  복잡하게 사용하지  말자는 뜻에서 함정을 미리 파 헤쳐 보았다.


2. 치환 연산자 ( +=, -=, *=, /=, %=, &=, |=, =, >>=, <<= ..)

 대입 연산자라고 하는 이러한 연산자들은 모두 =와 결합되어서 식의 복잡성을 줄여준다.

 x += 3; 은  x = x + 3;과 같다.

 x *= y + 1; 은  x = x * (y + 1);과 같다.

 x += y += z = 1; 은  z=1; y=y+z; x=x+y와 같다.

 치환은 a=b;처럼 단순치환일 수도 있고,  a=b=c=d; 처럼 다중치환일 수도 있으며, a += b처럼 복합치환일 수 있다.  다중 치환의 경우에는 식을 우측에서 평가하여  좌측의 변수로  차례대로 치환하게 된다.( 표1참조 - 우결합성 )

 a = b = c = d = 1;은

 a = ( b = ( c = ( d = 1 )));과 같으며, d=1;c=d;b=c;a=b;와 같다.

 a = b*c = d*e = 1;은 e=1; c=d*e; a=b*c;과 같다.


3. 관계 연산자 ( <, >, <=, >=, ==, != )

 이 연산자들은 자료의 크기 등을 판단할 때 사용하며, 식의 값이  참이면 1, 거짓이면 0의 값을 갖는다. 그리고 <=, >=는 부호의 순서가 바뀌면 안된다. 그리고, 관계 연산자들 중 ==, !=는 다른 관계 연산자들보다 우선순위가 낮다. 그리고 초보자들은 ==을 쓴다는 게 그만 =(대입연산자)를 쓰는 경우가 있다. 이러한 것은 오류를 찾기에도 힘들 뿐 아니라 실행 결과에도 심각한 영향을 미친다. ==와 =는 엄연히 다르므로 기억하자! 6.25! (?)

 a < b < c 의 평가 과정

 1) a < b 이면 참(1)이므로 1(a<b)<c이면 1(참)이 된다.

 2) a < b 가 아니면 거짓(0)이 되므로 0(a>=b)<c이면 1(참)이 된다.

 그 외의 경우는 모두 0이다.

 x > y + 2 는 관계 연산자들의 우선순위가 산술 연산자들보다 낮으므로  ( x > y ) + 2 가 아니라, x > (y+2) 와 같다. 그리고 관계 연산자들은 좌결합성을 가지므로  ex != wye == zee 는 실제로는 ( ex != wye ) == zee;와 같다. 위에서 보았듯이 처음에는 그냥 지나치기 쉬우나, 좌결합성이냐 우결합성이냐와 연산자들의 우선 순위는 중요하므로 잘 알아두자. 만일 마냥 헷갈린다면, ( )를 십분 활용하여 에러의 소지를 없앨 필요가 있다.


4. 논리 연산자 ( !, &&, || )

 (1) 논리부정 연산자(NOT) - 식의 값이 0(거짓)이면  '!식'의 값은 1(참)이 되고 식의 값이 참이면 거짓이 된다.

 (2) 논리곱 연산자(AND &&) - 여러 식중 한개라도 거짓의 값이 있으면 거짓이 된다.

 (3) 논리합 연산자(OR ||) - 여러 식중 한개라도 참이면 참의 값을 가지게 된다.

 (cat > rat) && ( debt == 100 ) 은 두 식이 모두 참이어야 참이 된다.

 (cat > rat) || ( debt == 100 ) 은 둘 중 하나만 참이어도 참이 된다.

 5>2 && 4>7 은 하나만 참이므로 거짓이다.

 5>2 || 4>7 은 둘 중 하나가 참이므로 참이 된다.

 !(4>7)은 4>7이 거짓이므로 참이 된다.


<예제2> x에 관한 여러 수식이 주어져 있다. 각 식의 x의 값이 어떻게 수행 되는 지 예측해 보라.

<리스트2>


 우선, 위 프로그램의 실행결과는 1 0 1 2 2이다. 예상결과와 맞았는가? 다르다면, 아래의 설명을 잘 읽어보자. 4,5,6행에서 6행은 우선순위에 의거하면 x = (x ||(y && z)); 로  괄호를 칠 수가 있다. 여기에 수를 대입해 보면, x = (1 ||(2 && 3)) = (1 || 1)= 1이 된다. (C에서는 식의 값이 0이 아닐 때는 모두 참으로 간주한다) 8,9,10행에서 9행을 우선순위에 의거하여 괄호를 쳐 보면, x = (x > y)||(z == y) && (x < z))와 같다. 여기에 수를 대입해 보면 결과는 0이 된다.

 11,12,13행에서 12행은 x = -( y++ ) + ( ++z ) = -(1)+(2) 로서 x=1, y=2, z=2가 된다.

 그러면, 아래를 보자.

 k = a && b++; 의 식은 어떻게 평가가 될까?

 1) k = a가 거짓일 때: b의 값은 변하지 않는다.

 2) k = a가 참일 때: b의 값은 1만큼 증가한다. 

                                 =======> 대강 감이 오리라고 믿는다.

                   

5. 비트 연산자

  비트 연산자란 비트조작을 위해 쓰이는 연산자이다. 주의할 점은 오퍼랜드는 정수 또는 정수형이라야 한다.


 (1) 비트합 연산자(OR- |) : 좌우의 식을 이진수로 하는 비트합을 구해준다.

    a = 117, b = 216일 때 a|b의 결과

    117  =>  0000 0000 0111 0101

    216  =>  0000 0000 1101 1000

    ============================

               0000 0000 1111 1101  =>  253

 비트합 연산자의 용도는 바로 특정한 비트를 1로 세트시킬때 이용된다.

    a = 117때 상위 4비트를 1로 한다.

    117  =>  0000 0000 0111 0101

             1111 0000 0000 0000

    ============================

             1111 0000 0111 0101  =>  1로 세트하려는 부분만 0으로


 (2) 비트곱 연산자(AND- &) : 좌우의 식을 2진수로 하는 비트곱을 구해준다.

    a = 117, b = 216일 때 a&b의 결과

    117  =>  0000 0000 0111 0101

    216  =>  0000 0000 1101 1000

    ============================

               0000 0000 0101 0000  =>  80

 비트곱 연산자의 용도는 특정 비트를 0의로 리셋하려는 경우에 이용된다.

    a = 44149일 때 상위 4비트를 0으로 한다.

    44149  =>  1010 1100 0111 0101

                 0000 1111 1111 1111

    ==============================

                 0000 1100 0111 0101  =>  0으로 리셋하려는 부분만 1로


 (3) 배타적 논리합 연산자(XOR- ^) : 좌우의 식을 2진수로 하는 배타적논리합을 구한다.

    a = 117, b = 216일 때 a^b의 결과

    117  =>  0000 0000 0111 0101

    216  =>  0000 0000 1101 1000

    ============================

               0000 0000 1010 1101  =>  173

 두 개의 비트가 동일하면 0, 다르면 1이 된다.

 (4) 비트반전 연산자(NOT- ~) : ~는 부호를 반전하는 연산자로서 비트1은 0으로, 0은 1로 만든다. (1의 보수 연산자라고도 한다)

     a = 117일 때 ~a의 결과

     117  =>  0000 0000 0111 0101

     ============================

                1111 1111 1000 1010  =>  -118

 (5) shift 연산자( <<,>> ) : 좌측 식의 결과를 우측식만큼 비트를  이동시킨다. 이 때 밀리는 쪽의 맨 끝 비트는 밀려나오고, 반대쪽이  마지막 비트는 0으로 채워진다.

  좌측으로 쉬프트한 경우에는 맨 우측에 무조건 0이 채워지지만  우측으로 쉬프트한 경우에는 부호가 없는 정수이거나 맨 좌측의  비트가 0(양수)이면 0을 채우고, 부호가 있는 정수이고 맨 좌측의  비트가 1(음수)일 때는 1을 채운다. 즉, 쓸데 없이 부호를 바꾸지  않는다고 볼 수 있다.

      a = 117일 때 a << 2 의 결과

      117  =>  0000 0000 0111 0101

      ============================

              00 0000 0001 1101 0100   <=  00

 또한 비트 연산자는 등호와 결합해서 치환 연산자를 이룰 수 있다.

  a = a >> b; 는  a >>= b, a = a & b; 는  a &= b와 같다.

 초보자들은 비트 연산자들의 쓰임에 대해 의구심을 가질지 모르나,  고급프로그램에서는 아주 요긴하게 쓰이고 있다. 비트 연산이 C의  저급언어의 특성을 대변하는 특징 주의 하나라고 볼 수 있다. 특히, 한글 출력에 있어서의 비트 연산의 쓰임은 필수적이다. 여러분들이 고급 과정으로 올라가면 이러한 이야기들이 모두 이해가 갈 것이다. 지금 우리는 이러한 비트 연산의 기능에 대해서만 알고 있자.


6. 순차 연산자( , ) - comma 연산자

 여러개의 식을 한 줄에 나열하는 기능을 가진 순차 연산자는 우선 순위가 가장 낮으며, 좌결합성을 가지며, 컴머 우측에 있는 식을  평가하여  얻은 값을 결과로 한다. (리스트2의 5행에 순차 연산자가 쓰였다)

 x = (y = 1, y++); 는  x = 2, y = 2 가 된다.

 x = (y = 1, ++y); 는  y = 1, x = ++y이므로 x = 2, y = 2가 된다.

 x = (y = 1, y+1); 은  y = 1, x = y+1이므로 x = 2, y = 1이 된다.

 x = (y = 1, z = 2); 는  y = 1, z = 2, x = 2가 된다.

 x = (y = 3, y+2); 는  y = 3, x = 5가 된다.


  <예제3> 아래 프로그램에서 x와 y의 값은 어떤 결과가 나오겠는가?

<리스트3>

결과는 직접 실행해 보시기 바란다.


7. 조건 연산자 ( ? : ) - 식1 ? 식2 : 식3

 if - else문을 연산자로 구현한 것으로서 3항 연산자이다.

 식1을 평가하여 참(1)이면 식2의 값을, 거짓(0)이면 식3의 값을 가진다.

우결합성을 가지므로 여러번 기술하였을 때는 맨 우측부터 평가된다.


<예제4> if (a > b) c = a;

         else c = b; 를 조건연산자로 구현하여라.

         또, a=1,b=2일 때  조건 연산을 행한뒤 a, b, c의 값은 어떻게 되겠는가?

<리스트4>  위의 조건식을 c = (a > b)? a: b;로 표현할 수 있다.


 x = (y > z) ? 1 : (y < z) ? 2 : 3;은 다음과 같다.

 i) y > z 이면 x = 1이 된다.

 ii) y > z가 아니면 y < z를 평가한다. y < z이면 x = 2가 된다.

 iii) i) ii) 둘다 아니면 x = 3 이 된다.


 위의 식을 if - else문으로 고치면 아래와 같다.

      if (y > z)  x = 1;

      else if (y < z) x = 2;

            else x = 3; 


8. 간접 연산자 ( * )

 포인터라고도 하며, 식이 가르키는 번지에 저장된 내용을 표시하는  연산자이다. 단항 연산자로서 곱하기(*)하고는 질적으로 틀린다.  모든 자료는 컴퓨터의 메모리에 저장되며, 메모리는 바이트 단위로  번지가 붙어있다. 포인터는 그 변수의 값이 가리키는 번지의 자료를  지정하는 것이라고 우선 알고 있자.


9. 번지 연산자 ( & ) - & 변수

 번지 연산자는 바로 다음에 오는 변수의 번지 자체를 구해 주는 연산자이다. 수치 자료를 입력받을 경우(scanf)에 쓴 기억이 날 것이다. &는  상수에는 쓸 수 없으며, 이 연산자가 붙은 경우에는 새로운 값을 대입할 수 없다. 즉 &3 이나 &x = 1234 등은 에러이다. 위 <리스트3>의 맨 마지막 행에 printf("%x ,&i)를 삽입시켜 보아라. 변수 i의 주소값이 16진수로 표시 될 것이다.


10. cast 연산자 -  (형) 연산자

 형변환 연산자는 원하는 데이터의 형을 괄호로 묶어 연산자 앞에  지정해 줌으로써 데이터 형을 변환시키는 역할을 한다.


<예제5> cast연산의 보기 - 실행결과를 예측해 보라.

<리스트5>


<설명>

8 , 9행 : 문자 'A'는 변수 ch에 문자로 지정됨. 정수변수 i는 'A'를 정수로 변환한 65를 받음.  fl은 65를 65.00으로 변환한 값을 받음. 

11,14행 : 문자변수 'A'를 정수 65로 변환하고 여기에 1을 더함. 그리고 정수 66을 문자 B로 변환하여 ch에 저장함 12,14행: ch의 값을 정수로 변환한 다음 2와 곱함. 결과(132)를 실수로 변환해 fl과 더함. 결과 197.00은 정수로 바뀌어 i에 저장됨.

13,14행 : ch의 값 'B'를 실수로 변환해 2.0과 곱함. i의 값(197)을 실수로 변환해 더한다. 결과(329.00)은 fl에 저장됨.

16,17행 : ch를 매우 큰 수로 치환하므로 예기치 않은 결과가 일어남.


<예제6> cast 연산자의 사용 예

<리스트6>


11. sizeof 연산자

 sizeof는 바로 다음에 나오는 변수나 자료형이 차지하는 메모리의 바이트 수를 구해주는 연산자이다.

 char c;

 sizeof(c); 1의 값을 가진다.

 sizeof(int); 2의 값을 가진다.

 이렇게 해서 C의 모든 연산자에 대해 간략하게 나마 알아 보았다.  초보자들에겐 부담스러운 양이겠지만- 또, 쓸데없는 연산자가 왜이리 많냐고 -,  C언어는 고급언어와 저급언어의 특징을 골고루 갖추고 있고, 저급언어의 특성을 십분 활용하려면 이러한 연산자들을 잘 사용할 줄 알아야 한다.


12. 연산자를 사용한 예제들

 몇 가지 예제를 통하여 연산자들의 실제 사용법에 관하여 살펴보자.

<예제7> 임의의 정수를 입력받아 그수를 2진수로 출력하는 프로그램작성.

         (C는 이진수를 지원하지 않는다)

<리스트7>


<참고> C에서 8진수의 표기는 수치앞에 0을 붙여 표시하고, 16진수는 0x를 붙여 표시한다. 이러한 수들은 항상 부호없는 정수로 취급한다. printf()함수의 포맷코드는 각각 %o와 %x이다.

 C에서 2진수를 출력하려면 최상위 비트부터 그 비트 패턴(1/0)을  출력시키는 방법을 사용한다.

 비트 패턴을 출력하는 방법은 우선 출력하려는 비트를 최하위 비트가  되도록 우로 쉬프트시킨 다음 이 값을 0000000000000001과 &(AND) 연산을 시켜, 최하위 비트를 제외한 다른 모든 비트들은 0의로 ?한다. 만약,  자리수가 16개이면 이런 작업을 16번 반복하여 얻어진 값을 하나씩 출력한다.

 <그림1> 상위에서 13번째 비트패턴을 조사하는 과정

        *

  0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0     원래의 수

  0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1     우로 13회 쉬프트

  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1     1과 & 연산

====================================

  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1     13번째 패턴이 구해졌다!


 <예제8> 123456789    와 같이 출력하는 프로그램을 작성하여라.

         *0000000* 1    (힌트: 가로+세로의 값이 10일 때와

         0*00000*0 2           가로와 세로의 값이 같을 때

         00*000*00 3            *을 출력하는 프로그램)

         000*0*000 4

         0000*0000 5

         000*0*000 6

         00*000*00 7

         0*00000*0 8

         *0000000* 9

<리스트8>


 위의 프로그램에서 단문과 복문 혼동으로 인한 에러가 있다.  그것을  직접 찾아보기 바란다.

 이번 장에서는 C의 연산자에 대해 알아 보았다. 되도록  이해하기 쉽도록 설명하려 노력을 했다. 10번 정도 읽으면 이해 못 할 것도 없다. 왠만한 C입문서에 버금가는 분량의 내용이므로 '학'실히 예제를 수행해 보면  모두 이해할 수 있을 것이다.


제 5장 - 함수 / 기억부류

 이번 장에서는 C에서의 함수 제작법과 내장 함수들을 간략히 소개하고 변수의 기억범위에 대해서 설명하고자 한다.

1. 내장 함수

 컴퓨터에서는 함수를  '주 프로그램으로부터  인수(Argument)를 전달받아 일련의 작업을 수행한 후 생성된 결과를 주프로그램(main함수)으로 전달하는 하나의 단위 프로그램'으로 정의한다.

 이 함수에는 컴파일러의 내장 함수(라이브러리 함수)와 사용자가 직접 만들어 사용하는 사용자 함수의 2가지 종류가 있다. 함수는 상호간의 독립성을 유지함으로써 프로그램을 구조적으로 구현하는데 많은 공헌을 한다.(제 2장 참고) 우리가 지금까지  사용해온 printf(), scanf(), getch() 등등은 모두  컴파일러에서 제공되는 내장 함수이다.  이 내장 함수의 종류는 수 백가지나 되는데,  이러한 함수들의 사용법은 컴파일러와 함께 제공되는 'Reference guide'에 모두 나와 있다. 그러므로 이 레퍼런스 가이드는 프로그래머의 필수품이라고 할 수 있다. 여러분들도 C에서 지원되는 풍부하고 다양한 함수들을 이용하려면 반드시 레퍼런스 가이드를 장만하기를 권한다.(필수사항)

 C에서는 이러한 수백개의 내장 함수들을 용도별로 나누어 놓았다.

먼저, 제2장으로 돌아가서 2번 항목을 자세히 읽고, 이 글로 다시 돌아와 주기 바란다. .. 

 2장에서 언급하였듯이 모든 함수들( main()함수 제외 => main()도 함수이다 )은 사용되기 전에 변수의 경우와 같이 프로그램 첫머리에 선언이 되어야 한다고 했다. 확장자가  .h인 화일들(헤더화일(Header file)이라고 함). 이 바로 내장 함수들을 기능별로 구분하여 선언 해 놓은 화일인데 우리는 프로그램 첫머리에   #include문을 사용함으로써 이 함수들을 선언한 화일을 프로그램에 포함시킬 수가 있는 것이다.

 이러한 헤더화일은 터보 C에서 30여가지가 있는데, 각 함수들을 30여가지 기능들로 분류하여 선언해 놓은 것이다. 예를 들어 printf()같은 기본  입출력 함수는  stdio.h 화일에 선언되어 있고, 그래픽 관련 함수들은 graphics.h 화일에, 문자열 처리 함수들은 string.h화일에 선언되어 있으며, 수학적 처리를 담당하는 함수들은 math.h에 선언되어 있다. 이러한  내장 함수들은 여러분들이 실제 프로그램 작성시  필요에 의해서 배울 수 있을 것이다.

 하지만, 이러한 내장 함수들도 함수의 개념이 잡혀 있어야만 무리없이 잘 사용할 수 있다. 그러면, 사용자함수를 제작하는 방법에 대하여 알아보자.

2. 사용자 함수

 특별한 경우가 아니라면 C에서 말하는 함수는 사용자가 정의한 함수를 가리킨다. C의 함수는 모두 횡적인 관계를 유지하고 있어, 함수들이  독립적으로 호출, 운용되며, 함수내에서 다른 함수를 호출하는 것은 가능하나 함수내에서 다른 함수를 정의할 수는 없다. 물론 사용자 함수도 내장 함수들 처럼 선언이 되어야 한다.  내장 함수와는 달리 사용자가 직접 선언을 해야 한다.

 함수는 하나의 단위 프로그램이므로 필요시 변수를  선언하여  사용할 수 있다. 이 변수들을 지역변수(local variable)라고 하는데, 함수내에서  선언된 변수들은 그 함수내에서만 효력을 가질 뿐 실행이 그 함수를  벗어나면 그 값을 상실하게 된다. 변수들의 통용범위에 대해서는 뒷부분에서  자세히 설명될 것이므로 우선 사용자 함수 제작법에 대해 알아보자.

 1) 함수의 형식

 type 함수명(가인수 리스트)

 가인수 형선언;

 {

    내부 변수의 선언;

    ......

    ...... <=함수의 본체

    return(계산 결과);

 }

(1)형선언

함수는 계산된 결과를 되돌려주므로 당연히 그  형을 명시하여야 한다. 형언 int, float, double 등 여태 배운  형선언 문자이면 된다. 함수의 형이 정수형(int)이거나 되돌려주는 값이 없을 때에는 형선언을 생략할 수 있다. 되돌리는 값이 없는 함수일 경우에는 void를 쓰거나 아무 것도 쓰지 않는다.

(2) 함수명

함수명은 변수명의 규칙에 어긋나지 않는  문자열이면 아무것이나 좋다. 가인수 리스트는 호출 프로그램에서 전달받은 인수(실인수)와 갯수가 동일해야 하며, 인수가 없는 경우에는 가인수 리스트를 생략할 수 있지만 ()자체를 생략하면 안된다.

(3) 가인수의 형선언

가인수가 있는 경우에는 가인수의 형을 선언해야 한다. 이 형선언은 main()프로그램에서 변수에 대해 형선언을 하는 것과 동일하다.

(4) 내부변수의 선언

함수에서 연산에 필요한 변수들을  선언하여 쓸 수가 있다. 이 변수들은 그 함수내에서만 통용되므로(지역 변수) 다른 함수의 내부 변수나 main()함수의 변수와 같아도 된다.

(5) return();

연산 결과를 주프로그램에 전달할 경우 ()안에  그 값이나 변수를 기술하면 된다. 전달할 값이 없으면 return()자체를 생략할 수 있다.

 <예제1> 3개의 실수 자료를 전달받아 최대값을 구하는 함수를 작성하라.

<리스트1>

 위에서 함수명은 max이며 인수로 실수형 a, b, c를 전달받는다. 이  함수는 중간 결과를 저장하기 위해 mx라는 변수를 사용하고 있으며, 이 변수의 형은 실수형으로 선언되어 있다.

 위의 1행과 2행을 아래와 같이 표현할 수 있다.

  float max(float a, float b, float c)

  {  

    ...

  }     <= 프로그래머들은 이 방식을 주로 애용한다.


 2) 함수의 호출

 함수는 일종의 부프로그램으로 스스로 수행되지는 않고 다른  프로그램에서 호출해야만 실행된다. 그러므로 주프로그램보다 앞에 있더라도  호출하지 않는한 실행되지 않는다.

 함수의 호출은 함수명과 인수만 기술하면 되는데, 식의 일부로도  사용할 수 있고 호출자체가 하나의 문장을 이루기도 한다. 예를 들어 다음의 문장은 함수 max()를 호출하며, 함수에서 계산된 결과를 k에 기억시킨다.

     k = max(x,y,z);

 위에서 x,y,z는 실제 값이 기억된 변수이므로  이들을  실인수라고 하고, max()함수의 인수란에 기술된 a,b,c를 가인수라고 한다. 실인수와  가인수는 이름이 서로 달라도 되지만 갯수와 형은 일치하여야 한다

<리스트1>에서 작성된 함수를 호출하는 주프로그램을 만들어 보면,


 우선 main()도 함수라는 것을 잊지 말기를 바란다. main()함수가 하는 일은 DOS로 부터 필요한 인수들을 받아 자신의 일을 행한 후, 어떤 값을 DOS에게로 돌려주는 함수이다. 자세한 것은 8장에 언급되어 있다.

 위에서 void main(void)란 것은 아무 인수도 받지 않고 되돌리는 값도 없을 때 void라는 키워드를 쓴다. 위 프로그램은 3개의 실수 자료를 입력받아 max()함수로 전달하여 연산결과를 구해온다. 연산된 결과는 max()함수 자체로 되돌려지므로  이 함수를 식의 일부로, 혹은 다른 함수의 인수로 사용할 수도 있다. 그러므로  다음과 같이 사용하는 것이 허용된다.

          k = max(x, y, z) * 10;

          printf("%f\n",max(x,y,z);


 C에서는 주프로그램인 main()도 하나의 함수로 취급되며, 이 함수는 프로그램상 단 한번만 표시되어야 한다.  함수는 main()함수의 앞에 둘 수도 있고, 뒤에 둘 수도 있다. 함수가 main()함수의 뒤에 있을 경우에는 프로그램의 첫머리 즉, #include다음, main()앞에서 선언을 해야 한다. 함수의 선언은 다음과 같이 함수의 형과 함수명, 그리고 (가인수 형선언)을 기술한다.


 그리고, 함수 선언시에는 정의할 때와는 달리 반드시 문장 끝에 ;가 붙는다는 것을 까먹지 말기를 바란다.

<예제2> 인수를 갖지 않으며 되돌리는 값이 없는 함수의 보기

<리스트2>

   이 예제에서는  함수의 선언을 myfunc.h라는 사용자 헤더 화일에 기술해 두고 #include문으로 포함시키는 방법을 섰다. < >는 C의 표준 헤더 화일을 표시할 때 쓰고, " "는 사용자 헤더화일을 표시할 때 주로 사용한다. (내부적으로는 <>는 C의 include디렉토리에서 먼저 화일을 찾고, ""는 현재 사용자의 디렉토리(TC를 실행시켰던 디렉토리)에서 먼저 헤더 화일을 찾는다)

<예제3> 정수 2의 0부터 10까지의 제곱승을 구하는 프로그램

<리스트3>

 3) 인수의 전달

 주프로그램(main()또는 함수)에서 부프로그램(함수)으로 인수를 전달하는 방법으로는 두 가지가 있다.

 Call by value(값에 의한 전달) - 주프로그램에서 전달된 인수를  부프로그램에서 전달받을 때 인수의 값을 받아오며, 그 값은 실인수와 다른 기억장소에 저장된다. 그러므로 함수에서 가인수의 값을 아무리  바꾸더라도 실인수에는 아무런 영향을 미치지 않는다. (<예제1>의 경우와 같다)

 Call by Reference(참조에 의한 전달) - 함수에 인수가 전달될 때는 실인수가 저장된 메모리의 번지가 전달된다. 그러므로 함수에서는  메모리의 번지를 참조하여 인수의 값을 꺼내온다. 결국 주프로그램의 실인수와 부프로그램(함수)의 가인수는 이름만 다를 뿐 같은 기억장소를 배정받으므로 함수에서 가인수의 값을 바꾸게 되면 실인수 자체가 바뀐다.  이러한 참조에 의한 전달은 기억장소를 절약할 수 있다는 장점과 함께 함수에서 주프로그램으로 여러 개의 계산 결과를 전달하고자 할 때 유리한 방법이다. ( scanf()함수를 상기하라)

 C에서는 참조전달이 허용되지 않으나 메모리 주소 연산자(&)와 포인터 연산자를 효과적으로 사용하면 참조전달과 같은 효과를 거둘 수 있다.

   호출측 : func(&a,&b,&c);      <= 각 실인수의 주소값을 전달한다

             ....

   피호출측 : func(int *x, int *y, int *z)   

             {                     

                 *x = 1; *y = 2; *z = 3;

                  ...

 위에서 호출측 프로그램에서는 피호출측 프로그램에 인수를 전달할 때 그 인수가 저장된 주소(&)를 전달하고 있으며, 피호출측 함수에서는 그  인수를 포인터(*)로 받아온다. 포인터란 어떤 값이 가리키는 곳(번지)의  내용을 나타내므로 포인터 자체의 값은 주소와 일치하며 그 주소에 1,2,3을 할당하므로 결국 호출 프로그램의 변수 a, b, c는 각각 1, 2, 3으로  바뀌게 되는 것이다. 그러므로 계산 결과를 함수의 가인수에 기억시켜 두면  주프로그램의 실인수 자체가 바뀌게 되어 여러 개의 계산 결과를 전달할  수가 있다.

 <예제4> 3개의 정수 자료를 전달받아 크기순으로 나열하는 프로그램 작성

<리스트4>

3. 기억 부류 (storage class)

 변수란 어떤 자료를 저장하기 위한 기억 장소로서, 구분방식이 두 가지가 있다. 그 두가지 구분 방식이란, 그 변수가 프로그램의 전체에 통용되느냐 일부분에 국한되느냐는 활용 범위에 따라, 지역 변수(Local variable)와 전역 변수(global variable)로, 또 기억장소와 기억방식에 따라, 자동(auto)변수,     정적(static)변수,  외부(external)변수, 레지스터(register)변수의 4가지 종류로 나뉜다.

1) 지역 변수

 하나의 단위 프로그램에서 선언된  변수를 말한다.  지역 변수는 그 단위 프로그램에서만 통용되며 그 프로그램을 벗어나면 변수의 효력을 상실한다. 우리가 이 강좌에서 여태 사용해 온 모든 변수가 바로 지역 변수이며 main()함수내에서만 사용 가능한 것들이었다. 지금까지는 모든 것을 main()함수에서만 처리하였으므로  전역 변수이냐, 지역 변수이냐 하는 것을 의식하지 않아도 되었다. 그러나 이제부터는  함수를 이용한 프로그램의 모듈화(단위화=구조화)를 해야하므로 변수의 이런 특징을 잘 알아야 한다.

 C는 블럭({}로 묶여진 부분) 내부에서 변수를 선언하는 것을 허용하며,이렇게 선언된 변수는 블럭내부에서만 통용된다. 블럭이 중첩된 경우에는 맨바깥쪽 블럭에서 선언된 변수가 안쪽의 블럭에도 영향을 미치지만  안쪽의 블럭에서 선언된 변수는 바깥쪽에 영향을 미치지 않는다.  만약  변수명이 일치할 경우에는 그 블럭에서 선언된 변수가 선택된다.

  블럭A:   {              

           int a,b,c;                

             ...                     

  블럭B:      {                    

              int k,b,s;             

                ...                  

  블럭C:         {                     변수의 통용 범위

                 int l,m,n;          

                   ...               

                 }                  

              }                     

           }              

  블럭D:   {              

           int a,b,c;      

             ...           

           }                    

  위의 경우에는 블럭A에서 선언된 변수 b를  블럭B에서도 선언하고  있다. 이 경우에 블럭A에서 선언된 변수 b는 블럭B에서는 효력을 발휘하지 못 한다. 그러므로 블럭이 중첩된 경우에는 변수명이 같지 않도록 주의해야  한다. 그러나 블럭이 다를 경우에는 변수명이 동일해도 상관이 없다(블럭A와 블럭D의 경우). 이와 같이 특정한 지역안에서만 통용되는 모든 변수의  무리를 지역 변수라고 한다.


2) 전역 변수( 외부 변수 )

 지역 변수와 상대되는 개념으로 전역 변수라는 것이 있다. 이 것은 말 그대로 프로그램의 모든 부분에 걸쳐서 영향을 미치는 변수를 말한다.  전역 변수는 프로그램 첫머리의 사용자 함수를 선언하는 부분에서 선언한다. 또한 두번째 관점에서의 외부 변수와 전역 변수는 같은 것이다.

    #include <라이브러리 모듈>

      (함수의 선언)     

      (전역 변수의 선언)               일반적으로 *.h화일에 모아둔다.

    main()

      ...

 전역(외부) 변수는 모든 함수에서 통용되며 함수 내부에서 그 값을  바꾸면 전역(외부) 변수 자체의 값이 바뀌게 된다. 즉, 주프로그램과 부프로그램이 변수를 같이 사용하는 것이 바로 전역(외부) 변수이다. 함수에서  전역(외부) 변수를 참조할 경우에는 함수의 첫머리 함수명 다음에  변수명을 같이 기술한다.

   extern type 변수명;


 extern(al)은, 외부에서 선언된 변수임을 나타내는 예약어이다. extern은 외부 변수가 함수의 뒤에서 선언된 경우에는  꼭 기술해야 되지만  앞에서 선언된 경우에는 생략할 수도 있다. 그러나 함수가 main() 앞에 오는 경우라면 반드시 기술해야 한다.


 초보자의 경우에는 주프로그램을 먼저 기술하고 함수는 나중에  기술하려 하겠지만 일반적으로 숙달된 프로그래머는 그 프로그램에서 사용할 함수를 모두 설계해서 기술한 다음 main()은 맨 나중에 배치한다. 처음에는  모든 변수를 전역 변수로 선언해서 사용하는 편이 프로그램을 작성하기에  편리하나, 이런 식으로 전역(외부) 변수를 남용하게 되면  함수의  독립성 즉, 프로그램의 모듈화에 역행을 하게 되므로 되도록 사용하지 말자.


 예를 들어 앞에서 설명했던 최대값을 구하는 함수(max)의 경우에는  어떤 프로그램에서든지 곧바로 삽입하여 사용할 수 있으며, 최대값을 구하는 경우에는 이 함수를 호출하면 된다. 이 때 계산 결과는 함수 이름(max) 자체에 의해 전달되므로 주 프로그램의 변수와  무관하게 되고,  이에 따라 이 함수만 따로 파일로 만들어 두고 필요할 때 마다 불러내어 사용할수 있다.

그러나 이 함수를 전역 변수에 의해 값을 전달할 경우에는 모든  프로그램의 전역 변수명을 일치시켜야 하므로 비효율적이다.

<예제5> 전역(외부) 변수 사용 예 보기.

<리스트5>

==sample1.c 파일==

 #include <stdio.h>

   int x; /*외부변수 선언*/

     main()

       {

         x = 16;

         sub1();

         sub2();

         sub3();

         sub4();

       }

         sub1()

           {

              x++;

              printf("sub1 x=%d\n",x);

           }

         sub2()

           {

              x++;

              printf("sub2 x=%d\n",x);

           }

==sample2.c 파일

 sub3()

   {

      extern int x;

      x++;

      printf("sub3 x=%d\n",x);

      x = 200;

    }

 sub4()

    {

       int x = 34;

       printf("sub4 x=%d\n",x);

    }

== sample.prj 화일 ==

 sample1.c

 sample2.c

 


 이러한 식으로 프로그램을 분할해서 모듈화를 시켜서 분할 컴파일이 가능 하다. prj화일은 프로젝트 화일이라는 것으로 여러개의 소스 화일을  각각 컴파일해서 하나의 실행화일로 만들어 주는 역할을 담당하는 화일하다. 이러한 모듈별 분할 컴파일은 여러분이 64kb를 넘는 대형 프로그램을  작성할 때 반드시 필요한 개념이다.( 자세한 사항은 각 컴파일러 메뉴얼을 참조하기 바란다 ) 프로그램의 실행결과는 여러분이 직접 실행해 보길 바란다.


3) 자동 변수

 자동 변수는 선언된 함수 내부나 혹은 그 함수내의 복문속에서만  효력을 가지고, 그 블럭이나 함수를 벗어나면 자동으로 소멸되는 지역 변수를  일컫는다. 이러한 종류의 변수들은 선언시 메모리를 할당받아 자료를 기억시키는데 쓰이지만 사용후에는 메모리에서 완전히 제거된다. 자동 변수는 변수의 선언시 형 앞에 auto를 붙이거나 아무 것도 붙이지 않는다. 이  때까지 사용해 온 변수들이 지역 변수이자 자동 변수이다. 자동 변수는 초기화하지 않으면 그 값은 미정이며, 컴파일시 변수의 값이 저장될 메모리의 위치만 할당할 뿐 초기화는 프로그램 실행시에 한다.  이 변수는  *그 함수의* 실행이 끝나면 자동적으로 소멸되며,  호출될 때마다 초기값을 가진다.


4) 정적 변수

 정적 변수는 프로그램의 종료 후에도 그 값이 소멸되지 않고 보관되며, 다시 호출될 때는 그 직전의 값을 참조할 수 있다. 정적 변수의 초기화는 프로그램의 컴파일시에 단 한번 하게 된다. 정적변수는 형 앞에 static이라 기술함으로써 선언된다. 예를 들어,

   static int a = 0, b = 0;

   a =+ 1 ; b += 1;

 에 의해 변수 a,b가 정적 변수로 선언되며, 초기값은 0이 된다. 초기값에 0을 대입하는 것은 컴파일시에 단 한번하고, 호출시에는 0이 대입되지  않는다. 이렇게 선언된 변수는 실행이 끝난 후에도 그 값이 남아있게 된다.  그러므로 호출될 때마다 변수 a, b가 1,2,3,4,...로 계속  증가된  결과를 얻게 된다.

 변수를 초기화하는 부분은 위와 같이 반드시 static 다음에  기술해야 한다. 만약  행을 바꾸어 기술하면 컴파일시에 초기화하지 않고 실행중에 초기화가  되므로 애써 기억한 자료가 다시 초기화되어 버린다.  정적 변수는 실행된 후에도 메모리에 상주하므로 기억장소 절약이라는 측면에서 볼 때 바람직한 형태가 아니므로 꼭 필요한 변수의 경우에만  사용하는 것이 좋다. 정적 변수는 지역 변수나 전역 변수에 모두 선언하여  사용할 수 있다.


 <예제6> 함수 내부에서 선언하는 static 변수

<리스트6>

 함수 내부에서의 static선언은 그 함수내의 국소적인 변수가 된다.(위의 예는 지역 정적 변수라고 할 수 있다)  위에서 k는 자동변수이므로 호출할 때마다 초기화가 되고, i는 정적 변수이므로 컴파일시 한 번만 초기화를 행하여 메모리에 초기치 1을  저장하고 뒤에는 sub가 호출될 때마다 +1씩 값을 증가시켜 변화시켜 간다.

<예제7> 함수 외부에서 선언되는 static 변수

<리스트7>


 함수 외부에서의 선언은 그 소스화일 내에서는 어디서나 참조가능한 내부 변수로 된다. (전역 정적 변수) 그러므로 변수값은 프로그램의 종료시까지 보존된다. 위 프로그램의 실행값은 차례로 4, 5, 6이 된다.  만일 다른 화일에서 k를 참조하려면, 그 화일의 선두에 extern static int k;를 첨가하면 된다.

 <예제7>의 경우처럼 외부적인 정적 변수 등의 폭 넓은 영역에 걸쳐  참조 할 수 있는 변수들은 절제해서 사용하여야 한다. auto변수(우리가  지금까지 사용한 변수들)를 되도록 많이 사용하여 프로그램의 모듈화, 구조적 특징을 손상시키지 않도록 하자.


5) 레지스터 변수

 레지스터 변수는 기억할 자료의 값을 메모리에 저장하는 대신 직접 CPU내의 기억장소인 레지스터(register)내에 기억시키는 변수이다. 이것은  for문 등의 제어 변수를 직접 레지스터에 기억시켜 둠으로써 실행 속도를  높일 목적으로 쓰인다. 그 형은 int형에 한한다. 사실 함수에서 선언되는 변수 중 처음 2개의 int형 변수는 자동적으로 레지스터 변수로 사용이  되므로 속도를 요하는 변수(루프안을 도는 변수 등)는 맨 처음에 선언하는  것이 유리하다. 레지스터 변수는 컴파일러에게 지시하는 것이지만 강제적인 것은 아니다.

 레지스터의 갯수가 한정되어 있을 뿐 아니라 또 그 시각에 사용하지  않는 레지스터가 있는지도 미지수이기 때문이다. 만약 사용 가능한  레지스터가 없다면 자동 변수로 할당 된다.

 <기억부류 사용예>

  int a;           /* 외부변수 a의 정의 겸 선언 */

                      (다른 모듈(-화일)에 알려질 수 있다)

  extern int b;    /* 외부변수 b의 선언 */

                       (통상 b는 다른 모듈에 정의되어 있을 것이다)

  static int c;    /* 외부 정적변수 c의 정의 겸 선언 */

                      (다른 모듈에는 알려지지 않는다)

  void main(void)

  {

     int d;        /*  자동변수 d의 정의 겸 선언  */

     auto int e;   /*   "       e        "     (auto는 생략가) */

     static int f; /* 내부정적변수 f의 정의 겸 선언 */

     register int g; /* 레지스터 변수 g의 정의 겸 선언 */

     .......

   }

  <기억부류 선택요령>       참고: Turbo C정복(임 인건 저)

  (1) 피치 못할 경우를 제외하고는 가능한 한 자동변수를 선택

  (2) 외부변수의 사용은 최대한 자제하고 공용성이 매우 높은 변수에 한해 외부변수로 정의한다.

  (3) 초기화가 꼭 필요하거나 공용성을 가지는 배열은 주로 외부형으로 정의한다.

  (4) 모든 외부변수(정적변수 포함)는 가능한 한 초기화를 한다.

  (5) 외부변수는 가능한 한 읽기 전용으로 한다.

  (6) 특정 외부 변수의 값을 변경하는 함수는 가능한 한 하나의 함수로 제한한다.

  (7) 자동변수의 값을 보존할 필요가 있을 경우 내부정적변수로 정의

  (8) 프로그램이 하나의 모듈로 구성되어 있을 경우 외부정적변수를 사용할 필요는 전혀 없다.


 4. 예제들

<예제8> 임의의 정수 n을 입력받아 n의 계승(!)을 구하는 프로그램 작성.

<리스트8>


 10행에서 return()은 함수의 계산 결과를 호출 프로그램으로 되돌리는 명령어이다. return(0)은 그 시점에서 의미가 없는  0을 되돌림으로서  함수 수행을 종료시키는 명령이다. main()도 일종의 함수이므로 return(0)을 사용할 수가 있다.

 <예제9> 두 점 (x1,y1),(x2,y2) 사이의 직선거리는 아래에 식에 의하여 구할 수 있다. n개의 점을 입력받아 각각의 점을 직선으로 연결 할 때의 직선거리의 합을 구하라.

                         ______________________

         ( 두 지점간 거리 = / (x1-x2)^2 + (y1-y2)^2 )

<리스트9>


 2행 : 외부라이브러리의 선언 ( 제곱근을 구하는 함수 pow()의 선언 )

 8행 : 두 지점간의 거리 계산 / 그냥 2를 쓰지않고 2.을 쓴 이유는 pow() 함수의 인수의 형이 실수이기 때문이다.

 10행 : 계산 결과를 되돌림

 15,16행 : 내부 변수의 선언

 22,23행 : 2번째 이후의 좌표 입력

 24행 : 두 지점간의 거리 누적

 25,26행 : 다음 지점을 입력하기 위한 준비


 함수는 프로그램을 기능별로 묶는 모듈러 프로그래밍을 가능하게 한다.

 프로그램은 물론 계산 결과가 정확해야 하지만 같은 계산 결과를  제공하는 것이라면 프로그램을 이해하기 쉽고 또,  디버깅하기  쉽도록 작성하는 것이 좋다.  2장에서 언급하였듯이 C에서는 외부  라이브러리를 컴파일러  제작사에서 제공하는 것은 물론 사용자 자신이 작성하는 것도 허용한다. 위에서  작성 했던 함수들을 적당한 이름으로 디스크에 수록하여 둔다면 그 함수가 필요한 경우에 #include문에 의해여 소스상에 삽입하여 실행할 수 있다.  그러므로 C에서 표준 라이브러리에 없는 함수라 할 지라도 자신이 설계해 둔다면 다른 여타 언어보다 훨씬 더 풍부한 함수 및 처리 체계를 구축할  수가 있을 것이다. 라이브러리를 만드는 법은 참고 서적을 참조하기 바란다.


제 6장 - 배열과 포인터

 지난 장까지의 내용은 여러분들도 무리없이 잘 따라왔을 것이다.  하지만 6장부터는 C의 가장 중요하고도 이해하기 어려운 포인터, 구조체. 공용체, 등등의 난관이 여러분 앞에 버티고 있다. 포인터에 관한 내용으로만 책 한권을 써재끼는 사람이 있는 것으로 봐서는 포인터라는 것은 난해한 것임에 틀림이 없다. 하지만 여기에 수록되는 예제들을 직접  수행시켜 보고,  설명을 잘 읽어 본다면 이해가 그렇게 어려운 것만은 아닐 것이다.


 1. 배열(Array)

 배열과 포인터는 서로 밀접하게 관련되어 있다. 그래서 보통 이 두가지는 동시에 논하여 진다. 먼저 배열에 관해서 알아보자.  배열은 일련된 공간에 저장된 자료의 집합이다. 여기서 자료란 배열 요소라고 하는데 이 요소들은 어떤 규칙에 의해 저장된다.  그리고 전장에서 배운 변수의 기억 부류의 통용 범위의 규칙도  배열에서도 똑같이 적용된다. (배열도 변수의 일종이다)

  int a[10], b[3][6], c, d;       /* 배열선언의 보기 */

 위의 배열 선언에 의해 생성되는 배열의 실체는 아래와 같다.

 

0

1

2

3

4

5

0

 

 

 

 

 

 

0

1

2

3

4

5

6

7

8

9

 

 

 

 

 

 

 

 

 

 

                           

                 

2

 

 

 

 

 

 

배열a                     


 위에서 보듯이 a[10]은 a라는 이름으로 int형의 자료를 넣을 수 있는  방을 10개 확보하라는 명령이다. (1차원 배열이다) 2차원 배열의 경우에는 b[3][6]과 같이 하는데, b라는 이름의 int 배열을 3행 6열로 선언하는 예이다. 지난 장에서 정적변수와 동적 변수를 배웠는데  배열에서도  정적 배열과 동적 배열이 있다. 정적 배열은 앞에 static를 붙이며, 1회에 한하여 모든 배열요소에 초기치를 부여할 수 있다. 초기치는 {}로 묶어서 표현한다. 동적 배열은 전체를 초기화할 수 없고 모든 요소를 하나씩 지정해서  초기화해야 한다.

 1)static char a[6] = {'a','b','c','d','e'};   /* 이 네가지 초기화 */

 2)static char a[6] = "abcde";                 /* 는 모두 쓸 수있다*/

 3)static char a[] = {'a','b','c','d','e'};    /*   (모두 같다)    */

 4)static char a[] = "abcde";      /* 대중적 */

 정적 배열의 경우 배열의 크기를 선언하지 않으면  컴파일러가  초기치의 갯수대로 방의 갯수를 결정해 준다. 그리고 문자 배열은 배열의 끝에 문자열의 끝임을 알리는 자동적으로 '\0'이 추가되므로  1), 2)의 경우처럼 문자열을  배열내에 저장할 때는 문자열의  길이보다 적어도 1개 이상 크게 배열 크기을 확보하여야 한다.(위에서 주로 많이 쓰이는 양식은 4번이다)

이차원 정적 배열에 초기화를 행하는 예를 보자.

   static int b[2][5] = {0,1,2,3,4},{5,6,7,8,9};

   static int b[2][5] = {{0,1,2,3,4},{5,6,7,8,9}};

 위의 두가지 표현은 서로 동일한 것이다.

 배열명은 배열의 선두 번지를 가리키는 포인터 상수이다. 그러므로  변수처럼 값을 대입할 수는 없지만 그 값을 참조하여 배열의 1행, 혹은 배열의 요소 전부를 읽어낼 수 있다. 다음과 같은 배열을 생각해 보자.

 1) static char c[3][7] = {{"ABCDEF\0"},{"GHIJKL\0"},{"MNOPQR\0"}};

 2) static char c[3][7] = {"ABCDEF\0",GHIJKL\0","MNOPQR\0"};

 3) static char c[3][7] = {"ABCDEF",GHIJKL","MNOPQR"}; 

 4) static char c[][7] = {"ABCDEF","GHIJKL",MNOPQR"};  /* 대중적 */

 위의 세가지 표현은 모두 동일한 표현이다. ( '\0'은 자동적으로  붙으므로 생략이 가능하다 ) 4번의 경우처럼 배열 첨자를 생략할 수 있으나 마지막 첨자까지는 생략할 수 없다. 그러면 저장 형태를 그림으로 보자.

 

0

1

2

3

4

5

6

 

0

A

B

C

D

E

F

\0

배열 c[3][7] 요소의 지정과 출력 형태

1

G

H

I

J

K

L

\0

printf("%c",c[1][2]);  => I 출력

2

M

N

O

P

Q

R

\0

printf("%s",c[1]; => GHIJKL  출력

 

 

 

 

 

 

 

 

* 문자열 출력이므로 %s 사용



배열c         



배열에서의 중요한 점을 간추려 보면 다음과 같다.

 1) 정적 배열이 아닌 이상 배열 크기의 기억 장소만을 확보할 뿐  거기에 대한 초기화는 하지 않는다.

 2) 배열명, 혹은 세로측(행)의 첨자만 기술하여 배열 전체, 혹은 그 행의 전체를 나타낼 수 있다.

 3) 배열 크기를 선언할 때 변수를 사용하지 못한다. 즉 int arr[n];과 같은 문장은 에러이다.

 4) 배열 첨자가 허용 범위를 벗어났는지의 여부를 조사하지 않는다.


<예제1> 초기화 되지 않은 배열의 값(정적 배열, 자동 배열)

<리스트1>


 위 프로그램을 실행시키면 자동 배열은 기억 장소만을 확보할 뿐 초기화하지 않으므로 그 기억장소의 쓰레기 값이 출력되며,  정적 배열은 초기화하지 않았을 경우 자동으로 0으로 채워지므로 0이 출력될 것이다.

<예제2> 배열의 초기화 - 크기보다 초기값의 갯수가 적은 경우

<리스트2>


 위 프로그램에서 days는 외부 배열로 선언되고 초기화되었다. 외부  배열도 정적 배열과 같이 초기화하지 않으면 0으로 자동적으로 채워진다. 위에서는 초기화를 하긴 하였으나, 배열요소 12개 전체를 한 것이 아니라 10개밖엔 초기화하지 않았다. 하지만 컴파일러는 자동적으로 남은  요소를 0으로 채워 버린다. 출력 결과를 보면 알 수 있을 것이다.


 배열 선언시 첨자를 생략하는 경우는 어떻게 될까? 1행을

  int days[] = {31,28,31,30,31,30,31,31,30,31};

 로 바꾸면 출력 결과는 10월까지만 나올 것이다. 왜냐하면 자동적으로 컴파일러가 배열 크기를 초기화 갯수와 같은 10으로 간주하기 때문이다.  배열 첨자를 생략할 경우에는 초기화시 주의가 필요하다.


 그리고      int i, arr[10];

             for (i=0;i<10;i++) {

                arr[i] = i+1;

                printf("arr[%d] = %d\n",i,i+1);

             }

 와 같이 배열 선언과 동시에 초기화하지 않을 시에는 절대로 배열 첨자를 생략하면 안된다. 위의 예는 10개의 방에 1에서 10까지 대입하는 보기이다

(** 변수나 배열은 선언과 동시에 초기화 (0으로라도) 하는 습관을 가지는게 쓰레기값 해소에 좋다 **)


<예제3> 1 - 12월의 이름을 영어로 배열에 기억시켜두고  1-12 의 수치를 입력하여 그에 대응하는 월의 이름을 출력하는 프로그램 작성.

<리스트3>


 6행 : 문자열 자체는 1차원 배열로 간주되므로 당연히 2차원 배열로 선언. 초기화에서 행의 갯수가 명확히 제시되므로 첫 배열 첨자 생략 가능 (마지막 첨자 [10]은 생략하면 않된다.)

 6행 - 9행 : ~C에서는 ;가 있어야 문장의 끝으로 간주하므로 한 행을 보기 좋게 여러 행에 걸쳐 기술할 수 있다.

 12행 : C에서는 첨자의 범위가 유호한 것인지 체크하는 일을 프로그래머가 알아서 해야 한다. 즉, 우리가 15를 입력해도 결과는 나온다.



<예제4> 매개 변수가 배열인 함수 (거품정렬을 행하는 프로그램)

<리스트4>

 1행 : 내장 함수인 ramdomize(),random()함수는 stdlib.h에 선언되어 있다

 2행 : #define은 매크로로써 프로그램 안의 MAX를 20으로 치환하라는 의미이다. 예를 들어 이런 식으로 매크로를 지정해 두면 x[]배열의  크기를 변화시킬 필요가 있을 때  x[]배열이 사용된  모든 부분을 찾아가 수를 변화시켜야 한다. 하지만, 이 경우에는 #define MAX 20에서  20을 다른 수로만 바꿔주면 된다.(매크로에 관해서는 마지막 장에서 공부할 것이다)

 4행 : 사용자 함수의 선언

 10행 : 난수 발생자를 초기화 하는 함수

 11행 : random(n)은 0에서 n-1까지의 정수 난수를 발생시켜 돌려주는 함수

 14행 : x는 배열 x[20]의 첫번째 원소 x[0]의 번지를 가리키는 포인터이다

 19행 : void bubble(x,n);

        int x[];          ===>  void bubble(int x[],unsigned n)

        unsigned n;      

        가인수 형선언을 함수명의 가인수 리스트에 위와 같이 포함시킬 수 있다.

 19-30행 : bubble()함수는 버블 정렬을 하는 함수이다(각종 정렬의 원리는 자료구조 관련 서적을 참고하길 바란다).

 배열도 변수처럼 함수끼리 주고받을 수 있다. 14행과 같이 배열명과 배열의 크기를 넘겨주면,  피호출측 함수는 배열을  처리할 수 있다. 배열명은 배열을 가리키는  주소값을 가지고 있으므로 참조에 의한 전달에 속한다고 할 수 있다. 그러므로 bubble()함수에서는 배열의 내용을 직접 바꾸는  것이 가능한 것이다.  ( 5장 #1 참고 )

<예제5> 매개 변수가 배열인 함수 - II

<리스트5>


<예제6> 2차원 배열을 함수에 넘겨주는 예제

<리스트6>


2. 포 인 터 (Pointer) - 포인터는 주소값(번지)이다.

 포인터는 다른 변수의 주소를 기억하는 변수이다. 포인터는 포인터  연산자 '*'를 이용해서 선언한다. 포인터는 번지를 기억한다고 했으므로  연산자 '&'와 동일하다고 생각할지 모르겠으나 실제로는 전혀 다르다.'&'는 번지 자체를 말하는 것이지만  포인터 변수는 그 포인터가 가리키는 '번지의 내용'을 말한다. 이와 같이 포인터를 이용하여 자료를 지정하는 것을 ' 자료의 간접 지정'이라고 말한다.

 포인터 변수는 그 포인터가 가리키는 실체의 형에 맞추어 선언해야 한다.

정수형의 자료를 가리키는 포인터라면 정수형으로 선언되어야 하며, 장차 실수형의 자료를 가리킬 포인터라면 실수형으로 선언해야 한다. 또한 문자열이나 단일 문자를 가리킬 포인터는 문자형으로 선언해야 한다.  예를 들어,

   int a = 10, b = 20, c = 30, *p;

   p = &a;

 는 정수형 변수와 정수형 포인터 변수를 선언하고 초기화한 것이다. 여기서 변수 a,b,c가 연속된 공간에 저장되며  그 선두 번지가 1000H라고 가정 할 경우 저장형태는 다음과 같다.

a

b

c

10

20

30

1000H

1002H

1004H

 이 때 &a는 1000H, &b는 1002H, &c는 1004H가 된다. 여기서 'p=&a'라고 명령하면 포인터 p의 실체는 1000H가 되지만  우리에게 되돌려 주는 값은 1000H에 저장된 값 즉 10이 된다.

 그리고 p += 1;에 의해 p이 값을 하나 증가시키면 포인터 p의 값은  그 자신이 가리키는 자료의 형(int)에 맞추어 자동으로 2가 증가되어 1002H가 되고 우리에게 20이라는 값을 되돌려 준다. 이와 같이 포인터를 이용하면 임의의 메모리 번지에 접근해서 그 값을 꺼낼 수 있게 된다. 또한 프로그래머는 포인터의 형만 적절히 지정하면 굳이 메모리 번지를 의식하지 않아도 메모리내의 자료를 정확히 엑세스할 수 있는 것이다. 즉, 포인터의 형이 정수형이면 연속된 2Byte이 값을 꺼내와 정수로 치환하여 돌려주고, 포인터가 실수형으로 선언되었을 때는 일련의 자료들을 실수형에 맞추어 변환한 다음 돌려준다.

(*하지만 볼랜드 C의 경우에는 변수가 메모리 공간에 역순으로 저장이 된다. 여기서는 설명의 편의상 TC를 기준으로 하였다*)

 포인터가 문자형일 경우에는  그 위치의 문자를 되돌려 주거나 '\0'을 만날 때까지의 문자열을 돌려준다.


<예제7> 정수형 변수에 각각 10,20,30,40,50,60을 기억시킨 후 포인터를 참조하여 그 값을 출력하는 프로그램 작성.

<리스트7>

변수(x)

주 소(&x)

값(*p)

포인터(p)

a

FFD2

10

FFD2

b

FFD4

20

FFD4

c

FFD6

30

FFD6

d

FFD8

40

FFD8

e

FFDA

50

FFDA

f

FFDC

60

FFDC

 <실행결과>  # TC의 경우이다.            

옆의 표에서 보듯이 포인터 자체의 값은 변수의 번지와 동일하나, 포인터를 참조한 값은 변수의 내용과 일치한다. 여기서 주목할 것은 p++로 포인터를 1씩 증가시키고 있지만 포인터는 자신의 형인 int형에 맞추어 2씩 증가하고 있다는 점이다.

  그렇다면, 여러분들이 직접 변수들을 실수형으로 선언하여, 실수형 포인터에서는 어떤 현상이 일어나는지 실행해 보라.

# 주소는 시스템에 따라 다르다.     <참고>. 문자열 포인터(문자열을 가리키는 포인터) - '터보 C 정복'

우선 예제를 보면서 시작하자.


     (실행결과)

     abcdefghijklmnopqrst

     abcdefghijklmnopqrst

     2000                 <--- 시스템에 따라 다르다.

     2000                       (두 개의 값이 같다는 점에 주목하라)

     Str length(array) : 20

     Str length(ptr)   : 20

     array[0] - a

     array[9] - j ptr[9] - j

     End of ptr: 0

     *(ptr + 9) = j

     ================================

문자 배열 array(상수)

a

b

c

d

e

f

g

h

i

j

k

l

m

n

o

p

q

r

s

t

\0

6행 수행 :

             

7행 수행 :   포인터 ptr -+   (변수)

 6행을 수행하면 배열 array는 내부적으로는 문자열"abcd.."가 저장된 공간의 첫째 영역의 주소값(2000)을 가지게 된다.   배열명은 그 배열의 시작점의 주소값을 가지는 <포인터 상수>이다.

  7행에서 문자배열의 시작 주소값(array)을 포인터 <변수>ptr에 대입하였음으로 ptr의 값도 array와 같은 주소값(2000)을 가지게 된다.  하지만 개념적으로는

         <ptr은 문자열"abcd..."의 선두번지를 가리킨다> 라고 한다.

9행, 10행 수행 :

 printf함수의 %s서식은 인수를 문자열 포인터로 인식하고 그 포인터가 가리키는 번지부터 널 종료문자(\0)까지의 문자들을 출력하는 기능을 가진다 그러므로, array와 ptr가 가리키는 주소를 찾아가 그 곳에 있는 문자(a)로부터 \0문자까지 출력을 하는 것이다.

11행, 12행 수행 :

 %p서식은 인수가 가지는 주소값을 출력하라는 서식이다. 위에서 array와 ptr을 같은 주소값을 가지는 것을 알 수 있다.

13행, 14행 수행 :

 strlen함수는 포인터를 전달받아 그 포인터가 가리키는 번지부터 널 종료문자 직전까지의 문자의 갯수를 세어서 정수값으로 리턴한다. 위에서 array와 ptr이 같은 문자열 영역을 가리킴을 알 수 있다.   포인터의 입장에서 보면 문자열과 문자 배열을 전혀 구분할 수 없고, 완전히 동등하게 취급된다. 문자 배열을 문자열로 간주하면 문자 배열이 곧 문자 배열이 되는  것이다.

15, 16, 17행 수행 :

 char array[21] = "...."배열에서 일반적으로 array[n]은 n번째(처음이 0번째) 문자를 나타내는 것을 잘 알고 있을 것이다. 그러면, ptr[n]이란 것은 무엇을  의미할까? 곧, <문자열> 포인터ptr이 가리키는 번지부터 n번째 문자열 요소를 가진다. 

 위에서 보듯이 배열과 포인터는 매우 밀접한 관계를 가짐을 알 수가 있다

 17행에서 strlen(ps)의 결과는 20이다. 그러므로 ptr[strlen[ptr])은 ptr[20]과 동일하다.  위의 그림에서 그 위치에는 널 종료문자 \0이 있으므로 화면에는 0이 출력된다.

18행 수행:

 px + 1; 의 의미는 과연 무엇일까?

이것은 px가 가리키는 배열 요소의 바로 다음 배열요소를 가리킨다

                               (배열요소가 있는 곳의 번지값을 가진다)

 여기서 주의 할 점은 px 바로 다음 바이트의 번지를 가리키는 것이 아님에 유의해야 한다. px+1이 바로 다음 바이트의 번지를 가리키게 되는 경우는 px가 문자열 포인터일 때뿐이다.(각 요소가 1byte크기의 문자이므로) 만일 px가 int형 포인터라면 px + 1은 2바이트 다음의 번지를 가진다.

 이렇게 C에서는 포인터가 무슨 형임에 상관없이 자동적으로 번지를 증가시켜줌에 유의해야 한다.

 그럼, ptr+9의 의미는 무엇일까? ptr이 가리키는 번지(a가 저장되어 있는 곳의 번지)로부터 9번째 요소가 저장되어 있는 곳(j)의 번지를 가리킨다.

 그런데 위에서 *(ptr + 9)라고 했다.  이것의 의미는 (ptr + 9)가 가리키는 곳에 있는 내용을 나타내라는 의미이다.

출력결과를 두고 보았을 때

라는 사실을 유추할 수 있다. 아예, 위 문장을 암기해 버리자.


     

a

b

c

d

e

f

g

h

i

j

k

l

m

n

o

p

q

r

s

t

\0


    ptr+0 ptr+2 ....             ptr+9  ==> 이 각각의 내용은 주소값

   *(ptr+0) ,  .....            *(ptr+9) ==> 이 각각의 내용은 문자

                            &array[9] == &(*(ptr+9)) == ptr+9

                             array[9] == *(ptr+9) == 'j'

###################################################################

* 필자가 본 책 중 포인터에 관하여 가장 자세히 설명된 책은 임인건 (turbo28)님의 강좌들과 '터보C정복'이었다. 하이텔 한글프로그래밍동호회의 초청강좌란에  포인터에 대해 집중적으로 파헤친 '정복 터보 C' 라는 강좌를 반드시 받아보길 권한다.

3. 포인터와 배열

 포인터는 배열과 아주 밀접한 관계를 가진다. 실제로 배열명은 배열의 선두 번지를 가리키는 '포인터 상수'이다. 배열은 그 내용이 배열 영역에 저장되나 문자열을 포인터 변수로 지정할 경우에는 그 내용이 단순 변수  영역에 저장된다. 또 배열은 첨자의 값을 계산해야 하지만  포인터는 연속된 메모리 영역의 '내용'을 꺼내오므로 처리속도도 빠르다.

 만일 arr[]가 배열이라면,

   arr == &arr[0] (배열명은 배열의 첫번째 요소의 번지를 나타내는)

                               ( 포인터 상수이다 )

<예제8> 포인터와 배열

<리스트8>


  위 프로그램의 실행 결과에서 번지의 증가량을 주목하라!             

  위의 예제는 배열과 포인터의 밀접한 관계를 보여준다.  이것은 배열의 각 원소를 구별하고  그 원소의 값을 획득하는데  포인터를 사용할 수 있음을 의미한다. 실제로 컴파일러는 배열 표기를 포인터로 변환시켜 처리한다.

 *(date+2)와 *date + 2는 엄연히 다른 것이다. 포인터 연산자'*'는 +보다높은 우선순위를 가지고 있으므로 후자는 (*date)+2를 의미한다.

     *(date + 2)  => date의 세번째 원소의 값

     *date + 2  => 첫번째 원소의 값에 2를 더한 값

 배열과 포인터의 이러한 관련성 때문에 프로그램 작성시 아무것이나 선택하여 사용할 수 있다. 함수가 배열을 인자로 넘겨받는 경우가 그 일례이다

.          ( <예제5> , <예제6> , <예제7> 참조 )


 그럼, 아래의 두 가지 비교를 보자.

*** 배열을 사용한 평균값을 구하는 함수

*** 포인터를 사용한 배열의 평균값을 구하는 함수


  그렇다면, 위의 두 함수를 호출하는 호출문은 어떻게 될까?

   mean(numb,size);

 위의 numb는 배열명이다. 앞에서 이야기 한 것 처럼,  int pa[]; 와 int *pa;는 같은 것이다.

 단지 차이점은 pa[]에서의 pa는 포인터 상수(변화시킬수 없다)이고, *pa에서의 pa는 포인터 변수(변화시킬 수 있다)라는 것이다. 다시 말해서 포인터 상수 pa는 pa++라는 표현이 불가능하나 포인터 변수 pa는 pa++는 표현이 가능하다.  비록, 배열과 포인터가 위와 같이 밀접하게 관련되어 있다고는 하지만 차이점도 가지고 있다. 주로 포인터가 훨씬 광범위하게 이용된다. 하지만 초보자들은 배열이 더 분명하고 혼동이 덜 간다고 느낄 것이다. 그러나,  여러가지 이점으로 볼 때 포인터가 훨씬 효율성이 높다고 할 것이다.


 문자열을 포인터 변수로 초기화했을 경우에는 배열처럼 처리할 수 있다.

 <배열과 포인터의 비교>

크리에이티브 커먼즈 라이선스
Creative Commons License

'Programming > VC++' 카테고리의 다른 글

[VC++] C/C++/MFC FAQ 모음  (0) 2007/08/01
[C] const와 pointer의 조합  (0) 2007/08/01
[C] C언어 강좌  (0) 2007/08/01
[C] 소켓 기본 함수  (0) 2007/08/01
[C] 고수준 파일 입출력 함수 정리  (0) 2007/08/01
[C] 시스템 호출 함수 정리  (0) 2007/08/01
Posted by 현수림
TAG C

댓글을 달아 주세요