00 개요
- 목적: C 언어에서 사용되는 구조체 이해하기
자료형 | ||
기초 자료형 Primary |
파생 자료형 Derived |
사용자-정의 자료형 User-Defined |
int / unsigned int short / unsigned short long / unsigned long char / unsigned char float double long double void ... |
function (함수) array (배열) pointer (포인터) reference (참조) |
class struct (구조체) union (공용체) typedef enum (열거형) |
- 동일한 종류의 데이터를 하나로 묶을 경우 배열을 사용했지만 (int numbers[5] = { 2, 5, 3, 7, 1 };), 다른 종류의 데이터(int, double, char, etc.)를 하나로 묶을 경우 구조체 사용
01 구조체란
1. 정의
- 여러 개의 변수(다른 데이터 종류 가능)들을 묶어서 새로운 자료형을 만들 수 있는 자료형
- 배열과 차이: 배열은 자료형이 같은 자료들을 하나로 묶는 반면 구조체는 자료형이 달라도 묶을 수 있음
2. 문법
- NOTE: 관례상 구조체이름(tag) 앞에 _(underslash) 또는 tag_ 또는 tag를 붙여줌
1) 구조체 선언
struct student {
int num;
char name[10];
double grade;
};
- 용어
- struct = student의 keyword
- student = tag
- { 내용 } = 내용은 struct member
- 구조체를 선언했다고 해서 변수 선언이 되지는 않음
- 구조체 선언은 구조체 안에 어떤 변수가 들어간다만 정의하는 틀 → 데이터를 저장할 수 있는 상태는 아님
- 구조체를 함수 밖에서 생성 시 전체 함수에서 사용할 수 있는 구조체를 선언함; 구조체를 함수 안에서 생성 시 그 함수 안에서만 사용하는 구조체를 선언함
2) 구조체 변수 선언
- 구조체 변수 선언 방법은 함수 안에서 선언함
- 여러 개 변수를 선언하려면 ',' (콤마 연산자)로 분리하여 선언 가능
struct student {
int num;
char name[10];
double grade;
};
int main(void) {
struct student s1; // 구조체 변수 (s1) 선언
struct student s2; // 구조체 변수 (s2) 선언
struct student s3,s4,s5; // 구조체 변수 (s3, s4, s5) 선언
}
4) 구조체 정의 및 선언 (동시 실행)
- 구조체를 정의만 하는 것과 차이: 끝에 구조체명 (s1) 추가
struct student {
int num;
char name[10];
double grade;
} s1; // s1 추가
5) 구조체 변수 초기화
- 구조체가 앞서 선언되어있을 경우만 사용
- 구조체 멤버가 선언된 순서대로 넣고 각 멤버의 자료형에 맞게 넣어야 됨
- NOTE: 중간에 어느 한 멤버 생략 불가능
struct student s1 = {24, "Kim", 4.3};
6) 구조체 변수 선언 및 초기화 (동시 실행)
- '{ }' (중괄호) 안에 '.' (멤버 연산자)와 멤버이름을 적고 값 할당
- 이 방법 사용 시 원하는 멤버 변수만 초기화 가능
- 멤버 변수가 정의된 순서와 초기화 순서는 상관 없으며, 초기화하지 않은 멤버 변수는 0으로 초기화됨
struct 구조체이름 구조체변수이름 = { .멤버이름1 = 값1, .멤버이름2 = 값2 ... }
struct student s1 = { .num = 21012345, .name = "김세종", .grade = 3.5 };
7) 구조체 참조
- 구조체변수.구조체멤버 사용하여 참조 가능
- NOTE: char name[10]은 문자 배열이라서 strcpy_s() 함수 사용 필수
s1.grade = 3.0;
strcpy_s(s1.name, 20, "Kim");
// strcpy(s1.name, "Kim"); // strcpy()는 strcpy_s()의 옛 버전
- s1: 구조체 변수
- grade, name: 구조체 멤버
8) 이름 없는 구조체
- 이름 없어도 되나 이름이 없을 경우 변수 생성 불가, 필요한 구조체 변수를 정의와 함께 선언 필수
struct {
int num;
char name[10];
double grade;
} s1, s2, s3;
- 여기서 s4를 함수 안에서 초기화하려면 위와 같은 구조체를 한 번 더 선언해야 함
9) 구조체를 멤버로 가지는 구조체
struct date{
int year;
int month;
int day;
};
struct student{
int num;
char name[10];
struct date dob; // date of birth
double grade;
};
- struct date dob는 구조체 안에 구조체가 들어가 있는 구조
- 이렇게 선언된 구조체를 초기화 하려면 다음과 같이 초기화 가능
s1.dob.year = 1983;
s1.dob.month = 03;
s1.dob.day = 29;
- s1에 있는 dob 안에 있는 year, month, day를 초기화 할 때 이렇게 씀
02 구조체 활용
1. 구조체와 배열
1) 구조체 안에 배열 생성
- 구조체 안에 배열 선언 가능
- 구조체를 여러 개 이어 만든 배열 생성 가능
struct 구조체이름 변수이름[크기];
struct student list[100]; // 구조체 배열 100개 생성
- 예시
#include <stdio.h>
#include <string.h>
struct student {
int num;
char name[20];
double grade;
};
int main(void) {
struct student arr[3]; // 크기가 3인 구조체 배열 생성
int i;
// 인덱스로 요소에 접근 후 .으로 멤버에 접근
arr[0].num = 21012345;
strcpy_s(arr[0].name, 20, "Kim");
arr[0].grade = 3.5;
arr[1].num = 21012346;
strcpy_s(arr[1].name, 20, "Park");
arr[1].grade = 4.0;
arr[2].num = 21012347;
strcpy_s(arr[2].name, 20, "Lee");
arr[2].grade = 2.7;
for (i = 0; i < 3; i++)
{
printf("학번: %d\n", arr[i].num);
printf("이름: %s\n", arr[i].name);
printf("학점: %.2f\n", arr[i].grade);
printf("\n");
}
return 0;
}
- output
2) 배열 안에 있는 구조체 초기화
list[2].num = 24;
strcpy(list[2].name = "홍길동"); // 문자열 저장은 항상 strcpy()를 이용
list[2].grade = 4.3;
3) 구조체 배열 초기화
struct 구조체이름 변수이름[크기] = {
{값1, 값2, 값3}
{값4, 값5, 값6}
{값7, 값8, 값9}
};
// 예시
struct student list[3] = {
{1, "Park", 3.42}
{2, "Kim", 4.31}
{3, "Lee", 2.98}
};
4) 구조체 배열 선언 및 초기화 (동시 실행)
struct 구조체이름 변수이름[크기] = {
{.멤버이름1 = 값1, .멤버이름2 = 값2 ...},
{.멤버이름1 = 값3, .멤버이름2 = 값4 ...},
{.멤버이름1 = 값5, .멤버이름2 = 값6 ...},
...
};
// 예시
struct student arr[3] = {
{ .num = 21012345, .name = "Kwon", .grade = 3.5 },
{ .num = 21012346, .name = "Hwang", .grade = 2.5 },
{ .num = 21012347, .name = "Hong", .grade = 4.5 }
};
2. 구조체와 포인터
- 포인터: 메모리의 주소값을 저장하는 변수
- 구조체 포인터: 구조체의 메모리 주소값을 저장하는 변수 (구조체를 가리키는 포인터)
- 구조체 포인터 변수도 일반 포인터 변수와 동일하게 변수이름 앞에 *를 붙여 선언
struct 구조체이름 * 구조체포인터;
1) 구조체 포인터 사용하여 구조체 멤버에 접근 방법 2가지
- * (참조 연산자) 사용
- -> (화살펴 연산자) 사용
1-1) * 사용
- NOTE: * (참조 연산자)는 . (멤버 연산자)보다 연산자 우선순위가 낮으므로 반듣시 ( ) (괄호)를 사용함
(*구조체포인터).멤버변수이름
- 예시
#include <stdio.h>
struct student{
int num;
char name[20];
double grade;
};
main(){
struct student s1 = {21012345, "Ahn", 4.0};
struct student * p = &s1;
printf("학번: %d\n", (*p).num);
printf("이름: %s\n", (*p).name);
printf("학점: %.2f\n", (*p).grade);
}
- output
1-2) -> 사용
구조체포인터 -> 멤버변수이름
- 예시
#include <stdio.h>
struct student{
int num;
char name[20];
double grade;
};
main() {
struct student s1 = {501, "Shin", 3.5};
struct student * p = &s1;
printf("학번: %d\n", p -> num);
printf("이름: %s\n", p -> name);
printf("학점: %.2f\n", p -> grade);
}
- output
2) 구조체에 쓰이는 포인터 2가지
- 구조체를 가리키는 포인터 (i.e., 구조체 포인터)
- 포인터를 멤버로 가지는 구조체
2-1) 구조체를 가리키는 포인터
- 변수에도 포인터 생성 가능하듯이 구조체에도 포인터 생성 가능
#include <stdio.h>
struct student {
int num;
char name[20];
double grade;
};
main() {
struct student s = { 24, "Kim", 4.3 };
struct student* p;
p = &s;
printf("학번 = %d 이름 = %s 학점 = %f \n", (*p).num, (*p).name, (*p).grade);
// 포인터를 통해 구조체에 접근함. (*p)가 구조체가 됨
}
- output
- *p가 구조체 전체를 가리키고 '.' (점) 뒤에 멤버를 붙여 사용
- 구조체 변수와 구조체 포인터의 조합:
구조체 수식 | 의미 |
(*p).number | 포인터 p가 가리키는 구조체의 멤버 number |
p->number | (*p).number와 동일 |
*p.number | 연산자의 우선순위에 의해 *(p.number)로 해석함 "구조체 p의 멤버 number가 가르키는 것"으로 해석함 이 때 number는 반드시 포인터여야 함, 아니면 error 발생 |
*p->number | 연산자의 우선순위에 의해 *(p->number)로 해석함 "p가 가르키는 구조체의 멤버 number가 가르키는내용"으로 해석함 이 때 number는 반드시 포인터여야 함, 아니면 error 발생 |
2-2) 포인터를 멤버로 가지는 구조체
- 구조체 안에서도 포인터 선언 가능
struct date{
int month;
int day;
int year;
};
struct student{
int num;
char name[20];
double grade;
struct date *dob; // 구조체 안에 포인터가 들어감
};
int main(void){
struct date d = {3, 20, 1990};
struct student s = {20190001, "Kim", 4.3};
s.dob = &d; // 포인터 dob에 구조체 d의 주소를 저장
}
- s.dob -> day 입력 시 dob에 있는 주소를 가지고 date 안에 있는 day값을 출력함
참조
'C' 카테고리의 다른 글
Declaration vs Definition (선언과 정의) (0) | 2024.06.24 |
---|---|
typedef (자료형 별칭 부여 키워드) (0) | 2024.06.21 |
strcpy() strcpy_s() (문자열 복사 함수) (0) | 2024.06.21 |
sizeof() 연산자 (0) | 2024.06.21 |
전처리기 (Preprocessor, Precompiler) (0) | 2024.06.19 |