구조체 활용

이지우·2022년 11월 9일
0

C언어

목록 보기
14/17

구조체 포인터

구조체 변수의 주소는 구조체 포인터에 저장하며 구조체 변수 전체를 가리킨다. (구조체 멤버 X)
☞ 구조체 변수의 주소를 구하면 멤버의 주소가 아니라 구조체 변수 전체의 주소가 구해진다.

# include <stdio.h>

struct score
{
	int kor;		// 국어 점수
    int eng;		// 영어 점수
    int math;		// 수학 점수
};

int main()
{
	struct score yuni = { 90, 80, 70 };		// 구조체 변수 선언과 초기화
    struct score *ps = &yuni;				// 구조체 포인터에 주소 저장
    
    printf("국어 : %d\n", (*ps).kor);		// 구조체 포인터로 멤버 접근
    printf("영어 : %d\n", ps -> eng);		// -> 연산자 사용
    printf("수학 : %d\n", ps -> math);
}

-> 연산자를 사용하여 구조체의 멤버에 쉽게 접근할 수 있다.

(*ps).kor   →   ps -> kor
(*ps).eng	→	ps -> eng
(*ps).math	→	ps -> math

구조체 배열

같은 형태의 구조체 변수가 많이 필요하면 배열로 선언하여 사용할 수 있다.

#include <stdio.h>

struct address
{
	char name[20];	// 이름
    int age;		// 나이
    char tel[20];	// 전화번호
    char addr[80];	// 주소
};

int main()
{
	struct address list[5] = {	// 요소가 5개인 구조체 배열 선언
    	{"홍길동", 23, "111-1111", "울릉도 독도"},
        {"이순신", 35, "222-2222", "서울 건천동"},
        {"장보고", 19, "333-3333", "완도 청해진"},
        {"유관순", 15, "444-4444", "충남 천안"},
        {"안중근", 45, "555-5555", "황해도 해주"}
    };
    int i;
    
    // 배열 요소 수만큼 반복
    for(i = 0; i < 5; i++)
    {
    	printf("%10s %5d %15s %20s\n", 
        	list[i].name, list[i].age, list[i].tel, list[i].addr);
    }
}

▼ 출력부분을 함수로 만들어 구조체 포인터로 다루기

#include <stdio.h>

struct address
{
	char name[20];	// 이름
    int age;		// 나이
    char tel[20];	// 전화번호
    char addr[80];	// 주소
};

// 각 배열 요소의 멤버 출력 함수
void print_list(struct address *lp)
{
	int i;
    
    // 배열 요소 수만큼 반복
    for(i = 0; i < 5; i++)
    {
    	printf("%10s %5d %15s %20s\n", 
        	(lp+i)->name, (lp+i)->age, (lp+i)->tel, (lp+i)->addr);
    }
}

int main()
{
	struct address list[5] = {	// 요소가 5개인 구조체 배열 선언
    	{"홍길동", 23, "111-1111", "울릉도 독도"},
        {"이순신", 35, "222-2222", "서울 건천동"},
        {"장보고", 19, "333-3333", "완도 청해진"},
        {"유관순", 15, "444-4444", "충남 천안"},
        {"안중근", 45, "555-5555", "황해도 해주"}
    };
    
    print_list(list);
}

함수의 매개변수는 구조체 포인터로 구조체 배열의 시작 주소를 가리키게 된다.

배열 표현	→	lp[i].name
포인터 표현	→	(*(lp+i)).name
->연산자 사용	→	(lp+i)->name

자기 참조 구조체

자기 참조 구조체는 자신의 구조체를 가리키는 포인터를 멤버로 가진다.

▼ 연결 리스트 예제

#include <stdio.h>

struct list
{
	int num;			// 데이터
    struct list *next;	// 구조체 자신을 가리키는 포인터 멤버
};

int main()
{
	struct list a = {10, 0}, b = {20, 0}, c = {30, 0};	// 구조체 변수 초기화
    struct list *head = &a, *current;	// 헤드 포인터 초기화
    
    a.next = &b;			// a의 포인터 멤버가 b를 가리킴
    b.next = &c;			// b의 포인터 멤버가 c를 가리킴
    
    printf("head->num : %d\n", head->num);	// head가 가리키는 a의 num 멤버 사용
    printf("head->next->num : %d\n", head->next->num);	// head로 b의 num 멤버 사용
    
    printf("list all : ");
    current = head;					 // 최초 current 포인터가 a를 가리킴
    while (current != NULL)			 // 마지막 구조체 변수까지 출력하면 반복 종료
    {
    	printf("%d	", current->num; // current가 가리키는 구조체 변수의 num 출력
        current = current->next;	 // current가 다음 구조체 변수를 가리키도록 함
    }
    printf("\n");
}


공용체

공용체는 구조체와 선언 방식이 비슷하지만 모든 멤버가 하나의 저장 공간을 같이 사용한다.

#include <stdio.h>

union student
{
	int num;		// 학번
    double grade;	// 학점
};

int main()
{
	union student s1 = { 315 };		// 공용체 변수 선언과 초기화
    
    printf("학번 : %d\n", s1.num);	// 학번 멤버 출력
    s1.grad = 4.4;					// 학점 멤버에 값 대입
    printf("학점 : %.1lf\n", s1.grade);
    printf("학번 : %d\n", s1.num);	// 학번 다시 출력
}

실행 결과 학번을 다시 출력했을 때 이상한 값이 출력된다.

  1. 공용체 변수의 크기는 멤버 중 크기가 가장 큰 멤버로 결정된다.
  2. 공용체 변수의 초기화는 중괄호를 사용하여 첫 번째 멤버만 초기화한다.
// 첫 번째 멤버가 아닌 멤버를 초기화할 때
union student a = { .grade = 4.3 };	// grade 멤버를 4.3으로 초기화

// 첫 번째 멤버만 초기화
union student a1 = { 315 };

여러 멤버가 하나의 저장 공간을 공유하므로 메모리를 절약할 수 있고 같은 공간에 저장된 값을 여러가지 형태로 사용할 수 있는 장점이 있다.


열거형

#include <stdio.h>

enum season {SPRING, SUMMER, FALL, WINTER};	// 열거형 선언

int main()
{
	enum season ss;		// 열거형 변수 선언
    char *pc = NULL;	// 문자열을 저장할 포인터
    
    ss = SPRING;		// 열거 멤버의 값 대입
    switch(ss)			// 열거 멤버 판단
    {
    case SPRING:			// 봄이면
    	pc = "inline";		// 인라인 문자열 선택
        break;
    case SUMMER:			// 여름이면   
    	pc = "swimming";	// 수영 문자열 선택
        break;
    case FALL:				// 가을이면
    	pc = "trip";		// 여행 문자열 선택
        break;
    case WINTER:			// 겨울이면
    	pc = "skiing";		// 스키 문자열 선택
        break;
    }
    printf("나의 레저 활동 => %s\n", pc);	// 선택된 문자열 출력
}

컴파일러는 멤버를 0부터 차례로 하나씩 큰 정수로 바꾼다.
☞ SPRING = 0 / SUMMER = 1 / FALL = 2 / WINTER = 3

원하는 값으로 설정할 수도 있다.

enum season {SPRING = 5, SUMMER, FALL = 10, WINTER};

이때 SUMMER와 WINTER은 이전 값의 하나 큰 정수로 바뀐다.


typedef를 사용한 형 재정의

typedef를 사용하면 자료형 이름에서 struct 같은 예약어를 생략할 수 있다.

#include <stdio.h>

struct student
{
	int num;
    double grade;
};

typedef struct student Student;		// Student형으로 재정의

void print_data(Student *ps)		// 매개변수는 Student형의 포인터
{
	printf("학번 : %d\n", ps -> num);		// Student 포인터로 멤버 접근
    printf("학점 : %.1lf\n", ps -> grade);
}

int main()
{
	Student s1 = { 315, 4.2 };
    
    print_data(&s1);
}

재정의 하기 전의 자료형을 굳이 사용할 필요가 없으면 형 선언과 동시에 재정의할 수 있다.

typedef struct		// 재정의될 것이므로 구조체 이름 생략
{
	int num;
    double grade;
} Student;			// 재정의된 자료형 이름
profile
노력형 인간

0개의 댓글