강의 컨설팅 트레이닝 무료진단 무료책자 마케팅편지 마케팅정보공유 다이어리 서비스제휴 고객센터

c강좌 (20) 자기참조 구조체
작성자 : 13 김영철
등록날짜 : 2009.01.29 16:50
3,540
***************************< 캠퍼스 C  강좌 >******************************
[제목] :
[코드] : campusc1-020 (초급)
[교재] : CAMPUS C (초급, Third edition)  [출판사 : 책과스승]
[알림] :이 파일은 "캠퍼스 C"에서 모든 분께 공개한 "초급 강좌"입니다.
        이 [알림]의 내용을 지우지 않는다면 누구에게나 임의로 복사해 줄 수
        있습니다.그러나 이 강좌 내용에 대한 저작권은 "캠퍼스 C"에 있습니다.

[연락처] : 605-8662 (서울) ("캠퍼스 C", 도서출판 "책과 스승")
           천리안 : go campusc  
           나우콤 : go lcampc
           하이텔 ID : campusc
****************************<< 목 차 >>************************************
<1> 자기 참조 구조체 (비상 연락망을 짜자)
        1> 자기 참조 구조체란 ?
        2> 한 방향 비상 연락망 만드는법
        3> 한 방향 비상 연락망 쓰는법
        4> 로보트의 추가, 삭제
        5> 양 방향 비상 연락망 만드는 법
<2>  시간 찍기 함수들
**************************< 내용 시작 >********************************
1> 자기 참조 구조체란 ?
-----------------------------------------------------------------------
        자기 참조 구조체란  말 그대로 자기 자신을  가리키는 구조체다. 특
별한 형식은 아니고  일반적인 포인터 형식인데, 이건  자료 구조의 측면에서
아주 중요한 의미를 갖는다.
        스트락춰는 중첩이  가능 하다고 했다.  그래서 아래에  자기 자신을
한번 중첩해 봤다. 멤버인 atom의 스트락춰 타입을 유심히 보자.
struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  atom;         <-- 요기
             } mazinga;

그런데 이 표현은 한마디로 얘기 해서 "틀린 표현"이다.

<문제> 이유는 무엇인가 ?
<답> 크기가 정해지지 않아서이다

        이제는 기본법칙을 응용해서 이런 문제쯤  쉽게 풀 수 있으리라고 믿
는다. 즉  다음과 같은 문제를 해결하지  못하기 때문에 위와  같은 선언법은
틀린것이다.

main()
{
        printf("%d", sizeof(mazinga));
}

즉 마징가의 크기는 "멤버 크기의 합"과 같은데 전부 더해보면 아래와 같다.

struct robot {          <-- (요기)                      
                 int  head;             <-- 2 바이트
                 int  arms[2];          <-- 4 바이트
                 int  *finger;          <-- 2 바이트
                 struct robot  atom;    <-- ?
             } mazinga;

        즉 아톰의 크기가 정해지지 않았기  때문에 전체 마징가의 크기를 정
할 수가 없다.  atom은 struct robot의 타입인데, 이 타입은  또 위의 (요기)
를 기준으로  봤을때 자기 자신 타입인  "struct robot atom"을  가지고 있기
때문에 크기를 정할  수 없다. 말장난 같은데  크기를  정하는 문제에 있어서
악순환을 하고 있다.

        따라서 이런 표현법은 허용이 안된다.  그러나 다음과 같이 포인터를
사용한 표현법은 가능하다.

struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *atom;
             } mazinga;

이렇게 포인터를 사용하면 크기의 문제를 교묘히  해결 할 수가 있다. 아시다
시피 포인터라고 "*"가 붙은것은  "몽땅"  2 바이트이다. 따라서 이번엔 아래
와 같이 크기가 명쾌하게 해결이 되었다.

struct robot {
                 int  head;             <-- 2 바이트
                 int  arms[2];          <-- 4 바이트
                 int  *finger;          <-- 2 바이트
                 struct robot  *atom;   <-- 2 바이트 (good !)
             } mazinga;                 --------------
                                        합 : 10 바이트

우리는 이런걸 "자기 참조 구조체" 라고  부르는데, 사실은 "자기 형 참조 구
조체"라고 하는것이 옳을것  같다. "자기"를 참조 하는것이  아니라 "자기 같
은것"을 참조 한다는 얘기다.
-----------------------------------------------------------------------
2> 한 방향 비상 연락망 만드는법
-----------------------------------------------------------------------
        이것은 소프트웨어 세계에서는  "자료 구조"의 한 종류로서  아주 유
용하게 사용될 수 있는 것이다.
        구체적인 예를 들면 비상 연락망으로 쓰일  수 있다.  옛날 중고등학
교 시절에는 방학만  하면 꼭 비상 연락망을 짰던 기억이  있다. 전쟁에 대비
해서인지는 잘 모르겠으나,  내 앞뒤로 꼭 연락할  사람이 연계(link)되 있었
다.
        멤버명을 조금 바꿔서 다음과 같이 "자기형 참조 구조체"를 만들자.

struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
             } mazinga;

위에서 next 라는  변수명이 씌였는데, 이게 다음  사람을 가리키는 손가락에
해당한다. 이 next는  반드시 struct robot 타입을 가리켜야  하기 때문에 현
재로는 mazinga 만을 가리킬 수가 있다.
        이제 아래와  같이 struct robot 타입   으로 로보트를  여러대 만들
자.

struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
             } mazinga,atom, robocop[3];

전부 5대를 만들었는데,  여기서 주의 할것은 이 로보트들은  크기가 다 똑같
다는 것이다. 옛날  만화영화처럼, 무지무지 큰 마징가 와  조그만 아톰을 생
각하면 안된다.  이건 단순히 한가지 모델로  구운 붕어빵 처럼  똑같은 형태
이고 다만 이름만  다를 뿐이다. 이렇게 만들어 놔야  "자기 참조 구조체"(자
기와 형태가 같은 놈을 가리키는 구조체)라고 할 수 있지 않겠는가 ?

        비상 연락망은 다음과 같이 짠다.  이것은 내용적으로 마당발의 집에
송창식의 주소를 넣어주는것과 똑같다. 즉

main()
{
        mazinga.next = &atom;
        atom.next = &robocop[0];
        robocop[0].next = &robocop[1];
        robocop[1].next = &robocop[2];
        robocop[2].next = 0x00;
}
이  작업을   하고  나면  (mazinga)-->   (atom)  -->   (robocop[0])  -->  
(robocop[1]) --> (robocop[2])
순서로  비상 연락망이  완성된것이다.  여기서  특히 맨  마지막  로보트인,
robocop[2]에는 "0x00"(null  pointer)를 넣어  준다는 것을  기억하자. null
포인터는 지난번 다뤄 본적이 있는데, 지금  처럼 더이상 아무도 가리키지 않
을때 사용한다고 했다. 즉 제일 마지막 사람에게 넣어준다.
        이 비상연락망은 이렇게  쓰일 수 있을것이다. 즉  어느날 갑자기 외
계에서 악당 로보트들이  침입하면 제일먼저, 순서에 따라,  마징가가 나가서
싸울것이다. 그러다 마징가가 부서지면 그다음 아톰이 나가서 싸운다...
        이런식으로 자기 참조 구조체는  비상연락망으로서 아주 유용하게 써
먹을 수 있는것이다.

자기 참조 구조체에서  초기화를 하는 방법을 좀더  구체적으로 살펴보면, 아
래와 같이 한다.
struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
             } mazinga = {
                        10,11,12,0,'\0',
                        },
               atom = {
                        10,11,12,0,'\0',
                        },
                 robocop[3] = {
                        10,11,12,0,'\0',
                        20,21,22,0,'\0',
                        30,31,32,0,0x00
                        };
main()
{
}
        이 방법은 좋은 표현법이 아닌것 같다.  왜냐하면  한눈에 내용을 이
해 하도록 명쾌하게  보이지를 않는 것 같다. 사실 내가  써놓고도 내가 읽기
힘들다. 그래서  보통은 지난번에 스트락춰의  표현 형태에서  살펴 보았듯이
아래와 같이 나눈다.
struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
             };
struct robot  mazinga = {
                        10,11,12,0,'\0',
                        };
struct robot  atom = {
                        10,11,12,0,'\0',
                     };
struct robot  robocop[3] = {
                        10,11,12,0,'\0',
                        20,21,22,0,'\0',
                        30,31,32,0,0x00
                        };

        스트락춰의 표현  자체가 복잡한데다가, 초기화 값까지  쓰니까 더욱
정신이 없는데, 그래도 이와 같이 나눠놓으면  그래도 중간중간에 숨을 좀 쉴
수 있을것 같다.
        내용상으로는 일반 스트락춰와 다를것이  없으나 포인터는 전부 0x00
으로 쓰인것을 보자. 일부러 연습을 위해서  0, '\0', 0x00 을 섞어서 썼는데
어느것이나 상관없다.
        지난시간에  숫자를  대입하는것은 "값"을  대입하는것이라고  했다.  
따라서 포인터에는 직접 숫자를 사용할 수없다. 즉

        int     lim_chungha = 100;      (o)
        int    *ma_dangbal =  100;      (x)

사실 "틀린다"라고  단정하기 보다는  컴파일할 때  "warning"에 해당하지만,
여러분들은 처음 배우는  입장이기 때문에 명확히 구분할  필요가 있다. 컴파
일러가 경고만 하고 마구 통과 시켜준다고  해서, 아무 개념없이 위의 표현을
쓰면 좋지않다. 위의 것은 다음과 같이  캐스트 연산자를 써서 주소임을 분명
히 밝히는게 좋다고 했다.

        int    *ma_dangbal =  (int *)100;       (0)

그러나 숫자 0x00  만은 일종의 예외로 인정된다.  컴퓨터라는게 보통은 예외
규정이 없는데, 이것은  소위 얘기하는 null pointer(0x00)에  해당하기 때문
이다.
        초기화를 이렇게  해놓으면 현재는  아무것도 가리키지  않는 상태이
다. 따라서 비상 연락망을 짤 때는 당연히  옆사람 주소를 넣어 주는데  보통
다음과 같이 한다.

1) 보통의 경우, 위에서 본 것 같이 일일이 지정해 준다

main()
{
        mazinga.next = &atom;
        atom.next = &robocop[0];
        robocop[0].next = &robocop[1];          <-- <배열 부분>
        robocop[1].next = &robocop[2];
        robocop[2].next = 0x00;
}

2) 위의 "<-- <배열 부분>"은 순환문을 사용하여 "돌려" 버린다.

main()
{
        int i;

        for(i=0; i <= 1; i++) {                 <-- 요기
                robocop[i].next = &robocop[i + 1];
        }
        robocop[2].next = 0x00;
}

위의 for문을 일반적으로 써보면 다음과 같다.
main()
{
        for(i=0; i <  sizeof(robocop)/sizeof(struct robot) - 1; i++) {
                robocop[i].next = &robocop[i + 1];
        }
        robocop[sizeof(robocop)/sizeof(struct robot) - 1].next = 0x00;
}

실제적으로 프로그램을 짜게 될때는 거의  "배열"을 쓰게 되므로 이런 순환문
을 많이 쓰게 될것이다.

        이렇게 해놓으면 한쪽 방향의 비상 연락망이 완성된 것이다.

-----------------------------------------------------------------------
3> 한 방향 비상 연락망 쓰는법
-----------------------------------------------------------------------
        이렇게 비상 연락망을  완성하면 이걸 써먹어야 하는데,  그 쓰는 법
은 거의 상투적이다.     위의 초기화 시켜논 값들을 그대로 이용해 보자.

struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
             };
struct robot  mazinga = {
                        10,11,12,0,'\0',
                        };
struct robot  atom = {
                        20,21,22,0,'\0',
                     };
struct robot  robocop[3] = {
                        30,31,32,0,'\0',
                        40,41,42,0,'\0',
                        50,51,52,0,0x00
                        };

struct robot  *asura;

이해를 돕기  위해, 각 로보트들이 갖고  있는 숫자들은 각  부분의 무게라고
하자. 즉 처음의  mazinga를 보면 head에는 10 이  들어가는데 이것은 머리를
만드는데  들어간  쇳덩어리의  무게라고 이해  하자는  것이다.  마찬가지로
arms[0] 은 11  톤, arms[1]은 12톤 이라고 생각하자.  현재 finger가 가리키
는 것은 없다. 지금의 내용과는 무관하므로  무시하고, *next 는 다음 로보트
를 가리키고 있다.
        그리고 포인터형 구조체  asura 가 나타났다. 이제  asura가 모든 로
보트의 머리 무게를 찍는걸 보자.

main()
{
        /*-------< 비상 연락망 작성 >-----*/

        mazinga.next = &atom;
        atom.next = &robocop[0];
        robocop[0].next = &robocop[1];
        robocop[1].next = &robocop[2];
        robocop[2].next = 0x00;         <-- <주의> null pointer 임

        /*------< 모든 로보트 머리 무게 찍기 >------*/

        for(asura = &mazinga; asura; asura = asura->next) {
                printf("%d ",asura->head );
        }
}
위와 같이 포인터  asura를 등장 시켜서 loop를  돌리는게 일반적인데, for()
문의 내부가 생소하게  보일 지도 모르겠다. 하나씩  자세하게 살펴보면 다음
과 같다.

        for(asura = &mazinga; asura ;  asura = asura->next) {
                  (요기1)     (요기2)    (요기 3)   

                printf("%d ",asura->head );
        }

        먼저 (요기 1) 부분은 초기화  하는 부분이다. asura는 struct robot
를 가리키는 포인터 이므로 mazinga를  가리키는 것은 지극히 당연하다. 여기
서는 "첫번째 로보트" 라는 의미를 내포하고 있는것이다.
        (요기 2) 부분은  조건을 비교하는 부분이다. 이 부분은 "a  < 0" 따
위의 비교문이 들어가는것이  일반적이지만, 기본 법칙은, 기초  상식 강좌에
서 언급한 적이 있는데,
        ---------------------------
        결과가 0 이면 "거짓" 이고
        0이 아닌 모든 수는 "참"이다
        ---------------------------
이 부분은 나중에 CPU의 flag 레지스터를  공부하고 나면 자연스럽게 알게 될
것이다. 그러나 그전  까지는 일단은 위의 법칙을 외우고  따져 보면 되는데,
처음 상태에서 asura에는 mazinga의 주소가  들어가 있으므로 그 주소는 일단
0x00 이 아니다.
이건 조건이 맞는다는  얘기다. 즉 참이다. 따라서 loop  문의 내부에 들어가
서 asura-> head를  찍는데, 현재 asura는 mazinga를 가지고  있기 때문에 결
국은 mazinga.head를 찍는것이다.
        이  과정을 마치면  (요기 3)  을  수행하는데, asura->next  부분을
asura에게  넣는다.   현재  asura는  mazinga   를  가지고   있기  때문에,
mazinga.next 는 mazinga  가  연락 해야할 다음  로보트인 atom을 의미한다.
그 atom을 asura에게  넣는다는 것이다. 그러면 이제  asura는 새로운 로보트
atom을 가리키는 것이  되고, 그 다음은 처음 asura =  &mazinga의 과정과 똑
같다. 즉 위의 과정을 atom으로만 바꿔 놓고 똑같이 반복하면 되는것이다.

        여기서 우리가  유의 할것은 맨 마지막  로보트인 robocop[2].next에
는   null  pointer가   들어가   있다는  것이다.   그리하여     asura   =
robocop[2].next 의 순간에  asura 에는 0x00(null pointer)가  들어가고, 그
러면 (요기 2)의  조건문에서 법칙에 따라 "거짓"으로  판명되어 Loop는 끝나
고 만다.
        여러분들은 아직도  스트링의 마지막에  0x00이 붙는다는  것을 기억
할 것이다. 지금  얘기하는 것도 그것과 똑같은 내용이다.  다만 여기서도 값
은 똑같은 0  이지만, 주소로서의 "null pointer" 로 인식  된다는 것이 다를
뿐이다.
        위에서 설명한 내용을  이해 하셨더라도 아마 직접  프로그램을 짜려
면 조금 정신이  없으리라고 생각된다. 그러나 사실 C에  익숙한 사람들도 정
신 없기는 매한가지다.  그래서 이런 상투적 표현은  잘 복사해놨다가 실제로
쓸 때  그대로 이용해 먹는 요령이  필요하다. 따라서 이런것  한두개 정도는
잘 이해한 후 잘 보관해 두도록 하자.
-----------------------------------------------------------------------
4> 로보트의 추가 삭제
-----------------------------------------------------------------------
        비상망을 짜고 나면,  흔히 인원의 변동이 있을 수  있다. 예를 들면
한 사람이 병원에  입원한다든가 하면 비상망이 끊기기 때문에  그 사람을 중
간에서 빼버려야 한다.
        프로그램을 짜다 보면 이런 작업도  거의 기본적으로 해야한다. 아래
에서 아톰이 갑자기 고장났다고 하면 빼는 과정은 다음과 같다.
struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
             } mazinga, atom, robocop[3];

main()
{
        /*---------< 비상망 짜기 >------*/
        mazinga.next = &atom;
        atom.next = &robocop[0];
        robocop[0].next = &robocop[1];
        robocop[1].next = &robocop[2];
        robocop[2].next = 0x00;

        /*-------< 아톰 빼기 >---------*/
        mazinga.next = &robocop[0];     <-- 로보캅[0]을 직접 대입
        atom.next = 0x00;               <-- null pointer 대입

        /*---------< 아톰 다시 끼우기 >------*/
        mazinga.next = &atom;
        atom.next = &robocop[0];


}
        과정은 지극히  간단해서 설명이 필요없을 지경이다.  여기서 관심을
가질 부분은, 아톰을 뺀다고 하여 완전히  없애버리는 것이 아니고 단순히 포
인터만 슬쩍 넘겨버린다는 것이다.
        이런 개념은 DOS 명령어인 "del" 이  쓰고 있는 방법이다. 우리가 다
음과 같이 "C:>\del xxx.hwp"를 쓰면 xxx.hwp의  내용을 직접 박박 지워 버리
는 것이 아니라 제목에만 슬쩍 지웠다고 표시해 두는것이다.
        따라서 다른 파일을 이 디스켓에  write 하지만 않는다면 실제적으로
내용은 고스란히 살아있다.  그래서 "디스켓 복구" 라는  작업이 가능 한것이
다. 중급 과정에서는 아마 이런 내용을 상세히 다룰 것이다.
        다시 원래 얘기를  하면, 아톰을 수리하고 다시  비상망에 끼워 넣을
려면, 포인터만 간단하게 조작하면된다. 끼워  넣는 방법은 위에 표시한 것과
같이 원래 비상망 만들때의 작업과 똑같다.
-----------------------------------------------------------------------
5> 양 방향 비상 연락망 만드는법
-----------------------------------------------------------------------
        위에서 다룬 한 방향 비상  연락망 짜는법은 자료 구조론의 세계에서
는 제일  기초에 해당한다. 따라서  앞으로 표현은 무궁무진한데,  이걸 전부
다룰려면, 그건 C를 떠난 다른 세계의 얘기가 된다.
        따라서 우리는  프로그램을 직접짜는데  많이 사용되는  부분만 다뤄
보는게 현명할 것 같다.
        양방향 비상 연락망을 짜려면 물론  자기 참조 스트락춰의 구조를 바
꿔야 되는데, 눈치 빠른 분들은 "한 방향  비상 연락망"으로 당장 응용 할 수
있을 것이다.
        스트락춰 구조는 다음과 같다.

struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
                 struct robot  *before;
             };

여기서는 보다시피 *before  가 하나 더 생겼다. 이름이  의미하는대로 앞 사
람을 가리키기  위한 포인터다. 이것도  역시 struct robot  타입이기 때문에
앞 사람(로보트)를 가리키는게 가능하다.
        이런 설계도로 실제 로보트를 만들었다.
struct robot {
                 int  head;
                 int  arms[2];
                 int  *finger;
                 struct robot  *next;
                 struct robot  *before;
             };

struct robot mazinga, atom, robocop[3];

내가 요즘은 만화영화를 안 보기 때문에  최신 로보트 이름을 모르겠다. 맨날
똑같은 이름이다.

이것도 역시 초기화 방법은 다를게 없다. 즉

struct robot  mazinga = {
                        10,11,12,0,'\0',0,
                        };
struct robot  atom = {
                        20,21,22,0,'\0',0,
                     };
struct robot  robocop[3] = {
                        30,31,32,0,'\0',0,
                        40,41,42,0,'\0',0,
                        50,51,52,0,0x00,0,
                        };

"0" 이 하나씩 추가 되었을 뿐이다. 이제 양방향 비상 연락망을 짜려면
다음과 같이 하면 된다.

        1) "한 방향 비상망" 짜는 방법 +
        2)  순서만 꺼꾸로 해서 한번더


main()
{
        /*-------< 한 방향 비상망 하는 방법 >-------*/
        mazinga.next = &atom;
        atom.next = &robocop[0];
        robocop[0].next = &robocop[1];
        robocop[1].next = &robocop[2];
        robocop[2].next = 0x00;

        /*-------< 꺼꾸로 한번더 >-------*/
        robocop[2].before = &robocop[1];
        robocop[1].before = &robocop[0];
        robocop[0].before = &atom;
        atom.before = mazinga;
        mazinga.before = 0x00;
}
보시다시피 방향만 반대로 된것이외에는 다를것이  아무것도 없다. 그러면 다
음의 숙제를 해보자

<문제> mazinga의 크기는 몇 바이트 인가요 ?
<숙제> 위에서 atom을  빼는 작업을 하고 실제로 빠졌는지  머리 무게를 다시
        한번 찍어보세요
<숙제> atom을 다시 끼워 보고 머리 무게를 찍어보세요. 잘 들어 갔나요 ?
<숙제> 위에서 배열 부분은 for()문을 이용하여 다시 써보세요.
<숙제> *asura 를 등장시켜서  다시 한번 각 로보트의 머리 무게를
        mazinga, atom, robocop[3] 순서대로 찍어보세요.
<숙제> 위 숙제를 순서를 꺼꾸로 해서 다시 한번 찍어보세요.

<숙제> 자기 가족의 신상 명세를 스트락춰로  구성해 보세요. 이때 필요한 멤
버들은 본인 스스로 정합니다. 예를 들면,

struct family {
                char    name[10];
                int     age;
                char    *hobby;
                .
                .
                .
                /* 필요한 부분 더 첨가 */
}

struct family father = { "로 보캅", 35, "고압선 만지기" };
struct family mother = { "소 머즈", 30, "소리 듣기" };
struct family twin[2] = { "로 보키", 1, "울기",
                          "로 보카", 1, "따라 울기" };
                .
                .
                .
        /* 필요하면 더 첨가 */

이 신상 명세로 양 방향 비상망을  짜고  화면에 순서대로(앞으로 한번, 뒤로
한번) 찍도록 프로그램을 짜보세요.
<숙제> 친구 주소록,  고객 명단, 도서목록 등 본인에게  관심있는  구조체를
        만들어 관심있는 자료를 전부 찍도록 연습해 보세요.
        (한 방향 비상 연락망 에서 "머리무게 찍기" 참조)

*********************************************************************** 
<2>  시간 찍기 함수들
*********************************************************************** 
        DOS 상에서 "date" 와 "time" 이라는 명령어를 아시지요 ? 즉

c:\> time  (enter)
c:\> date  (enter)

위와 같이 치면  현재의 날짜와 시간을 화면에 표시해  주고 시간(날짜)를 새
로 맞출지를 물어 봅니다.
        이와 같이 컴퓨터에는 시간을 기록하는  장치가 내장되 있습니다. 언
젠가도 얘기 했지만, CMOS 라는 조그만  칩에 이 데이타가 들어가 있지요. 이
칩은 항상 밧데리로  전원이 공급되기 때문에 우리가  컴퓨터를 끄고, 사용을
안 할 때에도 시간을 잘 간수하고 있습니다.
        그런데 여러분들도 이 시간이 틀리는  경우를 많이 보았을 것입니다.
특히 오래된 낡은 컴퓨터 일수록 시간이  엉망진창이 되는 경우가 많지요. 그
건 주로 밧데리가  오래되서 재충전이 안되기 때문입니다.  이런 경우는 아마
잘 아실 겁니다. "워크맨" 같은데에  쓰는 "재충전 밧데리"도 수명이 있어서,
예를 들면 200회 이상 충전하고 나면  버리고 다시 사야 되지요. 그것과 똑같
은 경우 입니다.
        컴퓨터에서 밧데리는 메인보드(제일 큰  기판)의 한쪽 구석에 있는데
생긴게 독특해서 누구나 쉽게 알아 볼 수  있을 겁니다. 보통은 큰 콘덴서 같
이 생겼지요. 이런 타입은 밧데리를 바꿀려면  납땜질을 다시 해서 빼고 끼워
넣어야 되니까 집에서  혼자 하시기는 조금 어렵겠지요.  요즘 나오는 것에는
납작한 단추처럼 생긴것도  있습니다. 전자 계산기나 전자  손목 시계에 들어
가는 것과 똑같은  형태로 생겼지요. 이런건 그냥 손으로 빼고  끼울 수 있게
되있습니다. 제가  보기엔 이런 단추타입의  밧데리를 사용하는  메인 보드가
더 질이 좋다고 (당연히 더 신형이고) 생각됩니다.
        대형 컴퓨터  시스템에서는 이 "시간"의 중요성이  아주 대단합니다.
즉 아주  정확하게 시간이 유지되야 한다는  것이지요. 우리가 쓰는  PC 처럼
시간이 맞았다 안맞았다 하면 아주 난리가  나는 겁니다. 예를 들면 여러분들
도 꼬박꼬박  돈을 내고 있는  나우누리, 천리안, 하이텔의  컴퓨터 시스템이
시간이 마구 틀린다고 생각해 보세요.  사용시간 체크하는데 문제가 심각하겠
지요 ?

        좌우간 C에서도 이  CMOS에 들어 있는 데이타를  이용해서 현재 컴퓨
터의 시간을 찍어  볼 수가 있습니다. 교재  [382쪽]에 보면
"시간과 날짜 함수"가  나와 있습니다. 이제는 여러분께서  함수의 선언 형태
를 보고 스스로 사용을 할 수  있는지 잘 모르겠는데, 이 clock(시간)에 관한
내용은 자세히 다룰려면 조금 복잡합니다  따라서 나중에 시간이 나면 다루기
로 하고 여기서는 함수를 이용하여  "실제로 써먹을 수있는 방법"에 대해서만
알아 봅니다.

        일단 다음과 같이 하면 화면에 현재 시간을 찍어 볼 수 있습니다.
------------------------------
#include        <stdio.h>
#include        <time.h>

main()
{
        time_t  t;
        struct tm       *struct_t;
        char            *string;

        time(&t);
        struct_t = localtime(&t);
        string   = asctime(struct_t);

        printf("%s", string);
}
--------------------------------
이 표현은  [397쪽]의 asctime() 함수의  사용법의 예와 똑같은 내용입니다.
표현법은  약간 다르지만(책의 표현이 더  좋은 방법) 내용은 같다는 것을 알
것입니다. 다음의 표현도 역시 똑같은 결과를 나타내는 것입니다.
--------------------------
#include        <stdio.h>
#include        <time.h>

main()
{
        time_t  t;

        time(&t);
        printf("%s", ctime(&t));

        getch();
}
----------------------------

        이 시간에 관한 내용은 "time.h" 라는  헤더 파일에 잘 정리가 되 있
습니다. 이것은 내용이 길지 않으므로 참고로 정리해서 잠깐만 보면,

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

typedef long    time_t;    <-- long 대신 time_t라고 쓰겠다는 뜻

typedef long clock_t;      <-- long 대신 clock_t라고 쓰겠다는 뜻

#define CLK_TCK 18.2       <-- 1초에 18.2 번 clock tick이 발생한다는 뜻
                                 (이 숫자만큼 인터럽트도 발생함  -> 중급
                                        강좌 참조)
struct  tm      {
        int     tm_sec;     <-- 스트락춰의  멤버 이름이 전부  "tm_" 으로
        int     tm_min;          시작.(이름을 쉽게 구별하는 좋은 방법)
        int     tm_hour;
        int     tm_mday;
        int     tm_mon;
        int     tm_year;
        int     tm_wday;
        int     tm_yday;
        int     tm_isdst;
};

                                <--  함수 찍는데 관련된 함수들 시작
char    *asctime (const struct tm *tblock);  
char    *ctime  (const time_t *time);
double   difftime(time_t time2, time_t time1);
struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t *timer);
time_t   time(time_t *timer);
clock_t  clock(void);
int      stime(time_t *tp);

<숙제> menu.c 에 시간을 표시하는 기능을 첨가 하세요.
************************< 끝 마치며 >**********************************
수고 하셨습니다
***********************************************************************

[출처]맨땅헤딩

"쇼핑몰·홈페이지·오픈마켓
블로그·페이스북·이메일 등의 각종 마케팅 글쓰기,
각종 광고, 영업, 판매, 제안서, 전단지
반응율 3배×10배 이상 높이는 마법의 8단계 공식"
자세히보기

Comments

번호 제목 글쓴이 날짜 조회
3165 vb 마우스휠 2 아론k 06.24 4009
3164 간단한 windows 스케줄 2 아론k 06.24 2996
3163 한글 영문변환 참고 문자표 2 아론k 06.24 4915
3162 자바 스윙 단축키 설정 2 나야나 05.26 3698
3161 자바 리플렉션 관련 2 나야나 05.26 2945
3160 간단한 sugest 기능 2 kkkkkkk 02.16 3562
3159 유니코드 사용하기 13 김영철 01.29 3213
3158 msxml 사용준비~!(checklist& 설정사항) 13 김영철 01.29 4177
3157 AJAX으로 놀자~ (채팅) 13 김영철 01.29 3316
3156 XML을 해야 하는 이유 13 김영철 01.29 6997
3155 AJAX 강의 2장 - XMLHttpRequest 오브젝트 사용하기 13 김영철 01.29 4839
3154 A Simpler Ajax Path 13 김영철 01.29 3203
3153 [AJAX] 한글지원문제 해결방법 13 김영철 01.29 3217
3152 [팁] XMLHttpRequest를 사용할 때 한글 파라미터의 인코딩 처리 방법 13 김영철 01.29 4409
3151 ServerXMLHTTP의 인코딩 문제 13 김영철 01.29 3722
3150 prototype.js 13 김영철 01.29 2807
3149 AJAX 관련 새로운 url 정리 13 김영철 01.29 3905
3148 Ajax를 쓰는 이유라고 할까나? 13 김영철 01.29 3153
3147 Ajax [www.atmarkit.co.jp] 13 김영철 01.29 3309
3146 Daum의 Ajax 개발 사례 13 김영철 01.29 4177
3145 AJAX관련 IE 버그. -1072896658 13 김영철 01.29 3359
3144 PHP 설정과 MySQL에 따른 Ajax 사용하기 13 김영철 01.29 3209
3143 mouse wheel 13 김영철 01.29 3072
3142 Ajax 간단한 예제(우편번호검색) 13 김영철 01.29 4018
3141 Prototype활용 (prototype속성) 13 김영철 01.29 2793
3140 [문서] prototype.js v1.4.0 13 김영철 01.29 2926
3139 동적테이블 속성도 복사 13 김영철 01.29 2884
3138 Aqua data studio 한글 깨짐 설정 13 김영철 01.29 9020
3137 삭제페이지 소스 13 김영철 01.29 2840
열람중 c강좌 (20) 자기참조 구조체 13 김영철 01.29 3541
마케팅
특별 마케팅자료
다운로드 마케팅자료
창업,경영
기획,카피,상품전략
동기부여,성취