UNIT 48 구조체 사용하기
48.0 구조체 사용하기
C 언어는 자료를 체계적으로 관리하기 위해 구조체라는 문법을 제공.
구조체는 struct 키워드로 정의하며 data structure(자료 구조)의 약어.
다음은 인적 정보를 표현한 구조체인데 struct Person은 Person 구조체를 정의한다는 뜻.
struct Person {
char name[20]; //이름
int age; //나이
char address[100]; //주소
};
Person 구조체를 사용하여 변수를 만들어내면 인적 정보를 손쉽게 추가할 수 있고, 구조체 자체도 배열로 만들면 10명이든 100명이든 인적 정보를 체계적으로 관리할 수 있음.
구조체는 관련 정보를 하나의 의미로 묶을 때 사용함. 특히 목적에 맞는 자료형을 만들어서 사용하는데 기본 자료형을 조합하여 만든 자료형을 파생형(derived type)이라 함.
48.1 구조체 만들고 사용하기
구조체는 struct 키워드로 정의함.
struct 구조체이름 {
자료형 멤버이름;
};
구조체는 정의만 해서는 사용 할 수 없음. 따라서 구조체도 변수로 선언해서 사용함.
-struct 구조체이름 변수이름;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Person {
char name[20]; //구조체 멤버 1
int age; //구조체 멤버 2
char address[100]; //구조체 멤버 3
};
int main()
{
struct Person p1; //구조체 변수 선언
//점으로 구조체 멤버에 접근하여 값 할당
strcpy(p1.name, "홍길동"); //strcpy(대상문자열, 원본문자열);
p1.age = 30;
strcpy(p1.address, "서울시 용산구 한남동");
//점으로 구조체 멤버에 접근하여 값 출력
printf("이름 : %s\n", p1.name); // 이름 : 홍길동
printf("나이 : %d\n", p1.age); // 나이 : 30
printf("주소 : %s\n", p1.address); //주소 : 서울시 용산구 한남동
return 0;
}
구조체는 보통 main 함수 바깥에 정의. 만약 함수 안에 구조체를 정의하면 해당 함수 안에서만 구조체를 사용할 수 있음.
지금까지 구조체 정의와 선언을 따로 했음. 닫는 중괄호와 세미콜론 사이에 변수를 지정해주면 구조체를 정의하는 동시에 변수를 선언할 수 있음.
struct 구조체이름 {
자료형 멤버이름;
} 변수;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Person {
char name[20]; //구조체 멤버 1
int age; //구조체 멤버 2
char address[100]; //구조체 멤버 3
} p1; //구조체를 정의하는 동시에 변수 p1 선언, 변수 뒤에만 ;
int main()
{
//점으로 구조체 멤버에 접근하여 값 할당
strcpy(p1.name, "홍길동"); //strcpy(대상문자열, 원본문자열);
p1.age = 30;
strcpy(p1.address, "서울시 용산구 한남동");
//점으로 구조체 멤버에 접근하여 값 출력
printf("이름 : %s\n", p1.name); // 이름 : 홍길동
printf("나이 : %d\n", p1.age); // 나이 : 30
printf("주소 : %s\n", p1.address); //주소 : 서울시 용산구 한남동
return 0;
}
참고 ) p1은 전역변수
자세히 보면 구조체 변수 p1 main 함수 바깥에 선언되어 있음. 이렇게 어떤 함수에도 속해있지 않은 변수를 전역 변수라고 함.
참고 ) 구조체 변수를 선언하는 동시에 초기화 하기
구조체 변수를 선언하는 동시에 값을 초기화하려면 중괄호 안에 . (점)과 멤버 이름을 적고 값을 할당.
struct 구조체이름 변수이름 = { .멤버이름1 = 값1, .멤버이름2 = 값2 };
멤버 이름과 할당 연산자 없이 값만 콤마로 구분하여 나열해도 됩니다. 단, 이 때는 구조체 멤버가 선언된 순서대로 넣고, 각 멤버의 자료형에 맞게 넣습니다. 즉, 처음부터 순서대로 값을 채워 넣어야 하며 중간에 있는 멤버만 값을 할당하거나, 중간에 있는 멤버만 생략할 수는 없습니다.
struct 구조체이름 변수이름 = { 값1, 값2 };
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Person {
char name[20]; //구조체 멤버 1
int age; //구조체 멤버 2
char address[100]; //구조체 멤버 3
};
int main()
{
struct Person p1 = { .name = "홍길동", .age = 30, .address = "서울시 용산구 한남동" };
printf("이름 : %s\n", p1.name);
printf("나이 : %d\n", p1.age);
printf("주소 : %s\n", p1.address);
struct Person p2 = { "고길동", 40, "서울시 서초구 반포동" };
printf("이름 : %s\n", p2.name);
printf("나이 : %d\n", p2.age);
printf("주소 : %s\n", p2.address);
return 0;
}
48.2 typedef로 struct 키워드 없이 구조체 선언하기
struct 키워드를 생략하려면 typeof로 구조체를 정의하면서 별칭(alias)를 지정해주면 됨.
typedef struct 구조체이름 {
자료형 멤버이름;
} 구조체 별칭;
구조체 이름과 구조체 별칭은 겹쳐도 됨. ( 예시에서는 구조체 이름을 _구조체 이름처럼 앞에 _를 붙일거임)
typeof로 구조체 별칭을 만들었다면 변수는 다음과 같이 선언
- 구조체별칭 변수이름;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
typedef struct _Person {
char name[20]; //구조체 멤버 1
int age; //구조체 멤버 2
char address[100]; //구조체 멤버 3
}Person; //typedef를 사용하여 구조체 별칭을 Person으로 정의
int main()
{
Person p1; //구조체 별칭 Person으로 변수 선언
//점으로 구조체 멤버에 접근하여 값 할당
strcpy(p1.name, "홍길동");
p1.age = 30;
strcpy(p1.address, "서울시 용산구 한남동");
//점으로 구조체 멤버에 접근하여 값 출력
printf("이름 : %s\n", p1.name);
printf("나이 : %d\n", p1.age);
printf("주소 : %s\n", p1.address);
return 0;
}
구조체 별칭을 사용하지 않고 구조체 이름으로 변수를 선언하고 싶다면 struct 키워드에 구조체 이름으로 변수를 선언하면 됨. struct _Person p1; 과 Person p1;은 완전히 같음.
struct _Person p1; //구조체 이름으로 변수 선언
참고) typedef 활용하기
typedef는 자료형의 별칭을 만드는 기능입니다. 따라서 구조체뿐만 아니라 모든 자료형의 별칭을 만들 수 있습니다.
- typedef 자료형 별칭
- typedef 자료형* 별칭
다음은 int를 별칭 MYINT, int 포인터를 별칭 PMYINT로 정의하는 예제입니다(보통 포인터 별칭은 포인터라는 의미로 앞에 P를 붙임). 별칭으로 변수와 포인터 변수를 선언한다는 점만 다를 뿐 사용 방법은 일반 변수, 포인터와 같습니다.
typedef int MYINT; //int를 별칭 MYINT로 정의
typedef int *PMYINT; //int 포인터를 별칭 PMYINT로 정의
MYINT num1; //MYINT로 변수 선언
PMYINT numPtr1; //PMYINT로 포인터 변수 선언
numPtr1 = &num1; //포인터에 변수의 주소 저장
//사용방법은 일반변수, 포인터와 같음
이처럼 typedef로 정의한 별칭을 사용자 정의 자료형, 사용자 정의 타입이라 부릅니다.
여기서 PMYINT는 안에 *가 이미 포함되어 있으므로 포인터 변수를 선언할 때 *를 붙여버리면 이중 포인터가 되므로 사용에 주의해야 합니다.
PMYINT *numPtr1; // PMYINT에는 *가 이미 포함되어 있어서 이중 포인터가 선언됨
int* *numPtr2; // PMYINT *와 같은 의미. 이중 포인터
참고) 구조체 태그
struct 뒤에 붙는 구조체 이름은 원래 구조체 태그(tag)라 부릅니다(나중에 배울 공용체, 열거형도 마찬가지로 공용체 태그, 열거형 태그라 부릅니다). 그리고 typedef로 정의한 구조체 별칭은 사용자 정의 타입의 이름이라 할 수 있습니다.
struct 태그 {
자료형 멤버이름;
};
typedef struct 태그 {
자료형 멤버이름;
} 타입이름;
C 언어는 나온지가 오래되다 보니 여러 가지 관습이 남아 있는데 구조체 태그와 타입 이름을 구분하기 위해 관례상 태그 앞에 _, tag_, tag를 붙이고 있습니다. 코드에 따라서 태그 뒤에 _t를 붙이기도 합니다.
- 예) _Person, tag_Person, tagPerson, Person_t
구조체 태그와 타입 이름은 사실상 같은 구조체를 지칭하므로 이름을 완전히 다르게 지을 필요는 없습니다. 요즘은 구조체 태그와 타입 이름을 똑같이 만들기도 합니다.
typedef struct Person { // 구조체 이름은 Person
char name[20];
int age;
char address[100];
} Person; // typedef로 정의한 타입 이름도 Person
이때는 구조체 변수를 struct Person p1;과 같이 선언해도 되고 Person p1;과 같이 선언해도 됩니다.
48.3 익명 구조체 사용하기
익명 구조체(anonymous structure)를 사용하면 구조체 이름을 지정하지 않아도 됨. 즉, typedef로 구조체를 정의하면서 이름을 생략할 수 있음. 단, 이때는 반드시 구조체 별칭을 지정해줘야함
typedef struct {
자료형 멤버이름;
} 구조체별칭;
변수는 구조체 별칭으로 선언하면 됨
- 구조체 별칭 변수이름;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
typedef struct { //구조체 이름이 없는 익명 구조체
char name[20]; //구조체 멤버 1
int age; //구조체 멤버 2
char address[100]; //구조체 멤버 3
}Person; //typedef를 사용하여 구조체 별칭을 Person으로 정의
int main()
{
Person p1; //구조체 별칭 Person으로 변수 선언
//점으로 구조체 멤버에 접근하여 값 할당
strcpy(p1.name, "홍길동");
p1.age = 30;
strcpy(p1.address, "서울시 용산구 한남동");
//점으로 구조체 멤버에 접근하여 값 출력
printf("이름 : %s\n", p1.name);
printf("나이 : %d\n", p1.age);
printf("주소 : %s\n", p1.address);
return 0;
}