1. 구조체 개요
1) 구조체(Structure)
- 의미상 관계가 있는 항목을 그룹으로 묶어 표현한 자료형
- 구조체는 int, char와 같이 변수의 모양을 의미
- 차이는 int, char는 기본적으로 정해져 있는 기본 자료형이고,
구조체는 사용자가 용도에 맞게 만들어 사용하는 사용자 자료형이다.
- 구조체를 구성하는 변수들을 멤버라고 부름
2. 구조체 정의, 선언, 사용
1) 구조체 정의
- 자료형을 정의하는 것 - 변수 선언과는 다른 개념
- struct 라는 키워드를 사용
- 일반적인 구조체 정의 형식
>> 형식
struct 구조체자료형이름{
멤버자료형 멤버변수;
멤버자료형 멤버변수;
...
}; // 세미콜론
>> 예시
struct student{
int id;
char name[8];
double grade;
};
- 정의만 해서는 메모리에 공간이 할당되지 않음
2) 구조체 사용
- 일반적인 변수 선언과 동일한 형태
- 자료형 변수명;
- 구조체에서는 'struct 구조체자료형이름' 이 통채로 자료형을 나타냄
struct student st1, st2; // 구조체 변수 선언
- 변수 선언을 해야 비로소 메모리에 공간이 할당됨
- 구조체 변수 자체는 메모리 공간을 따로 가지지 않고, 멤버들의 메모리로 구성됨
3) 구조체 변수 초기화
- 다른 초기화와 유사하게 중괄호 안에 멤버 변수 순서대로 초기화 값 나열
>> 예시
struct student st1 = {10, "Tom", 3.2};
4) 멤버변수 사용
- 구조체 멤버 연산자 (.) 사용 : 구조체변수.멤버변수
- 비교) 구조체 변수는 멤버변수 전체를 나타냄
- 멤버변수의 자료형에 의해 사용방법이 결정됨
- int형 멤버 변수 id는 일반적인 int 변수를 사용하는 것과 동일한 방식으로 사용
>> 예시
stuct student st1, st2;
st1.id = 10;
st1.id = st1.id * 2;
printf("id: %d, st1.id);
5) 구조체 정의와 선언의 다양한 형태
(1) 자료형 정의와 변수 선언을 따로 (가장 일반적 형태)
struct student{ // 구조체 자료형 정의
int id; char name[8]; double grade;
};
void main(){
struct student st1; // 지역 변수 st1 선언
}
(2) 자료형 정의와 변수 선언을 동시에
struct student{ // 구조체 자료형 정의
int id; char name[8]; double grade;
} st; // 전역 변수 st 선언
void main(){
struct student st1; // 지역 변수 st1 선언
}
- 정의 선언과 동시에 초기화도 가능
struct student{ // 구조체 자료형 정의
int id; char name[8]; double grade;
} st = {10, "Tom", 3.2}; // 전역 변수 st 선언 및 초기화
(3) 구조체 자료형 이름 생략 가능
- 다만, 자료형 이름이 없으므로, 다른 곳에서 선언 불가능
struct { // 구조체 자료형 정의 (이름 없음)
int id; char name[8]; double grade;
} st; // 전역 변수 st 선언(가능)
(4) 구조체 자료형을 함수 안에서 정의
- 정의한 함수 안에서만 사용 가능
void main(){
struct student{ // 구조체 자료형 정의 (함수 안)
int id; char name[8]; double grade;
};
struct student st1; // 구조체 변수 st1 선언
}
6) 구조체에 사용 가능한 연산자
- 구조체는 사용자가 만든 자료형이기 때문에
기본 자료형인 int, char, double 등에 비해 사용가능한 연산자가 제한적임
- 산술연산, 비교연산은 지원 안 됨
- 대입연산자(=), 주소연산자(&), 간접참조연산자(*), sizeof 연산자 등등.. 은 사용 가능
7) 구조체 변수의 대입 연산
- 모든 멤버 변수에 대해, 대입 연산이 수행됨
>>예시
struct student st1 = {10, "Tom", 3.2};
struct student st2;
st2 = st1; // 가능
8) 구조체에 할당되는 메모리 크기
- 구조체 크기는 구조체 멤버의 크기의 합이 아닐 수도 있다
- sizeof 연산자를 통해 구조체의 크기를 이용하자
3. 구조체 배열
- 구조체가 배열, 포인터, 함수등과 결합되어 확장될 수 있음
1) 구조체 배열
- 구조체가 원소로 사용된 배열
- 단, 구조체끼리의 묶음만 허용
- 선언, 접근, 초기화 등 구조체 배열에 대한 문법
- 일반 배열과 동일
2) 구조체 배열 선언과 접근: [] 사용
struct student ast[3];
ast[0].id = 10;
strcpy(ast[0].name, "Tom");
ast[0].grade = 3.2;
3) 구조체 배열 초기화 : 중괄호 {} 사용
- 생략된 부분은 0으로 초기화
int i;
struct student ast[3]
= { {10, "Tom", 3.2},
{20, "Alice"} };
// 생략된 부분은 모두 0으로 초기화
4. 구조체 포인터
1) 구조체 포인터
- 구조체 변수를 가리키는 포인터
- 구조체 변수의 시작주소가 저장
- 기본적인 사용법은 일반적인 포인터와 동일
- 다만, 구조체 포인터에서만 사용하는 표현법 존재
2) 구조체 포인터 변수 선언 및 연결
- 일반 포인터 선언과 동일: * 사용
- 주소연산자(&): 구조체 변수의 시작 주소
>>예시
struct student st1 = {10, "Tom", 3.2};
struct student *pst;
pst = &st1;
3) 간접 연산자(*)를 이용한 구조체 변수 접근
struct student st1 = {10, "Tom", 3.2}, st2;
struct student *pst = &st1;
st2 = *pst; // st2에 pst가 가리키는 구조체 변수를 대입
4) 간접 참조를 이용한 구조체 변수의 멤버 접근
(1) 방법 1: (*pst).id
- 포인터가 가리키는 변수에 접근하기 위해 간접연산자* 사용
- 구조체의 멤버에 접근하기 위해 멤버연산자. 사용
- *보다 .의 우선순위가 높기 때문에 괄호 반드시 필요
(2) 방법 2: pst->id
- 구조체 포인터에서만 사용하는 전용 연산자: ->
- 주로 이 연산자를 사용
5) 구조체 포인터 배열
- 구조체 포인터가 원소인 배열
>>예시
struct student st1 = {10, "Tom", 3.2}, st2;
struct student *past[3] = {&st1, &st2};
past[2] = past[1]; // 주소 값 대입: past[2]도 st2를 가리킴
*past[2] = *past[0]; // past[2]가 가리키는 구조체에 past[0]이 가리키는 구조체 대입
5. 구조체와 함수
1) 구조체를 함수의 인자로 사용
- 실인자의 값이 형식인자에 대입됨
- 구조체 변수라고 달라지는 건 없음
>> 예시
void print(struct student st) {
printf("id: %d\n", st.id);
printf("name: %s\n", st.name);
printf("grade: %.2f\n", st.grade);
}
2) 구조체를 함수의 반환형으로 사용
- 구조체 전체 값이 통째로 호출함수에게 전달됨
>> 예시
struct student init(){
struct student st = {0, "", 0};
return st;
}
3) 구조체 포인터를 함수 인자로 사용
- 실인자의 값이 형식이자에 대입됨
>>예시
void init_p(struct student *pst){
pst->id = 0;
pst->name[0] = '\0';
pst->grade = 0.0;
}
4) 구조체 주소를 반환하는 함수
- 일반 변수의 주소 반환과 동일
>>예시
struct student *next_addr(struct student *pst){
return pst+1;
}
5) 함수 호출 총정리
- 함수 인자나 반환 값의 자료형에 관계없이 함수 호출 과정은 동일
- 함수 호출 시에는 전달된 값을 형식인자에 대입
- 함수 종료 시에는 리턴 값이 통째로 호출함수에 전달
- 결론: 자료형마다 따로 외우려 하지 말고 원리 이해가 중요
6. 중첩 구조체 및 자기참조 구조체
1) 중첩 구조체(nested structure)
- 다른 구조체가 구조체의 멤버로 사용
>>예시
struct address{ // 구조체 address 정의
int zipcode; char *city;
};
struct student{ // 구조체 student 정의
int id; char name[8]; double grade;
struct address addr; // 멤버 addr의 자료형은 struct address
};
2) 중첩 구조체 주의사항
- 자신과 동일한 구조체 자료형은 멤버로 사용될 수 없음
- 자기자신을 정의하기 위해 자기 자신이 필요함 >> 순환 오류
7. typedef 사용자형 정의
1) 사용자형 정의
- typedef문을 이용하여 자료형의 이름을 새로 정의할 수 있음
typedef int INT; // INT 자료형 정의
typedef struct student STUDENT; // STUDENT 형 정의
'프로그래밍 언어 개념정리 > C언어 개념 정리' 카테고리의 다른 글
C언어 개념 정리: 연산자/함수/자료형 심화 (0) | 2024.11.21 |
---|---|
C언어 개념 정리: 동적 할당 (0) | 2024.11.18 |
C언어 개념 정리: 문자열 (1) | 2024.11.13 |
C언어 개념 정리: 포인터 (0) | 2024.11.12 |
C언어 개념 정리: 디버깅 기초 (1) | 2024.11.11 |