C // 구조체와 사용자 정의 자료형2
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={10, 20}; 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; } |
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; } |
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; } |
출력결과
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; } |
-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; } |
출력결과
[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; } |
출력결과
[1, 2]
radius: 3.5
[2, 4]
radius: 3.9
11행 : 3행에 정의된 구조체의 변수를 멤버로 선언하였다.
23행 : 구조체 변수의 멤버가 존재할 경우, 중괄호를 이용해도 되고 24행처럼 이용하지 않아도 된다.이용하지 않을경우 첫 멤버부터 순서대로 입력이 된다.
구조체를 정의하는 이유
구조체를 통해 연관있는 데이터를 하나로 묶을 수 있는 자료형을 정의하면, 데이터의 표현 및 관리가 용이해지고, 그만큼 합리적인 코드를 작성할 수 있게 된다.