typedef

typedef를 배우기 전에 다음의 코드를 살펴보자. 

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
struct point {
    int xpos;
    int ypos;
};
 
int main(void) {
    struct point pnt = { 23 };
    printf("[%d, %d]", pnt.xpos, pnt.ypos);
 
    return 0;
}
 
cs

9번 라인을 보면 struct point형 변수를 선언하기 위해 struct point pnt = {2, 3}; 으로 선언한 것을 볼 수 있다. 매번 struct를 사용하는 것은 불편하다. 그렇다면 int num = 10; 처럼 간단하게 할 수 있는 방법이 없을까? 있다. 바로 typedef를 사용하면 된다. 이를 다음의 소스코드와 이전의 소스코드를 비교하며 이해해보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
typedef struct {
    int xpos;
    int ypos;
} Point;
 
int main(void) {
    Point pnt = { 23 };
    printf("[%d, %d]", pnt.xpos, pnt.ypos);
 
    return 0;
}
 
cs

두 코드의 실행결과는 모두 동일하며 3번 라인을 보면 struct 앞에 typedef 키워드가 있고 point라는 구조체 이름이 빠지고 구조체의 마지막에 Point라고 붙여진것을 볼 수 있다. 이를 통해 9번 라인에서 볼 수 있듯이 단순하게 Point pnt = {2, 3}; 으로 구조체 변수를 간단하게 생성하는 것을 볼 수 있다.


함수로의 구조체 변수 전달과 반환

기본 자료형과 마찬가지로 구조체 변수 역시 매개변수에 복사가 되거나 반환될 수 있다. 다음의 코드를 살펴보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
typedef struct {
    int xpos;
    int ypos;
} Point;
 
void showPosition(Point pnt) {
    printf("[%d, %d] \n", pnt.xpos, pnt.ypos);
}
 
Point GetCurrentPosition(void) {
    Point cen;
    printf("pos를 입력하시오 : ");
    scanf("%d %d"&cen.xpos, &cen.ypos);
    return cen;
}
 
int main(void) {
    Point curPos = GetCurrentPosition();
    showPosition(curPos);
 
    return 0;
}
 
cs

<실행결과>

라인 9번에서 볼 수 있듯이 매개변수로 구조체 변수가 들어갔고 21번 라인에서 볼 수 있듯 반환값을 Point 변수 curpos에 대입하는것을 볼 수 있다. 또한 매개변수로 구조체의 포인터 변수도 들어갈 수 있다. 이를 통해 Call by reference도 할 수 있다. 이를 예시 코드를 통해 알아보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
typedef struct {
    int xpos;
    int ypos;
} Point;
 
void OrgSynTrans(Point* pnt) {
    pnt->xpos = pnt->xpos * -1;
    pnt->ypos = pnt->ypos * -1;
}
 
void showPosition(Point pnt) {
    printf("[%d, %d] \n", pnt.xpos, pnt.ypos);
}
 
int main(void) {
    Point pos = { 7-5 };
    OrgSynTrans(&pos);
    showPosition(pos);
    OrgSynTrans(&pos);
    showPosition(pos);
    return 0;
}
 
cs

<실행결과>

9번 라인에서 볼 수 있듯이 함수의 매개변수로 구조체의 주소값을 넘겨서 원점 대칭하는것을 알 수 있다. 따라서 메인함수의 좌표값을 메인함수 외부에서 변경하는것을 볼 수 있다.

또한 구조체 변수 역시 구조체의 멤버로 포함될 수 있다. 이를 구조체의 중첩이라 한다. 다음의 소스코드를 확인하자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
typedef struct {
    int xpos;
    int ypos;
} Point;
 
typedef struct {
    Point cen;
    double rad;
} Circle;
 
void showCircleInfo(Circle * c) {
    printf("[%d, %d] \n", (c->cen).xpos, (c->cen).ypos);
    printf("radius: %g \n\n", c->rad);
}
 
int main(void) {
    Circle c1 = { {12}, 3.5 }; // 구조체가 중첩 됨
    showCircleInfo(&c1);
 
    return 0;
}
 
cs

<실행결과>

20번 라인에서 볼 수 있듯이 구조체가 중첩된 것을 알 수 있다.


UNION

구조체와 공용체(union)의 차이

typedef struct {

    int mem1;

    int mem2;

    double mem3;

} Sbox;

 

typedef union {

    int mem1;

    int mem2;

    double mem3;

} Ubox;

위의 Sbox, Ubox의 sizeof 연산을 해보면 각각 16 byte, 8  byte 인것을 확인할 수 있다.  이를 그림으로 표현하면 다음과 같다.

이 union은 하나의 메모리 공간에 둘 이상의 방식으로 접근할 수 있다는 특성이 있다.

 


Enum 열거형

enum을 설명하기 전에 먼저 다음의 소스코드를 보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
 
typedef enum {
    Do = 1, Re = 2, Mi = 3, Fa = 4, Sol = 5, La = 6, Ti = 7
} Syllable;
 
void Sound(Syllable sy) {
    switch (sy) {
    case Do:
        puts("도 입니다.");
        return;
    case Re:
        puts("레 입니다.");
        return;
    case Mi:
        puts("미 입니다.");
        return;
    case Fa:
        puts("파 입니다");
        return;
    case Sol:
        puts("솔 입니다.");
        return;
    case La:
        puts("라 입니다.");
        return;
    case Ti:
        puts("시 입니다.");
        return;
    }
}
 
int main(void) {
    Syllable tone;
    for (tone = Do; tone <= Ti; tone++)
        Sound(tone);
    return 0;
}
 
cs

<실행결과>

열거형은 연관이 있는 이름을 동시에 상수로 선언할 수 있다는 장점이 존재한다.

 

이 포스팅은 윤성우님의 열혈 C를 기반으로 작성되었습니다.

'C' 카테고리의 다른 글

14. 메모리 및 동적할당  (0) 2021.06.28
11. 구조체와 사용자 정의 자료형  (0) 2021.06.27
10. 문자열 관련 함수  (0) 2021.06.27
9. 함수 포인터 & void 포인터  (0) 2021.06.26
8. 2차원 배열과 포인터  (0) 2021.06.26
구조체란?

구조체란 하나 이상의 변수를 묶어서 새로운 자료형을 정의하는 것이다. 예를 들자면 어떤 것의 좌표라고 가정해보자. x좌표 y좌표가 함께 존재해야만 의미가 있고 한 개씩 있으면 존재의 의미가 없는 것이다. 이 구조체를 정의해보자.

 

struct cord {

    int xPos;

    iny yPos;

                                                                      };

위와 같이 정의할 수 있다. 예를 들어 사람의 이름, 나이, 전화번호를 묶으면 다음과 같다

struct person {

    char name[20]; // 배열도 구조체의 멤버가 될 수 있다.

    char phoneNum[20];

    int age;

};

이제 이러한 구조체들을 이용하여 기본 자료형처럼 구조체 변수 선언을 할 수 있다. 다음을 보자.

 

struct type_name val_name;

이를 통해 위의 cord, person 구조체의 변수를 선언하면 다음과 같다. 또한 그림으로 표현하면 다음과 같다.

struct cord pos;

struct person man;

구조체 변수의 멤버에 접근하기 위해서는 다음과 같이 접근한다.

struct_var_name.struct_member_name;

예를 들면 pos.xPos; 이다. 이제 예시를 통해 두 점 사이의 거리를 구하는 예시 코드를 보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
 
struct point {
    int xpos;
    int ypos;
};
 
int main(void) {
    struct point pos1, pos2; // 구조체 변수 선언
    double dist;
 
    fputs("point1 pos: ", stdout);
    scanf("%d %d"&pos1.xpos, &pos1.ypos); // 구조체 변수 pos1의 멤버 xpos, ypos에 접근 
 
    fputs("point2 pos: ", stdout);
    scanf("%d %d"&pos2.xpos, &pos2.ypos); // 구조체 변수 pos2의 멤버 xpos, ypos에 접근 
 
    // 두 점 사이 거리 계산
    dist = sqrt((double)((pos1.xpos - pos2.xpos) * (pos1.xpos - pos2.xpos) + 
        (pos1.ypos - pos2.ypos) * (pos1.ypos - pos2.ypos)));
 
    printf("두 점의 거리는 %g 입니다. \n", dist);
 
    return 0;
}
 
cs

<실행결과>

다음의 방식으로 구조체 변수를 선언과 동시에 초기화할 수 있다.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
 
struct point {
    int xpos;
    int ypos;
};
 
struct person {
    char name[20];
    char phoneNum[20];
    int age;
};
 
int main(void) {
    struct point pos = { 1020 };
    struct person man = { "홍길동""010-0000-0000"21 };
    printf("%d %d \n", pos.xpos, pos.ypos);
    printf("%s %s %d\n", man.name, man.phoneNum, man.age);
    return 0;
}
 
cs

<실행결과>


구조체와 배열 & 포인터

int arr[]; 처럼 int형 배열을 선언할 수 있듯이 구조체 역시 배열을 설정할 수 있다. 만약 struct point가 있다고 가정하면

point형 변수는 struct point pos; 이며 이 point형 배열은 struct point arr[3]; 이다. 이를 그림으로 표현하면 다음과 같다.

소스코드를 통해 알아보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
struct point {
    int xpos;
    int ypos;
};
 
int main(void) {
    struct point arr[3];
    for (int i = 0; i < 3; i++) {
        printf("점의 좌표 입력 : ");
        scanf("%d %d"&arr[i].xpos, &arr[i].ypos);
    }
 
    for (int i = 0; i < 3; i++) {
        printf("[%d, %d] ", arr[i].xpos, arr[i].ypos);
    }
 
    return 0;
}
 
cs

<실행결과>

또한 구조체 배열은 다음과 같이도 초기화가 가능하다.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
struct person {
    char name[20];
    char phoneNum[20];
    int age;
};
 
int main(void) {
    struct person arr[3= {
        {"김김김""010-1111-1111"21},
        {"이이이""010-2222-2222"25},
        {"박박박""010-3333-3333"28}
    };
 
    for (int i = 0; i < 3; i++)
        printf("%s %s %d \n", arr[i].name, arr[i].phoneNum, arr[i].age);
 
    return 0;
}
 
cs

<실행결과>


구조체 포인터

int num = 5; num의 주소 값을 담는 포인터 변수 int * ptr = &num; 이듯이 구조체의 포인터 변수도 비슷하다.

struct point pos = {11, 22}; struct point * pptr = &pos; 접근 역시 마찬가지로 *ptr = 20; 이듯이 (*pptr).xpos = 10; 이런 식으로 접근할 수 있다. 혹은 다음과 같이 pptr->xpos = 10; 이렇게 접근이 가능하다.

이를 예시로 알아보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
struct point {
    int xpos;
    int ypos;
};
 
int main(void) {
    struct point pos1 = { 12 };
    struct point pos2 = { 100200 };
    struct point* pptr = &pos1;
 
    pptr->xpos += 4;
    pptr->ypos += 8;
    printf("[%d, %d] \n", pptr->xpos, pptr->ypos);
 
    pptr = &pos2;
    (*pptr).xpos += 5// 이렇게도 접근이 가능하다
    (*pptr).ypos += 10// 이렇게도 접근이 가능하다
    printf("[%d, %d] \n", (*pptr).xpos, (*pptr).ypos);
    return 0;
}
 
cs

<실행결과>


그렇다면 포인터 변수도 구조체 멤버가 당연히 될 수 있다. 이제 예시를 통해 소스코드를 살펴보자.

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
struct point {
    int xpos;
    int ypos;
};
 
struct circle {
    double radius;
    struct point* center; // 원의 중점 
};
 
int main(void) {
    struct point cen = { 23 };
    double rad = 5.5;
 
    struct circle ring = { rad, &cen };
    printf("원의 반지름: %g \n", ring.radius);
    printf("원의 중심 [%d, %d] \n", (ring.center)->xpos, (ring.center)->ypos);
 
    return 0;
}
 
cs

<실행결과>

이를 그림으로 표시하면 다음과 같다.

 

'C' 카테고리의 다른 글

14. 메모리 및 동적할당  (0) 2021.06.28
12. 구조체와 사용자 정의 자료형 2  (0) 2021.06.27
10. 문자열 관련 함수  (0) 2021.06.27
9. 함수 포인터 & void 포인터  (0) 2021.06.26
8. 2차원 배열과 포인터  (0) 2021.06.26

+ Recent posts