C언어 - 구조체

Jocy·2022년 5월 2일
0
post-thumbnail

1. 구조체란?

하나 이상의 변수를 묶어서 좀 더 편리하게 사용할 수 있도록 도와주는 도구

구조체를 사용하지 않는다면 저정된 정보들을 저장하기 위해서 일일이 하나하나 변수를 선언해야 합니다.
배열로 만드는 방법이 있지만 배열은 같은 자료형으로만 묶을 수 있기 때문
다른 자료형을 가진 변수들은 따로 선언을 해줘야하고 관리하기에도 까다로워서 비효율적입니다.

이럴 때 구조체를 사용하면 편리하게 여러개의 변수를 사용하고 관리할 수 있습니다.

구조체의 구조

struct 구조체 이름 { 구조체 멤버들 };

중괄호{} 뒤에 ;를 붙여줘야 합니다. 사용할 변수들은 안에 묶어서 적어주는데
이 변수들을 구조체 멤버 라고 합니다.

struct student jungle { 구조체 멤버들 };

라고 한다면 jungle의 자료형student 구조체가 되는 것입니다.
선언 후에는 구조체 멤버를 사용합니다. 변수이름.구조체 멤버 이름 과 같은 형태로 작성하면 됩니다.

구조체 멤버의 초기화

#include <stdio.h>

struct student
{
	int age;
	char phone_number[14];
	int s_id;
};

int main()
{
	struct student jungle = { .age = 31, .phone_number = "010-8765-4321", 20 };
	struct student jocy = { 33, "010-1234-5678"};

	printf("나이 : %d, 번호 : %s, id : %d\n", jungle.age, jungle.phone_number, jungle.s_id);
	printf("나이 : %d, 번호 : %s, id : %d\n", jocy.age, jocy.phone_number, jocy.s_id);

	return 0;
}

초기화 할 때에는 깂을 입력 해주려면 {.멤버이름 = 값}과 같은 형태로 초기화 할 수 있습니다.
멤버이름 입력하지 않으면 구조체를 정의했던 순서로 값이 들어갑니다.
값을 넣어주지 않은 멤버는 0으로 초기화 됩니다.

2. typedef를 이용한 구조체 선언

구조체를 선언할 때 조금 더 편리한 방법이 있습니다.
typedef 키워드를 사용하는 것 입니다. 해당 방법을 사용하면 구조체 이름을 생략할 수 있습니다.

구조체 이름을 생략하지 않고 typedef 사용하는 방법

#include <stdio.h>

typedef struct _Student {
	int age;
	char phone_number[14];
} Student;

int main(){
	Student jungle;
	
	printf("나이 : ");
	scanf("%d", &jungle.age);
	printf("번호 : ");
	scanf("%s", jungle.phone_number); // & 없는 이유 구조체 변수와 첫번째 구조체 멤버의 주소값은 같다
 	
	printf("----\n나이 : %d\n번호 : %s\n----", jungle.age, jungle.phone_number);
	
	return 0;
}

typedef 키워드는 C언어에서 자료형을 새롭게 이름을 붙일 때 쓰는 키워드 입니다.
typedef 를 이용하면 main 함수에서 구조체를 선언할 때 매번 struct를 써줄 필요가 없습니다.
typedef 를 사용할 때 구조체 별칭이 필요한데, 구조체 별칭은 구조체를 정의할 때 중괄호 뒤에 써주면 됩니다.
이렇게 사용하면 main 함수에 struct [구조체이름]을 써줄 필요 없이 별칭만 써도 구조체 선언이 가능합니다.
구조체 이름과 별칭을 둘다 쓸 때는 구조체 이름 앞에 _를 붙여줍니다.

익명 구조체

typedef struct {
	int age;
	char phone_number[14];
} Student;

이전에 사용한 구조체의 일부중에 구조체의 이름 _Student 이 빠진 것을 볼 수 있습니다.
이렇게 구조체 이름을 적지 않고 별칭만 사용하는 것을 익명 구조체라고 합니다.

구조체 배열

학생 정보를 저장하는 구조체를 만들면 많은 정보를 저장할 때 편리합니다.

#include <stdio.h>

typedef struct {
	char name[30];
	int age;
} Student;

int main(){
	Student Hogwarts[3] = { 
    	{.name = "해리 포터"}, 
        {.name = "헤르미온느 그레인저"}, 
        {.name = "론 위즐리"} 
    };
	
	Hogwarts[0].age = 10;
	Hogwarts[1].age = 10;
	Hogwarts[2].age = 10;
	
	printf("이름 : %s / 나이 : %d\n", Hogwarts[0].name, Hogwarts[0].age);
	printf("이름 : %s / 나이 : %d\n", Hogwarts[1].name, Hogwarts[1].age);
	printf("이름 : %s / 나이 : %d\n", Hogwarts[2].name, Hogwarts[2].age);
    
    // 출력문
    // 이름 : 해리 포터 / 나이 : 10
    // 이름 : 헤르미온느 그레인저 / 나이 : 10
    // 이름 : 론 위즐리 / 나이 : 10
	
	return 0;
}

구조체문자열은 선언할 때만 초기화 할 수 있으므로 먼저 선언과 동시에 초기화 해주고,
나이는 선언 후에 값을 대입합니다.

구조체 포인터

구조체를 가리키는 포인터를 구조체 포인터라고 합니다.

구조체는 struct [구조체 이름]이 자료형이라고 설명한 적이 있습니다.
따라서 구조체 포인터는 sturct [구조체이름] *ptr 과 같이 선언해야 합니다.

#include <stdio.h>

typedef struct {
	int s_id;
	int age;
} Student;

int main(){
	Student jungle;
	Student *ptr;
	
	ptr = &jungle;
	
	(*ptr).s_id = 1004; // 괄호를 사용하는 방식
	*ptr->age = 20; // 화살표를 사용하는 방식
    
	
	printf("jungle의 학번 : %d, 나이: %d\n", jungle.s_id, jungle.age);
}

구조체 포인터를 이용해서 값을 대입하고, 그 값을 이용할 수 있습니다.
주의해야 될 점은 *ptr.age처럼 바로 사용하는 것이 아니라 (*ptr).age 와 같이 괄호를 사용해줘야 합니다. .연산자의 일종이라 포인터 변수를 구조체처럼 참조하려고 하기 떄문에 오류가 발생합니다.

괄호를 사용하지 않으려면 -> 화살표를 이용해 *ptr->age 같이 사용할 수 있습니다.

중첩 구조체

중첩 구조체는 구조체 안에 구조체를 선언할 수 있는 것을 말합니다.

 #include <stdio.h>

typedef struct {
	char name[15];
	int age;
} Teacher;

typedef struct {
	char name[15];
	int age;
	Teacher teacher; 
} Student;

int main(){
	Student Student;
	Teacher Teacher;
	
	Student.teacher.age = 30;
	Teacher.age = 40;
	
	return 0;
}

Student안에 Teacher 구조체를 이용하고 싶으면 Student.teacher.age와 같이 연속적으로 멤버를 참조해야 사용할 수 있습니다. 물론 Teacher 구조체만 따로 선언해서 사용할 수도 있습니다.

자기 참조 구조체

구조체는 자기 자신을 참조하도록 구조체를 가질 수 있습니다.

typedef struct {
	char name[15];
	int age;
	struct Student *ptr; 
} Student;

연결 리스트트리 와 같은 자료구조에서 나오는 내용 입니다.

구조체 전달

구조체를 인자로 전달할 때 포인터로 전달, 구조체 그대로 전달 두가지의 방법이 있습니다.

구조체는 여러가지 자료형을 묶어서 새로운 자료형을 만든 것이기 때문에 포인터를 사용하지 않고 넘겨주면 구조체의 크기가 커질 수록 복사할 공간이 많이 필요하게되어 비효율적인 코드가 됩니다.
매개변수로 구조체를 전달할 때는 보통 포인터를 사용합니다. 값을 바꿀 필요가 없을 경우에도 마찬가지 입니다.

구조체 그대로 전달

#include <stdio.h>

typedef struct {
	int s_id;
	int age;
} Student;

void print_student(Student s){
	s.s_id = 2000;
	s.age = 25;
	
	printf("학번 : %d, 나이 : %d\n", s.s_id, s.age);
}

int main(){
	Student s;

	s.s_id = 1000;
	s.age = 20;
	
	print_student(s); // 학번 : 2000, 나이 : 25
    
	printf("학번 : %d, 나이: %d\n", s.s_id, s.age); // 학번 : 1000, 나이 : 20
}

print_student 함수 내에서는 바뀐 값이 출력 되었지만
main 함수에서의 값은 바뀌지 않았기 때문에 원래의 값이 출력 되었습니다.

포인터로 전달

#include <stdio.h>

typedef struct {
	int s_id;
	int age;
} Student;

void print_student(Student *s){
	s->s_id = 2000;
	s->age = 25;
	
	printf("학번 : %d, 나이 : %d\n", s->s_id, s->age);
}

int main(){
	Student s;

	s.s_id = 1000;
	s.age = 20;
	
	print_student(&s); // 학번 : 2000, 나이 : 25
    
	printf("학번 : %d, 나이: %d\n", s.s_id, s.age); // 학번 : 2000, 나이 : 25
}
profile
Software Engineer

0개의 댓글