C언어 (15) 구조체와 공용체
새로운 자료 구조인 구조체와 공용체, 열거형까지 알아보자.
구조체
배열이 타입이 같은 데이터를 하나로 묶는다면 구조체는 타입이 다른 데이터도 묶을 수 있다.
학생의 정보를 저장한다고 할 때 이름, 나이, 점수를 하나로 묶어 저장할 수 있으면 편할 것이다.
이런 여러개의 변수를 그룹화하여 새로운 자료형으로 만드는 것이 구조체이다.
구조체의 정의
우선 구조체를 만들려면 struct (구조체 이름)형태로 만든다.
그 다음 중괄호 안에는 구조체의 멤버 변수가 들어가고 마지막에는 ;(세미 콜론)가 필요하다.
1
2
3
4
struct point {
int x;
int y;
};
이렇게 정수형 x, y 좌표를 가진 구조체를 만들 수 있다.
구조체의 정의는 자료형을 새로 만드는 것과 같다고 생각하면 이해하기 편하다.
자료형을 만들었으면 그 자료형으로 변수를 선언해줘야 할 것이다.
구조체 변수의 선언과 사용
우선 구조체 변수를 선언하는 방법은 2가지가 있다.
1
2
3
4
5
#include <stdio.h>
struct point {
int x;
int y;
} p1, p2;
이렇게 구조체를 정의하면서 구조체 변수 p1, p2를 선언할 수도 있고,
1
2
3
4
5
6
7
8
9
#include <stdio.h>
struct point {
int x;
int y;
};
int main() {
struct point p1, p2;
return 0;
}
이렇게 구조체를 정의하고 따로 선언을 해줄 수도 있다.
새롭게 만든 struct point라는 자료형으로 변수를 선언해주는 것이다.
이 구조체 안의 변수를 멤버 변수라고 부르는데, 구조체 변수로 멤버 변수에 접근해보자.
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
struct point {
int x;
int y;
};
int main() {
struct point p1, p2;
p1.x = 10;
p1.y = 20;
printf("p1의 x좌표 : %d y좌표 : %d", p1.x, p1.y);
return 0;
}
.연산자를 이용해서 (구조체 변수).(멤버 변수)의 방법으로 각각에 접근할 수 있다.
나머지 사용은 변수를 사용하듯이 쓰면 된다.
구조체 변수의 초기화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct fish {
int weight;
double price;
};
int main() {
struct fish f1;
scanf("%d", &f1.weight);
f1.price = f1.weight * 84.5;
printf("f1의 무게 : %d 가격 : %lf\n", f1.weight, f1.price);
struct fish f2 = { 100, 9860.5 };
printf("f2의 무게 : %d 가격 : %lf\n", f2.weight, f2.price);
return 0;
}
f2를 초기화하는 것처럼 선언과 동시에 중괄호를 통해 값을 넣을 수 있다.
선언과 따로 중괄호에 초기화 하는 방법도 있다.
1
2
struct fish f2;
f2 = (struct fish){ 100, 9860.5 };
이렇게 형변환을 해주듯이 값 앞에 구조체를 앞에 써주면 값을 넣어줄 수 있다.
1
2
3
4
struct fish {
int weight = 0; // 에러
double price = 2.5; // 에러
};
구조체의 정의 안에서 멤버 변수를 초기화하는 것을 불가능하니 주의하자.
구조체의 복사
같은 구조체 타입을 가졌다면 변수를 복사할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
struct fish {
int weight;
double price;
};
int main() {
struct fish f1 = { 100, 9860.5 };
struct fish f2;
f2 = f1;
printf("f1의 무게 : %d 가격 : %lf\n", f1.weight, f1.price);
printf("f2의 무게 : %d 가격 : %lf\n", f2.weight, f2.price);
return 0;
}
이렇게 f2 = f1을 통해 f1의 값을 f2로 복사할 수 있다.
하지만 멤버 변수들의 자료형이 같더라도 구조체 이름이 다르면 복사할 수 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
struct fish {
int weight;
double price;
};
struct co {
int a;
double d;
};
int main() {
struct fish f1 = { 100, 9860.5 };
struct co c;
c = f1; // 에러 발생
printf("f1의 무게 : %d 가격 : %lf\n", f1.weight, f1.price);
return 0;
}
멤버 변수의 자료형들은 같지만 c는 struct co 구조체, f1은 struct fish 구조체 변수이므로 값을 넣을 수 없다.
그러면 같은 구조체 변수 간에 더하기나 뺄셈 같은 연산이 가능할까?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
struct fish {
int weight;
double price;
};
int main() {
struct fish f1 = { 100, 9860.5 };
struct fish f2 = { 80, 8890.2 };
f1 + f2; // 에러 발생
f1 - f2; // 에러 발생
printf("f1의 무게 : %d 가격 : %lf\n", f1.weight, f1.price);
printf("f2의 무게 : %d 가격 : %lf\n", f2.weight, f2.price);
return 0;
}
이는 불가능하다. 구조체 변수들은 사용자가 만든 자료형이기 때문에 이런 연산을 할 수 없다.
1
2
3
4
5
struct fish f1 = { 100, 9860.5 };
struct fish f2 = { 80, 8890.2 };
if(f1==f2){ // 에러 발생
printf("같습니다.\n");
}
같이 구조체를 비교하는 것 역시 안된다.
중첩 구조체
중첩 구조체란 구조체 안의 멤버 변수로 구조체가 들어있는 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
struct score {
int math;
int eng;
};
struct student {
int no;
struct score s;
};
int main() {
struct student st1;
struct student st2 = { 2, {90, 95} };
st1.s.math = 100;
st1.s.eng = 97;
st1.no = 1;
printf("학번 : %d 수학 : %d 영어 : %d\n", st1.no, st1.s.math, st1.s.eng);
printf("학번 : %d 수학 : %d 영어 : %d", st2.no, st2.s.math, st2.s.eng);
return 0;
}
초기화 방법은 struct student st2 = { 2, {90, 95} }; 처럼 구조체안의 구조체를 초기화하려면
중괄호를 한번 더 해서 초기화해줘야 한다.
각각에 접근하는 방법도, student의 score에 접근하니 st1.s 후 score의 멤버 변수에 접근한다.
그렇기에 st1.s.math, st1.s.eng 처럼 각각의 변수에 접근할 수 있다.
typedef
typedef는 자료형에 새로운 이름을 지어주는 키워드다.
구조체 변수를 선언할 때 struct (구조체 이름)을 다 적는 것은 너무 길다.
그 때 typedef struct score SCORE라는 코드를 적으면 SCORE은 struct score과 같은 의미를 가진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
typedef struct score {
int math;
int eng;
} SCORE;
struct student {
int no;
SCORE s;
};
int main() {
typedef struct student STU;
STU st1;
STU st2 = { 2, {90, 95} };
st1.s.math = 100;
st1.s.eng = 97;
st1.no = 1;
printf("학번 : %d 수학 : %d 영어 : %d\n", st1.no, st1.s.math, st1.s.eng);
printf("학번 : %d 수학 : %d 영어 : %d", st2.no, st2.s.math, st2.s.eng);
return 0;
}
typedef도 사용 방법이 두 가지가 있는데 struct score에 한 것처럼 정의를 하며 typedfef를 같이 쓴 뒤
구조체 맨 뒤에 재정의할 이름을 적는다.
두 번째 방법은 정의한 후 typedef struct student STU; 처럼 이름을 바꿀 수 있다.
이제 구조체 변수를 선언할 때 struct ~ 가 아니라 재정의한 짧은 이름으로 선언할 수 있다.
구조체의 메모리, 변수, 포인터, 함수 관련한 사용법에 대해 더 알아보자.