'구조체(structure)'는 서로 다른 자료형을 갖는 자료들을 하나의 자료형으로 정의하여 사용하는 자료형입니다. 배열은 같은 자료형만 모아서 사용할 수 있지만 구조체는 서로 다른 자료형을 모아서 사용할 수 있고, 사용자가 필요에 따라 정의하여 사용하므로 더 폭넓게 사용 가능합니다.
struct 구조체명{
멤버_자료형 멤버명;
멤버_자료형 멤버명;
...
};
구조체는 위와같은 형식으로 선언하고 아래와같이 사용 가능합니다.
#include <stdio.h>
struct student{ //struct로 student라는 구조체명 선언
char *name; //char 포인터 형식의 name이라는 멤버 정의
char *gender; //char 포인터 형식의 gender라는 멤버 정의
unsigned short number; //unsigned short 형식의 number라는 멤버 정의
};
int main(){
struct student giraffe; //giraffe라는 student 구조체 변수 선언
giraffe.name = "giraffe"; //giraffe라는 student 구조체 변수의 name 멤버에 자료값 입력
giraffe.gender = "male"; //giraffe라는 student 구조체 변수의 gender 멤버에 자료값 입력
giraffe.number = 1; //giraffe라는 student 구조체 변수의 number 멤버에 자료값 입력
printf("student name : %s\n", giraffe.name);
printf("student gender : %s\n", giraffe.gender);
printf("student number : %u\n", giraffe.number);
}
student name : giraffe
student gender : male
student number : 1
위와 같은 구조체 정의로 student라는 새로운 자료형을 정의하여 사용하였습니다.
구조체 변수 선언 부분에서 struct student giraffe;
형식 외에도
struct 구조체명 변수명, 배열명[배열크기], *포인터 변수명;
의 형식으로도 선언이 가능하고, 여러개를 나열하여 한번에 선언도 가능합니다.
struct student giraffe, zibra;
로 두 구조체 변수를 정의하고 멤버값들을 넣어 준 후,
zibra = giraffe;
처럼 배정 연산을 사용하여 각 멤버에 대응하는 값들을 복사해 줄 수도있습니다.
구조체는 다른 자료형처럼 선언과 동시에 초기화가 가능합니다.
struct student giraffe = {"giraffe", "male", 1};
구조체 멤버를 사용하기위해 멤버에 접근하는 것을 '구조체 멤버를 참조한다'라고 합니다.
참조 방법은 구조체명.멤버명
으로 접근하여 자료값을 대입하거나 꺼낼 수 있습니다.
구조체 포인터는 구조체 선언시 구조체 변수명 앞에 *를 붙여서 선언할 수 있습니다. 구조체 포인터도 포인터이므로 주소값을 갖습니다.
#include <stdio.h>
struct student{
char *name;
char *gender;
unsigned short number;
};
int main(){
struct student giraffe, *p;
p = &giraffe;
(*p).name = "giraffe"; //.(도트) 연산자의 우선 순위가 더 높으므로 괄호로 *p를 묶어줌
(*p).gender = "male";
(*p).number = 1;
printf("student name : %s\n", giraffe.name);
printf("student gender : %s\n", giraffe.gender);
printf("student number : %d\n", giraffe.number);
printf("\n");
p->name = "Giraffe"; //구조체 포인터로 멤버 접근시 ->(포인터 연산자)로 접근 가능
p->gender = "Male";
p->number = 2;
printf("student name : %s\n", giraffe.name);
printf("student gender : %s\n", giraffe.gender);
printf("student number : %d\n", giraffe.number);
}
student name : giraffe
student gender : male
student number : 1
student name : Giraffe
student gender : Male
student number : 2
구조체 포인터도 앞서 보았던 포인터처럼 사용하여 유용하게 활용할 수 있습니다.
함수를 사용할 때 매개변수로 구조체가 사용가능합니다.
구조체를 함수의 매개변수로 사용하는 것은 일반 변수를 매개변수로 사용하는 방법과 같습니다. 하지만 함수에 넘겨줄 때 구조체를 통째로 복사하기때문에 편리하지만 시간이 많이 걸리고, 기억공간이 낭비될 수 있습니다.
#include <stdio.h>
struct student{
char *name;
char *gender;
unsigned short number;
};
struct student print_info(struct student target);
int main(){
struct student giraffe;
giraffe.name = "giraffe";
giraffe.gender = "male";
giraffe.number = 1;
print_info(giraffe);
}
struct student print_info(struct student target){ //struct student 자체가 int처럼 일종의 자료형
printf("=====Student Information=====\n");
printf("student name : %s\n", target.name);
printf("student gender : %s\n", target.gender);
printf("student number : %d\n", target.number);
}
=====Student Information=====
student name : giraffe
student gender : male
student number : 1
구조체 자체를 함수의 매개변수로 사용할 때의 단점 때문에 포인터를 통해 주소값을 넘겨주는 것이 더 효율적입니다.
#include <stdio.h>
struct student{
char *name;
char *gender;
unsigned short number;
};
struct student print_info(struct student *target);
int main(){
struct student giraffe;
giraffe.name = "giraffe";
giraffe.gender = "male";
giraffe.number = 1;
print_info(&giraffe);
}
struct student print_info(struct student *target){
printf("=====Student Information=====\n");
printf("student name : %s\n", target->name);
printf("student gender : %s\n", target->gender);
printf("student number : %d\n", target->number);
}
=====Student Information=====
student name : giraffe
student gender : male
student number : 1
'typedef(type definitioin)'은 이미 존재하는 자료형에 새로운 이름을 붙여주는 키워드입니다.
typedef 기존_자료형_이름 새로운_자료형_이름
의 형식으로 사용합니다.
typedef unsigned int INT;
라고 선언하면 unsigned int라고 선언하지않고 INT라고 변수를 선언해도 unsigned int형으로 선언된 것과 동일하게 사용 가능합니다.
#include <stdio.h>
struct student{
char *name;
char *gender;
unsigned short number;
};
typedef struct student Student;
Student print_info(Student *target);
int main(){
Student giraffe;
giraffe.name = "giraffe";
giraffe.gender = "male";
giraffe.number = 1;
print_info(&giraffe);
}
Student print_info(Student *target){
printf("=====Student Information=====\n");
printf("student name : %s\n", target->name);
printf("student gender : %s\n", target->gender);
printf("student number : %d\n", target->number);
}
=====Student Information=====
student name : giraffe
student gender : male
student number : 1
위의 예시처럼 구조체에도 사용이 가능하며, struct student처럼 길게 적지않고 새로 정의한 이름으로 간편하게 사용할 수 있는 장점이 있습니다.
typedef struct student{
char *name;
char *gender;
unsigned short number;
}Student;
구조체 정의 후 따로 typedef struct student Student;
처럼 작성하지않고 구조체 정의시 위 처럼 바로 새로운 이름으로 정의할 수도 있습니다.
typedef struct{
char *name;
char *gender;
unsigned short number;
}Student;
그리고 더 간단하게 위처럼 작성할 수도 있습니다.
'공용체(union)'는 동일한 기억공간에 여러 자료형을 저장할 때 사용합니다. 주로 선택적으로 다른 자료형의 값을 가질 때 기억공간을 절약하기위해 사용합니다.
공용체의 사용방법은 구조체와 키워드만 다르고 대부분 동일합니다.
예를 들어 송금 시 우리나라 사람에게 보낸다면 우리나라의 원 단위는 정수형이므로 int형을 사용하면 되지만, 미국 사람에게 보낸다면 미국의 달러는 소수점까지 사용하므로 float형을 사용해야합니다. 이때 기억공간의 절약을 위해 택 1을 할 수 있는 이러한 상황에 사용하면 유용합니다.
#include <stdio.h>
typedef union{
int won;
float dollar;
}SendMoney;
int main(){
char country;
SendMoney money;
printf("어느 나라로 돈을 송금하시겠습니까?(한국 : K, 미국 : A) : ");
scanf("%c", &country);
if(country == 'K'){
printf("금액을 입력하세요. : ");
scanf("%d", &money.won);
printf("%d원을 송금하였습니다.", money.won);
}
else if(country == 'A'){
printf("금액을 입력하세요. : ");
scanf("%f", &money.dollar);
printf("%7.2f달러를 송금하였습니다.", money.dollar);
}
else{
printf("잘못 입력하셨습니다. 다시 시도해주세요.");
return 1;
}
return 0;
}
어느 나라로 돈을 송금하시겠습니까?(한국 : K, 미국 : A) : K
금액을 입력하세요. : 500
500원을 송금하였습니다.
어느 나라로 돈을 송금하시겠습니까?(한국 : K, 미국 : A) : A
금액을 입력하세요. : 433.7
433.70달러를 송금하였습니다.
어느 나라로 돈을 송금하시겠습니까?(한국 : K, 미국 : A) : U
잘못 입력하셨습니다. 다시 시도해주세요.
위의 예시는 송금하는 나라에 따라 int형이 필요한지, float형이 필요한지 나뉘기때문에 기억공간의 효율적 사용을 위해 공용체를 사용는게 좋습니다.
#include <stdio.h>
typedef union
{
char c;
int i;
long l;
float f;
double d;
} UNION;
int main(){
UNION Union;
int c, i, l, f, d, u;
c = sizeof(char);
i = sizeof(int);
l = sizeof(long);
f = sizeof(float);
d = sizeof(double);
u = sizeof(Union);
printf("sizeof char : %d\n", c);
printf("sizeof int : %d\n", i);
printf("sizeof long : %d\n", l);
printf("sizeof float : %d\n", f);
printf("sizeof double : %d\n", d);
printf("sizeof union : %d\n", u);
}
sizeof char : 1
sizeof int : 4
sizeof long : 4
sizeof float : 4
sizeof double : 8
sizeof union : 8
공용체는 가장 큰 기억공간을 갖는 멤버의 기억공간 크기를 갖습니다.
따라서 위의 예시에서는 가장 큰 기억공간을 갖는 멤버인 double형에 따라 8byte가 할당된 것을 알 수 있습니다.