programming/C

C // 구조체와 사용자 정의 자료형2

깨래 2017. 12. 30. 15:27

typedef선언


기존에 존재하는 자료형의 이름에 새 일므을 부여하는 것을 목적으로 하는 선언


typedef int INT;             // int의 또 다른 이름 INT를 부여


INT num;        // int num;    과 동일한 선언


typedef선언에 새로운 이름의 부여는 가장 마지막에 등장하는 단어를 중심으로 이루어진다. 


typedef A B C 가 선언되면, C가 새로운 이름이 되고, A와 B는 묶이게 된다.


ex)

새로 부여된 이름        대상 자료형

INT                            int

PTR_INT                    int *

UINT                         unsigned int

PTR_UINT                 unsigned int *

UCHAR                     unsigned char

PTR_UCHAR             unsigned char *


구조체의 정의와 typedef 선언


struct선언을 생략하고 구조체 정의를 해보자.


typedef struct point Point;    // struct point에 Point라는 이름을 부여!


이후로는 다음과 같이 struct선언을 생략한 형태로 구조체 변수를 선언할 수 있다.


Point pos;


ex)

struct point

{

int xpos;

int ypos;

};

typedef struct point Point;


위 문장을 간결하게 하면


typedef struct point

{

int xpos;

int ypos;

}Point;


이런 식으로 선언할 수 있다. 


위와 같이 구조체가 선언이 된다면, 두 가지 방식으로 구조체 변수를 선언할 수 있다.


Point pos1;        // typedef 선언을 이용한 변수의 선언

struct point pos2;    // struct선언을 추가한 형태의 변수선언


구조체의 이름을 생략할 수도 있다.


typedef struct person

{

char name[20];

char phoneNum[20];

int age;

}Person;


이렇게 구조체가 정의가 된다면, 구조체의 이름 person은 사실상 별 의미를 갖지 않게 된다. 구조체 변수를 선언할 때도 typedef에 의해 정의된 이름 Person을 사용하기 때문이다.


그럼 위의 코드를 아래 코드처럼 구조체의 이름을 생략할 수 있다.


typedef struct

{

char name[20];

char phoneNum[20];

int age;

}Person;


단 구조체의 이름을 생략하면 


struct person man;    // 불가능


이러한 선언은 불가능하게 된다. 


ex)

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
#include<stdio.h>
 
struct point
{
    int xpos;
    int ypos;
};
 
typedef struct point Point;
 
typedef struct
{
    char name[20];
    char phoneNum[20];
    int age;
}Person;
 
int main()
{
    Point pos={1020};
    Person man={"이승기""010-1212-0001"21};
    printf("%d %d \n", pos.xpos, pos.ypos);
    printf("%s %s %d \n",man.name, man.phoneNum, man.age);
 
    return 0;
}
 

cs

출력결과

10 20 

이승기 010-1212-0001 21 


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


ex)

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
#include<stdio.h>
 
typedef struct
{
    int xpos;
    int ypos;
}P1;
 
void ShowPos(P1 pos)
{
    printf("[%d, %d] \n",pos.xpos,pos.ypos);
}
 
P1 GCPos(void)
{
    P1 cen;
    printf("Input current pos:");
    scanf("%d %d",&cen.xpos,&cen.ypos);
    
    return cen;
}
 
int main()
{
    P1 curPos=GCPos();
    ShowPos(curPos);
    
    return 0;
}
 

cs

출력결과

Input current pos:3 5

[3, 5] 


25행 : 함수가 반환하는 값으로 구조체 변수 curPos를 초기화하고 있다. 그런데 이 문장에서 호출하는 함수는 20행에서 프로그램 사용자로부터 입력받은 위치정보로 초기화된 구조체 변수 cen을 반환하고 있다. 그 결과 변수 cen의 멤버에 저장된 값은 변수 curPos의 멤버에 나란히 저장된다.


26행 : 함수를 호출하면서 변수 curPos를 인자로 전달하고 있다. 따라서 변수 curPos에 저장된 값은 9행의 매개변수 pos에 나란히 저장(복사)된다.


또 한, 구조체의 멤버로 배열이 선언된다면 값의 반환과정에서 구조체의 멤버로 선언된 배열도 통째로 복사가 된다. 인자의 전달과정, 값의 반환과정에서 배열을 주고 받는다면, 주소값이 아닌 구조체를 사용하는 것도 생각해 볼 필요가 있다.

구조체는 구조체의 멤버로 선언된 배열을 통째로 복사하기 때문에!

ex)

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
#include<stdio.h>
 
typedef struct
{
    char name[20];
    char phoneNum[20];
    int age;
}Pers;
 
void ShowPers(Pers man)
{
    printf("name : %s \n",man.name);
    printf("name : %s \n",man.phoneNum);
    printf("name : %d \n",man.age);
}
 
Pers ReadPers(void)
{
    Pers man;
    printf("name? "); scanf("%s",man.name);
    printf("phone? "); scanf("%s",man.phoneNum);
    printf("age? "); scanf("%d",&man.age);
    
    return man;
}
int main()
{
    Pers man = ReadPers();
    ShowPers(man);
    
    return 0;
}
 

cs

출력결과

name? jung

phone? 010-1234-1234

age? 23

name : jung 

name : 010-1234-1234 

name : 23 

배열 통째로 복사하기!



ex)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
#include<stdio.h>
 
typedef struct
{
    int xpos;
    int ypos;
}P1;
 
void Org(P1 *ptr)
{
    ptr->xpos *= -1;
    ptr->ypos *= -1;
}
int main()
{
    P1 pos={7,-5};
    Org(&pos);
    printf("%d %d \n",pos.xpos,pos.ypos);
    Org(&pos);
    printf("%d %d \n",pos.xpos,pos.ypos);
    
    return 0;
}
 

cs

출력결과

-7 5

7 -5


9행 : 구조체의 포인터 변수도 매개변수로 선언이 되어서 call by reference형태의 함수호출을 구성할 수 있다.


구조체 변수를 대상으로 가능한 연산


구조체 변수를 대상으로는 대입연산만 가능하고, 그 외에 주소 값 반환을 목적으로 하는 & 연산이나 구조체 변수의 크기를 반환하는 sizeof정도의 연산만 허용이 된다. 


구조체 변수간 대입연산의 결과로 멤버 대 멤버의 복사가 이뤄진다.


덧셈이나 뺄셈을 하려면 함수를 직접 정의하여야 한다.


ex)

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
#include<stdio.h>
 
typedef struct
{
    int xpos;
    int ypos;
}Point;
 
Point AddPoint(Point pos1, Point pos2)
{
    Point pos={pos1.xpos + pos2.xpos, pos1.ypos + pos2.ypos};
    return pos;
}
 
Point MinPoint(Point pos1, Point pos2)
{
    Point pos={pos1.xpos - pos2.xpos, pos1.ypos - pos2.ypos};
    return pos;
}
 
int main()
{
    Point pos1={5,6};
    Point pos2={2,9};
    Point result;
    
    result=AddPoint(pos1, pos2);
    printf("[%d %d] \n", result.xpos, result.ypos);
    result=MinPoint(pos1, pos2);
    printf("[%d %d] \n", result.xpos, result.ypos);
    
    return 0;
}
 

cs

출력결과

[7 15] 

[3 -3] 


중첩된 구조체의 정의와 변수 선언


구조체 변수도 구조체의 멤버로 선언될 수 있다. 이럴 경우를 구조체의 중첩이라고 한다.


ex)

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
#include<stdio.h>
 
typedef struct
{
    int xpos;
    int ypos;
}Point;
 
typedef struct circle
{
    Point cen;
    double rad;
}Circle;
 
void ShowCircleInfo(Circle *cptr)
{
    printf("[%d, %d] \n", (cptr->cen).xpos, (cptr->cen).ypos);
    printf("radius: %g \n\n", cptr -> rad);
}
 
int main()
{
    Circle c1 = {{1,2},3.5};
    Circle c2 = {2,4,3.9};
    ShowCircleInfo(&c1);
    ShowCircleInfo(&c2);
 
    return 0;
}
 

cs

출력결과

[1, 2] 

radius: 3.5 

[2, 4] 

radius: 3.9 


11행 : 3행에 정의된 구조체의 변수를 멤버로 선언하였다.

23행 : 구조체 변수의 멤버가 존재할 경우, 중괄호를 이용해도 되고 24행처럼 이용하지 않아도 된다.이용하지 않을경우 첫 멤버부터 순서대로 입력이 된다.


구조체를 정의하는 이유


구조체를 통해 연관있는 데이터를 하나로 묶을 수 있는 자료형을 정의하면, 데이터의 표현 및 관리가 용이해지고, 그만큼 합리적인 코드를 작성할 수 있게 된다.