본문 바로가기

C/C++

[C언어와 알고리즘] 구조체 (6)

OSS 2012-08-17 17:12:52 3840
2011


글 정재준 rgbi3307@nate.com / 커널연구회 (www.kernel.bz ) 2011-04-05

연재 차례

 1. C언어 소개
 2. 형태, 연산자, 표현
 3. 제어 흐름
 4. 함수와 프로그램 구조
 5. 포인터와 배열
 6. 구조체
 7. 알고리즘 소개
8. 소팅을 통한 알고리즘 분석
9. 스택(Stack) 실습
10. 큐(Queue) 실습
11. 리스트(List) 실습
12. 트리(Tree) 실습
13. 해싱(Hash) 실습
14. 알고리즘 설계 및 분석기법
15. 진보된 알고리즘 소개

구 조체는 한 개 이상의 변수들을 관리하기 쉽도록 하나의 이름으로 묶은 것이며, 구조체 안의 변수들은 서로 다른 형태일 수 있다. 구조체들은 큰 프로그램에서 복잡한 데이터들을 취급할 때 유리하다. 왜냐하면, 서로 관련되는 변수들끼리 하나로 묶어서 처리할 수 있기 때문이다.  구조체에 대한 일반적인 예제로 사원관리 기록이 있다. 사원 정보는 이름, 주소, 주민번호, 급여액 등의 항목으로 구성된다. 구조체는 이러한 사원정보를 하나의 명칭으로 묶고 그 안에 멤버 변수들(이름, 주소, 주민번호, 급여액)을 정의한다.  이것을 표현해 보면 아래와 같다.

구조체 사원정보 {
    사원이름,
    주소,
    주민번호,
    급여액
};

또 다른 좋은 예제로 화면에 그래픽을 출력하기 위한 좌표정보를 구조체로 정의하는 것이 있다.

구조체 점 {
    X좌표,
    Y좌표
};

구 조체는 배열 및 변수와 같은 특성이 있어서 복사 및 할당할 수 있고, 함수에 전달 및 함수에 의해 반환될 수 있다.  구조체를 포인터 변수로 선언하면 이러한 작업들을 좀더 쉽게 구현할 수 있다. 구조체를 취급하는 방법들을 기초부터 단계적으로 알아보도록 하자.

구조체의 기본
화면에 그래픽을 출력하기 위한 정보를 구조체로 정의해 보자. 그래픽의 기본 구성단위는 점이다. 점의 위치는 화면의 XY좌표로 표현할 수 있으므로 점에 대한 구조체를 아래와 같이 선언한다.

   struct point {
    int x;
    int y;
   };

구조체는 다음과 같은 형태로 나열하여 선언할 수 있다.

   struct { ... } x, y, z;

이것은 아래와 같은 의미이다.

   int x, y, z;

왼쪽의 구조체 선언은 식별명칭(tag)만 부여되므로 기억장소를 차지하지 않는다. 이러한 명칭은 구조체를 실제적으로 정의할 때 다음과 같이 사용한다.

   struct point pt;

struct point 형태의 구조체를 pt라는 변수로 정의한다. 또한 구조체를 정의하면서 멤버값을 아래와 같이 초기화 할 수 있다.

   struct point maxpt = { 320, 200 };

구조체 멤버 연산자(.)를 사용하여 멤버값을 참조할 수 있다.

  structure-name.member

아래는 구조체 pt의 멤버값을 출력하는 것이다.

   printf(“%d,%d”, pt.x, pt.y);

구조체안에 구조체를 중첩하여 정의할 수 있다. 아래는 사각형(도형좌표) 구조체를 정의한 것이다.  사각형은 2개의 모서리 좌표점으로 정의할 수 있다.

struct rect {
    struct point pt1;
    struct point pt2;
   };

struct rect screen;

screen 구조체의 pt1 구조체 멤버안의 x좌표는 다음과 같이 참조한다.

   screen.pt1.x

(실습 소스)/*
    author:    Jung,JaeJoon (rgbi3307@nate.com ,
    http://www.kernel.bz/ )
    comments:    구조체기본
*/
#include <stdio.h>

int main ()
{
    //구조체선언
    struct point {
    int x;
    int y;
    };

    //구조체정의
    struct point pt;

    //구조체정의 및 초기값할당
    struct point maxpt = { 320, 200 };

    //구조체 멤버값 할당
    pt.x = 10;
    pt.y = 20;

    //구조체 멤버값 참조
    printf (“pt: %d, %dn”, pt.x, pt.y);
    printf (“maxpt: %d, %dn”, maxpt.x, maxpt.y);

    printf(“nPress any key to end...”);
    getchar();
    return 0;
}
(실행 결과)
$ cc -o ch0601 ch0601_basic01.c    컴파일 및 링크
$ ./ch0601    실행
pt: 10, 20
maxpt: 320, 200

Press any key to end...

구조체와 함수
구 조체에 대해서 수행할 수 있는 연산은 복사, 할당, 주소(&) 가져오기, 멤버변수에 접근이다.  함수의 매개변수에 전달하고 함수에 의해서 반환하는 것도 복사 및 할당하는 것이다. 따라서, 구조체는 함수의 매개변수에 입력되고 함수에 의해 반환될 수 있다. 구조체의 멤버 변수들은 상수값으로 초기화 할 수 있다. 특히 자동 구조체는 명시적인 할당을 통하여 초기화 해야 한다.
우선, 아래의 makepoint라는 함수를 이해해 보자. 이 함수는 매개변수로 입력 받은 XY 좌표값을 구조체 멤버 변수에 할당한 후 해당 구조체를 반환하는 역할을 한다.

   struct point makepoint (int x, int y)
   {
    struct point temp;
    temp.x = x;
    temp.y = y;
    return temp;
   }

위의 함수는 다음과 같이 활용할 수 있다:

   struct rect screen;
   struct point middle;
   struct point makepoint(int, int);

   screen.pt1 = makepoint(0,0);
   screen.pt2 = makepoint(XMAX, YMAX);
   middle = makepoint((screen.pt1.x + screen.pt2.x)/2,
    (screen.pt1.y + screen.pt2.y)/2);

아 래의 addpoint 함수는 매개변수로 두 개의 구조체를 받아서 멤버값인 XY좌표값을 각각 더한 후 구조체를 다시 반환하는 역할을 한다. 즉, 첫 번째 구조체인 p1의 XY좌표값에 두 번째 구조체인 p2의 XY좌표값을 더한 후 구조체 p1을 반환한다. 이때 구조체들이 값으로 전달되고 반환된다는 것을 알아두자.

   struct point addpoint(struct point p1, struct point p2)
   {
    p1.x += p2.x;
    p1.y += p2.y;
    return p1;
   }

또 다른 함수인 ptinrect는 사각형 구조체인 r안에 점 구조체인 p가 좌표상으로 안쪽에 있으면 1을 반환하고 그렇지 않으면 0을 반환한다.

   int ptinrect(struct point p, struct rect r)
   {
    return p.x >= r.pt1.x && p.x < r.pt2.x
    && p.y >= r.pt1.y && p.y < r.pt2.y;
   }

사각형은 왼쪽 상단의 모서리 좌표가 오른쪽 하단의 모서리 좌표보다 작을 때 유효하다. 다음의 canonrect 함수는 사각형 구조체를 매개변수로 전달 받아서 정상적인 사각형이 되도록 유효한 좌표를 재설정하여 반환하는 역할을 한다.
   #define min(a, b) ((a) < (b) ? (a) : (b))
   #define max(a, b) ((a) > (b) ? (a) : (b))

   struct rect canonrect(struct rect r)
   {
    struct rect temp;
    temp.pt1.x = min(r.pt1.x, r.pt2.x);
    temp.pt1.y = min(r.pt1.y, r.pt2.y);
    temp.pt2.x = max(r.pt1.x, r.pt2.x);
    temp.pt2.y = max(r.pt1.y, r.pt2.y);
    return temp;
   }

규모가 큰 구조체를 함수에 전달한다면, 구조체 전체를 복사하는 것보다 포인터를 전달하는 것이 더 효율적이다. 구조체 포인터는 일반적인 변수 포인터와 동일하다.

   struct point *pp;

pp는 struct point 구조체를 가리키는 포인터이다. *pp는 구조체이며 (*pp).x 와 (*pp).y는 멤버들이다. pp를 사용하는 예제를 보면,

   struct point origin, *pp;
   pp = &origin;
   printf(“origin is (%d,%d)n”, (*pp).x, (*pp).y);

구 조체 멤버 연산자 .은 *보다 우선순위가 높기 때문에 (*pp).x처럼 괄호를 해주어야 한다. *pp.x는 *(pp.x)라는 의미이고 x는 포인터가 아니므로 잘못된 표현식이다. 구조체 포인터는 빈번하게 사용되므로 이것을 위한 연산자가 따로 존재한다. p가 구조체 포인터라면 다음과 같이 구조체안의 멤머를 -> 연산자를 사용하여 참조할 수 있다.

p->member-of-structure
따라서, 구조체 포인터 pp의 멤버는 다음과 같이 참조한다.

   printf(“origin is (%d,%d)n”, pp->x, pp->y);

.과 ->은 둘다 왼쪽에서 오른쪽으로 연산한다.

   struct rect r, *rp = &r;

위의 구조체 멤버를 참조하는 아래의 4개는 동일한 표현식이다.

   r.pt1.x
   rp->pt1.x
   (r.pt1).x
   (rp->pt1).x

구조체 연산자 .과 ->는 둘다 ( )와 [ ]처럼 연산 우선순위가 가장 높다. 예를 들면, 아래에서

   struct {
    int len;
    char *str;
   } *p;
   ++p->len;

위의 표현식은 p가 아니라 len을 증가시킨다. ->의 연산우선순위가 높기 때문에 ++(p->len)와 같은 의미이다. ( )는 연산우선순위를 조정하고자 할 때 사용한다. 예를 들면,
(++p)->len는 len에 접근하기 전에 p를 먼저 증가시킨다.
(p++)->len는 len이 참조된 이후에 p가 증가되기 때문에, 사실상 ()는 불필요하다.
같은 방식으로, *p->str는 str이 가리키는 값을 가져온다.
*p->str++는 str이 가리키는 곳에 접근한 후에 str를 증가시킨다.(*s++와 같은 의미)
(*p->str)++는 str이 가리키는 곳의 값이 증가된다.
*p++->str는 str이 가리키는 곳에 접근한 후 p가 증가된다.

구조체 배열
C언어의 키워드가 몇 개 나타나는지 키워드마다 각각의 개수를 더하는 프로그램을 생각해 보자. 키워드 명칭을 보관하기 위한 문자열 배열과 개수를 계산하기 위한 정수 배열이 각각 필요하다.

   char *keyword[NKEYS];
   int keycount[NKEYS];

위와 같이 일반적인 배열로 코딩할 수 있지만, 각각의 키워드마다 개수는 항상 쌍으로 나타나므로 아래의 변수를 구조체 멤버 변수로 하여,

   char *word;
   int cout;

다음과 같이 구조체 배열로 정의할 수 있다.

   struct key {
    char *word;
    int count;
   } keytab[NKEYS];

위의 표현은 다음과 동일하다.

   struct key {
    char *word;
    int count;
   };
   struct key keytab[NKEYS];

구조체 배열의 멤버 변수들은 아래와 같이 정의하면서 초기화 할 수 있다.

   struct key {
    char *word;
    int count;
   } keytab[] = {
    “auto”, 0,
    “break”, 0,
    “case”, 0,
    “char”, 0,
    “const”, 0,
    “continue”, 0,
    “default”, 0,
    /* ... */
    “unsigned”, 0,
    “void”, 0,
    “volatile”, 0,
    “while”, 0
   };

구조체 멤버 변수들은 각각의 위치에 맞게끔 초기화 되지만, 아래와 같이 {}를 사용하여
행 단위로 구분해 줄 수도 있다.

   { “auto”, 0 },
   { “break”, 0 },
   { “case”, 0 },
   ...

하지만, 초기화 되는 값들의 위치와 개수가 계산되므로 행을 구분하는 { }를 생략해도 된다.
그 런데, 상수 NKEYS는 구조체 배열 keytab에 초기화 되어 있는 키워드들의 개수(배열의 인덱스수)이다. 이것은 초기화 되는 개수에 따라서 변화기 때문에, 컴파일시 자동으로 계산되도록 아래와 같은 수식을 통하여 컴파일러에게 알려준다.

배열의 인덱스수 = 배열의 전체 크기 / 배열의 한개 요소 크기
keytab의 인덱스수 = size of keytab / size of struct key

C언어는 컴파일시에 데이터 객체의 크기를 계산하는 연산자 sizeof를 제공한다.

sizeof 객체명

혹은

sizeof (데이터 타입명)

따라서, NKEYS는 다음과 같은 수식으로 정의할 수 있다.

#define NKEYS (sizeof keytab / sizeof(struct key))

혹은

#define NKEYS (sizeof keytab / sizeof(keytab[0]))

구조체 포인터
구조체 포인터를 이해하기 위해서 앞에서 실습한 프로그램을 몇 가지 수정해 보도록 하자. binsearch 함수에서 배열의 인덱스를 사용하는 대신에 포인터를 사용하여 다음과같이 수정한다.

   #include <stdio.h>
   #include <ctype.h>
   #include <string.h>
   #define MAXWORD 100

   int getword(char *, int);
   struct key *binsearch(char *, struct key *, int);

   main()
   {
    char word[MAXWORD];
    struct key *p;

    while (getword(word, MAXWORD) != EOF)
    if (isalpha(word[0]))
    if ((p=binsearch(word, keytab, NKEYS)) != NULL)
    p->count++;
    for (p = keytab; p < keytab + NKEYS; p++)
    if (p->count > 0)
    printf(“%4d %sn”, p->count, p->word);
    return 0;
   }

   //binsearch 함수는 구조체 포인터를 반환하도록 수정한다.
   struct key *binsearch (char *word, struct key *tab, int n)
   {
    int cond;
    struct key *low = &tab[0];
    struct key *high = &tab[n];
    struct key *mid;

    while (low < high) {
    mid = low + (high-low) / 2;
    if ((cond = strcmp(word, mid->word)) < 0)
    high = mid;
    else if (cond > 0)
    low = mid + 1;
    else
    return mid;
    }
    return NULL;
   }

수 정된 내용을 살펴보면, 첫째, binsearch 함수는 검색된 배열의 인덱스인 정수를 반환하는 대신에 구조체 포인터를 반환하도록 수정 되었다. 검색하고자 하는 단어를 발견하면 그곳의 포인터를 반환하고 단어를 발견하지 못하면 널(NULL)을 반환한다. 둘째, keytab의 요소들은 포인터로 접근한다. 이것이 가장 큰 차이점이다. low는 keytab의 시작 포인터이고 high는 keytab의 종료 포인터이다.  middle 포인터는 아래와 같이 계산하는 것이 아니라,

   mid = (low+high) / 2    /* 틀림 */

다음과 같이 계산하여 low 포인터와 high 포인터 사이의 중간 위치를 가리키도록 한다.

   mid = low + (high-low) / 2

구 조체 배열을 가리키는 포인터에서 중요한 점은 포인터가 배열의 범위를 벗어나지 않도록 하는 것이다. &tab[-1]과 &tab[n]의 주소는 둘 다 배열의 범위를 벗어나므로 오류가 발생한다. 따라서, 배열 포인터의 시작과 끝이 벗어나지 않도록 for 루프의 제어변수가 아래와 같이 연산되도록 한다.

   for (p = keytab; p < keytab + NKEYS; p++)

p 는 구조체 배열을 가리키는 포인터이므로 p++을 하면 구조체 배열의 다음 요소를 가리키게 된다. 한가지 주의할 점은 구조체의 크기는 멤버 변수들의 크기를 합한 것이 아닐 수도 있다는 것이다. 왜냐하면 서로 다른 데이터 타입간에 경계조건이 있을 수 있기 때문이다. 예를 들면, 다음의 구조체 멤버에서 char는 1바이트 int는 4바이트라고 생각하여 구조체의 크기는 5바이트라고 예상되지만,
   struct {
    char c;
    int i;
   };

실제적으로는 8바이트이다. 이것은 구조체 멤버 변수들간에 경계조건(패딩)이 있기 때문인데, 이것에 대한 자세한 내용은 이장의 마지막 부분의 구조체 패딩에서 자세히 설명한다.
끝으로, binsearch 함수는 구조체 포인터를 반환하므로 아래와 같이 선언한다.

   struct key *binsearch (char *word, struct key *tab, int n);

반환하는 데이터 타입(struct key *)의 표현이 너무 길어서 판독에 다소 어려움이 있을 수 있으므로 프로그램 개발자의 취향에 따라서 아래와 같이 표현할 수도 있다.

   struct key *
   binsearch (char *word, struct key *tab, int n);

typedef
C언어는 데이터 타입에 별명을 부여하기 위해서 typedef라는 것을 제공한다.  예를 들어, 아래와 같이 선언하면,

   typedef int Length;

Length는 int와 동일한 명칭이 되어 다음과 같이 사용할 수 있다.

   Length len, maxlen;
   Length *lengths[];

유사한 방법으로, 아래는 문자를 가리키는 포인터인 char*을 String이라는 별명으로 선언한다.

   typedef char *String;

String은 char*와 동일하게 취급되며 다음과 같이 사용될 수 있다.

   String p, lineptr[MAXLINES], alloc(int);
   int strcmp(String, String);
   p = (String) malloc(100);

아래는 구조체 포인터(struct tnode *)를 Treeptr이라는 별명으로 선언하는 것이며,

   typedef struct tnode *Treeptr;

아래는 구조체(struct tnode)를 Treenode라는 별명으로 선언하는 것이다.

   typedef struct tnode {
    char *word;
    int count;
   } Treenode;

아래의 talloc 함수는 위에서 typedef로 선언한 구조체 별명을 사용하는 예이다. 이 함수는 Treenode 구조체 크기만큼 malloc로 할당한 메모리의 시작 포인터(Treeptr)를 반환하는 역할을 한다.

   Treeptr talloc(void)
   {
    return (Treeptr) malloc(sizeof(Treenode));
   }
아래의 typedef 문장은 int를 반환하면서 두개의 매개변수(char *, char *)를 가지고 있는 함수를 가리키는 포인터를 PFI라는 별명으로 선언하는 것이다.

   typedef int (*PFI)(char *, char *);

위에서 선언된 PFI는 다음과 같이 사용된다.

   PFI strcmp, numcmp;

typedef 는 extern이나 static과 같은 저장 등급(storage class)이다. 관례상 typedef으로 선언되는 명칭은 대문자를 사용한다. typedef는 새로운 데이터 타입을 생성하는 것이 아니라 별명을 부여하는 것이다. typedef는 #define과 유사하며 프로그램 코드의 호환성과 판독성을 높여주는 장점이 있다.

Unions
union 은 변수이다. union은 서로 다른 크기의 데이터 타입(객체)들을 일정한 크기로 정하여 단일 저장소에 저장하도록 해준다.  union으로 선언된 하나의 변수에 여러 개의 데이터 타입을 나열할 수 있으나, 저장소에 접근할 때 union 변수 하나를 사용한다.  문법은 구조체와 유사하다.

   union u_tag {
    int ival;
    float fval;
    char *sval;
   } u;

union 으로 선언된 변수 u의 데이터 타입들(int, float, char *) 중에서 가장 큰 것이 union 변수 u의 저장소가 된다.  데이터 타입들은 단일 저장소인 u안에서 공유되며, 데이터 타입들 중에서 하나를 선택적으로 사용한다.  사용 문법은 구조체 멤버 변수 참조와 유사하다.

  union-name.member
혹은
  union-pointer->member

union은 구조체 안의 멤버로도 사용할 수 있다. 예를 들면,

   struct {
    char *name;
    int flags;
    int utype;
    union {
    int ival;
    float fval;
    char *sval;
    } u;
   } symtab[NSYM];

위의 구조체 배열 symtab에서 u의 멤버인 ival는 다음과 같이 참조한다.

   symtab[i].u.ival

또한 문자열 멤버인 sval의 첫 번째 문자는 다음과 같이 참조할 수 있다.

   *symtab[i].u.sval
또는
   symtab[i].u.sval[0]

union 안의 모든 멤버들은 저장소의 시작위치가 동일하며 같은 경계조건을 가지고 있다.  union에 대한 작업들(할당, 복사, 주소참조, 멤버접근)은 구조체와 유사하다.  그러나 union을 초기화 할 때는 첫 번째 멤버에 대해서 초기화 해야 한다.

비트 필드
기억장소를 절약하기 위해서 데이터 처리를 비트 단위로 해야 하는 경우가 있을 수 있다.  이때 구조체 멤버들을 비트 단위로 정의할 수 있다. 예를 들면,

   struct {
    unsigned int is_keyword : 1;
    unsigned int is_extern  : 1;
    unsigned int is_static  : 1;
   } flags;

위의 flags는 세 개의 비트 필드로 구성된 변수로 사용될 수 있다. 각각의 비트 필드는 구조체 멤버를 참조하듯이 flags.is_keyword,  flags.is_extern, flags.is_static으로 접근할 수 있다.

   flags.is_extern = flags.is_static = 1;

위의 문장은 비트 필드를 1로 설정(turn on)한다.

   flags.is_extern = flags.is_static = 0;

위의 문장은 비트 필드를 0으로 설정(turn off)한다.

   if (flags.is_extern == 0 && flags.is_static == 0)
    ...
위의 문장은 각각의 비트 필드에 접근한 값으로 if 논리식을 만든 것이다.
비 트 필드는 정수형 데이터 타입만으로 정의될 수 있으며 주소가 부여되지 않으므로 & 연산자를 사용할 수 없다. 그리고 비트 필드에 명칭을 부여하지 않고 콜론(:)으로만 정의할 수 있는데, 이것은 저장소를 임의로 확보하기 위한 padding의 용도이다.

구조체 padding
메 모리 배치선에 일치하지 않는(unaligned memory accesses) 접근은 N 바이트의 데이터를 메모리에서 읽고자 할 때, 시작주소가 N으로 나누어지지 않을 때 발생한다. (addr % N != 0). 예를 들면, 주소가 0x10004인 메모리에서 4바이트의 데이터는 읽기 좋지만, 0x10005인 주소에서는 메모리 배치선에 일치하지 않는(unaligned memory accesses) 접근이 발생한다.
N 바이트의 메모리에 접근하고자 할 때, 메모리 기준 주소(base address)는 N으로 나누어 지도록 한다. (addr % N == 0).  코드를 작성할 때, target architecture는 메모리 배치선이 맞추어 지도록 요구한다(Natural alignment). 실제적으로, 몇몇의 architectures 만이 Natural alignment을 요구하지만, 우리는 모든 architectures에 대하여 고려해야 하며, 이것은 호환성을 높일 수 있는 가장 손쉬운 방법이다. 만약, Natural alignment 조건에 위배되는 코드를 작성하게 되면, 특정 플랫폼에서 정확하게 동작하지 않을 수 있으며 성능저하의 원인이 된다.
다행히도 컴파일러가 메모리 배치선에 위배되지 않도록 코드를 생성해 준다. 아래의 구조체를 가지고 예를 들면,

struct foo {
u16  field1; //2바이트
u32  field2; //4바이트
u8  field3;  //1바이트
};

위의 foo 구조체의 인스턴스가 메모리 주소 0x10000에서 시작한다고 가정하면, 구조체 안의 필드들은 다음과 같은 주소에 배치된다고 직관적(기본적)으로 생각할 수 있다.

0x10000: field1
0x10002: field2
0x10006: field3

위 에서 field2의 크기는 4바이트 이지만, 주소는 4로 나누어 지지 않으므로 unaligned 접근이 발생한다. 다행히, 컴파일러가 이러한 문제를 알고 있으므로, field1과 field2사이에 2바이트 크기의 padding을 삽입한다.

0x10000: field1
0x10002: (padding)
0x10004: field2
0x10008: field3

이번에는 구조체 안의 필드 배열 순서를 아래와 같이 변경해 보자.

struct foo2 {
u32 field2; //4바이트
u16 field1; //2바이트
u8  field3; //1바이트
};
왼쪽의 foo2 구조체의 인스턴스가 메모리 주소 0x10000에서 시작한다고 가정하면, 구조체 안의 필드들은 아래와 같은 주소에 배치된다고 직관적(기본적)으로 생각할 수 있다.

0x10000: field2
0x10004: field1
0x10006: field3

위의 경우, 각각의 필드 주소는 메모리 배치선에 위배되지 않으므로, 컴파일러는 padding을 삽입하지 않는다.  단, 구조체 끝에 1바이트를 패딩하는데, 이것은 구조체들의 배치선을 일치시켜 주기 위함이다.

맺음말
이 번 연재에서는 구조체의 기본, 구조체와 함수, 구조체 배열, 구조체 포인터, typedef, Unions, 비트 필드, 구조체 padding 등에 대해서 기술하였다. 구조체는 다음부터 연재하게 되는 자료구조와 알고리즘에서 많이 사용하므로 사용법을 잘 이해해 두도록 하자.


필 / 자 / 소 / 개

(정 재준) 필자는 학창시절 마이크로프로세서 제어 기술을 배웠고, 10여년동안 쌓아온 IT관련 개발 경험을 바탕으로 “오라클실무활용SQL튜닝(혜지원)” 책을 집필하고, “월간임베디드월드” 잡지에 다수의 글을 기고하였다.  서울대병원 전산실에서 데이터베이스 관련 일을 하면서 학창시절부터 꾸준히 해온 리눅스 연구도 계속하고 있다.  특히, 스탠포드대학교의 John L. Hennessy 교수의 저서 “Computer Organization and Design” 책을 읽고 깊은 감명을 받았으며, 컴퓨터구조와 자료구조 및 알고리즘 효율성 연구를 통한 기술서적 집필에 노력하고 있다.  또한, 온라인 상에서 커널연구회 (http://www.kernel.bz/ )라는 웹사이트를 운영하며 관련기술들을 공유하고 있다.


※ 본 내용은 (주)테크월드(http://www.embeddedworld.co.kr)의 저작권 동의에 의해 공유되고 있습니다.
Copyright ⓒ
Techworld, Inc. 무단전재 및 재배포 금지

맨 위로
맨 위로