구조체와 공용체

코딩하는 기린·2022년 3월 6일
0

C

목록 보기
11/13

구조체

'구조체(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

'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가 할당된 것을 알 수 있습니다.

profile
Coding Giraffe.

0개의 댓글