C언어) 구조체와 typedef

Lapis0875·2022년 10월 22일
0

c언어

목록 보기
6/21
post-thumbnail

😎사용자 정의형

사용자 정의형이란, 기본 자료형 이외에 사용자가 직접 정의하는 데이터 형을 말해요.

  • 배열
  • 구조체
  • 공용체
  • 열거형

등이 사용자 정의형에 해당해요.

💡구조체

구조체는 서로 다른 형의 변수들을 하나의 단위로 묶을 수 있는 방법이에요. 예를들어, 학생의 정보를 저장할 때 학생의 학번, 이름, 학과 등의 정보를 묶어 학생이라는 한개의 단위로 취급할 수 있어요.

구조체의 선언

구조체는 아래와 같이 선언해요.

struct student
{
	int id;
    char name[10];
    char major[20];
}

struct 키워드를 사용해, 구조체를 만들 수 있어요.
위 예시에서, student는 구조체의 이름이에요.
id, name, major는 이 구조체의 멤버에요.
이렇게 선언한 구조체는 변수를 선언한 것이 아니라, struct student 라는 자료형을 선언한것이에요. 자료형이 오는 자리에 사용할 수 있어요.

struct student stu1, stu2;

구조체의 크기

이 구조체의 크기는 몇 바이트일까요?
구조체의 크기도 sizeof를 사용해 계산할 수 있지만, 각 멤버의 크기를 합해서도 계산할 수 있어요.
student 구조체의 경우, 메모리의 크기는 아래와 같아요.

멤버명맴버 크기
id4
name10
major20
--------
총합34

구조체의 사용

구조체 변수의 경우, 같은 구조체 형의 변수끼리만 값을 재정할 수 있어요.

struct student stu1, stu2;
stu1 = 10;		// 오류
stu1 = stu2;	// 가능

구조체 멤버의 경우, .을 사용해 접근할 수 있어요.

stu1.id = 201030;
strcpy(stu2.name, "홍길동");

다양한 구조체 선언방법

구조체 변수는 선언과 동시에도 변수를 선언할 수 있어요.

struct student
{
	int id;
	char name[10];
    char major[20];
} stu3;
struct student stu4;

이외에도, 구조체의 이름을 정하지 않은 채 선언할 수 있어요.

struct
{
	int id;
    char name[10];
    char major[20];
} stu5;

struct
{
	int id;
    char name[10];
    char major[20];
} stu6;

이 경우, stu5와 stu6은 같은 멤버로 구성되지만 다른 구조체 형으로 취급돼요. 따라서, stu5 = stu6 은 오류가 발생해요.

구조체의 초기화

구조체는 배열과 유사한 방식으로 초기화해요.

// 멤버 순서대로 초기화돼요.
struct student stu = {201030, "홍길동", "컴퓨터학부"};
// stu.id = 201030, stu.name = "홍길동", stu.major = "컴퓨터학부"

C99 이상부터, .연산자를 사용해 멤버를 지정하여 초기화 할 수 있어요.

struct student stu = {.name = "홍길동", .id = 201030, .major = "컴퓨터학부"};

복합 리터럴을 사용해서 구조체 멤버의 값을 배정할 수도 있어요.
복헙 리터럴은 캐스트를 사용해 형을 지정해요.

stu = (struct student) {201030, "홍길동", "컴퓨터학부"};
// 복합 리터럴 내부에서도 멤버를 지정해 초기화할 수 있어요.
stu = (struct student) {.name = "홍길동"};

구조체 멤버

구조체의 멤버로 다른 구조체가 올 수 있어요.

struct student
{
	char name[20];
    char major[20];
}
struct professor
{
	char name[20];
}
struct subject
{
	char name[20];
    struct professor prof;
    struct student student;
}

struct subject math;
math.professor.name = "홍길동";

구조체 포인터

구조체도 포인터로 가리킬 수 있어요.

struct student stu, *stu_p;
stu_p = &stu;

구조체의 포인터는 포인터와 동일하게 사용해요. 멤버에 바로 접근하지 못하고, 역참조 연산자를 통해 구조체를 가져와 멤버에 접근해야 해요.

stu_p.grade = 88;		// 오류 : stu_p는 포인터.
*stu_p.grade = 88;		// 오류 : stu_p.grade에 역참조 연산자 사용.
(*stu_p).grade = 88;	// 올바른 사용.

하지만, -> 연산자를 사용하면 구조체 포인터에서 바로 멤버에 접근할 수 있어요.

stu_p->grade = 88;

구조체 배열

구조체 배열은 일반적인 자료형들의 배열과 동일하게 사용해요.

struct student students[3];

구조체 배열을 초기화 하는 것 또한 동일해요. 단지 요소로 구조체의 초기화 구문을 쓸 뿐이에요.

students[3] = {{111111, "홍길동", "컴퓨터학부"}, {222222, "이몽룡", "국문학과"}, {333333, "이춘향", "철학과"}}; 

C99부터는 이렇게도 초기화 할 수 있어요.

students[3] = {
    [1] = {222222, "이몽룡", "국문학과"},
    [2] = {333333, "이춘향", "철학과"}
};

C99의 구조체 초기화 구문이랑 같이 사용할 수 있어요.

students[3] = {
	[1].id = 111111, [1].name = "홍길동", [1].major = "컴퓨터학부"
};

구조체와 함수

함수의 인자로 구조체가 전달될 때, 구조체는 값으로 전달돼요. 하지만, 구조체가 많은 멤버를 가지거나, 큰 배열을 멤버로 가질 경우 함수 인자로 구조체를 전달하는 것은 비효율적이에요.
따라서, 대부분의 프로그램에서는 함수의 인자로 구조체의 주소를 사용해요.

🔑typedef

typedef 키워드는 기존의 자료형으로부터 유도한 새로운 자료형을 만들기 위해 사용돼요. 일반적인 사용 방법은 4가지로 나눌 수 있어요.

typedef type_name new_type;
typedef type_name * new_type;						// 포인터 타입
typedef type_name new_type[size];					// 배열 타입
typedef type_name (*new_type)(parameter_type_list);	// 함수 포인터 타입

type_name은 기존에 알려진 자료형이고, new_type은 새로운 자료형의 이름이에요.

1. 일반 자료형 선언

typedef type_name new_type;

위 형태의 자료형 선언에 대해 알아볼게요. 대표적인 예시로 size_t형이 있어요. C표준에 따르면, size_t형은 부호가 없는 정수형이라 되어 있어요. 컴파일러는 아래와 같이 선언해 사용해요.

typedef unsigned int size_t

구조체 변수 등을 만들 때, 매번 struct student처럼 길게 쓰는게 불편할 때도 typedef를 사용할 수 있어요.

typedef struct student Student;

Student stu;

아예 구조체를 만들 때 typedef를 사용할 수도 있어요.

typedef struct
{
	int id;
    char name[10];
    char major[20];
} Student;

2. 포인터 형 선언

typedef type_name * new_type;

위와 같이 선언하면, type_name의 포인터 형을 만들 수 있어요.
간단한 예시로, int*형을 표현해보면 아래와 같아요.

typedef int *intptr;

intptr은 int형의 포인터 타입이에요.

3. 배열 형 선언

typedef type_name new_type[size];

위와 같이 선언하면 type_name형의 길이가 size인 배열 형을 만들 수 있어요.
예를 들어, 길이 10의 int형 배열에 대한 자료형을 만들어보면 아래와 같아요.

typedef int intarr[10];

4. 함수 포인터 형 선언

typedef return_type (*new_type)(parameter_type_list);

함수 포인터에 대한 자료형 선언이에요. 함수 포인터를 선언할 때, 자료형 부분을 아래와 같이 적었었어요.

int sum(int, int);

int (*f)(int, int) = sum;

여기서, int (*f)(int, int) 부분을 typedef로 선언하는거에요.
위 예시의 sum 함수에 대한 포인터 타입을 만들어보자면 아래와 같아요.

typedef int (*int_f)(int, int);

배운 내용들을 정리해보고 있어요. 잘못 기재된 내용이 있다면, 댓글로 지적해주시면 수정할게요.

profile
새내기 대학생 개발자에요 :D

0개의 댓글